feat(extract): capture annotation arguments and add a Kotlin annotation collector - #3
Open
fredagenttasks[bot] wants to merge 2 commits into
Open
feat(extract): capture annotation arguments and add a Kotlin annotation collector#3fredagenttasks[bot] wants to merge 2 commits into
fredagenttasks[bot] wants to merge 2 commits into
Conversation
…on collector
Annotation collection kept only the name, so `@GetMapping("/orders/{id}")`
was indistinguishable from a bare marker and the route path — the thing that
makes the declaration an HTTP endpoint — never reached the graph. The
collected annotations are now attached to the declaration's node as
`metadata.annotations`, each with its arguments: a single positional argument
is keyed `value` to match the Java/Spring shorthand, and a symbolic argument
(`@Table(TableNames.ORDERS)`) is tagged `kind: "reference"` instead of being
dropped.
Kotlin had no annotation collector at all — `_kotlin_extra_walk` handled only
`enum_entry` — so a Kotlin Spring service yielded no annotation data of any
kind. It reads both shapes the grammar produces: the declaration's `modifiers`
child, and the preceding `annotated_expression` sibling chain that a class
declaring a primary constructor gets instead, which is the shape almost every
constructor-injected bean has. Kotlin also now emits the
`references`/`context="attribute"` edges Java already did.
Kotlin `const val NAME = <literal>` properties become nodes carrying
`metadata.const_value`, so a constant referenced from an annotation argument
can be resolved to the value it holds.
`_java_annotation_names` is preserved as a wrapper over the new
`_java_annotations`, leaving its two existing attribute-edge callers unchanged.
Co-authored-by: fred-agent <fred-agent@bizzabo.com>
julia-elikhis
approved these changes
Jul 31, 2026
…aphify-Labs#1965) Ports oleksii-tumanov's upstream fix (Graphify-Labs#1965) into this fork's extraction/type-resolution layer, extending the annotation-argument capture and Kotlin annotation collector added in this branch. - collect method-scoped Kotlin receiver types from class properties, constructor parameters, getter returns, and local constructor/getter bindings, threaded through walk_calls alongside the existing Graphify-Labs#2241 extra_locals plumbing - register a corpus-level kotlin_member_calls resolver (_resolve_kotlin_member_calls) that resolves a member call only when the receiver type and the selected method's owner are unambiguous, guarded by package/import scope, inheritance, extension-function dispatch, companion binding, and lexical shadowing - preserve existing Kotlin dispatch for super, object/companion-qualified calls, private visibility, and inner-class dispatch receivers This closes the receiver-typing gap tracked by Graphify-Labs#1965: a Kotlin Spring Controller -> Service -> Repository chain (constructor injection) now produces resolved calls edges end-to-end instead of 0, per the new test_controller_service_repository_chain_resolves_end_to_end. Co-authored-by: fred-agent <fred-agent@bizzabo.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part 1 of the Fred Long-Term Knowledge Architecture Proposal needs endpoint nodes, and an endpoint is a route path. graphify collected annotation names and threw the arguments away, so
@GetMapping("/api/orders/{id}")was indistinguishable from a bare marker. Kotlin was worse: it had no annotation collector at all.Targets
v8(this fork's default branch), notmain.What changed
1. Annotation arguments are captured (Java).
_java_annotation_names(engine.py:551-574) read onlychild_by_field_name("name"). It is now a thin wrapper over a new_java_annotations, which also reads theannotation_argument_list. Both existing attribute-edge callers (engine.py:2753, :3341) are unchanged.2. Kotlin gains an annotation collector.
_kotlin_extra_walkhandled onlyenum_entry. The new collector reads both shapes the grammar produces — and the second one is the important one:Spring constructor injection hits the first case, so a naive port of the Java collector returns nothing for essentially every real controller. A guard (
_kotlin_is_annotation_chain) requires the sibling to hold only annotations, so an unrelated annotated expression that merely precedes the class isn't misattributed to it.Kotlin also now emits the
references/context="attribute"edges Java already did.3. Kotlin
const valvalues.@Table(TableNames.REGISTRATION)is a reference, and the graph held no value for it —TableNameswas a node, its members were not.const val NAME = <literal>properties now emit nodes carryingmetadata.const_value.4. Kotlin member calls now resolve by receiver type, closing Graphify-Labs#1965. Ports upstream PR
Graphify-Labs/graphify#1965(oleksii-tumanov/graphify#fix/kotlin-typed-receiver-calls) into this fork's extraction/type-resolution layer:walk_callsalongside the existingextra_locals(False indirect_call edges (INFERRED 0.8): call arguments bind as callees to an unrelated single-letter test helper across files Graphify-Labs/graphify#2241) plumbingkotlin_member_callsresolver (_resolve_kotlin_member_calls) resolves a member call (a.b()) only when the receiver type and the selected method's owner are unambiguous, guarded by package/import scope, inheritance, extension-function dispatch, companion binding, and lexical shadowingsuper, object/companion-qualified calls, private visibility, and inner-class dispatch is preservedThis closes the gap called out below: a Kotlin Spring
Controller -> Service -> Repositorychain (constructor injection) now produces resolvedcallsedges end-to-end, verified bytest_controller_service_repository_chain_resolves_end_to_end.Emitted shape
{ "label": "RegistrationController", "metadata": { "annotations": [ {"name": "RestController", "args": []}, {"name": "RequestMapping", "args": [{"name": "value", "value": "/api/registration", "kind": "string"}]} ] } }A single positional argument is keyed
value, matching the Java/Spring shorthand that@GetMapping("/x")meansvalue = "/x". A symbolic argument is taggedkind: "reference"rather than silently reduced.sanitize_metadataalready round-trips nested lists, so no export change was needed.Measured
On a 26-file Kotlin corpus mirroring
bizzabo/registration's annotation census, 58 / 58 annotations and 4 / 4 constants are captured:Before this change, Kotlin emitted zero annotation data of any kind.
A Kotlin
Controller -> Service -> Repositoryconstructor-injection chain now yields 2/2 resolvedcallsedges (controller -> service, service -> repository) instead of the previous 0.Tests
tests/test_kotlin_annotations.py(12 cases across both grammar shapes, array args,@Table(CONST), and the negative case where an unrelated annotated expression precedes a class),tests/test_java_annotation_args.py(positional, named-pair,field_access, marker, plus a regression test that the existing attribute edges are unchanged), andtests/test_kotlin_member_calls.py(43 cases: the four typed-receiver shapes from Graphify-Labs#1699, ambiguity/shadowing guards, extension/companion/inheritance dispatch, cross-file package/import resolution, portable-AST-cache stability, and the new controller/service/repository chain).Full suite: 3686 passed. The remaining failures are pre-existing and environmental (
tree_sitter_hcl/openai/boto3not installed,AWS_PROFILE-driven ollama backend detection, wheel-payload) — verified identical on a clean checkout of this branch's prior commit.Previously known gap — now closed
Kotlin member calls still don't resolve, so the controller -> service -> repository chain does not close onv8: the same corpus yields 0callsedges. That is upstreamGraphify-Labs/graphify#1965, still open. This PR is orthogonal — it is what makes the endpoint and table nodes extractable.Closed by porting
Graphify-Labs/graphify#1965in the latest commit (see item 4 above).Requested by:
Task Details:
This PR was created automatically by Fred Agent.