Lombok generates getters/setters, builder(), equals/hashCode/toString, and the @Slf4j log field at compile time, so they never appear in the source AST. Static extraction missed them entirely, so a bean.getName() / User.builder() / log.info() call resolved to nothing and call-chain analysis broke silently — the agent would conclude the method didn't exist. Add a synthesizeMembers hook on LanguageExtractor, called at the end of class extraction (class still on the scope stack, real members already extracted), and a Java implementation that synthesizes the mechanical members for @Getter, @Setter, @Data, @Value, @Builder/@SuperBuilder, @ToString, @EqualsAndHashCode, and the @Log* family. Each node is anchored on the field/class name-token leaf (so it pulls in no spurious value-reference scope), marked with a `lombok` decorator and a docstring naming the generating annotation, and never overrides a member the source already declares. Methods and fields are deduped separately since they're distinct namespaces in Java (a boolean field `isRunning` and its generated getter `isRunning()` coexist). Deliberately not synthesized: constructors (new X() already links via instantiates, and overloaded @NoArgs/@AllArgs/@RequiredArgs ctors would collide on a synthetic node id), fluent builder setters, and @Accessors(fluent=true). Validated on eladmin (274 Java files, Lombok-heavy): 100% accessor precision (878/878 map to a real field), 722 previously-broken calls now resolve; spring-petclinic (no Lombok) control synthesizes nothing. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
3e1547bbe1
commit
826810f128
@@ -174,6 +174,20 @@ export interface LanguageExtractor {
|
||||
*/
|
||||
visitNode?: (node: SyntaxNode, ctx: ExtractorContext) => boolean;
|
||||
|
||||
/**
|
||||
* Synthesize members that exist at compile time but not in the source AST,
|
||||
* called at the end of class extraction with the class still on the scope
|
||||
* stack (so `ctx.createNode` attaches containment + qualified names) and the
|
||||
* class's real members already extracted (so the hook can skip a member the
|
||||
* source explicitly declares). Used by Java for Lombok-generated accessors
|
||||
* (`@Getter`/`@Setter`/`@Data`/`@Value`/`@Builder` → `getX`/`setX`/`builder`/
|
||||
* `equals`/`hashCode`/`toString` + the `log` field), which are otherwise
|
||||
* invisible and break call-chain analysis (#912). The created nodes carry a
|
||||
* `lombok` decorator + a docstring naming the generating annotation, so an
|
||||
* agent can tell them apart from hand-written code.
|
||||
*/
|
||||
synthesizeMembers?: (classNode: SyntaxNode, ctx: ExtractorContext) => void;
|
||||
|
||||
/**
|
||||
* Classify a class_declaration node when the grammar reuses one node type
|
||||
* for multiple concepts (e.g. Swift uses class_declaration for classes, structs, and enums).
|
||||
|
||||
Reference in New Issue
Block a user