gitnexus 1.6.5-rc.34 → 1.6.5-rc.35
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/_shared/scope-resolution/symbol-definition.d.ts +2 -0
- package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
- package/dist/core/ingestion/class-extractors/configs/c-cpp.js +38 -0
- package/dist/core/ingestion/class-extractors/generic.js +8 -0
- package/dist/core/ingestion/class-types.d.ts +15 -0
- package/dist/core/ingestion/languages/cpp/interpret.d.ts +6 -1
- package/dist/core/ingestion/languages/cpp/interpret.js +6 -9
- package/dist/core/ingestion/languages/cpp/query.js +31 -0
- package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
- package/dist/core/ingestion/model/symbol-table.js +3 -0
- package/dist/core/ingestion/parsing-processor.js +40 -1
- package/dist/core/ingestion/scope-extractor.js +4 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.d.ts +1 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +12 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +11 -0
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +43 -1
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
- package/dist/core/ingestion/tree-sitter-queries.js +13 -0
- package/dist/core/ingestion/utils/ast-helpers.js +6 -1
- package/dist/core/ingestion/utils/template-arguments.d.ts +11 -0
- package/dist/core/ingestion/utils/template-arguments.js +65 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +1 -0
- package/dist/core/ingestion/workers/parse-worker.js +41 -1
- package/package.json +1 -1
|
@@ -28,6 +28,8 @@ export interface SymbolDefinition {
|
|
|
28
28
|
returnType?: string;
|
|
29
29
|
/** Declared type for non-callable symbols — fields/properties (e.g. 'Address', 'List<User>') */
|
|
30
30
|
declaredType?: string;
|
|
31
|
+
/** Generic/template specialization arguments for class-like symbols (e.g. ['User'], ['T*']). */
|
|
32
|
+
templateArguments?: string[];
|
|
31
33
|
/** Links Method/Constructor/Property to owning Class/Struct/Trait nodeId */
|
|
32
34
|
ownerId?: string;
|
|
33
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"symbol-definition.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/symbol-definition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB;;+FAE2F;IAC3F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;iHAC6G;IAC7G,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;uFACmF;IACnF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gGAAgG;IAChG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|
|
1
|
+
{"version":3,"file":"symbol-definition.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/symbol-definition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB;;+FAE2F;IAC3F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;iHAC6G;IAC7G,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;uFACmF;IACnF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gGAAgG;IAChG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gGAAgG;IAChG,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
// gitnexus/src/core/ingestion/class-extractors/configs/c-cpp.ts
|
|
2
2
|
import { SupportedLanguages } from '../../../../_shared/index.js';
|
|
3
|
+
import { extractTemplateArguments, stripTemplateArguments, } from '../../utils/template-arguments.js';
|
|
4
|
+
function shouldSkipCppTemplateDuplicateCapture(captureMap, definitionName, capturedName) {
|
|
5
|
+
if (captureMap['template-arguments'] !== undefined)
|
|
6
|
+
return false;
|
|
7
|
+
if (!definitionName)
|
|
8
|
+
return false;
|
|
9
|
+
const argsFromDefinitionName = extractTemplateArguments(definitionName);
|
|
10
|
+
if (argsFromDefinitionName === undefined)
|
|
11
|
+
return false;
|
|
12
|
+
const argsFromCaptureName = capturedName ? extractTemplateArguments(capturedName) : undefined;
|
|
13
|
+
// Generic class capture emits only `List`, while the specialization-aware
|
|
14
|
+
// capture emits `List` + `@declaration.template-arguments`. Skip the former
|
|
15
|
+
// when the declaration name itself is templated to avoid duplicate class defs.
|
|
16
|
+
return argsFromCaptureName === undefined;
|
|
17
|
+
}
|
|
18
|
+
function extractCppTemplateArgumentsWithFallback(captureMap, definitionName, capturedName) {
|
|
19
|
+
return ((captureMap['template-arguments']
|
|
20
|
+
? extractTemplateArguments(captureMap['template-arguments'].text)
|
|
21
|
+
: undefined) ??
|
|
22
|
+
(definitionName ? extractTemplateArguments(definitionName) : undefined) ??
|
|
23
|
+
(capturedName ? extractTemplateArguments(capturedName) : undefined));
|
|
24
|
+
}
|
|
3
25
|
export const cClassConfig = {
|
|
4
26
|
language: SupportedLanguages.C,
|
|
5
27
|
typeDeclarationNodes: ['struct_specifier', 'enum_specifier'],
|
|
@@ -8,4 +30,20 @@ export const cppClassConfig = {
|
|
|
8
30
|
language: SupportedLanguages.CPlusPlus,
|
|
9
31
|
typeDeclarationNodes: ['class_specifier', 'struct_specifier', 'enum_specifier'],
|
|
10
32
|
ancestorScopeNodeTypes: ['namespace_definition', 'class_specifier', 'struct_specifier'],
|
|
33
|
+
extractName: (node) => {
|
|
34
|
+
const nameNode = node.childForFieldName?.('name');
|
|
35
|
+
if (!nameNode)
|
|
36
|
+
return undefined;
|
|
37
|
+
if (nameNode.type !== 'template_type')
|
|
38
|
+
return undefined;
|
|
39
|
+
return stripTemplateArguments(nameNode.text);
|
|
40
|
+
},
|
|
41
|
+
extractTemplateArguments: (node) => {
|
|
42
|
+
const nameNode = node.childForFieldName?.('name');
|
|
43
|
+
if (!nameNode || nameNode.type !== 'template_type')
|
|
44
|
+
return undefined;
|
|
45
|
+
return extractTemplateArguments(nameNode.text);
|
|
46
|
+
},
|
|
47
|
+
shouldSkipClassCapture: ({ captureMap, definitionNode, nameNode }) => shouldSkipCppTemplateDuplicateCapture(captureMap, definitionNode?.childForFieldName?.('name')?.text, nameNode?.text),
|
|
48
|
+
extractTemplateArgumentsFromCapture: ({ captureMap, definitionNode, nameNode }) => extractCppTemplateArgumentsWithFallback(captureMap, definitionNode?.childForFieldName?.('name')?.text, nameNode?.text),
|
|
11
49
|
};
|
|
@@ -116,10 +116,12 @@ export function createClassExtractor(config) {
|
|
|
116
116
|
(isClassLikeLabel(fallback?.type) ? fallback.type : undefined);
|
|
117
117
|
if (!name || !type)
|
|
118
118
|
return null;
|
|
119
|
+
const templateArguments = config.extractTemplateArguments?.(node);
|
|
119
120
|
return {
|
|
120
121
|
name,
|
|
121
122
|
type,
|
|
122
123
|
qualifiedName: buildQualifiedName(node, name) || name,
|
|
124
|
+
...(templateArguments !== undefined ? { templateArguments } : {}),
|
|
123
125
|
};
|
|
124
126
|
};
|
|
125
127
|
return {
|
|
@@ -131,5 +133,11 @@ export function createClassExtractor(config) {
|
|
|
131
133
|
extractQualifiedName(node, simpleName) {
|
|
132
134
|
return extract(node, { name: simpleName })?.qualifiedName ?? null;
|
|
133
135
|
},
|
|
136
|
+
shouldSkipClassCapture(context) {
|
|
137
|
+
return config.shouldSkipClassCapture?.(context) ?? false;
|
|
138
|
+
},
|
|
139
|
+
extractTemplateArgumentsFromCapture(context) {
|
|
140
|
+
return config.extractTemplateArgumentsFromCapture?.(context);
|
|
141
|
+
},
|
|
134
142
|
};
|
|
135
143
|
}
|
|
@@ -5,6 +5,12 @@ export interface ExtractedClassSymbol {
|
|
|
5
5
|
name: string;
|
|
6
6
|
type: ClassLikeNodeLabel;
|
|
7
7
|
qualifiedName: string;
|
|
8
|
+
templateArguments?: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface ClassCaptureContext {
|
|
11
|
+
captureMap: Record<string, SyntaxNode>;
|
|
12
|
+
definitionNode: SyntaxNode | null;
|
|
13
|
+
nameNode: SyntaxNode | undefined;
|
|
8
14
|
}
|
|
9
15
|
/**
|
|
10
16
|
* Cross-language qualified type names are normalized to dot-separated scope
|
|
@@ -21,6 +27,10 @@ export interface ClassExtractor {
|
|
|
21
27
|
type?: NodeLabel | null;
|
|
22
28
|
}): ExtractedClassSymbol | null;
|
|
23
29
|
extractQualifiedName(node: SyntaxNode, simpleName: string): string | null;
|
|
30
|
+
shouldSkipClassCapture?(context: ClassCaptureContext & {
|
|
31
|
+
nodeLabel: ClassLikeNodeLabel;
|
|
32
|
+
}): boolean;
|
|
33
|
+
extractTemplateArgumentsFromCapture?(context: ClassCaptureContext): string[] | undefined;
|
|
24
34
|
}
|
|
25
35
|
export interface ClassExtractionConfig {
|
|
26
36
|
language: SupportedLanguages;
|
|
@@ -31,4 +41,9 @@ export interface ClassExtractionConfig {
|
|
|
31
41
|
extractName?: (node: SyntaxNode) => string | undefined;
|
|
32
42
|
extractType?: (node: SyntaxNode) => ClassLikeNodeLabel | undefined;
|
|
33
43
|
extractScopeSegments?: (node: SyntaxNode) => string[] | null | undefined;
|
|
44
|
+
extractTemplateArguments?: (node: SyntaxNode) => string[] | undefined;
|
|
45
|
+
shouldSkipClassCapture?(context: ClassCaptureContext & {
|
|
46
|
+
nodeLabel: ClassLikeNodeLabel;
|
|
47
|
+
}): boolean;
|
|
48
|
+
extractTemplateArgumentsFromCapture?(context: ClassCaptureContext): string[] | undefined;
|
|
34
49
|
}
|
|
@@ -25,6 +25,11 @@ export declare function interpretCppImport(captures: CaptureMatch): ParsedImport
|
|
|
25
25
|
export declare function interpretCppTypeBinding(captures: CaptureMatch): ParsedTypeBinding | null;
|
|
26
26
|
/**
|
|
27
27
|
* Normalize a C++ type name: strip pointer/array/reference syntax,
|
|
28
|
-
* qualifiers,
|
|
28
|
+
* qualifiers, while preserving template arguments for specialization-aware
|
|
29
|
+
* receiver binding (`List<User>` vs `List<Order>`).
|
|
30
|
+
*
|
|
31
|
+
* Keeping template arguments here allows receiver-bound fallback to match
|
|
32
|
+
* specialization-specific class defs first; non-template behavior is preserved
|
|
33
|
+
* by base-name fallback in resolveClassBindingForName.
|
|
29
34
|
*/
|
|
30
35
|
export declare function normalizeCppTypeName(text: string): string;
|
|
@@ -82,7 +82,12 @@ export function interpretCppTypeBinding(captures) {
|
|
|
82
82
|
}
|
|
83
83
|
/**
|
|
84
84
|
* Normalize a C++ type name: strip pointer/array/reference syntax,
|
|
85
|
-
* qualifiers,
|
|
85
|
+
* qualifiers, while preserving template arguments for specialization-aware
|
|
86
|
+
* receiver binding (`List<User>` vs `List<Order>`).
|
|
87
|
+
*
|
|
88
|
+
* Keeping template arguments here allows receiver-bound fallback to match
|
|
89
|
+
* specialization-specific class defs first; non-template behavior is preserved
|
|
90
|
+
* by base-name fallback in resolveClassBindingForName.
|
|
86
91
|
*/
|
|
87
92
|
export function normalizeCppTypeName(text) {
|
|
88
93
|
let t = text.trim();
|
|
@@ -90,14 +95,6 @@ export function normalizeCppTypeName(text) {
|
|
|
90
95
|
t = t
|
|
91
96
|
.replace(/\b(const|volatile|restrict|static|extern|inline|mutable|constexpr|consteval)\b/g, '')
|
|
92
97
|
.trim();
|
|
93
|
-
// Strip template parameters (loop handles nested: Map<List<int>> → Map)
|
|
94
|
-
while (t.includes('<')) {
|
|
95
|
-
const stripped = t.replace(/<[^<>]*>/g, '');
|
|
96
|
-
if (stripped === t)
|
|
97
|
-
break; // avoid infinite loop on malformed input
|
|
98
|
-
t = stripped;
|
|
99
|
-
}
|
|
100
|
-
t = t.trim();
|
|
101
98
|
// Strip pointer stars
|
|
102
99
|
while (t.endsWith('*'))
|
|
103
100
|
t = t.slice(0, -1).trim();
|
|
@@ -31,21 +31,47 @@ const CPP_SCOPE_QUERY = `
|
|
|
31
31
|
name: (type_identifier) @declaration.name
|
|
32
32
|
body: (field_declaration_list)) @declaration.class
|
|
33
33
|
|
|
34
|
+
(class_specifier
|
|
35
|
+
name: (template_type
|
|
36
|
+
(type_identifier) @declaration.name
|
|
37
|
+
(template_argument_list) @declaration.template-arguments)
|
|
38
|
+
body: (field_declaration_list)) @declaration.class
|
|
39
|
+
|
|
34
40
|
(struct_specifier
|
|
35
41
|
name: (type_identifier) @declaration.name
|
|
36
42
|
body: (field_declaration_list)) @declaration.struct
|
|
37
43
|
|
|
44
|
+
(struct_specifier
|
|
45
|
+
name: (template_type
|
|
46
|
+
(type_identifier) @declaration.name
|
|
47
|
+
(template_argument_list) @declaration.template-arguments)
|
|
48
|
+
body: (field_declaration_list)) @declaration.struct
|
|
49
|
+
|
|
38
50
|
;; ─── Declarations — class / struct inside template_declaration ───────
|
|
39
51
|
(template_declaration
|
|
40
52
|
(class_specifier
|
|
41
53
|
name: (type_identifier) @declaration.name
|
|
42
54
|
body: (field_declaration_list)) @declaration.class)
|
|
43
55
|
|
|
56
|
+
(template_declaration
|
|
57
|
+
(class_specifier
|
|
58
|
+
name: (template_type
|
|
59
|
+
(type_identifier) @declaration.name
|
|
60
|
+
(template_argument_list) @declaration.template-arguments)
|
|
61
|
+
body: (field_declaration_list)) @declaration.class)
|
|
62
|
+
|
|
44
63
|
(template_declaration
|
|
45
64
|
(struct_specifier
|
|
46
65
|
name: (type_identifier) @declaration.name
|
|
47
66
|
body: (field_declaration_list)) @declaration.struct)
|
|
48
67
|
|
|
68
|
+
(template_declaration
|
|
69
|
+
(struct_specifier
|
|
70
|
+
name: (template_type
|
|
71
|
+
(type_identifier) @declaration.name
|
|
72
|
+
(template_argument_list) @declaration.template-arguments)
|
|
73
|
+
body: (field_declaration_list)) @declaration.struct)
|
|
74
|
+
|
|
49
75
|
;; ─── Declarations — enum ─────────────────────────────────────────────
|
|
50
76
|
(enum_specifier
|
|
51
77
|
name: (type_identifier) @declaration.name) @declaration.enum
|
|
@@ -222,6 +248,11 @@ const CPP_SCOPE_QUERY = `
|
|
|
222
248
|
type: (type_identifier) @type-binding.type
|
|
223
249
|
declarator: (identifier) @type-binding.name) @type-binding.annotation
|
|
224
250
|
|
|
251
|
+
;; Covers: List<User> users;
|
|
252
|
+
(declaration
|
|
253
|
+
type: (template_type) @type-binding.type
|
|
254
|
+
declarator: (identifier) @type-binding.name) @type-binding.annotation
|
|
255
|
+
|
|
225
256
|
;; ─── Type bindings — pointer variable declaration ───────────────────
|
|
226
257
|
;; Covers: User* ptr = new User()
|
|
227
258
|
(declaration
|
|
@@ -130,6 +130,9 @@ export const createSymbolTable = () => {
|
|
|
130
130
|
: {}),
|
|
131
131
|
...(metadata?.returnType !== undefined ? { returnType: metadata.returnType } : {}),
|
|
132
132
|
...(metadata?.declaredType !== undefined ? { declaredType: metadata.declaredType } : {}),
|
|
133
|
+
...(metadata?.templateArguments !== undefined
|
|
134
|
+
? { templateArguments: metadata.templateArguments }
|
|
135
|
+
: {}),
|
|
133
136
|
...(metadata?.ownerId !== undefined ? { ownerId: metadata.ownerId } : {}),
|
|
134
137
|
};
|
|
135
138
|
// A. File Index — unconditional.
|
|
@@ -11,6 +11,7 @@ import { getDefinitionNodeFromCaptures, findEnclosingClassInfo, getLabelFromCapt
|
|
|
11
11
|
import { detectFrameworkFromAST } from './framework-detection.js';
|
|
12
12
|
import { buildTypeEnv } from './type-env.js';
|
|
13
13
|
import { buildMethodProps, arityForIdFromInfo, typeTagForId, constTagForId, buildCollisionGroups, } from './utils/method-props.js';
|
|
14
|
+
import { extractTemplateArguments, templateArgumentsIdTag } from './utils/template-arguments.js';
|
|
14
15
|
import { logger } from '../logger.js';
|
|
15
16
|
import { getTreeSitterBufferSize, getTreeSitterContentByteLength, TREE_SITTER_MAX_BUFFER, } from './constants.js';
|
|
16
17
|
// ============================================================================
|
|
@@ -58,6 +59,7 @@ export const mergeChunkResults = (graph, symbolTable, chunkResults) => {
|
|
|
58
59
|
parameterTypes: sym.parameterTypes,
|
|
59
60
|
returnType: sym.returnType,
|
|
60
61
|
declaredType: sym.declaredType,
|
|
62
|
+
templateArguments: sym.templateArguments,
|
|
61
63
|
ownerId: sym.ownerId,
|
|
62
64
|
qualifiedName: sym.qualifiedName,
|
|
63
65
|
});
|
|
@@ -365,6 +367,20 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
|
|
|
365
367
|
})
|
|
366
368
|
: null;
|
|
367
369
|
const nodeLabel = extractedClassSymbol?.type ?? defaultNodeLabel;
|
|
370
|
+
const isClassLikeLabel = nodeLabel === 'Class' ||
|
|
371
|
+
nodeLabel === 'Struct' ||
|
|
372
|
+
nodeLabel === 'Interface' ||
|
|
373
|
+
nodeLabel === 'Enum' ||
|
|
374
|
+
nodeLabel === 'Record';
|
|
375
|
+
if (isClassLikeLabel &&
|
|
376
|
+
provider.classExtractor?.shouldSkipClassCapture?.({
|
|
377
|
+
captureMap,
|
|
378
|
+
definitionNode,
|
|
379
|
+
nameNode,
|
|
380
|
+
nodeLabel,
|
|
381
|
+
}) === true) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
368
384
|
// Synthesize name for constructors without explicit @name capture (e.g. Swift init)
|
|
369
385
|
if (!nameNode && nodeLabel !== 'Constructor' && !extractedClassSymbol)
|
|
370
386
|
return;
|
|
@@ -464,7 +480,26 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
|
|
|
464
480
|
arityTag += typeTagForId(cached.map, nodeName, arityForId, seqDefMethodInfo, language, cached.groups);
|
|
465
481
|
arityTag += constTagForId(cached.map, nodeName, arityForId, seqDefMethodInfo, cached.groups);
|
|
466
482
|
}
|
|
467
|
-
const
|
|
483
|
+
const classTemplateArguments = extractedClassSymbol?.templateArguments ??
|
|
484
|
+
provider.classExtractor?.extractTemplateArgumentsFromCapture?.({
|
|
485
|
+
captureMap,
|
|
486
|
+
definitionNode,
|
|
487
|
+
nameNode,
|
|
488
|
+
}) ??
|
|
489
|
+
(captureMap['template-arguments']
|
|
490
|
+
? extractTemplateArguments(captureMap['template-arguments'].text)
|
|
491
|
+
: undefined) ??
|
|
492
|
+
(nameNode && nameNode.text ? extractTemplateArguments(nameNode.text) : undefined);
|
|
493
|
+
const classTemplateTag = (nodeLabel === 'Class' ||
|
|
494
|
+
nodeLabel === 'Struct' ||
|
|
495
|
+
nodeLabel === 'Interface' ||
|
|
496
|
+
nodeLabel === 'Enum' ||
|
|
497
|
+
nodeLabel === 'Record') &&
|
|
498
|
+
classTemplateArguments !== undefined &&
|
|
499
|
+
classTemplateArguments.length > 0
|
|
500
|
+
? templateArgumentsIdTag(classTemplateArguments)
|
|
501
|
+
: '';
|
|
502
|
+
const nodeId = generateId(nodeLabel, `${file.path}:${qualifiedName}${classTemplateTag}${arityTag}`);
|
|
468
503
|
const classNodeForSymbol = definitionNodeForRange || definitionNode || nameNode;
|
|
469
504
|
const qualifiedTypeName = extractedClassSymbol?.qualifiedName ??
|
|
470
505
|
(classNodeForSymbol && provider.classExtractor?.isTypeDeclaration(classNodeForSymbol)
|
|
@@ -490,6 +525,9 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
|
|
|
490
525
|
? isVueSetupTopLevel(nameNode || definitionNodeForRange)
|
|
491
526
|
: cachedExportCheck(provider.exportChecker, nameNode || definitionNodeForRange, nodeName),
|
|
492
527
|
...(qualifiedTypeName !== undefined ? { qualifiedName: qualifiedTypeName } : {}),
|
|
528
|
+
...(classTemplateArguments !== undefined && classTemplateArguments.length > 0
|
|
529
|
+
? { templateArguments: classTemplateArguments }
|
|
530
|
+
: {}),
|
|
493
531
|
...(frameworkHint
|
|
494
532
|
? {
|
|
495
533
|
astFrameworkMultiplier: frameworkHint.entryPointMultiplier,
|
|
@@ -543,6 +581,7 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
|
|
|
543
581
|
parameterTypes: methodProps.parameterTypes,
|
|
544
582
|
returnType: methodProps.returnType,
|
|
545
583
|
declaredType,
|
|
584
|
+
templateArguments: classTemplateArguments,
|
|
546
585
|
ownerId: enclosingClassId ?? undefined,
|
|
547
586
|
qualifiedName: qualifiedTypeName,
|
|
548
587
|
});
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
* - `ParsedFile.referenceSites` — pre-resolution usage facts.
|
|
60
60
|
*/
|
|
61
61
|
import { buildPositionIndex, buildScopeTree, canParentScope, makeScopeId } from '../../_shared/index.js';
|
|
62
|
+
import { extractTemplateArguments } from './utils/template-arguments.js';
|
|
62
63
|
// ─── Public entry point ─────────────────────────────────────────────────────
|
|
63
64
|
/**
|
|
64
65
|
* Drive the five extraction passes and return a `ParsedFile`.
|
|
@@ -362,6 +363,8 @@ function buildDefFromDeclarationMatch(match, anchor, filePath) {
|
|
|
362
363
|
return undefined;
|
|
363
364
|
const qualifiedCap = match['@declaration.qualified_name'];
|
|
364
365
|
const qualifiedName = qualifiedCap?.text;
|
|
366
|
+
const templateArguments = extractTemplateArguments(match['@declaration.template-arguments']?.text ?? '') ??
|
|
367
|
+
extractTemplateArguments(qualifiedName ?? nameCap.text);
|
|
365
368
|
// Optional arity metadata — producers (e.g. Python emit-captures)
|
|
366
369
|
// synthesize these on function/method declarations. Their absence is
|
|
367
370
|
// the normal case for other producers; readers treat undefined as
|
|
@@ -381,6 +384,7 @@ function buildDefFromDeclarationMatch(match, anchor, filePath) {
|
|
|
381
384
|
...(parameterTypes !== undefined ? { parameterTypes } : {}),
|
|
382
385
|
...(declaredType !== undefined ? { declaredType } : {}),
|
|
383
386
|
...(returnType !== undefined ? { returnType } : {}),
|
|
387
|
+
...(templateArguments !== undefined ? { templateArguments } : {}),
|
|
384
388
|
};
|
|
385
389
|
}
|
|
386
390
|
function parseIntCapture(cap) {
|
|
@@ -40,6 +40,7 @@ export declare function resolveDefGraphId(filePath: string, def: {
|
|
|
40
40
|
qualifiedName?: string;
|
|
41
41
|
type?: NodeLabel;
|
|
42
42
|
parameterTypes?: readonly string[];
|
|
43
|
+
templateArguments?: readonly string[];
|
|
43
44
|
}, nodeLookup: GraphNodeLookup): string | undefined;
|
|
44
45
|
/** Derive the simple (unqualified) name of a def from its `qualifiedName`. */
|
|
45
46
|
export declare function simpleQualifiedName(def: SymbolDefinition): string | undefined;
|
|
@@ -79,6 +79,18 @@ export function resolveDefGraphId(filePath, def, nodeLookup) {
|
|
|
79
79
|
if (pHit !== undefined)
|
|
80
80
|
return pHit;
|
|
81
81
|
}
|
|
82
|
+
if ((def.type === 'Class' ||
|
|
83
|
+
def.type === 'Struct' ||
|
|
84
|
+
def.type === 'Interface' ||
|
|
85
|
+
def.type === 'Enum' ||
|
|
86
|
+
def.type === 'Record') &&
|
|
87
|
+
def.templateArguments !== undefined &&
|
|
88
|
+
def.templateArguments.length > 0) {
|
|
89
|
+
const tKey = qualifiedKey(filePath, def.type, `${qn}~${def.templateArguments.join(',')}`);
|
|
90
|
+
const tHit = nodeLookup.get(tKey);
|
|
91
|
+
if (tHit !== undefined)
|
|
92
|
+
return tHit;
|
|
93
|
+
}
|
|
82
94
|
const qualifiedHit = nodeLookup.get(qualifiedKey(filePath, def.type, qn));
|
|
83
95
|
if (qualifiedHit !== undefined)
|
|
84
96
|
return qualifiedHit;
|
|
@@ -86,6 +86,17 @@ export function buildGraphNodeLookup(graph) {
|
|
|
86
86
|
// Each overload is unique — set unconditionally.
|
|
87
87
|
lookup.set(pKey, node.id);
|
|
88
88
|
}
|
|
89
|
+
if ((node.label === 'Class' ||
|
|
90
|
+
node.label === 'Struct' ||
|
|
91
|
+
node.label === 'Interface' ||
|
|
92
|
+
node.label === 'Enum' ||
|
|
93
|
+
node.label === 'Record') &&
|
|
94
|
+
props.templateArguments !== undefined &&
|
|
95
|
+
props.templateArguments.length > 0) {
|
|
96
|
+
const tKey = qualifiedKey(props.filePath, node.label, `${qualified}~${props.templateArguments.join(',')}`);
|
|
97
|
+
if (!lookup.has(tKey))
|
|
98
|
+
lookup.set(tKey, node.id);
|
|
99
|
+
}
|
|
89
100
|
}
|
|
90
101
|
// Fallback key: simple name. First-wins within a file — used when
|
|
91
102
|
// the caller doesn't know the qualifier (unqualified free-call
|
|
@@ -37,6 +37,48 @@ import { tryEmitEdge } from '../graph-bridge/edges.js';
|
|
|
37
37
|
import { resolveCompoundReceiverClass } from '../passes/compound-receiver.js';
|
|
38
38
|
import { resolveDefGraphId } from '../graph-bridge/ids.js';
|
|
39
39
|
import { narrowOverloadCandidates, isOverloadAmbiguousAfterNormalization, } from './overload-narrowing.js';
|
|
40
|
+
import { extractTemplateArguments, stripTemplateArguments, } from '../../utils/template-arguments.js';
|
|
41
|
+
function normalizeTemplateArgToken(value) {
|
|
42
|
+
return value.replace(/\s+/g, '');
|
|
43
|
+
}
|
|
44
|
+
function resolveClassBindingForName(scopeId, rawClassName, scopes) {
|
|
45
|
+
const direct = findClassBindingInScope(scopeId, rawClassName, scopes);
|
|
46
|
+
if (direct !== undefined)
|
|
47
|
+
return direct;
|
|
48
|
+
if (!rawClassName.includes('<'))
|
|
49
|
+
return undefined;
|
|
50
|
+
const baseName = stripTemplateArguments(rawClassName).replace(/\s+/g, '');
|
|
51
|
+
if (baseName.length === 0)
|
|
52
|
+
return undefined;
|
|
53
|
+
const wantedArgs = extractTemplateArguments(rawClassName)?.map(normalizeTemplateArgToken);
|
|
54
|
+
if (wantedArgs !== undefined && wantedArgs.length > 0) {
|
|
55
|
+
// qualifiedNames is a Map and may not contain the stripped base name at all
|
|
56
|
+
// (e.g., unresolved type binding or only template-qualified entries), so
|
|
57
|
+
// default to [] before checking `.length`.
|
|
58
|
+
const qnameIds = scopes.qualifiedNames.get(baseName) ?? [];
|
|
59
|
+
if (qnameIds.length === 0) {
|
|
60
|
+
return findClassBindingInScope(scopeId, baseName, scopes);
|
|
61
|
+
}
|
|
62
|
+
const matches = [];
|
|
63
|
+
for (const id of qnameIds) {
|
|
64
|
+
const def = scopes.defs.get(id);
|
|
65
|
+
if (def === undefined || !isClassLike(def.type))
|
|
66
|
+
continue;
|
|
67
|
+
const defArgs = def.templateArguments?.map(normalizeTemplateArgToken);
|
|
68
|
+
if (defArgs !== undefined &&
|
|
69
|
+
defArgs.length === wantedArgs.length &&
|
|
70
|
+
defArgs.every((value, i) => value === wantedArgs[i])) {
|
|
71
|
+
matches.push(def);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (matches.length === 1)
|
|
75
|
+
return matches[0];
|
|
76
|
+
// Scope extractor only records class definitions with bodies in C++, so
|
|
77
|
+
// forward declarations are not expected here. Keep fallback behavior for
|
|
78
|
+
// safety in non-ODR or mixed-language edge cases.
|
|
79
|
+
}
|
|
80
|
+
return findClassBindingInScope(scopeId, baseName, scopes);
|
|
81
|
+
}
|
|
40
82
|
export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, handledSites, provider, index, model) {
|
|
41
83
|
let emitted = 0;
|
|
42
84
|
// Per-pass dedup so the multiple cases don't double-emit if two of
|
|
@@ -322,7 +364,7 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
|
|
|
322
364
|
}
|
|
323
365
|
// ── Case 4: simple typeBinding (`u: U`) ──────────────────────
|
|
324
366
|
if (typeRef !== undefined && !typeRef.rawName.includes('.')) {
|
|
325
|
-
let ownerDef =
|
|
367
|
+
let ownerDef = resolveClassBindingForName(site.inScope, typeRef.rawName, scopes);
|
|
326
368
|
// `findClassBindingInScope(..., typeRef.rawName)` only works when
|
|
327
369
|
// rawName is itself a class symbol reachable through scope bindings.
|
|
328
370
|
// For languages with namespace-style imports (Go), imported types
|
|
@@ -4,7 +4,7 @@ export declare const PYTHON_QUERIES = "\n(class_definition\n name: (identifier)
|
|
|
4
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; Heritage - extends class\n(class_declaration name: (identifier) @heritage.class\n (superclass (type_identifier) @heritage.extends)) @heritage\n\n; Heritage - implements interfaces\n(class_declaration name: (identifier) @heritage.class\n (super_interfaces (type_list (type_identifier) @heritage.implements))) @heritage.impl\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(union_specifier name: (type_identifier) @name) @definition.union\n(enum_specifier name: (type_identifier) @name) @definition.enum\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\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; Struct embedding (anonymous fields = inheritance)\n(type_declaration\n (type_spec\n name: (type_identifier) @heritage.class\n type: (struct_type\n (field_declaration_list\n (field_declaration\n type: (type_identifier) @heritage.extends))))) @definition.struct\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 name: (identifier) @name)) @definition.const\n(var_declaration (var_spec name: (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
|
-
export declare const CPP_QUERIES = "\n; Classes, Structs, Namespaces\n(class_specifier name: (type_identifier) @name) @definition.class\n(struct_specifier name: (type_identifier) @name) @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 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: (qualified_identifier name: (identifier) @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: (qualified_identifier name: (identifier) @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: (pointer_declarator declarator: (function_declarator declarator: (identifier) @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)] @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)] @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 (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\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; Heritage\n(class_specifier name: (type_identifier) @heritage.class\n (base_class_clause (type_identifier) @heritage.extends)) @heritage\n(class_specifier name: (type_identifier) @heritage.class\n (base_class_clause (access_specifier) (type_identifier) @heritage.extends)) @heritage\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";
|
|
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(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 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: (qualified_identifier name: (identifier) @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: (qualified_identifier name: (identifier) @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: (pointer_declarator declarator: (function_declarator declarator: (identifier) @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)] @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)] @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\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; Heritage\n(class_specifier name: (type_identifier) @heritage.class\n (base_class_clause (type_identifier) @heritage.extends)) @heritage\n(class_specifier name: (type_identifier) @heritage.class\n (base_class_clause (access_specifier) (type_identifier) @heritage.extends)) @heritage\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";
|
|
8
8
|
export declare const CSHARP_QUERIES = "\n; Types\n(class_declaration name: (identifier) @name) @definition.class\n(interface_declaration name: (identifier) @name) @definition.interface\n(struct_declaration name: (identifier) @name) @definition.struct\n(enum_declaration name: (identifier) @name) @definition.enum\n(record_declaration name: (identifier) @name) @definition.record\n(delegate_declaration name: (identifier) @name) @definition.delegate\n\n; Namespaces (block form and C# 10+ file-scoped form)\n(namespace_declaration name: (identifier) @name) @definition.namespace\n(namespace_declaration name: (qualified_name) @name) @definition.namespace\n(file_scoped_namespace_declaration name: (identifier) @name) @definition.namespace\n(file_scoped_namespace_declaration name: (qualified_name) @name) @definition.namespace\n\n; Methods & Properties\n(method_declaration name: (identifier) @name) @definition.method\n(local_function_statement name: (identifier) @name) @definition.function\n(constructor_declaration name: (identifier) @name) @definition.constructor\n(property_declaration name: (identifier) @name) @definition.property\n\n; Primary constructors (C# 12): class User(string name, int age) { }\n(class_declaration name: (identifier) @name (parameter_list) @definition.constructor)\n(record_declaration name: (identifier) @name (parameter_list) @definition.constructor)\n\n; Using\n(using_directive (qualified_name) @import.source) @import\n(using_directive (identifier) @import.source) @import\n\n; Calls\n(invocation_expression function: (identifier) @call.name) @call\n(invocation_expression function: (member_access_expression name: (identifier) @call.name)) @call\n\n; Null-conditional method calls: user?.Save()\n; Parses as: invocation_expression \u2192 conditional_access_expression \u2192 member_binding_expression \u2192 identifier\n(invocation_expression\n function: (conditional_access_expression\n (member_binding_expression\n (identifier) @call.name))) @call\n\n; Constructor calls: new Foo() and new Foo { Props }\n(object_creation_expression type: (identifier) @call.name) @call\n\n; Target-typed new (C# 9): User u = new(\"x\", 5)\n(variable_declaration type: (identifier) @call.name (variable_declarator (implicit_object_creation_expression) @call))\n\n; Local variable declarations\n(local_declaration_statement\n (variable_declaration\n (variable_declarator\n (identifier) @name))) @definition.variable\n\n; Heritage\n(class_declaration name: (identifier) @heritage.class\n (base_list (identifier) @heritage.extends)) @heritage\n(class_declaration name: (identifier) @heritage.class\n (base_list (generic_name (identifier) @heritage.extends))) @heritage\n\n; Interface inheritance: interface IFoo : IBar / interface IFoo : IBar, IBaz\n; Without these patterns, interface-to-interface relationships are never\n; captured, so transitive \"class X implements IBar\" chains are broken.\n(interface_declaration name: (identifier) @heritage.class\n (base_list (identifier) @heritage.extends)) @heritage\n(interface_declaration name: (identifier) @heritage.class\n (base_list (generic_name (identifier) @heritage.extends))) @heritage\n\n; Write access: obj.field = value\n(assignment_expression\n left: (member_access_expression\n expression: (_) @assignment.receiver\n name: (identifier) @assignment.property)\n right: (_)) @assignment\n";
|
|
9
9
|
export declare const RUST_QUERIES = "\n; Functions & Items\n(function_item name: (identifier) @name) @definition.function\n(function_signature_item name: (identifier) @name) @definition.function\n(struct_item name: (type_identifier) @name) @definition.struct\n(enum_item name: (type_identifier) @name) @definition.enum\n(trait_item name: (type_identifier) @name) @definition.trait\n(impl_item type: (type_identifier) @name !trait) @definition.impl\n(impl_item type: (generic_type type: (type_identifier) @name) !trait) @definition.impl\n(mod_item name: (identifier) @name) @definition.module\n\n; Type aliases, const, static, macros\n(type_item name: (type_identifier) @name) @definition.type\n(const_item name: (identifier) @name) @definition.const\n(static_item name: (identifier) @name) @definition.static\n(macro_definition name: (identifier) @name) @definition.macro\n\n; Use statements\n(use_declaration argument: (_) @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: (scoped_identifier name: (identifier) @call.name)) @call\n(call_expression function: (generic_function function: (identifier) @call.name)) @call\n\n; Struct literal construction: User { name: value }\n(struct_expression name: (type_identifier) @call.name) @call\n\n; Struct fields \u2014 named field declarations inside struct bodies\n(field_declaration_list\n (field_declaration\n name: (field_identifier) @name) @definition.property)\n\n; Heritage (trait implementation) \u2014 all combinations of concrete/generic trait \u00D7 concrete/generic type\n(impl_item trait: (type_identifier) @heritage.trait type: (type_identifier) @heritage.class) @heritage\n(impl_item trait: (generic_type type: (type_identifier) @heritage.trait) type: (type_identifier) @heritage.class) @heritage\n(impl_item trait: (type_identifier) @heritage.trait type: (generic_type type: (type_identifier) @heritage.class)) @heritage\n(impl_item trait: (generic_type type: (type_identifier) @heritage.trait) type: (generic_type type: (type_identifier) @heritage.class)) @heritage\n\n; Write access: obj.field = value\n(assignment_expression\n left: (field_expression\n value: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)\n right: (_)) @assignment\n\n; Write access: obj.field += value (compound assignment)\n(compound_assignment_expr\n left: (field_expression\n value: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)\n right: (_)) @assignment\n";
|
|
10
10
|
export declare const PHP_QUERIES = "\n; \u2500\u2500 Namespace \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(namespace_definition\n name: (namespace_name) @name) @definition.namespace\n\n; \u2500\u2500 Classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(class_declaration\n name: (name) @name) @definition.class\n\n; \u2500\u2500 Interfaces \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(interface_declaration\n name: (name) @name) @definition.interface\n\n; \u2500\u2500 Traits \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(trait_declaration\n name: (name) @name) @definition.trait\n\n; \u2500\u2500 Enums (PHP 8.1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(enum_declaration\n name: (name) @name) @definition.enum\n\n; \u2500\u2500 Top-level functions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(function_definition\n name: (name) @name) @definition.function\n\n; \u2500\u2500 Methods (including constructors) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(method_declaration\n name: (name) @name) @definition.method\n\n; \u2500\u2500 Class properties (including Eloquent $fillable, $casts, etc.) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(property_declaration\n (property_element\n (variable_name\n (name) @name))) @definition.property\n\n; Constructor property promotion (PHP 8.0+: public Address $address in __construct)\n(method_declaration\n parameters: (formal_parameters\n (property_promotion_parameter\n name: (variable_name\n (name) @name)))) @definition.property\n\n; \u2500\u2500 Imports: use statements \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n; Simple: use App\\Models\\User;\n(namespace_use_declaration\n (namespace_use_clause\n (qualified_name) @import.source)) @import\n\n; \u2500\u2500 Function/method calls \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n; Regular function call: foo()\n(function_call_expression\n function: (name) @call.name) @call\n\n; Method call: $obj->method()\n(member_call_expression\n name: (name) @call.name) @call\n\n; Nullsafe method call: $obj?->method()\n(nullsafe_member_call_expression\n name: (name) @call.name) @call\n\n; Static call: Foo::bar() (php_only uses scoped_call_expression)\n(scoped_call_expression\n name: (name) @call.name) @call\n\n; Constructor call: new User()\n(object_creation_expression (name) @call.name) @call\n\n; Const declarations at class scope\n(const_declaration\n (const_element\n (name) @name)) @definition.const\n\n; \u2500\u2500 Heritage: extends \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(class_declaration\n name: (name) @heritage.class\n (base_clause\n [(name) (qualified_name)] @heritage.extends)) @heritage\n\n; \u2500\u2500 Heritage: implements \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(class_declaration\n name: (name) @heritage.class\n (class_interface_clause\n [(name) (qualified_name)] @heritage.implements)) @heritage.impl\n\n; \u2500\u2500 Heritage: use trait (must capture enclosing class name) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(class_declaration\n name: (name) @heritage.class\n body: (declaration_list\n (use_declaration\n [(name) (qualified_name)] @heritage.trait))) @heritage\n\n; \u2500\u2500 Heritage: trait uses another trait (transitive trait composition) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n; PHP allows a trait body to contain \"use OtherTrait;\". The trait-uses-trait\n; IMPLEMENTS edge is required by buildPhpMro to compute the full transitive\n; trait closure (depth 3+ chains).\n(trait_declaration\n name: (name) @heritage.class\n body: (declaration_list\n (use_declaration\n [(name) (qualified_name)] @heritage.trait))) @heritage\n\n; PHP HTTP consumers: file_get_contents('/path'), curl_init('/path')\n(function_call_expression\n function: (name) @_php_http (#match? @_php_http \"^(file_get_contents|curl_init)$\")\n arguments: (arguments\n (argument (string (string_content) @http_client.url)))) @http_client\n\n; Write access: $obj->field = value\n(assignment_expression\n left: (member_access_expression\n object: (_) @assignment.receiver\n name: (name) @assignment.property)\n right: (_)) @assignment\n\n; Write access: ClassName::$field = value (static property)\n(assignment_expression\n left: (scoped_property_access_expression\n scope: (_) @assignment.receiver\n name: (variable_name (name) @assignment.property))\n right: (_)) @assignment\n";
|
|
@@ -673,7 +673,15 @@ export const GO_QUERIES = `
|
|
|
673
673
|
export const CPP_QUERIES = `
|
|
674
674
|
; Classes, Structs, Namespaces
|
|
675
675
|
(class_specifier name: (type_identifier) @name) @definition.class
|
|
676
|
+
(class_specifier
|
|
677
|
+
name: (template_type
|
|
678
|
+
(type_identifier) @name
|
|
679
|
+
(template_argument_list) @template-arguments)) @definition.class
|
|
676
680
|
(struct_specifier name: (type_identifier) @name) @definition.struct
|
|
681
|
+
(struct_specifier
|
|
682
|
+
name: (template_type
|
|
683
|
+
(type_identifier) @name
|
|
684
|
+
(template_argument_list) @template-arguments)) @definition.struct
|
|
677
685
|
(namespace_definition name: (namespace_identifier) @name) @definition.namespace
|
|
678
686
|
(enum_specifier name: (type_identifier) @name) @definition.enum
|
|
679
687
|
|
|
@@ -755,6 +763,11 @@ export const CPP_QUERIES = `
|
|
|
755
763
|
|
|
756
764
|
; Templates
|
|
757
765
|
(template_declaration (class_specifier name: (type_identifier) @name)) @definition.template
|
|
766
|
+
(template_declaration
|
|
767
|
+
(class_specifier
|
|
768
|
+
name: (template_type
|
|
769
|
+
(type_identifier) @name
|
|
770
|
+
(template_argument_list) @template-arguments))) @definition.template
|
|
758
771
|
(template_declaration (function_definition declarator: (function_declarator declarator: (identifier) @name))) @definition.template
|
|
759
772
|
|
|
760
773
|
; Includes
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { generateId } from '../../../lib/utils.js';
|
|
2
|
+
import { extractTemplateArguments, stripTemplateArguments, templateArgumentsIdTag, } from './template-arguments.js';
|
|
2
3
|
/**
|
|
3
4
|
* Ordered list of definition capture keys for tree-sitter query matches.
|
|
4
5
|
* Used to extract the definition node from a capture map.
|
|
@@ -370,8 +371,12 @@ export const findEnclosingClassInfo = (node, filePath, resolveEnclosingOwner) =>
|
|
|
370
371
|
current.children?.some((c) => c.type === 'interface')) {
|
|
371
372
|
label = 'Interface';
|
|
372
373
|
}
|
|
374
|
+
const templateArguments = extractTemplateArguments(nameNode.text);
|
|
375
|
+
const classIdName = templateArguments !== undefined
|
|
376
|
+
? `${stripTemplateArguments(nameNode.text)}${templateArgumentsIdTag(templateArguments)}`
|
|
377
|
+
: nameNode.text;
|
|
373
378
|
return {
|
|
374
|
-
classId: generateId(label, `${filePath}:${
|
|
379
|
+
classId: generateId(label, `${filePath}:${classIdName}`),
|
|
375
380
|
className: nameNode.text,
|
|
376
381
|
};
|
|
377
382
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse top-level generic/template arguments from a type-like string.
|
|
3
|
+
*
|
|
4
|
+
* Examples:
|
|
5
|
+
* - `List<int>` -> ['int']
|
|
6
|
+
* - `Map<string, vector<int>>` -> ['string', 'vector<int>']
|
|
7
|
+
* - `List<T*>` -> ['T*']
|
|
8
|
+
*/
|
|
9
|
+
export declare function extractTemplateArguments(text: string): string[] | undefined;
|
|
10
|
+
export declare function stripTemplateArguments(text: string): string;
|
|
11
|
+
export declare function templateArgumentsIdTag(templateArguments?: readonly string[]): string;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse top-level generic/template arguments from a type-like string.
|
|
3
|
+
*
|
|
4
|
+
* Examples:
|
|
5
|
+
* - `List<int>` -> ['int']
|
|
6
|
+
* - `Map<string, vector<int>>` -> ['string', 'vector<int>']
|
|
7
|
+
* - `List<T*>` -> ['T*']
|
|
8
|
+
*/
|
|
9
|
+
export function extractTemplateArguments(text) {
|
|
10
|
+
const start = text.indexOf('<');
|
|
11
|
+
if (start === -1)
|
|
12
|
+
return undefined;
|
|
13
|
+
let depth = 0;
|
|
14
|
+
let end = -1;
|
|
15
|
+
for (let i = start; i < text.length; i += 1) {
|
|
16
|
+
const ch = text[i];
|
|
17
|
+
if (ch === '<')
|
|
18
|
+
depth += 1;
|
|
19
|
+
else if (ch === '>') {
|
|
20
|
+
depth -= 1;
|
|
21
|
+
if (depth === 0) {
|
|
22
|
+
end = i;
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
if (depth < 0)
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (end === -1)
|
|
30
|
+
return undefined;
|
|
31
|
+
const inner = text.slice(start + 1, end);
|
|
32
|
+
if (inner.trim().length === 0)
|
|
33
|
+
return undefined;
|
|
34
|
+
const args = [];
|
|
35
|
+
let tokenStart = 0;
|
|
36
|
+
let nested = 0;
|
|
37
|
+
for (let i = 0; i < inner.length; i += 1) {
|
|
38
|
+
const ch = inner[i];
|
|
39
|
+
if (ch === '<')
|
|
40
|
+
nested += 1;
|
|
41
|
+
else if (ch === '>')
|
|
42
|
+
nested -= 1;
|
|
43
|
+
else if (ch === ',' && nested === 0) {
|
|
44
|
+
const token = inner.slice(tokenStart, i).replace(/\s+/g, '');
|
|
45
|
+
if (token.length > 0)
|
|
46
|
+
args.push(token);
|
|
47
|
+
tokenStart = i + 1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const last = inner.slice(tokenStart).replace(/\s+/g, '');
|
|
51
|
+
if (last.length > 0)
|
|
52
|
+
args.push(last);
|
|
53
|
+
return args.length > 0 ? args : undefined;
|
|
54
|
+
}
|
|
55
|
+
export function stripTemplateArguments(text) {
|
|
56
|
+
const start = text.indexOf('<');
|
|
57
|
+
if (start === -1)
|
|
58
|
+
return text;
|
|
59
|
+
return text.slice(0, start);
|
|
60
|
+
}
|
|
61
|
+
export function templateArgumentsIdTag(templateArguments) {
|
|
62
|
+
if (templateArguments === undefined || templateArguments.length === 0)
|
|
63
|
+
return '';
|
|
64
|
+
return `~${templateArguments.join(',')}`;
|
|
65
|
+
}
|
|
@@ -45,6 +45,7 @@ import { generateId } from '../../../lib/utils.js';
|
|
|
45
45
|
import { preprocessImportPath } from '../import-processor.js';
|
|
46
46
|
import { extractVueScript, extractTemplateComponents, isVueSetupTopLevel, } from '../vue-sfc-extractor.js';
|
|
47
47
|
import { buildMethodProps, arityForIdFromInfo, typeTagForId, constTagForId, buildCollisionGroups, } from '../utils/method-props.js';
|
|
48
|
+
import { extractTemplateArguments, templateArgumentsIdTag } from '../utils/template-arguments.js';
|
|
48
49
|
import { extractParsedFile } from '../scope-extractor-bridge.js';
|
|
49
50
|
import { logger } from '../../logger.js';
|
|
50
51
|
// ============================================================================
|
|
@@ -1545,6 +1546,20 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1545
1546
|
})
|
|
1546
1547
|
: null;
|
|
1547
1548
|
const nodeLabel = extractedClassSymbol?.type ?? defaultNodeLabel;
|
|
1549
|
+
const isClassLikeLabel = nodeLabel === 'Class' ||
|
|
1550
|
+
nodeLabel === 'Struct' ||
|
|
1551
|
+
nodeLabel === 'Interface' ||
|
|
1552
|
+
nodeLabel === 'Enum' ||
|
|
1553
|
+
nodeLabel === 'Record';
|
|
1554
|
+
if (isClassLikeLabel &&
|
|
1555
|
+
provider.classExtractor?.shouldSkipClassCapture?.({
|
|
1556
|
+
captureMap,
|
|
1557
|
+
definitionNode,
|
|
1558
|
+
nameNode,
|
|
1559
|
+
nodeLabel,
|
|
1560
|
+
}) === true) {
|
|
1561
|
+
continue;
|
|
1562
|
+
}
|
|
1548
1563
|
// Dedup: variable captures (Const/Static/Variable) may overlap with higher-priority
|
|
1549
1564
|
// captures (e.g. `const fn = () => {}` matches both @definition.function and @definition.const).
|
|
1550
1565
|
// Skip variable captures whose definition node was already processed.
|
|
@@ -1634,7 +1649,26 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1634
1649
|
arityTag += typeTagForId(defMethodMap, nodeName, arityForId, defMethodInfo, language, groups);
|
|
1635
1650
|
arityTag += constTagForId(defMethodMap, nodeName, arityForId, defMethodInfo, groups);
|
|
1636
1651
|
}
|
|
1637
|
-
const
|
|
1652
|
+
const classTemplateArguments = extractedClassSymbol?.templateArguments ??
|
|
1653
|
+
provider.classExtractor?.extractTemplateArgumentsFromCapture?.({
|
|
1654
|
+
captureMap,
|
|
1655
|
+
definitionNode,
|
|
1656
|
+
nameNode,
|
|
1657
|
+
}) ??
|
|
1658
|
+
(captureMap['template-arguments']
|
|
1659
|
+
? extractTemplateArguments(captureMap['template-arguments'].text)
|
|
1660
|
+
: undefined) ??
|
|
1661
|
+
(nameNode && nameNode.text ? extractTemplateArguments(nameNode.text) : undefined);
|
|
1662
|
+
const classTemplateTag = (nodeLabel === 'Class' ||
|
|
1663
|
+
nodeLabel === 'Struct' ||
|
|
1664
|
+
nodeLabel === 'Interface' ||
|
|
1665
|
+
nodeLabel === 'Enum' ||
|
|
1666
|
+
nodeLabel === 'Record') &&
|
|
1667
|
+
classTemplateArguments !== undefined &&
|
|
1668
|
+
classTemplateArguments.length > 0
|
|
1669
|
+
? templateArgumentsIdTag(classTemplateArguments)
|
|
1670
|
+
: '';
|
|
1671
|
+
const nodeId = generateId(nodeLabel, `${file.path}:${qualifiedName}${classTemplateTag}${arityTag}`);
|
|
1638
1672
|
const classNodeForSymbol = definitionNode || nameNode;
|
|
1639
1673
|
const qualifiedTypeName = extractedClassSymbol?.qualifiedName ??
|
|
1640
1674
|
(classNodeForSymbol && provider.classExtractor?.isTypeDeclaration(classNodeForSymbol)
|
|
@@ -1743,6 +1777,9 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1743
1777
|
? isVueSetupTopLevel(nameNode || definitionNode)
|
|
1744
1778
|
: cachedExportCheck(provider.exportChecker, nameNode || definitionNode, nodeName),
|
|
1745
1779
|
...(qualifiedTypeName !== undefined ? { qualifiedName: qualifiedTypeName } : {}),
|
|
1780
|
+
...(classTemplateArguments !== undefined && classTemplateArguments.length > 0
|
|
1781
|
+
? { templateArguments: classTemplateArguments }
|
|
1782
|
+
: {}),
|
|
1746
1783
|
...(frameworkHint
|
|
1747
1784
|
? {
|
|
1748
1785
|
astFrameworkMultiplier: frameworkHint.entryPointMultiplier,
|
|
@@ -1766,6 +1803,9 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1766
1803
|
parameterTypes: methodProps.parameterTypes,
|
|
1767
1804
|
returnType: methodProps.returnType,
|
|
1768
1805
|
...(declaredType !== undefined ? { declaredType } : {}),
|
|
1806
|
+
...(classTemplateArguments !== undefined && classTemplateArguments.length > 0
|
|
1807
|
+
? { templateArguments: classTemplateArguments }
|
|
1808
|
+
: {}),
|
|
1769
1809
|
...(enclosingClassId ? { ownerId: enclosingClassId } : {}),
|
|
1770
1810
|
visibility: methodProps.visibility,
|
|
1771
1811
|
isStatic: methodProps.isStatic,
|
package/package.json
CHANGED