gitnexus 1.6.10-rc.45 → 1.6.10-rc.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/_shared/scope-resolution/types.d.ts +14 -2
  2. package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
  3. package/dist/core/ingestion/class-extractors/configs/jvm.js +24 -0
  4. package/dist/core/ingestion/languages/java/captures.js +78 -1
  5. package/dist/core/ingestion/languages/java/query.js +8 -0
  6. package/dist/core/ingestion/languages/java/scope-resolver.js +6 -0
  7. package/dist/core/ingestion/languages/javascript/query.js +7 -0
  8. package/dist/core/ingestion/languages/kotlin/query.js +6 -0
  9. package/dist/core/ingestion/languages/typescript/query.js +17 -0
  10. package/dist/core/ingestion/scope-extractor.js +2 -0
  11. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +17 -0
  12. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +9 -0
  13. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +95 -1
  14. package/dist/core/ingestion/scope-resolution/pipeline/run.js +2 -0
  15. package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
  16. package/dist/core/ingestion/scope-resolution/scope/walkers.js +63 -44
  17. package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
  18. package/dist/core/ingestion/tree-sitter-queries.js +4 -0
  19. package/dist/core/ingestion/type-extractors/jvm.js +17 -2
  20. package/dist/core/ingestion/utils/ast-helpers.d.ts +1 -0
  21. package/dist/core/ingestion/utils/ast-helpers.js +99 -1
  22. package/dist/core/run-analyze.js +21 -9
  23. package/dist/core/search/fts-indexes.d.ts +15 -0
  24. package/dist/core/search/fts-indexes.js +23 -0
  25. package/dist/storage/parse-cache.js +1 -1
  26. package/dist/storage/repo-manager.d.ts +8 -2
  27. package/dist/storage/repo-manager.js +7 -1
  28. package/package.json +1 -1
@@ -27,8 +27,20 @@ import type { SymbolDefinition } from './symbol-definition.js';
27
27
  export type ScopeId = string;
28
28
  /** Stable symbol-definition identifier (graph nodeId). */
29
29
  export type DefId = string;
30
- /** Kinds of lexical scope a `Scope` node can represent. */
31
- export type ScopeKind = 'Module' | 'Namespace' | 'Class' | 'Function' | 'Block' | 'Expression';
30
+ /**
31
+ * Kinds of lexical scope a `Scope` node can represent.
32
+ *
33
+ * `Object` is a hoist boundary ONLY: an object/record literal body
34
+ * (TS/JS `{...}`, Kotlin anonymous `object {...}`). Members are
35
+ * reachable via property access, never as bare identifiers, so
36
+ * scope-chain walkers (`scope/walkers.ts`) must skip an `Object`
37
+ * scope's own bindings while still traversing past it to the parent
38
+ * (#2545/#2551) -- unlike `Block`, where a nested closure legitimately
39
+ * DOES see a sibling `let`/`const` from an enclosing `if`/`for`/`while`,
40
+ * a nested closure inside an object literal must NOT see a sibling
41
+ * property's name as a free identifier.
42
+ */
43
+ export type ScopeKind = 'Module' | 'Namespace' | 'Class' | 'Function' | 'Block' | 'Expression' | 'Object';
32
44
  /** Source-text range. 1-based `startLine`/`endLine`; 0-based `startCol`/`endCol`. */
33
45
  export interface Range {
34
46
  readonly startLine: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/types.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  // gitnexus/src/core/ingestion/class-extractors/configs/jvm.ts
2
2
  import { SupportedLanguages } from '../../../../_shared/index.js';
3
+ import { synthesizeJavaAnonymousClassName } from '../../utils/ast-helpers.js';
3
4
  // ---------------------------------------------------------------------------
4
5
  // Java
5
6
  // ---------------------------------------------------------------------------
@@ -10,6 +11,12 @@ export const javaClassConfig = {
10
11
  'interface_declaration',
11
12
  'enum_declaration',
12
13
  'record_declaration',
14
+ // Anonymous class bodies (`new Runnable() { ... }`) — the matching
15
+ // JAVA_QUERIES pattern only captures `object_creation_expression`
16
+ // WITH a `class_body`, and `extractName` below returns undefined for
17
+ // any other shape, so plain `new Foo()` constructor calls never
18
+ // produce a Class node (#2550).
19
+ 'object_creation_expression',
13
20
  ],
14
21
  fileScopeNodeTypes: ['package_declaration'],
15
22
  ancestorScopeNodeTypes: [
@@ -18,6 +25,23 @@ export const javaClassConfig = {
18
25
  'enum_declaration',
19
26
  'record_declaration',
20
27
  ],
28
+ extractName(node) {
29
+ if (node.type === 'object_creation_expression') {
30
+ return synthesizeJavaAnonymousClassName(node);
31
+ }
32
+ return undefined;
33
+ },
34
+ // An anonymous body whose name CANNOT be synthesized (no supported host
35
+ // type declaration) must not become a Class node at all. Without this
36
+ // skip, `extract()`'s `extractTypeNameFromNode` fallback names the node
37
+ // after the CONSTRUCTED type — emitting a phantom `Class:...:Runnable`
38
+ // for `new Runnable() { ... }` (empirically caught in review).
39
+ shouldSkipClassCapture({ definitionNode }) {
40
+ return (definitionNode !== null &&
41
+ definitionNode !== undefined &&
42
+ definitionNode.type === 'object_creation_expression' &&
43
+ synthesizeJavaAnonymousClassName(definitionNode) === undefined);
44
+ },
21
45
  };
22
46
  // ---------------------------------------------------------------------------
23
47
  // Kotlin
@@ -13,7 +13,7 @@
13
13
  *
14
14
  * Pure given the input source text. No I/O, no globals consulted.
15
15
  */
16
- import { nodeIfType, nodeToCapture, syntheticCapture } from '../../utils/ast-helpers.js';
16
+ import { nodeIfType, nodeToCapture, synthesizeJavaAnonymousClassName, syntheticCapture, } from '../../utils/ast-helpers.js';
17
17
  import { splitImportDeclaration } from './import-decomposer.js';
18
18
  import { computeJavaArityMetadata } from './arity-metadata.js';
19
19
  import { synthesizeJavaReceiverBinding } from './receiver-binding.js';
@@ -184,9 +184,79 @@ export function emitJavaScopeCaptures(sourceText, _filePath, cachedTree) {
184
184
  ...resolveVarTypeBindings(out),
185
185
  ...synthesizeJavaInheritanceReferences(tree.rootNode),
186
186
  ...synthesizeJavaExplicitConstructorReferences(tree.rootNode),
187
+ ...synthesizeJavaAnonymousClassDeclarations(tree.rootNode),
187
188
  ...synthesizeCallableFlowCaptures(tree.rootNode, JAVA_CALLABLE_CAPTURE_OPTIONS),
188
189
  ];
189
190
  }
191
+ /**
192
+ * Synthesize `@declaration.class` matches for anonymous class bodies
193
+ * (`new Runnable() { ... }`), named by the same javac-style authority
194
+ * (`synthesizeJavaAnonymousClassName` → `Worker$N`) the structure phase
195
+ * uses — the two layers agree by construction (#2550).
196
+ *
197
+ * The anchor is the `class_body` node: it shares its range with the
198
+ * `(object_creation_expression (class_body) @scope.class)` scope rule in
199
+ * query.ts, so the def is owned by that Class scope's `ownedDefs`
200
+ * (making `populateClassOwnedMembers` stamp `ownerId` on the anonymous
201
+ * class's methods) and the name auto-hoists to the enclosing scope —
202
+ * exactly the binding shape a named class declaration produces.
203
+ */
204
+ function synthesizeJavaAnonymousClassDeclarations(rootNode) {
205
+ const out = [];
206
+ for (const oce of rootNode.descendantsOfType('object_creation_expression')) {
207
+ const name = synthesizeJavaAnonymousClassName(oce);
208
+ if (name === undefined)
209
+ continue;
210
+ const body = oce.namedChildren.find((c) => c.type === 'class_body');
211
+ if (body === undefined)
212
+ continue;
213
+ out.push({
214
+ '@declaration.class': nodeToCapture('@declaration.class', body),
215
+ '@declaration.name': syntheticCapture('@declaration.name', body, name),
216
+ });
217
+ // Inheritance: the anonymous class extends/implements its constructed
218
+ // type. Anchor the `@reference.inherits` on the `class_body` — its
219
+ // range equals the anonymous Class scope, so the reference site's
220
+ // enclosing class resolves to the SYNTHESIZED `Worker$N` def (anchoring
221
+ // on the constructed-type node would sit OUTSIDE the anonymous scope
222
+ // and mis-attribute the edge to the lexically enclosing class). The
223
+ // synthetic `@reference.name` carries the base's simple name; a JDK
224
+ // type with no repo def simply resolves to nothing (no edge). Without
225
+ // this edge `mroFor(Worker$N)` is empty and the #2550 instance-
226
+ // ownership gate suppressed TRUE bare calls to inherited methods
227
+ // inside the anonymous body (empirically caught in review).
228
+ const constructedType = oce.childForFieldName?.('type');
229
+ const baseSimpleName = constructedType !== null && constructedType !== undefined
230
+ ? javaBaseSimpleNameOf(constructedType)
231
+ : undefined;
232
+ if (baseSimpleName !== undefined) {
233
+ out.push({
234
+ '@reference.inherits': nodeToCapture('@reference.inherits', body),
235
+ '@reference.name': syntheticCapture('@reference.name', body, baseSimpleName),
236
+ });
237
+ }
238
+ // Receiver typeBinding: `Runnable handler = new Runnable() { ... }`
239
+ // binds `handler` to the ANONYMOUS class (`Worker$1`), not the declared
240
+ // interface — the instance is what `handler.run()` dispatches into, and
241
+ // the declared type is frequently a JDK interface with no repo def.
242
+ // Appended after the raw matches, so it overwrites the declared-type
243
+ // binding the `@type-binding.annotation` query rule produced for the
244
+ // same variable (pass-4 applies bindings in match order; last wins).
245
+ const declarator = oce.parent;
246
+ if (declarator !== null && declarator.type === 'variable_declarator') {
247
+ const varName = declarator.childForFieldName?.('name');
248
+ const declNode = declarator.parent ?? declarator;
249
+ if (varName !== null && varName !== undefined) {
250
+ out.push({
251
+ '@type-binding.annotation': nodeToCapture('@type-binding.annotation', declNode),
252
+ '@type-binding.name': nodeToCapture('@type-binding.name', varName),
253
+ '@type-binding.type': syntheticCapture('@type-binding.type', oce, name),
254
+ });
255
+ }
256
+ }
257
+ }
258
+ return out;
259
+ }
190
260
  /**
191
261
  * Synthesize `@reference.call.constructor` captures for explicit constructor
192
262
  * invocations — `super(...)` and `this(...)` (F38 #1928). tree-sitter-java
@@ -377,6 +447,13 @@ function emitJavaInheritanceBase(out, base) {
377
447
  });
378
448
  }
379
449
  /** Resolve a Java base-type node to its bare simple-name identifier node. */
450
+ /** Simple name of a constructed/base type node, reusing the same node
451
+ * shapes `javaBaseLookupNameNode` handles (`Runnable`, `a.b.Base`,
452
+ * `Box<T>`). Returns undefined when the node is none of those. */
453
+ function javaBaseSimpleNameOf(typeNode) {
454
+ const nameNode = javaBaseLookupNameNode(typeNode);
455
+ return nameNode === null ? undefined : nameNode.text;
456
+ }
380
457
  function javaBaseLookupNameNode(node) {
381
458
  switch (node.type) {
382
459
  case 'type_identifier':
@@ -37,6 +37,14 @@ const JAVA_SCOPE_QUERY = `
37
37
  (record_declaration) @scope.class
38
38
  (annotation_type_declaration) @scope.class
39
39
 
40
+ ;; Anonymous class body: \`new Runnable() { public void run() {} }\`.
41
+ ;; Without its own scope, a method's auto-hoist (scope-extractor.ts) has
42
+ ;; nowhere to stop and leaks the name past the anonymous class into the
43
+ ;; enclosing scope -- the same failure mode fixed for TS/JS object
44
+ ;; literals (#2545).
45
+ (object_creation_expression
46
+ (class_body) @scope.class)
47
+
40
48
  (method_declaration) @scope.function
41
49
  (constructor_declaration) @scope.function
42
50
 
@@ -31,6 +31,12 @@ const javaScopeResolver = {
31
31
  collapseMemberCallsByCallerTarget: true,
32
32
  hoistTypeBindingsToModule: true,
33
33
  stripReceiverCastExpressions: true,
34
+ // #2550: every Java method belongs to a class instance — a free call may
35
+ // resolve to a Method only when the caller's enclosing class chain
36
+ // (self + MRO) contains the method's owner. Closes the finalize-bucket
37
+ // leak (unqualified `run()` matching an unrelated same-file anonymous
38
+ // class's method). C# is the intended next adopter.
39
+ freeCallsRequireInstanceOwnership: true,
34
40
  populateNamespaceSiblings: populateJavaPackageSiblings,
35
41
  populateRangeBindings: populateJavaCrossFileReturnTypes,
36
42
  };
@@ -66,6 +66,13 @@ const JAVASCRIPT_SCOPE_QUERY = `
66
66
  (arrow_function) @scope.function
67
67
  (method_definition) @scope.function
68
68
 
69
+ ;; Object literals get their own scope boundary -- see the matching
70
+ ;; comment in typescript/query.ts (#2545/#2551). Prevents a
71
+ ;; method_definition/property-arrow's auto-hoist from leaking its name
72
+ ;; past the literal into the enclosing scope, and (unlike Block) keeps
73
+ ;; sibling properties from seeing each other as bare identifiers.
74
+ (object) @scope.object
75
+
69
76
  ;; Declarations — classes
70
77
  (class_declaration
71
78
  name: (identifier) @declaration.name) @declaration.class
@@ -15,6 +15,12 @@ const KOTLIN_SCOPE_QUERY = `
15
15
  (class_declaration) @scope.class
16
16
  (object_declaration) @scope.class
17
17
  (companion_object) @scope.class
18
+ ;; Anonymous object expression: \`val h = object { fun fetch() {} }\`
19
+ ;; (distinct from the named \`object_declaration\`/\`companion_object\` above).
20
+ ;; Without its own scope, a method's auto-hoist (scope-extractor.ts) has
21
+ ;; nowhere to stop and leaks the name past the literal into the enclosing
22
+ ;; scope -- the same failure mode fixed for TS/JS object literals (#2545).
23
+ (object_literal) @scope.class
18
24
  (function_declaration) @scope.function
19
25
 
20
26
  ;; Secondary-constructor body scope (issue #1919 review CF1). A
@@ -96,6 +96,23 @@ const TYPESCRIPT_SCOPE_QUERY = `
96
96
  (arrow_function) @scope.function
97
97
  (function_expression) @scope.function
98
98
 
99
+ ;; Object literals (the { ... } value expression, NOT object_type or
100
+ ;; object_pattern) get their own scope boundary. Without it, a
101
+ ;; method_definition/property-arrow's auto-hoist (scope-extractor.ts)
102
+ ;; has nowhere to stop and leaks the name past the literal into whatever
103
+ ;; lexically encloses it -- e.g. 'export default { async fetch(req) {} }'
104
+ ;; would bind fetch at Module scope, letting an unrelated same-file
105
+ ;; fetch(...) call (the platform global) incorrectly resolve to it
106
+ ;; (#2545). Object (not Block or Class): object-literal members are
107
+ ;; reachable only via property access, never as bare identifiers -- not
108
+ ;; even by a SIBLING property's function body, unlike a real Block
109
+ ;; (if/for/while, where a nested closure legitimately sees a sibling
110
+ ;; let/const) or a Class (implicit-this sibling dispatch). Scope-chain
111
+ ;; walkers (scope-resolution/scope/walkers.ts) skip an Object scope's
112
+ ;; own bindings entirely while still treating it as a hoist boundary
113
+ ;; (#2551).
114
+ (object) @scope.object
115
+
99
116
  ;; Type aliases that contain an object_type are structurally class-like —
100
117
  ;; they define a shape with named members. Emit @scope.class so the
101
118
  ;; field-extractor's type-alias-with-object-type handling (in
@@ -308,6 +308,8 @@ function resolveKindForScopeMatch(match, anchor, provider) {
308
308
  return 'Block';
309
309
  case 'expression':
310
310
  return 'Expression';
311
+ case 'object':
312
+ return 'Object';
311
313
  default:
312
314
  return null;
313
315
  }
@@ -626,6 +626,23 @@ export interface ScopeResolver {
626
626
  * but is too loose as a default for strict module systems.
627
627
  */
628
628
  readonly allowGlobalFreeCallFallback?: boolean;
629
+ /**
630
+ * In this language every `Method` belongs to a class instance, so a
631
+ * FREE (receiver-less) call may resolve to a `Method` only when the
632
+ * caller's enclosing class chain — the class itself plus its MRO —
633
+ * contains the method's owner (#2550). Suppresses the finalize-bucket
634
+ * leak where an unqualified call matched any same-file method by bare
635
+ * name (`materializeBindings` flattens every declaration onto module
636
+ * scope). Java opts in; C# is the intended next adopter.
637
+ *
638
+ * NOT implemented via `LanguageProvider.builtInNames`: that mechanism
639
+ * has unrelated consumers (`parse-worker`'s call-site extraction gate
640
+ * suppresses member calls too; `type-env`'s return-type lookup) which
641
+ * assume a flagged name is never a real repository declaration —
642
+ * false for common method names like `run`/`get`/`compare` (verified
643
+ * regression).
644
+ */
645
+ readonly freeCallsRequireInstanceOwnership?: boolean;
629
646
  /**
630
647
  * When true, a constructor-form call `Type(...)` links to the Class def
631
648
  * itself rather than its explicit Constructor def. Default
@@ -57,6 +57,15 @@ export declare function emitFreeCallFallback(graph: KnowledgeGraph, scopes: Scop
57
57
  * fail at the call site. Three-valued; `'unknown'` keeps the
58
58
  * candidate (monotonicity). */
59
59
  readonly constraintCompatibility?: ScopeResolver['constraintCompatibility'];
60
+ /** Platform/language built-in names (e.g. `fetch`, `setTimeout`) that
61
+ * are never real repository declarations. Gates the finalize-bucket
62
+ * guard below (#2545) -- see `hasGenuineLexicalBinding`. */
63
+ readonly isBuiltInName?: (name: string) => boolean;
64
+ /** Instance-ownership gate (#2550): a free call may resolve to a
65
+ * `Method` only when the caller's enclosing class chain (self + MRO)
66
+ * contains the method's owner. See
67
+ * `ScopeResolver.freeCallsRequireInstanceOwnership`. */
68
+ readonly freeCallsRequireInstanceOwnership?: boolean;
60
69
  readonly recordResolutionOutcome?: ResolutionOutcomeRecorder;
61
70
  /** Call sites owned by a later precise pass (for example callable-value-flow). */
62
71
  readonly skipSites?: ReadonlySet<string>;
@@ -17,7 +17,7 @@
17
17
  * generalization plan.
18
18
  */
19
19
  import { resolveCallerGraphId, resolveDefGraphId } from '../graph-bridge/ids.js';
20
- import { findAllCallableBindingsInScope, findCallableBindingInScope, findCallableBindingsAndAdlBlocker, resolveInheritanceBaseInScope, } from '../scope/walkers.js';
20
+ import { findAllCallableBindingsInScope, findCallableBindingInScope, findCallableBindingsAndAdlBlocker, findEnclosingClassDef, resolveInheritanceBaseInScope, } from '../scope/walkers.js';
21
21
  import { isOverloadAmbiguousAfterNormalization, narrowOverloadCandidates, } from './overload-narrowing.js';
22
22
  export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _referenceIndex, handledSites, model, workspaceIndex, options = {}) {
23
23
  let emitted = 0;
@@ -109,6 +109,72 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
109
109
  // available AND the binding scope contains multiple overloads,
110
110
  // refine with narrowOverloadCandidates (#1578).
111
111
  fnDef = findCallableBindingInScope(site.inScope, site.name, scopes);
112
+ if (fnDef !== undefined &&
113
+ options.isBuiltInName?.(site.name) === true &&
114
+ fnDef.filePath === parsed.filePath &&
115
+ !hasGenuineLexicalBinding(site.inScope, site.name, scopes)) {
116
+ // A platform/language built-in (e.g. `fetch`, `setTimeout`)
117
+ // with no binding reachable via the TRUE lexical scope chain
118
+ // (Scope.bindings only) -- the match came solely from
119
+ // finalize's per-file "local + imports + wildcards" bucket,
120
+ // which flattens every declaration in the file onto the
121
+ // module scope regardless of true nesting depth
122
+ // (gitnexus-shared's `materializeBindings`). That flattening
123
+ // is correct for its purpose (cross-file import targets) but
124
+ // over-matches same-file built-in-shadowing declarations that
125
+ // were never really module-scope-visible -- e.g. a Cloudflare
126
+ // Worker's `export default { fetch(req) {} }` handler (#2545).
127
+ // Leave the call unresolved rather than emit a false edge.
128
+ //
129
+ // `fnDef.filePath === parsed.filePath` is the load-bearing
130
+ // guard against a real regression: `materializeBindings`'s
131
+ // flat bucket is per-file, so the leak this guard targets is
132
+ // ALWAYS same-file. A cross-file match at this point can only
133
+ // come from a genuine import/namespace/workspace-FQN channel
134
+ // (the separate, gated `pickUniqueGlobalCallable` global
135
+ // fallback runs later and isn't what populated `fnDef` here)
136
+ // -- e.g. `import { fetch } from './fetch-polyfill'` must
137
+ // keep resolving. Without this check, that import silently
138
+ // stopped resolving (verified via a scratch probe fixture).
139
+ fnDef = undefined;
140
+ }
141
+ // Instance-ownership gate (#2550). Placement matters: after the
142
+ // scope-chain lookup, BEFORE overload narrowing -- a suppressed
143
+ // candidate must not participate in overload selection. The
144
+ // legitimate same-class bare call already resolved earlier via
145
+ // `pickImplicitThisOverload`; an inherited bare call passes the
146
+ // MRO arm here; what remains is the finalize-bucket leak (an
147
+ // unrelated same-file method matched by bare name).
148
+ //
149
+ // Same-file only (mirrors the #2545 guard's load-bearing
150
+ // condition): the `materializeBindings` bucket is per-file, so
151
+ // the leak is ALWAYS same-file. A cross-file Method match here
152
+ // came through a genuine import channel -- e.g. the arity-
153
+ // narrowing parity fixtures resolve a bare `writeAudit(u)` to
154
+ // an imported class's method, which must keep working
155
+ // (suppressing it broke `java.test.ts`'s arity-filtering suite,
156
+ // verified empirically).
157
+ if (fnDef !== undefined &&
158
+ options.freeCallsRequireInstanceOwnership === true &&
159
+ fnDef.type === 'Method' &&
160
+ fnDef.ownerId !== undefined &&
161
+ fnDef.filePath === parsed.filePath) {
162
+ const enclosing = findEnclosingClassDef(site.inScope, scopes);
163
+ const ownerReachable = enclosing !== undefined &&
164
+ (enclosing.nodeId === fnDef.ownerId ||
165
+ scopes.methodDispatch.mroFor(enclosing.nodeId).includes(fnDef.ownerId));
166
+ if (!ownerReachable) {
167
+ recordSuppressedOutcome(options.recordResolutionOutcome, {
168
+ phase: 'free-call-fallback',
169
+ filePath: parsed.filePath,
170
+ name: site.name,
171
+ range: site.atRange,
172
+ reason: 'free-call-instance-ownership',
173
+ candidates: [fnDef],
174
+ });
175
+ fnDef = undefined;
176
+ }
177
+ }
112
178
  if (fnDef !== undefined && options.conversionRankFn !== undefined) {
113
179
  const allCallables = findAllCallableBindingsInScope(site.inScope, site.name, scopes);
114
180
  if (allCallables.length > 1) {
@@ -709,3 +775,31 @@ export function pickImplicitThisOverload(site, scopes, workspaceIndex, model, ho
709
775
  return undefined;
710
776
  return candidates[0];
711
777
  }
778
+ /**
779
+ * True when `name` is bound somewhere along the TRUE lexical scope
780
+ * chain from `startScope` -- i.e. via `Scope.bindings` (the raw,
781
+ * nesting-aware per-scope map built during extraction), NOT via
782
+ * finalize's `indexes.bindings` module-scope bucket (which flattens
783
+ * every declaration in the file onto the module scope regardless of
784
+ * true nesting -- see `hasGenuineLexicalBinding`'s caller for why that
785
+ * distinction matters, #2545).
786
+ */
787
+ function hasGenuineLexicalBinding(startScope, name, scopes) {
788
+ let currentId = startScope;
789
+ const visited = new Set();
790
+ while (currentId !== null) {
791
+ if (visited.has(currentId))
792
+ return false;
793
+ visited.add(currentId);
794
+ const scope = scopes.scopeTree.getScope(currentId);
795
+ if (scope === undefined)
796
+ return false;
797
+ // `Object` scopes (object/record literal bodies) are a hoist
798
+ // boundary only -- never a genuine lexical binding, not even to
799
+ // their own nested children (#2551, mirrors scope/walkers.ts).
800
+ if (scope.kind !== 'Object' && scope.bindings.get(name) !== undefined)
801
+ return true;
802
+ currentId = scope.parent;
803
+ }
804
+ return false;
805
+ }
@@ -508,6 +508,8 @@ export function runScopeResolution(input, provider) {
508
508
  allowGlobalFallback: provider.allowGlobalFreeCallFallback === true,
509
509
  constructorCallTargetsClass: provider.constructorCallTargetsClass === true,
510
510
  isFileLocalDef: provider.isFileLocalDef,
511
+ isBuiltInName: provider.languageProvider.isBuiltInName,
512
+ freeCallsRequireInstanceOwnership: provider.freeCallsRequireInstanceOwnership === true,
511
513
  isCallableVisibleFromCaller: provider.isCallableVisibleFromCaller,
512
514
  resolveAdlCandidates: provider.resolveAdlCandidates,
513
515
  conversionRankFn: provider.conversionRankFn,
@@ -1,5 +1,5 @@
1
1
  import type { Range } from '../../../_shared/index.js';
2
- export type ResolutionSuppressionReason = 'adl-ordinary-lookup-blocked' | 'conversion-rank-tied' | 'inline-ns-ambiguous' | 'member-lookup-ambiguous' | 'selected-callable-deleted' | 'overload-ambiguous' | 'overload-ambiguous-normalization';
2
+ export type ResolutionSuppressionReason = 'adl-ordinary-lookup-blocked' | 'conversion-rank-tied' | 'inline-ns-ambiguous' | 'member-lookup-ambiguous' | 'selected-callable-deleted' | 'overload-ambiguous' | 'overload-ambiguous-normalization' | 'free-call-instance-ownership';
3
3
  export type ResolutionOutcome = {
4
4
  readonly kind: 'resolved';
5
5
  readonly targetId: string;
@@ -577,20 +577,26 @@ function walkScopeChain(startScope, name, scopes, predicate) {
577
577
  const scope = scopes.scopeTree.getScope(currentId);
578
578
  if (scope === undefined)
579
579
  return undefined;
580
- // Local first: a `const x` in this scope shadows any imported `x`.
581
- const localBindings = scope.bindings.get(name);
582
- if (localBindings !== undefined) {
583
- for (const b of localBindings) {
580
+ // `Object` scopes (object/record literal bodies) are a hoist
581
+ // boundary only -- their members are reachable via property access,
582
+ // never bare identifiers, so they contribute nothing to lookup
583
+ // (#2545/#2551). Still traverse past to the parent.
584
+ if (scope.kind !== 'Object') {
585
+ // Local first: a `const x` in this scope shadows any imported `x`.
586
+ const localBindings = scope.bindings.get(name);
587
+ if (localBindings !== undefined) {
588
+ for (const b of localBindings) {
589
+ if (predicate(b.def))
590
+ return b.def;
591
+ }
592
+ }
593
+ // Then imported/augmented bindings — only consulted when no local match.
594
+ const importedBindings = lookupBindingsAt(currentId, name, scopes);
595
+ for (const b of importedBindings) {
584
596
  if (predicate(b.def))
585
597
  return b.def;
586
598
  }
587
599
  }
588
- // Then imported/augmented bindings — only consulted when no local match.
589
- const importedBindings = lookupBindingsAt(currentId, name, scopes);
590
- for (const b of importedBindings) {
591
- if (predicate(b.def))
592
- return b.def;
593
- }
594
600
  currentId = scope.parent;
595
601
  }
596
602
  return undefined;
@@ -626,28 +632,32 @@ export function findAllCallableBindingsInScope(startScope, callableName, scopes)
626
632
  const scope = scopes.scopeTree.getScope(currentId);
627
633
  if (scope === undefined)
628
634
  return [];
629
- const out = [];
630
- const seen = new Set();
631
- const pushCallable = (def) => {
632
- if (def.type !== 'Function' && def.type !== 'Method' && def.type !== 'Constructor')
633
- return;
634
- if (seen.has(def.nodeId))
635
- return;
636
- seen.add(def.nodeId);
637
- out.push(def);
638
- };
639
- const localBindings = scope.bindings.get(callableName);
640
- if (localBindings !== undefined) {
641
- for (const b of localBindings) {
635
+ // `Object` scopes are a hoist boundary only -- see walkScopeChain's
636
+ // comment (#2545/#2551). Skip lookup here, still traverse to parent.
637
+ if (scope.kind !== 'Object') {
638
+ const out = [];
639
+ const seen = new Set();
640
+ const pushCallable = (def) => {
641
+ if (def.type !== 'Function' && def.type !== 'Method' && def.type !== 'Constructor')
642
+ return;
643
+ if (seen.has(def.nodeId))
644
+ return;
645
+ seen.add(def.nodeId);
646
+ out.push(def);
647
+ };
648
+ const localBindings = scope.bindings.get(callableName);
649
+ if (localBindings !== undefined) {
650
+ for (const b of localBindings) {
651
+ pushCallable(b.def);
652
+ }
653
+ }
654
+ const importedBindings = lookupBindingsAt(currentId, callableName, scopes);
655
+ for (const b of importedBindings) {
642
656
  pushCallable(b.def);
643
657
  }
658
+ if (out.length > 0)
659
+ return out;
644
660
  }
645
- const importedBindings = lookupBindingsAt(currentId, callableName, scopes);
646
- for (const b of importedBindings) {
647
- pushCallable(b.def);
648
- }
649
- if (out.length > 0)
650
- return out;
651
661
  currentId = scope.parent;
652
662
  }
653
663
  return [];
@@ -694,16 +704,22 @@ export function findCallableBindingsAndAdlBlocker(startScope, name, scopes) {
694
704
  nonCallableFound = true;
695
705
  }
696
706
  };
697
- const localBindings = scope.bindings.get(name);
698
- if (localBindings !== undefined) {
699
- for (const b of localBindings) {
707
+ // `Object` scopes are a hoist boundary only (#2545/#2551) -- never
708
+ // reached by C++'s ADL path in practice (no language reusing this
709
+ // function emits `@scope.object`), guarded for consistency with the
710
+ // other scope-chain walkers in this file.
711
+ if (scope.kind !== 'Object') {
712
+ const localBindings = scope.bindings.get(name);
713
+ if (localBindings !== undefined) {
714
+ for (const b of localBindings) {
715
+ process(b.def);
716
+ }
717
+ }
718
+ const importedBindings = lookupBindingsAt(currentId, name, scopes);
719
+ for (const b of importedBindings) {
700
720
  process(b.def);
701
721
  }
702
722
  }
703
- const importedBindings = lookupBindingsAt(currentId, name, scopes);
704
- for (const b of importedBindings) {
705
- process(b.def);
706
- }
707
723
  if (anyBinding) {
708
724
  // ISO C++: a block-scope function declaration (Function or Block scope)
709
725
  // that is NOT a using-declaration blocks ADL. If we found callables at
@@ -930,18 +946,21 @@ export function findExportedDefByName(name, inScope, scopes, index) {
930
946
  const scope = scopes.scopeTree.getScope(currentId);
931
947
  if (scope === undefined)
932
948
  break;
933
- const local = scope.bindings.get(name);
934
- if (local !== undefined) {
935
- for (const b of local) {
949
+ // `Object` scopes are a hoist boundary only (#2545/#2551).
950
+ if (scope.kind !== 'Object') {
951
+ const local = scope.bindings.get(name);
952
+ if (local !== undefined) {
953
+ for (const b of local) {
954
+ if (b.def.type === 'Function' || b.def.type === 'Method')
955
+ return b.def;
956
+ }
957
+ }
958
+ const finalized = lookupBindingsAt(currentId, name, scopes);
959
+ for (const b of finalized) {
936
960
  if (b.def.type === 'Function' || b.def.type === 'Method')
937
961
  return b.def;
938
962
  }
939
963
  }
940
- const finalized = lookupBindingsAt(currentId, name, scopes);
941
- for (const b of finalized) {
942
- if (b.def.type === 'Function' || b.def.type === 'Method')
943
- return b.def;
944
- }
945
964
  currentId = scope.parent;
946
965
  }
947
966
  // Workspace-wide fallback: the first locally-declared callable binding
@@ -1,7 +1,7 @@
1
1
  export declare const TYPESCRIPT_QUERIES: string;
2
2
  export declare const JAVASCRIPT_QUERIES: string;
3
3
  export declare const PYTHON_QUERIES = "\n(class_definition\n name: (identifier) @name) @definition.class\n\n(function_definition\n name: (identifier) @name) @definition.function\n\n(import_statement\n name: (dotted_name) @import.source) @import\n\n; import numpy as np \u2192 aliased_import captures the module name so the\n; import path is resolved and named-binding extraction stores \"np\" \u2192 \"numpy\".\n(import_statement\n name: (aliased_import\n name: (dotted_name) @import.source)) @import\n\n(import_from_statement\n module_name: (dotted_name) @import.source) @import\n\n(import_from_statement\n module_name: (relative_import) @import.source) @import\n\n(call\n function: (identifier) @call.name) @call\n\n(call\n function: (attribute\n attribute: (identifier) @call.name)) @call\n\n; Class attribute type annotations \u2014 PEP 526: address: Address or address: Address = Address()\n; Both bare annotations (address: Address) and annotated assignments (name: str = \"test\")\n; are parsed as (assignment left: ... type: ...) in tree-sitter-python.\n(expression_statement\n (assignment\n left: (identifier) @name\n type: (type)) @definition.property)\n\n; Plain variable assignments without type annotation: x = 5, MAX_SIZE = 100\n; Overlap with @definition.property (typed) is handled by parse-worker dedup.\n(expression_statement\n (assignment\n left: (identifier) @name)) @definition.variable\n\n; Write access: obj.field = value\n(assignment\n left: (attribute\n object: (_) @assignment.receiver\n attribute: (identifier) @assignment.property)\n right: (_)) @assignment\n\n; Write access: obj.field += value (compound assignment)\n(augmented_assignment\n left: (attribute\n object: (_) @assignment.receiver\n attribute: (identifier) @assignment.property)\n right: (_)) @assignment\n\n; Python HTTP clients: requests.get('/path'), httpx.post('/path'), session.get('/path')\n(call\n function: (attribute\n attribute: (identifier) @http_client.method)\n arguments: (argument_list\n (string (string_content) @http_client.url))) @http_client\n\n; Python decorators: @app.route, @router.get, etc.\n; The first positional argument is captured three ways (#2391): a string literal\n; path via @decorator.arg (quote-free, the fast path); a bare constant name or a\n; plus-concatenation via @decorator.arg_expr (resolved cross-file by the constant\n; resolver). The anchored optional alternation pins to the FIRST arg and stays\n; optional, so no-arg decorators (@app.tool(), etc.) and non-path first args still\n; match.\n(decorator\n (call\n function: (attribute\n object: (identifier) @decorator.receiver\n attribute: (identifier) @decorator.name)\n arguments: (argument_list\n .\n [\n (string (string_content)? @decorator.arg) @decorator.arg_str\n (identifier) @decorator.arg_expr\n (binary_operator) @decorator.arg_expr\n ]?))) @decorator\n";
4
- export declare const JAVA_QUERIES = "\n; Classes, Interfaces, Enums, Annotations\n(class_declaration name: (identifier) @name) @definition.class\n(interface_declaration name: (identifier) @name) @definition.interface\n(enum_declaration name: (identifier) @name) @definition.enum\n(annotation_type_declaration name: (identifier) @name) @definition.annotation\n\n; Methods & Constructors\n(method_declaration name: (identifier) @name) @definition.method\n(constructor_declaration name: (identifier) @name) @definition.constructor\n\n; Fields \u2014 typed field declarations inside class bodies\n(field_declaration\n declarator: (variable_declarator\n name: (identifier) @name)) @definition.property\n\n; Imports - capture any import declaration child as source\n(import_declaration (_) @import.source) @import\n\n; Calls\n(method_invocation name: (identifier) @call.name) @call\n(method_invocation object: (_) name: (identifier) @call.name) @call\n(method_reference) @call\n\n; Constructor calls: new Foo()\n(object_creation_expression type: (type_identifier) @call.name) @call\n\n; Local variable declarations inside method bodies\n(local_variable_declaration\n declarator: (variable_declarator\n name: (identifier) @name)) @definition.variable\n\n; Write access: obj.field = value\n(assignment_expression\n left: (field_access\n object: (_) @assignment.receiver\n field: (identifier) @assignment.property)\n right: (_)) @assignment\n";
4
+ export declare const JAVA_QUERIES = "\n; Classes, Interfaces, Enums, Annotations\n(class_declaration name: (identifier) @name) @definition.class\n(interface_declaration name: (identifier) @name) @definition.interface\n(enum_declaration name: (identifier) @name) @definition.enum\n(annotation_type_declaration name: (identifier) @name) @definition.annotation\n\n; Anonymous class bodies: new Runnable() { ... } \u2014 no @name capture; the\n; class extractor synthesizes the javac-style Worker$N name (#2550)\n(object_creation_expression (class_body)) @definition.class\n\n; Methods & Constructors\n(method_declaration name: (identifier) @name) @definition.method\n(constructor_declaration name: (identifier) @name) @definition.constructor\n\n; Fields \u2014 typed field declarations inside class bodies\n(field_declaration\n declarator: (variable_declarator\n name: (identifier) @name)) @definition.property\n\n; Imports - capture any import declaration child as source\n(import_declaration (_) @import.source) @import\n\n; Calls\n(method_invocation name: (identifier) @call.name) @call\n(method_invocation object: (_) name: (identifier) @call.name) @call\n(method_reference) @call\n\n; Constructor calls: new Foo()\n(object_creation_expression type: (type_identifier) @call.name) @call\n\n; Local variable declarations inside method bodies\n(local_variable_declaration\n declarator: (variable_declarator\n name: (identifier) @name)) @definition.variable\n\n; Write access: obj.field = value\n(assignment_expression\n left: (field_access\n object: (_) @assignment.receiver\n field: (identifier) @assignment.property)\n right: (_)) @assignment\n";
5
5
  export declare const C_QUERIES = "\n; Functions (direct declarator)\n(function_definition declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(declaration declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n\n; Functions returning pointers (pointer_declarator wraps function_declarator)\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(declaration declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n\n; Functions returning double pointers (nested pointer_declarator)\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name)))) @definition.function\n\n; Structs, Unions, Enums, Typedefs\n(struct_specifier name: (type_identifier) @name) @definition.struct\n(type_definition\n type: (struct_specifier\n body: (field_declaration_list))\n declarator: (type_identifier) @name) @definition.struct\n(union_specifier name: (type_identifier) @name) @definition.union\n(enum_specifier name: (type_identifier) @name) @definition.enum\n(type_definition\n type: (enum_specifier\n body: (enumerator_list))\n declarator: (type_identifier) @name) @definition.enum\n(enumerator name: (identifier) @name) @definition.const\n(type_definition declarator: (type_identifier) @name) @definition.typedef\n\n; Macros\n(preproc_function_def name: (identifier) @name) @definition.macro\n(preproc_def name: (identifier) @name) @definition.macro\n\n; Includes\n(preproc_include path: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n\n; Variable declarations: int x = 5; or int x;\n(declaration\n declarator: (init_declarator\n declarator: (identifier) @name)) @definition.variable\n";
6
6
  export declare const GO_QUERIES = "\n; Functions & Methods\n(function_declaration name: (identifier) @name) @definition.function\n(method_declaration name: (field_identifier) @name) @definition.method\n(method_elem name: (field_identifier) @name) @definition.method\n\n; Types\n(type_declaration (type_spec name: (type_identifier) @name type: (struct_type))) @definition.struct\n(type_declaration (type_spec name: (type_identifier) @name type: (interface_type))) @definition.interface\n\n; Imports\n(import_declaration (import_spec path: (interpreted_string_literal) @import.source)) @import\n(import_declaration (import_spec_list (import_spec path: (interpreted_string_literal) @import.source))) @import\n\n; Struct fields \u2014 named field declarations inside struct types\n(field_declaration_list\n (field_declaration\n name: (field_identifier) @name) @definition.property)\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (selector_expression field: (field_identifier) @call.name)) @call\n\n; Const/var declarations\n(const_declaration (const_spec (identifier) @name)) @definition.const\n(var_declaration (var_spec (identifier) @name)) @definition.variable\n(var_declaration (var_spec_list (var_spec (identifier) @name))) @definition.variable\n\n; Short variable declaration: x := 5\n(short_var_declaration left: (expression_list (identifier) @name)) @definition.variable\n\n; Struct literal construction: User{Name: \"Alice\"}\n(composite_literal type: (type_identifier) @call.name) @call\n\n; Write access: obj.field = value\n(assignment_statement\n left: (expression_list\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property))\n right: (_)) @assignment\n\n; Write access: obj.field++ / obj.field--\n(inc_statement\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)) @assignment\n(dec_statement\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)) @assignment\n";
7
7
  export declare const CPP_QUERIES = "\n; Classes, Structs, Namespaces\n(class_specifier name: (type_identifier) @name) @definition.class\n(class_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments)) @definition.class\n; Out-of-line nested definition: class Outer::Inner { ... } / struct Outer::Inner { ... }.\n; Key the node by the full qualified_identifier text so the def materializes a\n; node that matches the HAS_METHOD owner id (also the full qualified text) and\n; stays distinct from a same-tail type in another scope (#1975, #1978).\n(class_specifier name: (qualified_identifier) @name) @definition.class\n(struct_specifier name: (qualified_identifier) @name) @definition.struct\n(struct_specifier name: (type_identifier) @name) @definition.struct\n(struct_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments)) @definition.struct\n(namespace_definition name: (namespace_identifier) @name) @definition.namespace\n(enum_specifier name: (type_identifier) @name) @definition.enum\n\n; Typedefs and unions (common in C-style headers and mixed C/C++ code)\n(type_definition\n type: (struct_specifier\n body: (field_declaration_list))\n declarator: (type_identifier) @name) @definition.struct\n(type_definition\n type: (enum_specifier\n body: (enumerator_list))\n declarator: (type_identifier) @name) @definition.enum\n(enumerator name: (identifier) @name) @definition.const\n(type_definition declarator: (type_identifier) @name) @definition.typedef\n(union_specifier name: (type_identifier) @name) @definition.union\n\n; Macros\n(preproc_function_def name: (identifier) @name) @definition.macro\n(preproc_def name: (identifier) @name) @definition.macro\n\n; Functions & Methods (direct declarator)\n(function_definition declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(function_definition declarator: (function_declarator declarator: (operator_name) @name)) @definition.function\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name))) @definition.method\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (operator_name) @name))) @definition.method\n\n; Functions/methods returning pointers (pointer_declarator wraps function_declarator)\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name)))) @definition.method\n\n; Functions/methods returning double pointers (nested pointer_declarator)\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name)))) @definition.function\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name))))) @definition.method\n\n; Functions/methods returning references (reference_declarator wraps function_declarator)\n(function_definition declarator: (reference_declarator (function_declarator declarator: (identifier) @name))) @definition.function\n(function_definition declarator: (reference_declarator (function_declarator declarator: (operator_name) @name))) @definition.function\n(function_definition declarator: (reference_declarator (function_declarator declarator: (qualified_identifier name: (identifier) @name)))) @definition.method\n(function_definition declarator: (reference_declarator (function_declarator declarator: (qualified_identifier name: (operator_name) @name)))) @definition.method\n\n; Destructors (destructor_name is distinct from identifier in tree-sitter-cpp)\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (destructor_name) @name))) @definition.method\n\n; Function declarations / prototypes (common in headers)\n(declaration declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(declaration declarator: (function_declarator declarator: (operator_name) @name)) @definition.function\n(declaration declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(declaration declarator: (reference_declarator (function_declarator declarator: (operator_name) @name))) @definition.function\n\n; Class/struct data member fields (Address address; int count;)\n; Uses field_identifier to exclude method declarations (which use function_declarator)\n(field_declaration\n declarator: (field_identifier) @name) @definition.property\n\n; Pointer member fields (Address* address;)\n(field_declaration\n declarator: (pointer_declarator\n declarator: (field_identifier) @name)) @definition.property\n\n; Reference member fields (Address& address;)\n(field_declaration\n declarator: (reference_declarator\n (field_identifier) @name)) @definition.property\n\n; Inline class method declarations (inside class body, no body: void save();)\n; tree-sitter-cpp uses field_identifier (not identifier) for names inside class bodies\n(field_declaration declarator: (function_declarator declarator: [(field_identifier) (identifier) (operator_name)] @name)) @definition.method\n\n; Inline class method declarations returning a pointer (User* lookup();)\n(field_declaration declarator: (pointer_declarator declarator: (function_declarator declarator: [(field_identifier) (identifier)] @name))) @definition.method\n\n; Inline class method declarations returning a reference (User& lookup();)\n(field_declaration declarator: (reference_declarator (function_declarator declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method\n\n; Inline class method definitions (inside class body, with body: void Foo() { ... })\n(field_declaration_list\n (function_definition\n declarator: (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name) (destructor_name)] @name)) @definition.method)\n\n; Inline class methods returning a pointer type (User* lookup(int id) { ... })\n(field_declaration_list\n (function_definition\n declarator: (pointer_declarator\n declarator: (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method)\n\n; Inline class methods returning a reference type (User& lookup(int id) { ... })\n(field_declaration_list\n (function_definition\n declarator: (reference_declarator\n (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method)\n\n; Templates\n(template_declaration (class_specifier name: (type_identifier) @name)) @definition.template\n(template_declaration\n (class_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments))) @definition.template\n(template_declaration (function_definition declarator: (function_declarator declarator: (identifier) @name))) @definition.template\n\n; Includes\n(preproc_include path: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n(call_expression function: (qualified_identifier name: (identifier) @call.name)) @call\n(call_expression function: (template_function name: (identifier) @call.name)) @call\n(binary_expression operator: \"+\" @call.name) @call\n(binary_expression operator: \"<<\" @call.name) @call\n\n; Constructor calls: new User()\n(new_expression type: (type_identifier) @call.name) @call\n\n; Variable declarations: int x = 5; or auto x = 5;\n(declaration\n declarator: (init_declarator\n declarator: (identifier) @name)) @definition.variable\n\n; Structured bindings: auto [a, b] = makePair(); (one @name per bound identifier)\n(declaration\n declarator: (init_declarator\n declarator: (structured_binding_declarator\n (identifier) @name))) @definition.variable\n\n; Structured bindings, reference form: auto& [x, y] = tup;\n(declaration\n declarator: (init_declarator\n declarator: (reference_declarator\n (structured_binding_declarator\n (identifier) @name)))) @definition.variable\n\n; Write access: obj.field = value\n(assignment_expression\n left: (field_expression\n argument: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)\n right: (_)) @assignment\n\n";
@@ -744,6 +744,10 @@ export const JAVA_QUERIES = `
744
744
  (enum_declaration name: (identifier) @name) @definition.enum
745
745
  (annotation_type_declaration name: (identifier) @name) @definition.annotation
746
746
 
747
+ ; Anonymous class bodies: new Runnable() { ... } — no @name capture; the
748
+ ; class extractor synthesizes the javac-style Worker$N name (#2550)
749
+ (object_creation_expression (class_body)) @definition.class
750
+
747
751
  ; Methods & Constructors
748
752
  (method_declaration name: (identifier) @name) @definition.method
749
753
  (constructor_declaration name: (identifier) @name) @definition.constructor
@@ -1,10 +1,20 @@
1
- import { findChild } from '../utils/ast-helpers.js';
1
+ import { findChild, synthesizeJavaAnonymousClassName, } from '../utils/ast-helpers.js';
2
2
  import { extractSimpleTypeName, extractVarName, extractGenericTypeArgs, resolveIterableElementType, methodToTypeArgPosition, extractElementTypeFromString, } from './shared.js';
3
3
  // ── Java ──────────────────────────────────────────────────────────────────
4
4
  const JAVA_DECLARATION_NODE_TYPES = new Set([
5
5
  'local_variable_declaration',
6
6
  'field_declaration',
7
7
  ]);
8
+ /** `Runnable handler = new Runnable() { ... }` — the variable's effective
9
+ * type is the ANONYMOUS class (`Worker$1`), not the declared interface;
10
+ * that is the instance `handler.run()` dispatches into (#2550). Returns
11
+ * undefined for declarators without an anonymous-body initializer. */
12
+ const anonymousInitializerTypeName = (declarator) => {
13
+ const valueNode = declarator.childForFieldName('value');
14
+ if (!valueNode || valueNode.type !== 'object_creation_expression')
15
+ return undefined;
16
+ return synthesizeJavaAnonymousClassName(valueNode);
17
+ };
8
18
  /** Java: Type x = ...; Type x; */
9
19
  const extractJavaDeclaration = (node, env) => {
10
20
  const typeNode = node.childForFieldName('type');
@@ -22,7 +32,7 @@ const extractJavaDeclaration = (node, env) => {
22
32
  if (nameNode) {
23
33
  const varName = extractVarName(nameNode);
24
34
  if (varName)
25
- env.set(varName, typeName);
35
+ env.set(varName, anonymousInitializerTypeName(child) ?? typeName);
26
36
  }
27
37
  }
28
38
  };
@@ -42,6 +52,11 @@ const extractJavaInitializer = (node, env, _classNames) => {
42
52
  continue;
43
53
  if (valueNode.type !== 'object_creation_expression')
44
54
  continue;
55
+ const anonName = anonymousInitializerTypeName(child);
56
+ if (anonName) {
57
+ env.set(varName, anonName);
58
+ continue;
59
+ }
45
60
  const ctorType = valueNode.childForFieldName('type');
46
61
  if (!ctorType)
47
62
  continue;
@@ -102,6 +102,7 @@ export interface EnclosingClassInfo {
102
102
  */
103
103
  qualifiedClassId?: string;
104
104
  }
105
+ export declare const synthesizeJavaAnonymousClassName: (node: SyntaxNode) => string | undefined;
105
106
  export declare const findEnclosingClassInfo: (node: SyntaxNode, filePath: string, resolveEnclosingOwner?: (node: SyntaxNode) => SyntaxNode | null,
106
107
  /**
107
108
  * Optional (#1978): returns the enclosing type's fully-qualified name
@@ -270,7 +270,14 @@ export function getLabelFromCaptures(captureMap, provider) {
270
270
  return null;
271
271
  const hasDefaultExportHocNameSeed = captureMap['definition.function'] !== undefined &&
272
272
  (captureMap['hoc'] !== undefined || captureMap['callee'] !== undefined);
273
- if (!captureMap['name'] && !captureMap['definition.constructor'] && !hasDefaultExportHocNameSeed)
273
+ // Nameless `definition.class` passes through: a class extractor may
274
+ // synthesize the name (Java anonymous class bodies → `Worker$N`, #2550).
275
+ // Downstream stays safe — parse-worker skips any nameless definition the
276
+ // extractor could not name (its `!nameNode && !extractedClassSymbol` gate).
277
+ if (!captureMap['name'] &&
278
+ !captureMap['definition.constructor'] &&
279
+ !captureMap['definition.class'] &&
280
+ !hasDefaultExportHocNameSeed)
274
281
  return null;
275
282
  if (captureMap['definition.function']) {
276
283
  if (provider.labelOverride) {
@@ -353,6 +360,82 @@ export function getLabelFromCaptures(captureMap, provider) {
353
360
  * `MAX_ENCLOSING_WALK_ITERATIONS` defense-in-depth guard below prevents
354
361
  * pathological hooks from creating an infinite loop. */
355
362
  const MAX_ENCLOSING_WALK_ITERATIONS = 4096;
363
+ /**
364
+ * Synthesize a javac-style name for a Java anonymous class body:
365
+ * `new Runnable() { ... }` inside top-level class `Worker` becomes
366
+ * `Worker$1` (`$N` = 1-based source order of anonymous bodies within the
367
+ * top-level class). Returns undefined when the node is not an
368
+ * `object_creation_expression` carrying a `class_body` child — which also
369
+ * keeps this a no-op for C#, whose `object_creation_expression` uses
370
+ * `initializer_expression`, never `class_body` (#2550).
371
+ *
372
+ * The SAME name must be produced by every layer that keys the anonymous
373
+ * class (structure-phase node id, enclosing-owner walk, scope-side
374
+ * declaration synthesis, receiver typeBinding) — they agree by all calling
375
+ * this one helper.
376
+ */
377
+ /** Type-declaration node types that can host (and name) a Java anonymous
378
+ * class body — javac numbers `$N` per top-level type of any of these
379
+ * kinds. Enum constant bodies (`A { ... }`) are a different node shape
380
+ * and remain unmodeled. */
381
+ const JAVA_ANON_HOST_TYPES = new Set([
382
+ 'class_declaration',
383
+ 'enum_declaration',
384
+ 'interface_declaration',
385
+ 'record_declaration',
386
+ ]);
387
+ /** Per-parse-tree memo of anonymous-body numbering: tree → (startIndex →
388
+ * synthesized name). Keyed by the tree OBJECT via WeakMap so entries die
389
+ * with the parse; without it every call re-scans the host subtree
390
+ * (`descendantsOfType`), and the helper is called from four independent
391
+ * layers per anonymous body — quadratic on anon-heavy files (old-style
392
+ * listener-per-widget Java). */
393
+ const javaAnonNameMemo = new WeakMap();
394
+ export const synthesizeJavaAnonymousClassName = (node) => {
395
+ if (node.type !== 'object_creation_expression')
396
+ return undefined;
397
+ const hasClassBody = node.namedChildren?.some((c) => c.type === 'class_body');
398
+ if (hasClassBody !== true)
399
+ return undefined;
400
+ const tree = node.tree;
401
+ if (tree !== undefined) {
402
+ const cached = javaAnonNameMemo.get(tree)?.get(node.startIndex);
403
+ if (cached !== undefined)
404
+ return cached;
405
+ }
406
+ // Topmost enclosing host type declaration — javac numbers per top-level type.
407
+ let topHost = null;
408
+ let cursor = node.parent;
409
+ let iterations = 0;
410
+ while (cursor) {
411
+ if (++iterations > MAX_ENCLOSING_WALK_ITERATIONS)
412
+ return undefined;
413
+ if (JAVA_ANON_HOST_TYPES.has(cursor.type))
414
+ topHost = cursor;
415
+ cursor = cursor.parent;
416
+ }
417
+ if (topHost === null)
418
+ return undefined;
419
+ const topName = topHost.childForFieldName?.('name')?.text;
420
+ if (topName === undefined || topName.length === 0)
421
+ return undefined;
422
+ const anonBodies = (topHost.descendantsOfType?.('object_creation_expression') ?? []).filter((c) => c.namedChildren?.some((n) => n.type === 'class_body'));
423
+ if (tree !== undefined) {
424
+ let byStart = javaAnonNameMemo.get(tree);
425
+ if (byStart === undefined) {
426
+ byStart = new Map();
427
+ javaAnonNameMemo.set(tree, byStart);
428
+ }
429
+ for (let i = 0; i < anonBodies.length; i++) {
430
+ byStart.set(anonBodies[i].startIndex, `${topName}$${i + 1}`);
431
+ }
432
+ return byStart.get(node.startIndex);
433
+ }
434
+ const index = anonBodies.findIndex((c) => c.startIndex === node.startIndex);
435
+ if (index === -1)
436
+ return undefined;
437
+ return `${topName}$${index + 1}`;
438
+ };
356
439
  export const findEnclosingClassInfo = (node, filePath, resolveEnclosingOwner,
357
440
  /**
358
441
  * Optional (#1978): returns the enclosing type's fully-qualified name
@@ -411,6 +494,21 @@ getQualifiedOwnerName) => {
411
494
  }
412
495
  }
413
496
  }
497
+ // Java: an anonymous class body (`new Runnable() { ... }`) owns its
498
+ // members — attribute to the synthesized `Worker$N` class, not the
499
+ // lexically enclosing named class (#2550). `synthesizeJavaAnonymousClassName`
500
+ // returns undefined for `object_creation_expression` without a
501
+ // `class_body` (plain `new Foo()`, and every C# shape), so the walk
502
+ // continues unchanged for those.
503
+ if (current.type === 'object_creation_expression') {
504
+ const anonName = synthesizeJavaAnonymousClassName(current);
505
+ if (anonName !== undefined) {
506
+ return {
507
+ classId: generateId('Class', `${filePath}:${anonName}`),
508
+ className: anonName,
509
+ };
510
+ }
511
+ }
414
512
  if (CLASS_CONTAINER_TYPES.has(current.type)) {
415
513
  // Delegate language-specific container remapping to the provider hook.
416
514
  if (resolveEnclosingOwner) {
@@ -15,7 +15,7 @@ import { runPipelineFromRepo } from './ingestion/pipeline.js';
15
15
  import { resetDegradedParseCounter } from './tree-sitter/safe-parse.js';
16
16
  import { initLbug, loadGraphToLbug, getLbugStats, executeQuery, executeWithReusedStatement, closeLbug, closeLbugBeforeExit, loadCachedEmbeddings, deleteNodesForFiles, deleteAllCommunitiesAndProcesses, deleteAllInterprocTaintPaths, deleteAllCallSummaries, deleteAllInjects, queryImportersBatch, loadFTSExtension, wipeLbugDbFiles, LbugWipeError, DELETE_FILES_CHUNK_SIZE, } from './lbug/lbug-adapter.js';
17
17
  import { escapeCypherString } from './lbug/cypher-escape.js';
18
- import { createSearchFTSIndexes, initialiseSearchFTSStemmer, verifySearchFTSIndexes, } from './search/fts-indexes.js';
18
+ import { buildSearchIndexesOrDegrade, createSearchFTSIndexes, initialiseSearchFTSStemmer, verifySearchFTSIndexes, } from './search/fts-indexes.js';
19
19
  import { cjkSegmentationModeMismatch, getSearchFTSCjkSegmentation, initialiseSearchFTSCjkSegmentation, } from './search/cjk-segmentation.js';
20
20
  import { getExtensionCapabilities, resolveAnalyzeInstallPolicy } from './lbug/extension-loader.js';
21
21
  import { diagnoseExtensionLoad } from './lbug/extension-load-error.js';
@@ -1206,8 +1206,17 @@ export async function runFullAnalysis(repoPath, options, callbacks) {
1206
1206
  const ftsAvailable = await loadFTSExtension(undefined, {
1207
1207
  policy: resolveAnalyzeInstallPolicy(),
1208
1208
  });
1209
+ // Tracks whether search indexes actually ended up usable this run — starts
1210
+ // as ftsAvailable (extension loaded) but flips to false below when the
1211
+ // build/verify step itself fails, so capabilities.fts.status / ftsSkipped
1212
+ // stay honest even though that failure no longer aborts the whole analyze.
1213
+ let ftsReady = ftsAvailable;
1209
1214
  if (ftsAvailable) {
1210
- await createSearchFTSIndexes({
1215
+ // Degrade rather than throw: createSearchFTSIndexes re-tokenizes every
1216
+ // stored row on every run, so a native tokenizer error on a single
1217
+ // pre-existing row (#2544/#2546) must not discard this run's otherwise-
1218
+ // successful graph/embeddings work — only keyword search degrades.
1219
+ const ftsResult = await buildSearchIndexesOrDegrade(executeQuery, {
1211
1220
  onIndexStart: options.verbose
1212
1221
  ? (table, indexName) => log(`FTS: creating ${table}.${indexName}`)
1213
1222
  : undefined,
@@ -1215,12 +1224,15 @@ export async function runFullAnalysis(repoPath, options, callbacks) {
1215
1224
  ? (table, indexName) => log(`FTS: ready ${table}.${indexName}`)
1216
1225
  : undefined,
1217
1226
  });
1218
- const missingIndexNames = await verifySearchFTSIndexes(executeQuery);
1219
- if (missingIndexNames.length > 0) {
1220
- throw new Error(`FTS verification failed - missing indexes after analyze: ${missingIndexNames.join(', ')}. ` +
1221
- 'Check FTS extension availability, then retry `gitnexus analyze --force` for a full rebuild.');
1227
+ if (ftsResult.ok) {
1228
+ progress('fts', 90, 'Search indexes ready');
1229
+ }
1230
+ else {
1231
+ ftsReady = false;
1232
+ log(`FTS index build failed (${ftsResult.error}) — keyword search degraded this run. ` +
1233
+ 'Graph and embeddings analysis completed successfully. Run `gitnexus analyze --repair-fts` to retry.');
1234
+ progress('fts', 90, 'Search indexes skipped (build failed)');
1222
1235
  }
1223
- progress('fts', 90, 'Search indexes ready');
1224
1236
  }
1225
1237
  else {
1226
1238
  // For a missing runtime dependency (#2374) the file is present, so the
@@ -1559,7 +1571,7 @@ export async function runFullAnalysis(repoPath, options, callbacks) {
1559
1571
  // meta.json / `gitnexus doctor` honest about degraded search.
1560
1572
  fts: {
1561
1573
  provider: 'ladybugdb-fts',
1562
- status: ftsAvailable ? runtimeCapabilities.fts : 'unavailable',
1574
+ status: ftsReady ? runtimeCapabilities.fts : 'unavailable',
1563
1575
  },
1564
1576
  vectorSearch: {
1565
1577
  provider: effectiveSemanticMode === 'vector-index' ? 'ladybugdb-vector' : 'exact-scan',
@@ -1723,7 +1735,7 @@ export async function runFullAnalysis(repoPath, options, callbacks) {
1723
1735
  repoPath,
1724
1736
  stats: meta.stats,
1725
1737
  pipelineResult,
1726
- ftsSkipped: !ftsAvailable,
1738
+ ftsSkipped: !ftsReady,
1727
1739
  isPrimaryBranch: !placement.branch,
1728
1740
  };
1729
1741
  }
@@ -26,3 +26,18 @@ export declare function initialiseSearchFTSStemmer(): string;
26
26
  export declare function getSearchFTSStemmer(): string;
27
27
  export declare function createSearchFTSIndexes(options?: CreateSearchFTSIndexesOptions): Promise<void>;
28
28
  export declare function verifySearchFTSIndexes(executeQuery: (cypher: string) => Promise<unknown[]>): Promise<string[]>;
29
+ export interface BuildSearchIndexesResult {
30
+ ok: boolean;
31
+ error?: string;
32
+ }
33
+ /**
34
+ * Build + verify FTS indexes, catching any failure instead of letting it
35
+ * propagate. `createSearchFTSIndexes` re-tokenizes every stored row on every
36
+ * analyze run (see the `ponytail:` comment above) — a native LadybugDB
37
+ * tokenizer error on a single pre-existing row (e.g. a "Failed calling
38
+ * LOWER: Invalid UTF-8", #2544/#2546) must not discard an otherwise-
39
+ * successful analyze's graph/embeddings work. The caller degrades keyword
40
+ * search for this run instead, mirroring the existing FTS-extension-
41
+ * unavailable degrade path in `run-analyze.ts`.
42
+ */
43
+ export declare function buildSearchIndexesOrDegrade(executeQuery: (cypher: string) => Promise<unknown[]>, options?: CreateSearchFTSIndexesOptions): Promise<BuildSearchIndexesResult>;
@@ -152,3 +152,26 @@ export async function verifySearchFTSIndexes(executeQuery) {
152
152
  }
153
153
  return missing;
154
154
  }
155
+ /**
156
+ * Build + verify FTS indexes, catching any failure instead of letting it
157
+ * propagate. `createSearchFTSIndexes` re-tokenizes every stored row on every
158
+ * analyze run (see the `ponytail:` comment above) — a native LadybugDB
159
+ * tokenizer error on a single pre-existing row (e.g. a "Failed calling
160
+ * LOWER: Invalid UTF-8", #2544/#2546) must not discard an otherwise-
161
+ * successful analyze's graph/embeddings work. The caller degrades keyword
162
+ * search for this run instead, mirroring the existing FTS-extension-
163
+ * unavailable degrade path in `run-analyze.ts`.
164
+ */
165
+ export async function buildSearchIndexesOrDegrade(executeQuery, options) {
166
+ try {
167
+ await createSearchFTSIndexes(options);
168
+ const missing = await verifySearchFTSIndexes(executeQuery);
169
+ if (missing.length > 0) {
170
+ return { ok: false, error: `missing indexes after build: ${missing.join(', ')}` };
171
+ }
172
+ return { ok: true };
173
+ }
174
+ catch (e) {
175
+ return { ok: false, error: e instanceof Error ? e.message : String(e) };
176
+ }
177
+ }
@@ -52,7 +52,7 @@ import { fileURLToPath } from 'url';
52
52
  // the main thread (the #1983 OOM). Because the two stores share this version,
53
53
  // any future change to the `ParsedFile` serialization shape MUST bump
54
54
  // SCHEMA_BUMP so both invalidate in lockstep.
55
- const SCHEMA_BUMP = 17; // Callable-value-flow operands now retain expression kind/qualified identity and formal signature metadata. (16 = direct callee identity; 15 = always-on callableFlowSites; 14 = #2437 value refs.)
55
+ const SCHEMA_BUMP = 18; // Java anonymous class bodies emit synthesized Worker$N Class nodes and re-keyed methods (#2550). (17 = callable-value-flow operand identity; 16 = direct callee identity; 15 = always-on callableFlowSites.)
56
56
  const GITNEXUS_PKG_VERSION = (() => {
57
57
  try {
58
58
  // package.json sits at gitnexus/package.json — two levels up from
@@ -335,8 +335,14 @@ export interface RepoMeta {
335
335
  * only covers changed files (`computeEffectiveWriteSet`), so a top-up against a
336
336
  * pre-v7 index would silently omit the new edges for every unchanged file pair;
337
337
  * force a full re-analyze instead (same contract as v2–v6).
338
- */
339
- export declare const INCREMENTAL_SCHEMA_VERSION = 7;
338
+ * v8: Java anonymous class bodies became first-class Class nodes (#2550):
339
+ * `new Runnable() { run(){} }` now emits `Class:...:Worker$1` and its methods
340
+ * re-keyed from `Worker.run` to `Worker$1.run`. Node identities move on
341
+ * unchanged files — a top-up against a pre-v8 index would strand the old
342
+ * `Worker.run`-keyed Method nodes alongside the new ones (the v5 Route
343
+ * precedent); force a full re-analyze instead.
344
+ */
345
+ export declare const INCREMENTAL_SCHEMA_VERSION = 8;
340
346
  export interface IndexedRepo {
341
347
  repoPath: string;
342
348
  storagePath: string;
@@ -112,8 +112,14 @@ export const cloneDirBelongsToEntry = (cloneDir, entryPath) => registryPathEqual
112
112
  * only covers changed files (`computeEffectiveWriteSet`), so a top-up against a
113
113
  * pre-v7 index would silently omit the new edges for every unchanged file pair;
114
114
  * force a full re-analyze instead (same contract as v2–v6).
115
+ * v8: Java anonymous class bodies became first-class Class nodes (#2550):
116
+ * `new Runnable() { run(){} }` now emits `Class:...:Worker$1` and its methods
117
+ * re-keyed from `Worker.run` to `Worker$1.run`. Node identities move on
118
+ * unchanged files — a top-up against a pre-v8 index would strand the old
119
+ * `Worker.run`-keyed Method nodes alongside the new ones (the v5 Route
120
+ * precedent); force a full re-analyze instead.
115
121
  */
116
- export const INCREMENTAL_SCHEMA_VERSION = 7;
122
+ export const INCREMENTAL_SCHEMA_VERSION = 8;
117
123
  const GITNEXUS_DIR = '.gitnexus';
118
124
  const GITNEXUS_EXCLUDE_ENTRY = `${GITNEXUS_DIR}/`;
119
125
  export const INDEX_METADATA_FILE = 'gitnexus.json';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.10-rc.45",
3
+ "version": "1.6.10-rc.47",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",