Skip to content

fix(kotlin): resolve qualified supertype to its tail type name#1793

Open
Synvoya wants to merge 1 commit into
Graphify-Labs:v8from
Synvoya:fix/kotlin-qualified-supertype
Open

fix(kotlin): resolve qualified supertype to its tail type name#1793
Synvoya wants to merge 1 commit into
Graphify-Labs:v8from
Synvoya:fix/kotlin-qualified-supertype

Conversation

@Synvoya

@Synvoya Synvoya commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Bug

A Kotlin class with a qualified supertype resolves its heritage edge to the package root instead of the type. class Foo : com.example.Base() emits Foo --inherits--> com instead of Foo --inherits--> Base, collapsing every qualified base/interface onto a bogus com node.

Root cause

_kotlin_user_type_name returned the first identifier child of a user_type node. The tree-sitter-kotlin grammar stores a qualified name as flat identifier children:

user_type "com.example.Base"
  identifier "com"
  .
  identifier "example"
  .
  identifier "Base"

So the walker returned com.

Minimal repro

class Foo : com.example.Base(), com.example.Iface

Before: inherits {(Foo, com)}, implements {(Foo, com)}.

Fix

Scan the direct children and keep the last identifier/type_identifier segment. Type arguments live in a separate type_arguments child (not an identifier), so generics like com.ex.Container<String> correctly resolve to Container. This mirrors the existing C++ qualified-base handling that uses the unqualified tail. Simple (Base) and delegated (Bar by baz) supertypes are unaffected — a single-segment user_type still returns that segment.

After the fix:

  • Foo --inherits--> Base
  • Foo --implements--> Iface

Testing

  • Added test_kotlin_qualified_supertype_uses_tail_name to tests/test_languages.py. Fails before, passes after.
  • tests/test_languages.py: 315 passed, 13 skipped — the existing Kotlin simple-supertype and interface-delegation tests still pass.

_kotlin_user_type_name returned the first identifier child of a user_type
node. For a qualified supertype like `com.example.Base` the Kotlin grammar
stores the segments as flat identifier children (com, example, Base), so
the walker returned the package root `com` instead of `Base`, collapsing
every qualified base/interface onto a bogus `com` node.

Scan the direct children and keep the last identifier/type_identifier
segment (type arguments live in a separate type_arguments child, so
generics are ignored). Mirrors the C++ qualified-base handling that uses
the unqualified tail.

Adds a regression test for `class Foo : com.example.Base(), com.example.Iface`.
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.

1 participant