gitnexus 1.6.10-rc.49 → 1.6.10-rc.50
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/dist/core/ingestion/class-extractors/configs/jvm.js +12 -7
- package/dist/core/ingestion/languages/java/captures.js +39 -0
- package/dist/core/ingestion/languages/java/query.js +6 -0
- package/dist/core/ingestion/scope-resolution/scope/walkers.js +10 -0
- 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/utils/ast-helpers.js +86 -33
- 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
|
@@ -17,6 +17,9 @@ export const javaClassConfig = {
|
|
|
17
17
|
// any other shape, so plain `new Foo()` constructor calls never
|
|
18
18
|
// produce a Class node (#2550).
|
|
19
19
|
'object_creation_expression',
|
|
20
|
+
// Enum constant bodies (`enum E { A { ... } }`) — javac's other
|
|
21
|
+
// anonymous shape, named E$N by the same authority (#2555).
|
|
22
|
+
'enum_constant',
|
|
20
23
|
],
|
|
21
24
|
fileScopeNodeTypes: ['package_declaration'],
|
|
22
25
|
ancestorScopeNodeTypes: [
|
|
@@ -26,20 +29,22 @@ export const javaClassConfig = {
|
|
|
26
29
|
'record_declaration',
|
|
27
30
|
],
|
|
28
31
|
extractName(node) {
|
|
29
|
-
if (node.type === 'object_creation_expression') {
|
|
32
|
+
if (node.type === 'object_creation_expression' || node.type === 'enum_constant') {
|
|
30
33
|
return synthesizeJavaAnonymousClassName(node);
|
|
31
34
|
}
|
|
32
35
|
return undefined;
|
|
33
36
|
},
|
|
34
|
-
// An anonymous body whose name CANNOT be synthesized
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
37
|
+
// An anonymous body whose name CANNOT be synthesized must not become a
|
|
38
|
+
// Class node at all. Without this skip, `extract()`'s
|
|
39
|
+
// `extractTypeNameFromNode` fallback fabricates a name — the CONSTRUCTED
|
|
40
|
+
// type for `new Runnable() { ... }` (phantom `Class:...:Runnable`,
|
|
41
|
+
// empirically caught in review) or the constant's own identifier for an
|
|
42
|
+
// `enum_constant` (`Class:...:A`).
|
|
39
43
|
shouldSkipClassCapture({ definitionNode }) {
|
|
40
44
|
return (definitionNode !== null &&
|
|
41
45
|
definitionNode !== undefined &&
|
|
42
|
-
definitionNode.type === 'object_creation_expression'
|
|
46
|
+
(definitionNode.type === 'object_creation_expression' ||
|
|
47
|
+
definitionNode.type === 'enum_constant') &&
|
|
43
48
|
synthesizeJavaAnonymousClassName(definitionNode) === undefined);
|
|
44
49
|
},
|
|
45
50
|
};
|
|
@@ -255,8 +255,47 @@ function synthesizeJavaAnonymousClassDeclarations(rootNode) {
|
|
|
255
255
|
}
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
|
+
// Enum constant bodies (`enum E { A { ... } }`) — javac's other
|
|
259
|
+
// anonymous shape (#2555). Same synthesis, same body anchor; the
|
|
260
|
+
// constant's class extends its HOST ENUM (javac semantics), so the
|
|
261
|
+
// inherits reference names the enum — giving `mroFor(E$N) ∋ E` and
|
|
262
|
+
// keeping bare calls from the body to the enum's own helpers alive
|
|
263
|
+
// through the ownership gate's MRO arm. No receiver typeBinding piece:
|
|
264
|
+
// constants are not variable initializers; `E.A.hook()` dispatch rides
|
|
265
|
+
// the existing enum receiver machinery.
|
|
266
|
+
for (const constant of rootNode.descendantsOfType('enum_constant')) {
|
|
267
|
+
const name = synthesizeJavaAnonymousClassName(constant);
|
|
268
|
+
if (name === undefined)
|
|
269
|
+
continue;
|
|
270
|
+
const body = constant.childForFieldName?.('body');
|
|
271
|
+
if (body === null || body === undefined || body.type !== 'class_body')
|
|
272
|
+
continue;
|
|
273
|
+
out.push({
|
|
274
|
+
'@declaration.class': nodeToCapture('@declaration.class', body),
|
|
275
|
+
'@declaration.name': syntheticCapture('@declaration.name', body, name),
|
|
276
|
+
});
|
|
277
|
+
const hostEnum = javaEnclosingEnumNameOf(constant);
|
|
278
|
+
if (hostEnum !== undefined) {
|
|
279
|
+
out.push({
|
|
280
|
+
'@reference.inherits': nodeToCapture('@reference.inherits', body),
|
|
281
|
+
'@reference.name': syntheticCapture('@reference.name', body, hostEnum),
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
258
285
|
return out;
|
|
259
286
|
}
|
|
287
|
+
/** Simple name of the enum_declaration enclosing an enum_constant, or
|
|
288
|
+
* undefined (grammar guarantees one exists in well-formed source). */
|
|
289
|
+
function javaEnclosingEnumNameOf(constant) {
|
|
290
|
+
let cursor = constant.parent;
|
|
291
|
+
while (cursor !== null) {
|
|
292
|
+
if (cursor.type === 'enum_declaration') {
|
|
293
|
+
return cursor.childForFieldName?.('name')?.text ?? undefined;
|
|
294
|
+
}
|
|
295
|
+
cursor = cursor.parent;
|
|
296
|
+
}
|
|
297
|
+
return undefined;
|
|
298
|
+
}
|
|
260
299
|
/**
|
|
261
300
|
* Synthesize `@reference.call.constructor` captures for explicit constructor
|
|
262
301
|
* invocations — `super(...)` and `this(...)` (F38 #1928). tree-sitter-java
|
|
@@ -45,6 +45,12 @@ const JAVA_SCOPE_QUERY = `
|
|
|
45
45
|
(object_creation_expression
|
|
46
46
|
(class_body) @scope.class)
|
|
47
47
|
|
|
48
|
+
;; Enum constant body: \`enum E { A { public void hook() {} } }\` --
|
|
49
|
+
;; javac's other anonymous-class shape (E$N), same scope-boundary need
|
|
50
|
+
;; and same class_body anchor (#2555).
|
|
51
|
+
(enum_constant
|
|
52
|
+
body: (class_body) @scope.class)
|
|
53
|
+
|
|
48
54
|
(method_declaration) @scope.function
|
|
49
55
|
(constructor_declaration) @scope.function
|
|
50
56
|
|
|
@@ -763,6 +763,16 @@ export function populateClassOwnedMembers(parsed) {
|
|
|
763
763
|
return;
|
|
764
764
|
if (q.includes('.'))
|
|
765
765
|
return; // already qualified (dotted)
|
|
766
|
+
// A synthesized anonymous-class def (Java `$`-chain binary name,
|
|
767
|
+
// #2550/#2555 — `M3$2`, `EnumWrap$Mode$1`) already carries its
|
|
768
|
+
// COMPLETE name. Prefixing it (`M3.M3$2`) desyncs from the
|
|
769
|
+
// structure-phase node id (`M3$2.hook`), so same-named methods
|
|
770
|
+
// across sibling enum-constant bodies collapse onto the first
|
|
771
|
+
// body's node via the simple-name fallback (empirically caught in
|
|
772
|
+
// review). Class-like only: `$`-named MEMBERS (legal in JS/TS)
|
|
773
|
+
// still qualify normally against their class.
|
|
774
|
+
if (isClassLike(def.type) && q.includes('$'))
|
|
775
|
+
return;
|
|
766
776
|
const classQ = classDef.qualifiedName;
|
|
767
777
|
if (classQ === undefined || classQ.length === 0)
|
|
768
778
|
return;
|
|
@@ -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; 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";
|
|
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; Enum constant bodies: enum E { A { ... } } \u2014 javac's other anonymous\n; shape, synthesized as E$N by the same naming authority (#2555)\n(enum_constant body: (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";
|
|
@@ -748,6 +748,10 @@ export const JAVA_QUERIES = `
|
|
|
748
748
|
; class extractor synthesizes the javac-style Worker$N name (#2550)
|
|
749
749
|
(object_creation_expression (class_body)) @definition.class
|
|
750
750
|
|
|
751
|
+
; Enum constant bodies: enum E { A { ... } } — javac's other anonymous
|
|
752
|
+
; shape, synthesized as E$N by the same naming authority (#2555)
|
|
753
|
+
(enum_constant body: (class_body)) @definition.class
|
|
754
|
+
|
|
751
755
|
; Methods & Constructors
|
|
752
756
|
(method_declaration name: (identifier) @name) @definition.method
|
|
753
757
|
(constructor_declaration name: (identifier) @name) @definition.constructor
|
|
@@ -375,15 +375,39 @@ const MAX_ENCLOSING_WALK_ITERATIONS = 4096;
|
|
|
375
375
|
* this one helper.
|
|
376
376
|
*/
|
|
377
377
|
/** Type-declaration node types that can host (and name) a Java anonymous
|
|
378
|
-
* class body
|
|
379
|
-
*
|
|
380
|
-
*
|
|
378
|
+
* class body. Naming follows JLS 13.1: the binary name is the
|
|
379
|
+
* IMMEDIATELY enclosing type's binary name + `$N`, so the synthesized
|
|
380
|
+
* name is the `$`-joined chain of enclosing host names
|
|
381
|
+
* (`EnumWrap$Mode$1`), numbered per immediate host in source order. */
|
|
381
382
|
const JAVA_ANON_HOST_TYPES = new Set([
|
|
382
383
|
'class_declaration',
|
|
383
384
|
'enum_declaration',
|
|
384
385
|
'interface_declaration',
|
|
385
386
|
'record_declaration',
|
|
386
387
|
]);
|
|
388
|
+
/** The two Java anonymous-class-body shapes (#2550/#2555): an
|
|
389
|
+
* `object_creation_expression` with a `class_body` child
|
|
390
|
+
* (`new Runnable() { ... }`), and an `enum_constant` with a `body:`
|
|
391
|
+
* field (`enum E { A { ... } }` — javac's other `E$N` shape). */
|
|
392
|
+
const isJavaAnonymousBodyNode = (node) => (node.type === 'object_creation_expression' &&
|
|
393
|
+
node.namedChildren?.some((c) => c.type === 'class_body') === true) ||
|
|
394
|
+
(node.type === 'enum_constant' && node.childForFieldName?.('body')?.type === 'class_body');
|
|
395
|
+
/** Nearest ancestor of `node` that is an enclosing TYPE per JLS 13.1 —
|
|
396
|
+
* a named host declaration OR another anonymous body (both shapes).
|
|
397
|
+
* Anonymous ancestors chain through: an anon inside an anon is
|
|
398
|
+
* `Host$1$1`, and an anon inside an enum constant body is `E$1$1`. */
|
|
399
|
+
const nearestJavaEnclosingType = (node) => {
|
|
400
|
+
let cursor = node.parent;
|
|
401
|
+
let iterations = 0;
|
|
402
|
+
while (cursor) {
|
|
403
|
+
if (++iterations > MAX_ENCLOSING_WALK_ITERATIONS)
|
|
404
|
+
return null;
|
|
405
|
+
if (JAVA_ANON_HOST_TYPES.has(cursor.type) || isJavaAnonymousBodyNode(cursor))
|
|
406
|
+
return cursor;
|
|
407
|
+
cursor = cursor.parent;
|
|
408
|
+
}
|
|
409
|
+
return null;
|
|
410
|
+
};
|
|
387
411
|
/** Per-parse-tree memo of anonymous-body numbering: tree → (startIndex →
|
|
388
412
|
* synthesized name). Keyed by the tree OBJECT via WeakMap so entries die
|
|
389
413
|
* with the parse; without it every call re-scans the host subtree
|
|
@@ -392,10 +416,7 @@ const JAVA_ANON_HOST_TYPES = new Set([
|
|
|
392
416
|
* listener-per-widget Java). */
|
|
393
417
|
const javaAnonNameMemo = new WeakMap();
|
|
394
418
|
export const synthesizeJavaAnonymousClassName = (node) => {
|
|
395
|
-
if (node
|
|
396
|
-
return undefined;
|
|
397
|
-
const hasClassBody = node.namedChildren?.some((c) => c.type === 'class_body');
|
|
398
|
-
if (hasClassBody !== true)
|
|
419
|
+
if (!isJavaAnonymousBodyNode(node))
|
|
399
420
|
return undefined;
|
|
400
421
|
const tree = node.tree;
|
|
401
422
|
if (tree !== undefined) {
|
|
@@ -403,38 +424,68 @@ export const synthesizeJavaAnonymousClassName = (node) => {
|
|
|
403
424
|
if (cached !== undefined)
|
|
404
425
|
return cached;
|
|
405
426
|
}
|
|
406
|
-
//
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
427
|
+
// JLS 13.1: the binary name is the IMMEDIATELY ENCLOSING TYPE's binary
|
|
428
|
+
// name + `$N`. The enclosing type may itself be anonymous — then its
|
|
429
|
+
// own synthesized name is the prefix (recursion, memo-bounded):
|
|
430
|
+
// `NestHost$1$1` for an anon inside an anon, `E$1$1` for an anon
|
|
431
|
+
// inside an enum constant body. For a named enclosing type the prefix
|
|
432
|
+
// is the `$`-joined chain of named hosts (`EnumWrap$Mode`).
|
|
433
|
+
const enclosing = nearestJavaEnclosingType(node);
|
|
434
|
+
if (enclosing === null)
|
|
435
|
+
return undefined;
|
|
436
|
+
let prefix;
|
|
437
|
+
if (isJavaAnonymousBodyNode(enclosing)) {
|
|
438
|
+
const enclosingName = synthesizeJavaAnonymousClassName(enclosing);
|
|
439
|
+
if (enclosingName === undefined)
|
|
412
440
|
return undefined;
|
|
413
|
-
|
|
414
|
-
topHost = cursor;
|
|
415
|
-
cursor = cursor.parent;
|
|
441
|
+
prefix = enclosingName;
|
|
416
442
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
443
|
+
else {
|
|
444
|
+
const hostNames = [];
|
|
445
|
+
let cursor = enclosing;
|
|
446
|
+
let iterations = 0;
|
|
447
|
+
while (cursor) {
|
|
448
|
+
if (++iterations > MAX_ENCLOSING_WALK_ITERATIONS)
|
|
449
|
+
return undefined;
|
|
450
|
+
if (JAVA_ANON_HOST_TYPES.has(cursor.type)) {
|
|
451
|
+
const hostName = cursor.childForFieldName?.('name')?.text;
|
|
452
|
+
if (hostName === undefined || hostName.length === 0)
|
|
453
|
+
return undefined;
|
|
454
|
+
hostNames.unshift(hostName);
|
|
455
|
+
}
|
|
456
|
+
cursor = cursor.parent;
|
|
457
|
+
}
|
|
458
|
+
prefix = hostNames.join('$');
|
|
459
|
+
}
|
|
460
|
+
// All anonymous bodies (both shapes) whose immediately enclosing TYPE
|
|
461
|
+
// is THIS one, in source order. `descendantsOfType` over the subtree
|
|
462
|
+
// also finds bodies belonging to nested enclosing types — filter them
|
|
463
|
+
// out by re-deriving each candidate's own enclosing type.
|
|
464
|
+
const candidates = [
|
|
465
|
+
...(enclosing.descendantsOfType?.('object_creation_expression') ?? []),
|
|
466
|
+
...(enclosing.descendantsOfType?.('enum_constant') ?? []),
|
|
467
|
+
]
|
|
468
|
+
.filter(isJavaAnonymousBodyNode)
|
|
469
|
+
.filter((c) => {
|
|
470
|
+
const host = nearestJavaEnclosingType(c);
|
|
471
|
+
return (host !== null && host.startIndex === enclosing.startIndex && host.type === enclosing.type);
|
|
472
|
+
})
|
|
473
|
+
.sort((a, b) => a.startIndex - b.startIndex);
|
|
423
474
|
if (tree !== undefined) {
|
|
424
475
|
let byStart = javaAnonNameMemo.get(tree);
|
|
425
476
|
if (byStart === undefined) {
|
|
426
477
|
byStart = new Map();
|
|
427
478
|
javaAnonNameMemo.set(tree, byStart);
|
|
428
479
|
}
|
|
429
|
-
for (let i = 0; i <
|
|
430
|
-
byStart.set(
|
|
480
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
481
|
+
byStart.set(candidates[i].startIndex, `${prefix}$${i + 1}`);
|
|
431
482
|
}
|
|
432
483
|
return byStart.get(node.startIndex);
|
|
433
484
|
}
|
|
434
|
-
const index =
|
|
485
|
+
const index = candidates.findIndex((c) => c.startIndex === node.startIndex);
|
|
435
486
|
if (index === -1)
|
|
436
487
|
return undefined;
|
|
437
|
-
return `${
|
|
488
|
+
return `${prefix}$${index + 1}`;
|
|
438
489
|
};
|
|
439
490
|
export const findEnclosingClassInfo = (node, filePath, resolveEnclosingOwner,
|
|
440
491
|
/**
|
|
@@ -494,13 +545,15 @@ getQualifiedOwnerName) => {
|
|
|
494
545
|
}
|
|
495
546
|
}
|
|
496
547
|
}
|
|
497
|
-
// Java: an anonymous class body
|
|
498
|
-
//
|
|
499
|
-
//
|
|
500
|
-
//
|
|
501
|
-
//
|
|
502
|
-
//
|
|
503
|
-
|
|
548
|
+
// Java: an anonymous class body owns its members — attribute to the
|
|
549
|
+
// synthesized `Worker$N`/`E$N` class, not the lexically enclosing
|
|
550
|
+
// named type (#2550/#2555). Covers both shapes: `new Runnable() { ... }`
|
|
551
|
+
// and enum constant bodies (`enum E { A { ... } }`). The synthesis
|
|
552
|
+
// returns undefined for shape-less nodes (plain `new Foo()`, a body-less
|
|
553
|
+
// enum constant, and every C# `object_creation_expression`), so the
|
|
554
|
+
// walk continues unchanged for those — including on to
|
|
555
|
+
// `enum_declaration`, which sits in CLASS_CONTAINER_TYPES below.
|
|
556
|
+
if (current.type === 'object_creation_expression' || current.type === 'enum_constant') {
|
|
504
557
|
const anonName = synthesizeJavaAnonymousClassName(current);
|
|
505
558
|
if (anonName !== undefined) {
|
|
506
559
|
return {
|
|
@@ -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 = 19; // Java enum constant bodies emit E$N Class nodes; anonymous naming switched to JLS 13.1 immediate-host chains (#2555). (18 = Worker$N anonymous bodies; 17 = callable-value-flow operand identity; 16 = direct callee identity.)
|
|
56
56
|
const GITNEXUS_PKG_VERSION = (() => {
|
|
57
57
|
try {
|
|
58
58
|
// package.json sits at gitnexus/package.json — two levels up from
|
|
@@ -341,8 +341,14 @@ export interface RepoMeta {
|
|
|
341
341
|
* unchanged files — a top-up against a pre-v8 index would strand the old
|
|
342
342
|
* `Worker.run`-keyed Method nodes alongside the new ones (the v5 Route
|
|
343
343
|
* precedent); force a full re-analyze instead.
|
|
344
|
-
|
|
345
|
-
|
|
344
|
+
* v9: Java enum constant bodies joined the instance model and anonymous
|
|
345
|
+
* naming switched to JLS 13.1 immediately-enclosing-type chains (#2555): `enum E { A {
|
|
346
|
+
* hook(){} } }` now emits `Class:...:E$1` with methods re-keyed from
|
|
347
|
+
* `E.hook` to `E$1.hook`, and nested-host anonymous names re-key
|
|
348
|
+
* (`EnumWrap$1` → `EnumWrap$Mode$1`). Same contract as v8: identities move
|
|
349
|
+
* on unchanged files; force a full re-analyze.
|
|
350
|
+
*/
|
|
351
|
+
export declare const INCREMENTAL_SCHEMA_VERSION = 9;
|
|
346
352
|
export interface IndexedRepo {
|
|
347
353
|
repoPath: string;
|
|
348
354
|
storagePath: string;
|
|
@@ -118,8 +118,14 @@ export const cloneDirBelongsToEntry = (cloneDir, entryPath) => registryPathEqual
|
|
|
118
118
|
* unchanged files — a top-up against a pre-v8 index would strand the old
|
|
119
119
|
* `Worker.run`-keyed Method nodes alongside the new ones (the v5 Route
|
|
120
120
|
* precedent); force a full re-analyze instead.
|
|
121
|
+
* v9: Java enum constant bodies joined the instance model and anonymous
|
|
122
|
+
* naming switched to JLS 13.1 immediately-enclosing-type chains (#2555): `enum E { A {
|
|
123
|
+
* hook(){} } }` now emits `Class:...:E$1` with methods re-keyed from
|
|
124
|
+
* `E.hook` to `E$1.hook`, and nested-host anonymous names re-key
|
|
125
|
+
* (`EnumWrap$1` → `EnumWrap$Mode$1`). Same contract as v8: identities move
|
|
126
|
+
* on unchanged files; force a full re-analyze.
|
|
121
127
|
*/
|
|
122
|
-
export const INCREMENTAL_SCHEMA_VERSION =
|
|
128
|
+
export const INCREMENTAL_SCHEMA_VERSION = 9;
|
|
123
129
|
const GITNEXUS_DIR = '.gitnexus';
|
|
124
130
|
const GITNEXUS_EXCLUDE_ENTRY = `${GITNEXUS_DIR}/`;
|
|
125
131
|
export const INDEX_METADATA_FILE = 'gitnexus.json';
|
package/package.json
CHANGED