gitnexus 1.6.6-rc.80 → 1.6.6-rc.81
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.
|
@@ -24,22 +24,18 @@
|
|
|
24
24
|
* V2 additionally walks class ancestors (via MRO), so base-class enclosing
|
|
25
25
|
* namespaces also contribute associated namespaces.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* set,
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* workspace lookup (only contributed when a Function/Method named `worker` exists
|
|
40
|
-
* in `utils`). For unqualified refs the workspace is searched for any Function
|
|
41
|
-
* def with that simple name. Locally-declared function-pointer variables
|
|
42
|
-
* (e.g. `void (*g)()`) and function parameters are excluded from this path.
|
|
27
|
+
* Function-reference arguments follow ISO C++ `[basic.lookup.argdep]`:
|
|
28
|
+
* associated entities come from the parameter types and return type of each
|
|
29
|
+
* referenced function in the overload set, not from the function's enclosing
|
|
30
|
+
* namespace. For `void worker()`, the associated set is empty. For
|
|
31
|
+
* `void worker(api::Token)` or `api::Token make_token()`, `api` is associated
|
|
32
|
+
* through `Token`.
|
|
33
|
+
*
|
|
34
|
+
* For qualified refs (e.g. `utils::worker`) the workspace lookup is restricted
|
|
35
|
+
* to functions/methods named `worker` in `utils`; for unqualified refs the
|
|
36
|
+
* workspace is searched for matching functions/methods by simple name. Locally
|
|
37
|
+
* declared function-pointer variables and function parameters are excluded
|
|
38
|
+
* from this path.
|
|
43
39
|
*
|
|
44
40
|
* ADL candidates are merged with ordinary unqualified-lookup candidates
|
|
45
41
|
* in the free-call fallback before overload narrowing.
|
|
@@ -94,11 +90,8 @@ export interface CppAdlArgInfo {
|
|
|
94
90
|
/** When set, the arg is a potential free-function reference (not a locally-
|
|
95
91
|
* declared function-pointer variable or function parameter). Contains the
|
|
96
92
|
* identifier text as written in source (e.g. `"utils::worker"` or
|
|
97
|
-
* `"worker"`).
|
|
98
|
-
*
|
|
99
|
-
* lookup confirms a Function/Method with that simple name exists in the
|
|
100
|
-
* namespace before contributing; for unqualified refs every namespace
|
|
101
|
-
* containing a matching Function/Method def is contributed. */
|
|
93
|
+
* `"worker"`). Resolution contributes associated namespaces from each
|
|
94
|
+
* referenced Function/Method def's parameter and return types. */
|
|
102
95
|
readonly functionRefText?: string;
|
|
103
96
|
}
|
|
104
97
|
/** Record per-call-site argument info. Called once per call site from
|
|
@@ -24,22 +24,18 @@
|
|
|
24
24
|
* V2 additionally walks class ancestors (via MRO), so base-class enclosing
|
|
25
25
|
* namespaces also contribute associated namespaces.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* set,
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* namespace. For `void worker()`, the standard-compliant associated set is empty.
|
|
34
|
-
* GitNexus instead contributes the enclosing namespace of any Function/Method
|
|
35
|
-
* def whose simple name matches, because it enables the dominant real-world ADL
|
|
36
|
-
* pattern at reasonable precision cost.
|
|
27
|
+
* Function-reference arguments follow ISO C++ `[basic.lookup.argdep]`:
|
|
28
|
+
* associated entities come from the parameter types and return type of each
|
|
29
|
+
* referenced function in the overload set, not from the function's enclosing
|
|
30
|
+
* namespace. For `void worker()`, the associated set is empty. For
|
|
31
|
+
* `void worker(api::Token)` or `api::Token make_token()`, `api` is associated
|
|
32
|
+
* through `Token`.
|
|
37
33
|
*
|
|
38
|
-
* For qualified refs (e.g. `utils::worker`) the
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
34
|
+
* For qualified refs (e.g. `utils::worker`) the workspace lookup is restricted
|
|
35
|
+
* to functions/methods named `worker` in `utils`; for unqualified refs the
|
|
36
|
+
* workspace is searched for matching functions/methods by simple name. Locally
|
|
37
|
+
* declared function-pointer variables and function parameters are excluded
|
|
38
|
+
* from this path.
|
|
43
39
|
*
|
|
44
40
|
* ADL candidates are merged with ordinary unqualified-lookup candidates
|
|
45
41
|
* in the free-call fallback before overload narrowing.
|
|
@@ -67,6 +63,7 @@
|
|
|
67
63
|
* but logically share the same namespace. ADL must consider candidates
|
|
68
64
|
* declared in either file.
|
|
69
65
|
*/
|
|
66
|
+
import { normalizeCppParamType } from './arity-metadata.js';
|
|
70
67
|
import { isCppInlineNamespaceScope } from './inline-namespaces.js';
|
|
71
68
|
const argInfoBySite = new Map();
|
|
72
69
|
const noAdlSites = new Set();
|
|
@@ -157,7 +154,7 @@ export function pickCppAdlCandidates(site, callerParsed, scopes, parsedFiles) {
|
|
|
157
154
|
for (const arg of args) {
|
|
158
155
|
collectAssociatedNamespacesForAdlArg(arg, scopes, associatedNamespaces);
|
|
159
156
|
if (arg.functionRefText !== undefined) {
|
|
160
|
-
|
|
157
|
+
collectFunctionTypeAssociatedNamespaces(arg.functionRefText, scopes, parsedFiles, associatedNamespaces);
|
|
161
158
|
}
|
|
162
159
|
}
|
|
163
160
|
if (associatedNamespaces.size === 0)
|
|
@@ -405,22 +402,10 @@ function findCppClassDefBySimpleName(simpleName, scopes) {
|
|
|
405
402
|
return { classDef: firstMatch, ambiguous: false };
|
|
406
403
|
}
|
|
407
404
|
/**
|
|
408
|
-
* Contribute associated namespaces for a function-reference argument
|
|
409
|
-
*
|
|
410
|
-
* - **Qualified refs** (`utils::worker`, `outer::inner::fn`): the namespace
|
|
411
|
-
* is extracted from the qualifier text (converting `::` to `.` for dot-joined
|
|
412
|
-
* QName matching). A workspace lookup then **verifies** that a Function or
|
|
413
|
-
* Method def named `worker` (the simple name after the last `::`) actually
|
|
414
|
-
* exists in the extracted namespace. This prevents false positives from
|
|
415
|
-
* namespace-qualified variables, enum values, and static data members, which
|
|
416
|
-
* also produce `qualified_identifier` AST nodes in tree-sitter-cpp (the
|
|
417
|
-
* AST node type alone does not distinguish functions from non-function names).
|
|
418
|
-
* - **Unqualified refs** (`worker`): the workspace is searched for any
|
|
419
|
-
* Function/Method def whose simple name matches. Every distinct enclosing
|
|
420
|
-
* namespace found is added — overloads across the same namespace produce
|
|
421
|
-
* a single entry; GitNexus does not select a specific overload at this stage.
|
|
405
|
+
* Contribute associated namespaces for a function-reference argument by walking
|
|
406
|
+
* the referenced overload set's parameter and return types.
|
|
422
407
|
*/
|
|
423
|
-
function
|
|
408
|
+
function collectFunctionTypeAssociatedNamespaces(refText, scopes, parsedFiles, out) {
|
|
424
409
|
const colonIdx = refText.lastIndexOf('::');
|
|
425
410
|
if (colonIdx !== -1) {
|
|
426
411
|
// Qualified ref: extract namespace prefix and normalise :: → dot notation.
|
|
@@ -445,21 +430,18 @@ function collectFunctionRefNamespaces(refText, parsedFiles, out) {
|
|
|
445
430
|
if (def.type !== 'Function' && def.type !== 'Method')
|
|
446
431
|
continue;
|
|
447
432
|
const simple = def.qualifiedName?.split('.').pop() ?? def.qualifiedName ?? '';
|
|
448
|
-
if (simple === simpleName)
|
|
449
|
-
out
|
|
450
|
-
return; // Namespace confirmed; no need to scan further files.
|
|
451
|
-
}
|
|
433
|
+
if (simple === simpleName)
|
|
434
|
+
collectAssociatedNamespacesForFunctionDef(def, scopes, out);
|
|
452
435
|
}
|
|
453
436
|
}
|
|
454
437
|
}
|
|
455
438
|
return;
|
|
456
439
|
}
|
|
457
|
-
// Unqualified
|
|
458
|
-
//
|
|
440
|
+
// Unqualified function references are approximated workspace-wide, matching
|
|
441
|
+
// the previous V1 lookup scope. The stricter part of this PR is what each
|
|
442
|
+
// overload contributes: only namespaces from parameter/return types, never
|
|
443
|
+
// the function's own enclosing namespace.
|
|
459
444
|
for (const parsed of parsedFiles) {
|
|
460
|
-
const scopesById = new Map();
|
|
461
|
-
for (const sc of parsed.scopes)
|
|
462
|
-
scopesById.set(sc.id, sc);
|
|
463
445
|
for (const scope of parsed.scopes) {
|
|
464
446
|
if (scope.kind !== 'Namespace')
|
|
465
447
|
continue;
|
|
@@ -469,10 +451,101 @@ function collectFunctionRefNamespaces(refText, parsedFiles, out) {
|
|
|
469
451
|
const simple = def.qualifiedName?.split('.').pop() ?? def.qualifiedName ?? '';
|
|
470
452
|
if (simple !== refText)
|
|
471
453
|
continue;
|
|
472
|
-
|
|
473
|
-
if (nsQName !== '')
|
|
474
|
-
out.add(nsQName);
|
|
454
|
+
collectAssociatedNamespacesForFunctionDef(def, scopes, out);
|
|
475
455
|
}
|
|
476
456
|
}
|
|
477
457
|
}
|
|
478
458
|
}
|
|
459
|
+
function collectAssociatedNamespacesForFunctionDef(def, scopes, out) {
|
|
460
|
+
const parameterTypes = def.parameterTypeClasses?.map((typeClass) => typeClass.base);
|
|
461
|
+
for (const paramType of parameterTypes ?? def.parameterTypes ?? []) {
|
|
462
|
+
collectAssociatedNamespacesForFunctionTypeText(paramType, scopes, out);
|
|
463
|
+
}
|
|
464
|
+
if (def.returnType !== undefined) {
|
|
465
|
+
collectAssociatedNamespacesForFunctionTypeText(def.returnType, scopes, out);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
function collectAssociatedNamespacesForFunctionTypeText(typeText, scopes, out) {
|
|
469
|
+
for (const token of extractCppTypeNameTokens(typeText)) {
|
|
470
|
+
if (isIgnoredCppAdlNamespace(token.namespaceName))
|
|
471
|
+
continue;
|
|
472
|
+
addAssociatedNamespaceForClassName(token.simpleName, scopes, out);
|
|
473
|
+
if (token.namespaceName !== '')
|
|
474
|
+
out.add(token.namespaceName);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
function extractCppTypeNameTokens(typeText) {
|
|
478
|
+
const cleaned = normalizeCppParamType(typeText);
|
|
479
|
+
if (cleaned === '' || isPrimitiveCppAdlType(cleaned))
|
|
480
|
+
return [];
|
|
481
|
+
const out = [];
|
|
482
|
+
const seen = new Set();
|
|
483
|
+
const tokenSource = typeText.includes('<') ? `${cleaned} ${typeText}` : cleaned;
|
|
484
|
+
for (const rawToken of tokenSource.match(/[A-Za-z_]\w*(?:::[A-Za-z_]\w*)*/g) ?? []) {
|
|
485
|
+
if (isPrimitiveCppAdlType(rawToken))
|
|
486
|
+
continue;
|
|
487
|
+
const segments = rawToken.split('::').filter((part) => part.length > 0);
|
|
488
|
+
const simpleName = segments.at(-1) ?? '';
|
|
489
|
+
if (simpleName === '' || isPrimitiveCppAdlType(simpleName))
|
|
490
|
+
continue;
|
|
491
|
+
const namespaceName = segments.length > 1 ? segments.slice(0, -1).join('.') : '';
|
|
492
|
+
const key = `${namespaceName}\0${simpleName}`;
|
|
493
|
+
if (seen.has(key))
|
|
494
|
+
continue;
|
|
495
|
+
seen.add(key);
|
|
496
|
+
out.push({
|
|
497
|
+
simpleName,
|
|
498
|
+
namespaceName,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
return out;
|
|
502
|
+
}
|
|
503
|
+
const CPP_ADL_PRIMITIVE_OR_KEYWORD_TYPES = new Set([
|
|
504
|
+
'alignas',
|
|
505
|
+
'alignof',
|
|
506
|
+
'auto',
|
|
507
|
+
'bool',
|
|
508
|
+
'char',
|
|
509
|
+
'char8_t',
|
|
510
|
+
'char16_t',
|
|
511
|
+
'char32_t',
|
|
512
|
+
'class',
|
|
513
|
+
'const',
|
|
514
|
+
'consteval',
|
|
515
|
+
'constexpr',
|
|
516
|
+
'constinit',
|
|
517
|
+
'decltype',
|
|
518
|
+
'double',
|
|
519
|
+
'enum',
|
|
520
|
+
'explicit',
|
|
521
|
+
'extern',
|
|
522
|
+
'float',
|
|
523
|
+
'inline',
|
|
524
|
+
'int',
|
|
525
|
+
'long',
|
|
526
|
+
'mutable',
|
|
527
|
+
'noexcept',
|
|
528
|
+
'null',
|
|
529
|
+
'register',
|
|
530
|
+
'short',
|
|
531
|
+
'signed',
|
|
532
|
+
'static',
|
|
533
|
+
'string',
|
|
534
|
+
'struct',
|
|
535
|
+
'template',
|
|
536
|
+
'thread_local',
|
|
537
|
+
'typename',
|
|
538
|
+
'union',
|
|
539
|
+
'unknown',
|
|
540
|
+
'unsigned',
|
|
541
|
+
'void',
|
|
542
|
+
'volatile',
|
|
543
|
+
'wchar_t',
|
|
544
|
+
'...',
|
|
545
|
+
]);
|
|
546
|
+
function isPrimitiveCppAdlType(typeText) {
|
|
547
|
+
return CPP_ADL_PRIMITIVE_OR_KEYWORD_TYPES.has(typeText);
|
|
548
|
+
}
|
|
549
|
+
function isIgnoredCppAdlNamespace(namespaceName) {
|
|
550
|
+
return namespaceName === 'std' || namespaceName.startsWith('std.');
|
|
551
|
+
}
|
|
@@ -89,6 +89,10 @@ export function emitCppScopeCaptures(sourceText, filePath, cachedTree) {
|
|
|
89
89
|
if (arity.parameterTypeClasses !== undefined) {
|
|
90
90
|
grouped['@declaration.parameter-type-classes'] = syntheticCapture('@declaration.parameter-type-classes', fnNode, JSON.stringify(arity.parameterTypeClasses));
|
|
91
91
|
}
|
|
92
|
+
const returnType = extractCppDeclarationReturnType(fnNode);
|
|
93
|
+
if (returnType !== undefined) {
|
|
94
|
+
grouped['@declaration.return-type'] = syntheticCapture('@declaration.return-type', fnNode, returnType);
|
|
95
|
+
}
|
|
92
96
|
if (hasExplicitSpecifier(fnNode)) {
|
|
93
97
|
grouped['@declaration.is-explicit'] = syntheticCapture('@declaration.is-explicit', fnNode, 'true');
|
|
94
98
|
}
|
|
@@ -311,6 +315,32 @@ export function emitCppScopeCaptures(sourceText, filePath, cachedTree) {
|
|
|
311
315
|
detectCppDependentBases(tree.rootNode, filePath);
|
|
312
316
|
return out;
|
|
313
317
|
}
|
|
318
|
+
function extractCppDeclarationReturnType(fnNode) {
|
|
319
|
+
const typeNode = fnNode.childForFieldName('type');
|
|
320
|
+
if (typeNode === null)
|
|
321
|
+
return undefined;
|
|
322
|
+
const funcDeclarator = findFunctionDeclarator(fnNode);
|
|
323
|
+
if (funcDeclarator !== null && isCppUnsupportedReturnTypeDeclarator(funcDeclarator)) {
|
|
324
|
+
return undefined;
|
|
325
|
+
}
|
|
326
|
+
const typeText = typeNode.text.trim();
|
|
327
|
+
if (typeText !== 'auto')
|
|
328
|
+
return typeText.length > 0 ? typeText : undefined;
|
|
329
|
+
if (funcDeclarator === null)
|
|
330
|
+
return typeText;
|
|
331
|
+
for (let i = 0; i < funcDeclarator.namedChildCount; i++) {
|
|
332
|
+
const child = funcDeclarator.namedChild(i);
|
|
333
|
+
if (child?.type !== 'trailing_return_type')
|
|
334
|
+
continue;
|
|
335
|
+
const typeDesc = child.firstNamedChild;
|
|
336
|
+
return typeDesc?.text.trim() || typeText;
|
|
337
|
+
}
|
|
338
|
+
return typeText;
|
|
339
|
+
}
|
|
340
|
+
function isCppUnsupportedReturnTypeDeclarator(funcDeclarator) {
|
|
341
|
+
const text = funcDeclarator.text;
|
|
342
|
+
return /\boperator\b/.test(text) || /(^|[(:\s])~\s*[A-Za-z_]\w*/.test(text);
|
|
343
|
+
}
|
|
314
344
|
/**
|
|
315
345
|
* Walk every C++ class/struct base clause and emit `@reference.inherits`
|
|
316
346
|
* captures for each base so scope resolution can resolve them into EXTENDS
|
|
@@ -853,6 +853,7 @@ const KNOWN_SUB_TAGS = new Set([
|
|
|
853
853
|
'@declaration.required-parameter-count',
|
|
854
854
|
'@declaration.parameter-types',
|
|
855
855
|
'@declaration.parameter-type-classes',
|
|
856
|
+
'@declaration.return-type',
|
|
856
857
|
'@declaration.template-constraints',
|
|
857
858
|
'@declaration.is-explicit',
|
|
858
859
|
]);
|
package/package.json
CHANGED