Skip to content

fix(kotlin-extractor): collect members declared in enum class bodies#446

Open
tirth8205 wants to merge 2 commits into
Egonex-AI:mainfrom
tirth8205:fix/kotlin-extractor-enum-class-body
Open

fix(kotlin-extractor): collect members declared in enum class bodies#446
tirth8205 wants to merge 2 commits into
Egonex-AI:mainfrom
tirth8205:fix/kotlin-extractor-enum-class-body

Conversation

@tirth8205

Copy link
Copy Markdown
Contributor

Problem

An enum class body is parsed by tree-sitter as an enum_class_body node, not class_body. extractClassDeclaration in kotlin-extractor.ts only looked up findChild(declNode, "class_body"), which returns null for an enum class, so collectClassBody was never invoked.

As a result, every method and property declared inside an enum class body was silently dropped:

  • not added to the class's methods[]
  • not added to the top-level functions[]
  • not added to exports[]

For example, enum class Direction { NORTH, SOUTH; fun opposite(): Direction = NORTH } yielded classes: [{ name: "Direction", methods: [], properties: [] }] and functions: [] — the opposite method vanished entirely. (Enum primary-constructor val/var properties still worked, since those come from primary_constructor, not the body.)

Fix

Look up either body variant before collecting members:

const body =
  findChild(declNode, "class_body") ??
  findChild(declNode, "enum_class_body");

collectClassBody already only reacts to function_declaration / property_declaration / object_declaration children, so the enum_entry children of an enum body are harmlessly ignored — no other change is needed.

Testing

  • Added a test collects methods declared inside an enum class body to kotlin-extractor.test.ts. It fails before the fix (expected [] to include 'opposite') and passes after.
  • The full core test suite is green: 693 passed.
  • Typecheck (tsc --noEmit) exits 0 and ESLint on both changed files exits 0.

🤖 Generated with Claude Code

An `enum class` body is parsed by tree-sitter as an `enum_class_body`
node, not `class_body`. extractClassDeclaration only looked up
`class_body`, which returns null for an enum class, so collectClassBody
was never invoked. Every method/property declared inside an enum class
body was silently dropped from the class's methods[], the top-level
functions[], and exports[].

Fix: look up either body variant before collecting members
(`findChild(declNode, "class_body") ?? findChild(declNode,
"enum_class_body")`). collectClassBody already only reacts to
function_declaration / property_declaration / object_declaration
children, so the enum_entry children are harmlessly ignored.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@thejesh23 thejesh23 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1. Enum constants themselves are not surfaced as members.
collectClassBody only reacts to function_declaration / property_declaration / object_declaration, so enum_entry children (NORTH, SOUTH) are silently dropped. For a fix targeted at enum bodies, omitting the entries themselves is the larger gap — they're the canonical "members" of an enum and would be the natural thing to land in properties[] (parallels the val/var primary-constructor handling). My in-flight Dart PR #435 will hit the same modeling question for enum_constant_declaration.

2. Companion object inside an enum body is not exercised.
object_declaration is handled, but companion_object is a distinct node type in tree-sitter-kotlin and won't match. An enum class with companion object { fun create(): Direction = NORTH } likely still loses create. Worth a test, and a separate findChild(body, "companion_object") branch if confirmed.

3. Test gap: properties and export are not asserted.
The new test only checks classes[0].methods and functions. It does not assert result.exports contains opposite (the default-public path through isExported is the actual regression surface), nor that the enum entries appear anywhere. Consider adding both, plus a private fun case to lock down visibility.

Nit: the comment "enum class body is parsed as enum_class_body" is the load-bearing fact — worth linking the tree-sitter-kotlin grammar node name in the comment so the next maintainer doesn't have to re-derive it.

…odies

collectClassBody now handles `companion_object` (its own tree-sitter-kotlin
node, not a subtype of object_declaration) by recursing into its class_body
so companion functions/properties surface in methods[]/functions[]/exports[],
and surfaces `enum_entry` constants as exported properties. Also names the
grammar source in the enum_class_body comment.

Adds tests for companion methods (class + enum bodies), enum-constant
properties/exports, body-level default-public exports, and the private-fun
negative export path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@tirth8205

Copy link
Copy Markdown
Contributor Author

All four points addressed in 78e5da4. Node shapes were confirmed against the real tree-sitter-kotlin parse tree before implementing.

1. Enum constants now surfaced. enum_entry is a direct named child of enum_class_body, each carrying its name as an identifier child. collectClassBody now pushes each entry into properties[] and exports[] (enum constants are always public). Test: surfaces enum constants (enum_entry) as properties asserts both NORTH/SOUTH in properties and in exports.

2. Companion object handled. Confirmed companion_object is its own node type — a sibling of class_member_declaration, not a subtype of object_declaration — so it never matched the existing branch. Added an else if (member.type === "companion_object") branch that surfaces the (optional) companion name as a property and recurses into its class_body, so companion functions like create land in methods[]/functions[]/exports[]. Tests cover a companion inside both a plain class body and an enum class body.

3. Export/visibility gap closed. The enum test now asserts exports contains the default-public body member opposite. Added a does NOT export a private function declared inside a class body test asserting a body-level private fun is excluded from exports while still appearing in the class's methods[].

Nit. The enum_class_body comment now names the grammar source (@tree-sitter-grammars/tree-sitter-kotlin, enum_class_body rule).

Full core suite green (697/697), tsc --noEmit clean.

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.

2 participants