gitnexus 1.6.10-rc.46 → 1.6.10-rc.48
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.
- package/README.md +2 -0
- package/dist/_shared/scope-resolution/types.d.ts +14 -2
- package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
- package/dist/core/ingestion/class-extractors/configs/jvm.js +24 -0
- package/dist/core/ingestion/languages/java/captures.js +78 -1
- package/dist/core/ingestion/languages/java/query.js +8 -0
- package/dist/core/ingestion/languages/java/scope-resolver.js +6 -0
- package/dist/core/ingestion/languages/javascript/query.js +7 -0
- package/dist/core/ingestion/languages/kotlin/query.js +6 -0
- package/dist/core/ingestion/languages/typescript/query.js +17 -0
- package/dist/core/ingestion/scope-extractor.js +2 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +17 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +9 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +95 -1
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +2 -0
- package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
- package/dist/core/ingestion/scope-resolution/scope/walkers.js +63 -44
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
- package/dist/core/ingestion/tree-sitter-queries.js +4 -0
- package/dist/core/ingestion/type-extractors/jvm.js +17 -2
- package/dist/core/ingestion/utils/ast-helpers.d.ts +1 -0
- package/dist/core/ingestion/utils/ast-helpers.js +99 -1
- package/dist/core/lbug/lbug-config.d.ts +9 -2
- package/dist/core/lbug/lbug-config.js +57 -3
- package/dist/storage/parse-cache.js +1 -1
- package/dist/storage/repo-manager.d.ts +8 -2
- package/dist/storage/repo-manager.js +7 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -471,6 +471,8 @@ Configure the behavior with these environment variables:
|
|
|
471
471
|
| `GITNEXUS_FTS_CJK_SEGMENTATION` | `none`, `bigram` | `none` | `bigram` inserts overlapping character-bigram boundaries into Chinese/Japanese Han-ideograph spans in `content`/`description` before FTS indexing, so LadybugDB's space-only tokenizer can see sub-phrase word boundaries. Scoped to CJK Unified Ideographs only — Japanese Hiragana/Katakana and Korean Hangul are not currently segmented. Unlike `GITNEXUS_FTS_STEMMER`, this rewrites stored text — enabling it on an already-indexed repo requires a full `gitnexus analyze --force`; neither `--repair-fts` nor a plain incremental `analyze` applies it to previously-indexed files. Set the same value wherever `analyze` and search-serving processes (CLI query, MCP server, web server) run. |
|
|
472
472
|
| `GITNEXUS_COMMUNITY_ENGINE` | `graphology`, `icebug`, `auto` | `graphology` | Community-detection engine used during analyze. `graphology` uses the bundled default path. `icebug` and `auto` currently behave identically: both try the experimental Icebug CSR path and fall back to Graphology if the optional native module is unavailable or incompatible. |
|
|
473
473
|
| `GITNEXUS_WAL_CHECKPOINT_THRESHOLD` | integer `>= -1` | `67108864` (64 MiB) | LadybugDB WAL auto-checkpoint threshold during analyze (bytes). Auto-checkpoint remains enabled; `-1` keeps Ladybug's stock ~16 MiB. Larger thresholds reduce checkpoint frequency but increase the WAL size at rotation time — choose a smaller value on disk-constrained environments. |
|
|
474
|
+
| `GITNEXUS_LBUG_BUFFER_POOL_SIZE` | integer `>= 0` (bytes) | min(2 GiB, 80% RAM) | LadybugDB buffer-pool ceiling for every GitNexus database (analyze, MCP server, serve, group bridges). Bounded so a long-lived `gitnexus mcp` process or a large incremental `analyze` cannot grow toward LadybugDB's native 80%-of-RAM default and OOM the host (#2557). `0` restores that native unbounded default; invalid values warn and fall back to the default. |
|
|
475
|
+
| `GITNEXUS_LBUG_MAX_DB_SIZE` | positive integer (bytes) | `17179869184` (16 GiB) | Upper bound for a single LadybugDB database file. This is an mmap/disk-address-space ceiling, not a memory limit — it does not constrain the buffer pool (use `GITNEXUS_LBUG_BUFFER_POOL_SIZE` for that). Raise it when indexing genuinely huge monorepos; invalid values silently fall back to the default. |
|
|
474
476
|
|
|
475
477
|
```bash
|
|
476
478
|
# Offline/airgapped: never reach the network for extensions
|
|
@@ -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
|
-
/**
|
|
31
|
-
|
|
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":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAI/D,4FAA4F;AAC5F,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B,0DAA0D;AAC1D,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC;AAE3B
|
|
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
|
|
@@ -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
|
-
//
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
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
|
-
|
|
698
|
-
|
|
699
|
-
|
|
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
|
-
|
|
934
|
-
if (
|
|
935
|
-
|
|
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
|
-
|
|
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) {
|
|
@@ -39,8 +39,15 @@ export declare function resolveNativeSafeStorageDir(storagePath: string, subdir:
|
|
|
39
39
|
* `true` (0.16.0). Existing call sites that relied on the positional
|
|
40
40
|
* default must now pass `false` explicitly to preserve behaviour.
|
|
41
41
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
42
|
+
* 3. `bufferManagerSize` (not a 0.16.0 change, same pin-explicitly
|
|
43
|
+
* principle): `0` means "native default", and the native default buffer
|
|
44
|
+
* pool is 80% of physical RAM. A long-lived `gitnexus mcp` process or a
|
|
45
|
+
* large incremental analyze can balloon to that ceiling and OOM-kill the
|
|
46
|
+
* host session (#2557), so GitNexus pins an explicit bounded pool — see
|
|
47
|
+
* `resolveBufferManagerSize`.
|
|
48
|
+
*
|
|
49
|
+
* Putting these in one shared module guarantees every `new lbug.Database(...)`
|
|
50
|
+
* call site agrees on the same ceilings and behaviour.
|
|
44
51
|
*/
|
|
45
52
|
/**
|
|
46
53
|
* Upper bound for any single GitNexus LadybugDB file (graph index, group
|
|
@@ -227,8 +227,15 @@ export function resolveNativeSafeStorageDir(storagePath, subdir) {
|
|
|
227
227
|
* `true` (0.16.0). Existing call sites that relied on the positional
|
|
228
228
|
* default must now pass `false` explicitly to preserve behaviour.
|
|
229
229
|
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
230
|
+
* 3. `bufferManagerSize` (not a 0.16.0 change, same pin-explicitly
|
|
231
|
+
* principle): `0` means "native default", and the native default buffer
|
|
232
|
+
* pool is 80% of physical RAM. A long-lived `gitnexus mcp` process or a
|
|
233
|
+
* large incremental analyze can balloon to that ceiling and OOM-kill the
|
|
234
|
+
* host session (#2557), so GitNexus pins an explicit bounded pool — see
|
|
235
|
+
* `resolveBufferManagerSize`.
|
|
236
|
+
*
|
|
237
|
+
* Putting these in one shared module guarantees every `new lbug.Database(...)`
|
|
238
|
+
* call site agrees on the same ceilings and behaviour.
|
|
232
239
|
*/
|
|
233
240
|
/**
|
|
234
241
|
* Upper bound for any single GitNexus LadybugDB file (graph index, group
|
|
@@ -286,6 +293,53 @@ const resolveCheckpointThreshold = () => {
|
|
|
286
293
|
}
|
|
287
294
|
return DEFAULT_WAL_CHECKPOINT_THRESHOLD;
|
|
288
295
|
};
|
|
296
|
+
/**
|
|
297
|
+
* Default ceiling for the LadybugDB buffer pool in bytes (#2557).
|
|
298
|
+
*
|
|
299
|
+
* The pool is a page cache with eviction, so the ceiling trades throughput
|
|
300
|
+
* on very large working sets for a machine that stays alive: 2 GiB is
|
|
301
|
+
* ~40× the GitNexus self-index, while the native 80%-of-RAM default let a
|
|
302
|
+
* `detect_changes` call grow a 105 MiB on-disk index to 19.5 GiB RSS and
|
|
303
|
+
* OOM-kill the reporter's session. The `min` with 80% of `os.totalmem()`
|
|
304
|
+
* keeps sub-2.5-GiB machines at the native-equivalent bound (no regression
|
|
305
|
+
* there); the 64 MiB floor keeps tiny containers above any plausible
|
|
306
|
+
* native minimum pool size.
|
|
307
|
+
*/
|
|
308
|
+
const DEFAULT_BUFFER_POOL_CAP = 2 * 1024 * 1024 * 1024;
|
|
309
|
+
const BUFFER_POOL_FLOOR = 64 * 1024 * 1024;
|
|
310
|
+
const parseBufferPoolSize = (raw) => {
|
|
311
|
+
if (raw === undefined)
|
|
312
|
+
return undefined;
|
|
313
|
+
const normalized = raw.trim();
|
|
314
|
+
if (normalized.length === 0)
|
|
315
|
+
return undefined;
|
|
316
|
+
const parsed = Number(normalized);
|
|
317
|
+
if (!Number.isFinite(parsed) || parsed < 0)
|
|
318
|
+
return undefined;
|
|
319
|
+
return Math.floor(parsed);
|
|
320
|
+
};
|
|
321
|
+
const defaultBufferPoolSize = () => Math.min(DEFAULT_BUFFER_POOL_CAP, Math.max(BUFFER_POOL_FLOOR, Math.floor(os.totalmem() * 0.8)));
|
|
322
|
+
/**
|
|
323
|
+
* Resolve the `bufferManagerSize` passed to every `new lbug.Database(...)`.
|
|
324
|
+
* `GITNEXUS_LBUG_BUFFER_POOL_SIZE` (bytes) overrides the default; `0` is a
|
|
325
|
+
* deliberate escape hatch that restores LadybugDB's native unbounded
|
|
326
|
+
* 80%-of-RAM default. Resolved at call time (not module load) so tests can
|
|
327
|
+
* stub the env var and `os.totalmem`.
|
|
328
|
+
*/
|
|
329
|
+
const resolveBufferManagerSize = () => {
|
|
330
|
+
const raw = process.env.GITNEXUS_LBUG_BUFFER_POOL_SIZE;
|
|
331
|
+
if (raw === undefined)
|
|
332
|
+
return defaultBufferPoolSize();
|
|
333
|
+
const parsed = parseBufferPoolSize(raw);
|
|
334
|
+
if (parsed !== undefined)
|
|
335
|
+
return parsed;
|
|
336
|
+
// Non-empty but unparseable input: warn the operator and fall back —
|
|
337
|
+
// mirrors the GITNEXUS_WAL_CHECKPOINT_THRESHOLD env path above.
|
|
338
|
+
if (raw.trim().length > 0) {
|
|
339
|
+
logger.warn({ rawValue: raw, fallback: defaultBufferPoolSize() }, `Ignoring invalid GITNEXUS_LBUG_BUFFER_POOL_SIZE=${raw}; expected integer >= 0 (bytes; 0 restores the native 80%-of-RAM default); falling back to min(2 GiB, 80% of RAM).`);
|
|
340
|
+
}
|
|
341
|
+
return defaultBufferPoolSize();
|
|
342
|
+
};
|
|
289
343
|
/** Matches WAL corruption errors from the LadybugDB engine. */
|
|
290
344
|
const WAL_CORRUPTION_RE = /corrupt(ed)?\s+wal|invalid\s+wal\s+record|wal.*corrupt|checksum.*wal/i;
|
|
291
345
|
export const WAL_RECOVERY_SUGGESTION = 'WAL corruption detected. Run `gitnexus analyze --force` to rebuild the index.';
|
|
@@ -496,7 +550,7 @@ export const classifyDeleteAllError = (err) => {
|
|
|
496
550
|
};
|
|
497
551
|
export function createLbugDatabase(lbugModule, databasePath, options = {}) {
|
|
498
552
|
// .d.ts declares fewer args than the native constructor accepts.
|
|
499
|
-
return new lbugModule.Database(databasePath,
|
|
553
|
+
return new lbugModule.Database(databasePath, resolveBufferManagerSize(), // bufferManagerSize (#2557: default min(2 GiB, 80% RAM); GITNEXUS_LBUG_BUFFER_POOL_SIZE overrides; 0 restores the native 80%-of-RAM default)
|
|
500
554
|
false, // enableCompression (pinned for v0.16.0)
|
|
501
555
|
options.readOnly ?? false, LBUG_MAX_DB_SIZE, true, // autoCheckpoint (always on)
|
|
502
556
|
resolveCheckpointThreshold(), // checkpointThreshold (default 64 MiB; override with GITNEXUS_WAL_CHECKPOINT_THRESHOLD; -1 keeps Ladybug stock ~16 MiB)
|
|
@@ -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 =
|
|
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
|
-
|
|
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 =
|
|
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