Skip to content

fix(extractors): extract Kotlin annotations and constructor properties (#3835) - #3949

Open
hopstreax wants to merge 1 commit into
Graphify-Labs:v8from
hopstreax:fix/kotlin-annotations-properties-3835
Open

hopstreax wants to merge 1 commit into
Graphify-Labs:v8from
hopstreax:fix/kotlin-annotations-properties-3835

Conversation

@hopstreax

Copy link
Copy Markdown
Contributor

Summary

Fixes #3835 by restoring Kotlin annotation and property dependency extraction while preserving Graphify's existing class-level JVM graph model.

Changes

  • Extract Kotlin declaration annotations from classes, constructor properties, functions, and properties.
  • Support Kotlin use-site targets such as @get:Transient.
  • Support bracketed annotations such as @get:[Transient VisibleForTesting].
  • Extract annotation class literals such as Customer::class.
  • Restore field references for primary-constructor val/var properties.
  • Restore generic_arg references for generic constructor and class-body properties.
  • Handle annotations on property getters/setters.
  • Preserve the distinction between constructor properties and plain constructor parameters.
  • Avoid introducing Kotlin property/member nodes.

Tests

  • pytest tests/test_kotlin_grammar.py tests/test_kotlin_object_literal.py — 42 passed
  • pytest tests/test_languages.py -k "kotlin or java" — 46 passed
  • git diff --check — clean

Architectural Notes

This implementation intentionally uses Graphify's existing class-level dependency representation:

Order --references(context="field")--> Customer
Order --references(context="generic_arg")--> OrderLine
Order --references(context="attribute")--> ManyToOne
Order --references(context="attribute")--> Customer

It does not introduce Kotlin-specific property/member nodes, avoiding inconsistencies with the existing Java/Kotlin JVM graph model and type-resolution infrastructure.

@github-actions

Copy link
Copy Markdown

Thanks for the pull request, @hopstreax. A maintainer will review it soon.

Want to talk it through while it is in review? Come join us on our Discord server. For longer-form discussion there is also GitHub Discussions.

A couple of things that speed up review: make sure the test suite passes on Python 3.10 and 3.13, and that the change keeps extraction deterministic.

@graphify-labs graphify-labs Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.

Formal verification. No changes could be formally verified in this run.


Graphify review — findings

Extends Kotlin annotation handling for JPA-style code: _kotlin_annotation_names now also reads annotations on property getters and setters and dedupes repeated names. A new _kotlin_annotation_class_literal_refs adds references edges with context="attribute" for class literals in annotation arguments, such as Customer::class, skipping Kotlin and Java builtins. These edges are emitted for classes, properties, and primary-constructor val/var parameters, and constructor-parameter annotations now produce edges even when the parameter's type node isn't found.

Worth a look

  • Class-literal detection likely never matches Foo::class in the Kotlin grammar — graphify/extractors/engine.py:820 · Escalate · medium
    • agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 774 functions depend on the 299 functions this change touches.

Health — this change adds coupling hotspots:

  • new: _extract_generic() — 18 callers, 29 callees
  • new: extract_js() — 87 callers, 4 callees
  • new: extract_xaml() — 19 callers, 17 callees
  • new: extract_objc() — 27 callers, 9 callees
  • new: extract_julia() — 19 callers, 7 callees
  • new: extract_cpp() — 29 callers, 3 callees
  • new: extract_vue() — 10 callers, 7 callees
  • new: walk() — 1 callers, 65 callees
  • …and 9 more — each is listed as a finding

Verification — 774 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 711 function(s) in the blast radius were not formally verified this run

Test selection

Test selection

26 of 308 test file(s) selected (8%) via static blast radius.

  • tests/test_astro_extraction.py — impact
  • tests/test_build.py — impact
  • tests/test_cjs_module_extension.py — impact
  • tests/test_cpp_nested_and_cli.py — impact
  • tests/test_dotnet.py — impact
  • tests/test_extract.py — impact
  • tests/test_extract_php_closures.py — impact
  • tests/test_import_extension_resolution.py — impact
  • tests/test_indirect_call_block_scoped_shadow.py — impact
  • tests/test_indirect_dispatch.py — impact
  • tests/test_indirect_dispatch_assign_return.py — impact
  • tests/test_indirect_dispatch_getattr.py — impact
  • tests/test_js_exported_scalar_bindings.py — impact
  • tests/test_kotlin_grammar.py — impact, changed-test
  • tests/test_languages.py — impact
  • tests/test_multilang.py — impact
  • tests/test_python_underscore_resolution.py — impact
  • tests/test_rationale.py — impact
  • tests/test_ruby_resolution.py — impact
  • tests/test_scala_self_type.py — impact
  • tests/test_swift_computed_properties.py — impact
  • tests/test_swift_protocol_requirements.py — impact
  • tests/test_trailing_newline_not_a_syntax_error.py — impact
  • tests/test_ts_new_expression_calls.py — impact
  • tests/test_typescript_module_extensions.py — impact
  • tests/test_vue_extraction.py — impact

Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.

Formal verification

Could not verify: Could not verify \_extract\_generic.

The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: no capturable inputs from the test suite; property tier: parameter `config` is annotated `LanguageConfig` — outside the synthesizable primitive/collection set

Could not verify: Could not verify \_kotlin\_annotation\_names.

The verifier did not have enough to check \_kotlin\_annotation\_names, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: no capturable inputs from the test suite; property tier: not verifiable: all 200 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly AttributeError — names the real obstacle, not a sampling gap)

· 17 more finding(s) on lines outside this diff (see the check run).

@safishamsi

Copy link
Copy Markdown
Collaborator

Thanks @hopstreax. Heads-up that most of this PR's scope already landed on v8: #3848 (0.9.68) added Kotlin annotations (class/function/property, use-site targets, bracketed lists) as references/context=attribute edges and val/var primary-constructor properties as field refs, and #3915 (0.9.72) fixed the annotated-inferred-property UnboundLocalError. So the annotation + ctor-property extraction this PR describes is redundant now, and a cherry-pick would conflict heavily in the _kotlin_annotation_names / ctor-param region.

There is one genuinely net-new piece worth having on its own: annotation-argument class-literal extraction — mining X::class inside annotation arguments (e.g. @ManyToOne(targetEntity = Customer::class) -> Order --references(attribute)--> Customer) via your _kotlin_annotation_class_literal_refs helper. Nothing in v8 does that today, it's well-tested, and it correctly uses context=attribute, filters builtins, strips FQ prefixes, and de-dups.

Could you resubmit just that slice as a focused PR against current v8 (the ::class helper + its emit sites + test_kotlin_annotation_class_literal), dropping the now-redundant annotation/ctor refactor and its duplicate tests? That'll rebase cleanly and land easily. (Optional: if you can confirm the inferred-type ctor-param annotation case actually produces a different graph on current v8 — tree-sitter-kotlin tends to parse @Volatile var x = 0 in a ctor as an ERROR node — that hoist could come along too.) Marking changes-requested for now.

This branch has not been deployed

No deployments
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: annotations and primary-constructor properties are not extracted (JPA relationships lost)

2 participants