Skip to content

fix(kotlin): forbid enum case names equal to the enum type name#2999

Merged
schani merged 4 commits into
masterfrom
agent/fix-issue-1815
Jul 22, 2026
Merged

fix(kotlin): forbid enum case names equal to the enum type name#2999
schani merged 4 commits into
masterfrom
agent/fix-issue-1815

Conversation

@schani

@schani schani commented Jul 20, 2026

Copy link
Copy Markdown
Member

Bug

Kotlin enum-typed output could generate an invalid enum constant with the
same name as its enclosing enum class, e.g.:

enum class Category(val value: String) {
    Category(" "), // invalid: same name as the enum class itself
    Empty(" ");
    ...
}

This happens when a JSON string value with no identifier-safe characters
(e.g. whitespace-only or a NUL byte) legalizes to an empty name. quicktype's
naming falls back to Empty for such values, and when two case values
collide on that fallback, ConvenienceRenderer.makeNameForEnumCase proposes
an "alternative" name of the form ${enumCombinedName}_${caseName} to
disambiguate them. Kotlin's name-styling strips all non-identifier
characters from that alternative, so a value like "Category_ " collapses
down to just "Category" — colliding, silently, with the enum type's own
name.

Root cause

KotlinRenderer.forbiddenForEnumCases (in
packages/quicktype-core/src/language/Kotlin/KotlinRenderer.ts) didn't
forbid the enum's own type name from being reused as a case name, so nothing
caught this second-order collision.

Fix

KotlinRenderer.forbiddenForEnumCases now includes the enum's own Name in
its forbidden-names list, forcing the namer to keep looking for a
non-colliding alternative instead of silently reusing the enum's own name.
This follows the same pattern already used by CSharpRenderer for object
properties (forbiddenForObjectProperties forbids the class's own name).

Test coverage

Added test/inputs/json/priority/kotlin-enum-class-case-collision.json, a
JSON fixture (runs for every language, per priority/ fixture conventions)
with repeated whitespace-only and empty-string values for a category
property, enough to trigger quicktype's string-to-enum inference and
reproduce the exact class-name/case-name collision from the issue.

Verification

  • npm run build passes.
  • npm run test:unit passes (163/163).
  • Manually reproduced the bug on unfixed master via
    node dist/index.js --src <repro.json> --src-lang json --lang kotlin --framework jackson --top-level SomeClass,
    confirmed the generated enum class Category { Category(...), ... }
    collision, then confirmed after the fix the case is renamed (e.g. to
    Purple) instead of colliding with the class name.
  • Ran the new fixture through Jackson, Klaxon, and kotlinx-flavored Kotlin
    generation manually — all produce non-colliding case names.
  • QUICKTEST=true FIXTURE=python script/test passes (62/62), confirming the
    new shared JSON fixture doesn't break other languages.
  • The Kotlin fixture test itself (which compiles/runs the generated code)
    was not run locally because kotlinc/kotlin are not installed in this
    environment; CI will exercise FIXTURE=kotlin and the other Kotlin
    variants (kotlin-jackson, kotlinx) against the new fixture.

Fixes #1815.

🤖 Generated with Claude Code

schani and others added 4 commits July 20, 2026 17:15
Co-Authored-By: gpt-5.6-sol via pi <noreply@openai.com>
The new priority fixture kotlin-enum-class-case-collision.json is a
top-level JSON array, which the kotlinx renderer emits as
`typealias TopLevel = JsonArray<T>` — invalid Kotlin, since kotlinx's
JsonArray takes no type arguments. This is a pre-existing, documented
kotlinx limitation (see the ~40 existing top-level-array entries in this
same skipJSON block and the TODO in KotlinXRenderer.ts), unrelated to the
enum-naming fix in this PR.

The enum case/class name-collision fix lives in the shared KotlinRenderer
base class and remains covered by the kotlin (klaxon) and kotlin-jackson
fixture runs, which handle top-level arrays as `class TopLevel : ArrayList<T>`
and do run this fixture.

Co-Authored-By: Claude <noreply@anthropic.com>
#1815)

The new priority JSON input kotlin-enum-class-case-collision.json is a
top-level array. quicktype's TypeScript --just-types renderer collapses
a top-level array's element type onto the top-level name itself instead
of emitting an array alias, so the C# code generated from that
intermediate TypeScript expects a JSON object and throws when run
against the original array JSON. This is the same pre-existing
top-level-array limitation already covered by ~70 other entries in
skipTypeScriptTests; add this fixture alongside them.

Co-Authored-By: gpt-5.6-sol via pi <noreply@openai.com>
@schani
schani merged commit 1072d17 into master Jul 22, 2026
28 checks passed
@schani
schani deleted the agent/fix-issue-1815 branch July 22, 2026 01:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Kotlin enum class does not compile - enum value equal to enum name

1 participant