gitnexus 1.6.5-rc.40 → 1.6.5-rc.41

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.
@@ -15,14 +15,14 @@
15
15
  *
16
16
  * ## Current boundary
17
17
  *
18
- * The current implementation covers ONE associated-entity rule: an argument that's a directly-named
19
- * class type (`audit::Event e`) contributes its **direct enclosing
20
- * namespace** to the candidate set. V2 extends that one step to
21
- * pointer-typed and reference-typed class args (`audit::Event* p`,
22
- * `audit::Event& r`, `audit::Event&& rr`): they contribute the pointee /
23
- * referred class's enclosing namespace too. Function-pointer arguments,
24
- * template specializations, base-class associated namespaces, and the
25
- * rest of the full closure are still deliberately excluded.
18
+ * The current implementation covers class-typed arguments (value, pointer,
19
+ * and reference) and template specializations with explicit type arguments:
20
+ * - `audit::Event e`, `audit::Event* p`, `audit::Event** pp`
21
+ * - `audit::Event& r`, `audit::Event&& rr`
22
+ * - `std::vector<audit::Event>` (template namespace + template-arg namespaces)
23
+ *
24
+ * Function-pointer arguments, base-class associated namespaces, and the rest
25
+ * of the full closure are still deliberately excluded.
26
26
  *
27
27
  * The current implementation also short-circuits to ADL only when ordinary lookup is empty
28
28
  * (`findCallableBindingInScope` returned undefined). ISO C++ would
@@ -61,8 +61,20 @@ import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexe
61
61
  */
62
62
  export interface CppAdlArgInfo {
63
63
  /** Simple class-like type name (last segment of qualified name); empty
64
- * for primitives, literals, function pointers, template specs, etc. */
64
+ * for primitives, literals, function pointers, etc. */
65
65
  readonly simpleClassName: string;
66
+ /** Template's own simple class-like name (e.g. `vector` for
67
+ * `std::vector<N::T>`), empty when arg type is not a template spec. */
68
+ readonly templateSimpleClassName: string;
69
+ /** Template's own enclosing namespace (dot-qualified, e.g. `std`), empty
70
+ * when unavailable / unqualified. */
71
+ readonly templateNamespace: string;
72
+ /** Class-like names extracted from explicit type template arguments,
73
+ * recursively bounded. */
74
+ readonly templateArgClassNames: readonly string[];
75
+ /** Enclosing namespaces extracted from explicit type template arguments,
76
+ * recursively bounded. */
77
+ readonly templateArgNamespaces: readonly string[];
66
78
  }
67
79
  /** Sentinel returned by `pickCppAdlCandidates` when ADL surfaces multiple
68
80
  * candidates that share normalized parameter types — the caller MUST
@@ -15,14 +15,14 @@
15
15
  *
16
16
  * ## Current boundary
17
17
  *
18
- * The current implementation covers ONE associated-entity rule: an argument that's a directly-named
19
- * class type (`audit::Event e`) contributes its **direct enclosing
20
- * namespace** to the candidate set. V2 extends that one step to
21
- * pointer-typed and reference-typed class args (`audit::Event* p`,
22
- * `audit::Event& r`, `audit::Event&& rr`): they contribute the pointee /
23
- * referred class's enclosing namespace too. Function-pointer arguments,
24
- * template specializations, base-class associated namespaces, and the
25
- * rest of the full closure are still deliberately excluded.
18
+ * The current implementation covers class-typed arguments (value, pointer,
19
+ * and reference) and template specializations with explicit type arguments:
20
+ * - `audit::Event e`, `audit::Event* p`, `audit::Event** pp`
21
+ * - `audit::Event& r`, `audit::Event&& rr`
22
+ * - `std::vector<audit::Event>` (template namespace + template-arg namespaces)
23
+ *
24
+ * Function-pointer arguments, base-class associated namespaces, and the rest
25
+ * of the full closure are still deliberately excluded.
26
26
  *
27
27
  * The current implementation also short-circuits to ADL only when ordinary lookup is empty
28
28
  * (`findCallableBindingInScope` returned undefined). ISO C++ would
@@ -132,14 +132,7 @@ export function pickCppAdlCandidates(site, callerParsed, scopes, parsedFiles) {
132
132
  // Collect associated namespace QNames from every participating class-typed arg.
133
133
  const associatedNamespaces = new Set();
134
134
  for (const arg of args) {
135
- if (arg.simpleClassName === '')
136
- continue;
137
- const classDef = findCppClassDefBySimpleName(arg.simpleClassName, scopes);
138
- if (classDef === undefined)
139
- continue;
140
- const nsQName = classToNamespaceQualifiedName.get(classDef.nodeId);
141
- if (nsQName !== undefined)
142
- associatedNamespaces.add(nsQName);
135
+ collectAssociatedNamespacesForAdlArg(arg, scopes, associatedNamespaces);
143
136
  }
144
137
  if (associatedNamespaces.size === 0)
145
138
  return undefined;
@@ -196,6 +189,34 @@ export function pickCppAdlCandidates(site, callerParsed, scopes, parsedFiles) {
196
189
  // unique-survivor requirement (see `pick-implicit-this-overload.test.ts`).
197
190
  return ADL_AMBIGUOUS;
198
191
  }
192
+ function collectAssociatedNamespacesForAdlArg(arg, scopes, associatedNamespaces) {
193
+ // For template args this may be the template name itself (e.g. `vector`);
194
+ // simple-name lookup can match project classes with the same name (known
195
+ // V1/V2 simplification).
196
+ addAssociatedNamespaceForClassName(arg.simpleClassName, scopes, associatedNamespaces);
197
+ // Includes template-owner namespaces (e.g. `std` in std::vector<T>). If
198
+ // that surfaces extra candidates, ADL_AMBIGUOUS suppression below prevents
199
+ // arbitrary edge emission.
200
+ if (arg.templateNamespace.length > 0)
201
+ associatedNamespaces.add(arg.templateNamespace);
202
+ for (const ns of arg.templateArgNamespaces) {
203
+ if (ns.length > 0)
204
+ associatedNamespaces.add(ns);
205
+ }
206
+ for (const className of arg.templateArgClassNames) {
207
+ addAssociatedNamespaceForClassName(className, scopes, associatedNamespaces);
208
+ }
209
+ }
210
+ function addAssociatedNamespaceForClassName(simpleClassName, scopes, associatedNamespaces) {
211
+ if (simpleClassName.length === 0)
212
+ return;
213
+ const classDef = findCppClassDefBySimpleName(simpleClassName, scopes);
214
+ if (classDef === undefined)
215
+ return;
216
+ const nsQName = classToNamespaceQualifiedName.get(classDef.nodeId);
217
+ if (nsQName !== undefined)
218
+ associatedNamespaces.add(nsQName);
219
+ }
199
220
  /** Walk upward from a Class scope, finding the innermost enclosing
200
221
  * Namespace scope, and return that namespace's qualified name (dot-
201
222
  * joined, outermost-first). Returns '' when the class has no enclosing
@@ -657,12 +657,14 @@ function isParenthesizedFunctionCall(callNode) {
657
657
  }
658
658
  /**
659
659
  * Per-argument ADL classification: walk each argument of a free call and
660
- * decide whether it resolves to a directly-named class or class-pointer
661
- * type (ADL fires) or to an excluded shape such as a reference, function
662
- * pointer, primitive, literal, or template specialization.
660
+ * classify its declared type for associated-namespace lookup.
663
661
  *
664
- * Class-typed values and class pointers (`N::S`, `N::S*`, `N::S**`) all
665
- * preserve the pointee class name for associated-namespace lookup.
662
+ * Value/pointer/reference class-typed args and template specializations
663
+ * with explicit type arguments contribute; function pointers, primitives,
664
+ * literals, and other unsupported shapes produce an empty result.
665
+ *
666
+ * Class-typed values/pointers/references (`N::S`, `N::S*`, `N::S&`) all
667
+ * preserve the class name for associated-namespace lookup.
666
668
  * Function pointers remain excluded even when their return type names a
667
669
  * class, because the associated entity is the pointed-to function type,
668
670
  * not the return type.
@@ -682,7 +684,14 @@ function inferCppCallAdlArgs(callNode) {
682
684
  }
683
685
  return out;
684
686
  }
685
- const EMPTY_ADL_ARG = { simpleClassName: '' };
687
+ const ADL_TEMPLATE_RECURSION_MAX_DEPTH = 8;
688
+ const EMPTY_ADL_ARG = {
689
+ simpleClassName: '',
690
+ templateSimpleClassName: '',
691
+ templateNamespace: '',
692
+ templateArgClassNames: [],
693
+ templateArgNamespaces: [],
694
+ };
686
695
  function classifyAdlArg(argNode) {
687
696
  // Literals and primitive-shaped expressions never have associated namespaces.
688
697
  if (argNode.type === 'number_literal' ||
@@ -783,21 +792,51 @@ function lookupAdlIdentifierType(identNode) {
783
792
  if (isFunctionPointer || nameText !== varName)
784
793
  continue;
785
794
  const simpleClassName = extractAdlSimpleTypeName(typeNode);
786
- return { simpleClassName };
795
+ const { templateSimpleClassName, templateNamespace, templateArgClassNames, templateArgNamespaces, } = extractAdlTemplateInfo(typeNode);
796
+ return {
797
+ simpleClassName,
798
+ templateSimpleClassName,
799
+ templateNamespace,
800
+ templateArgClassNames,
801
+ templateArgNamespaces,
802
+ };
787
803
  }
788
804
  return EMPTY_ADL_ARG;
789
805
  }
790
806
  /** Extract the simple class-like type name from a `type:` field node.
791
- * Returns '' for primitives, template specializations, and any other
807
+ * Returns '' for primitives and any other
792
808
  * unsupported type-only shape. Function pointers are filtered at the
793
809
  * declarator level in `lookupAdlIdentifierType`. */
794
810
  function extractAdlSimpleTypeName(typeNode) {
811
+ if (typeNode.type === 'type_descriptor') {
812
+ const innerType = typeNode.childForFieldName('type');
813
+ if (innerType !== null)
814
+ return extractAdlSimpleTypeName(innerType);
815
+ for (let i = 0; i < typeNode.childCount; i++) {
816
+ const child = typeNode.child(i);
817
+ if (child === null)
818
+ continue;
819
+ if (child.type === 'type_identifier' ||
820
+ child.type === 'qualified_identifier' ||
821
+ child.type === 'template_type') {
822
+ return extractAdlSimpleTypeName(child);
823
+ }
824
+ }
825
+ return '';
826
+ }
795
827
  if (typeNode.type === 'primitive_type')
796
828
  return '';
797
829
  if (typeNode.type === 'sized_type_specifier')
798
830
  return '';
799
831
  if (typeNode.type === 'type_identifier')
800
832
  return typeNode.text;
833
+ if (typeNode.type === 'template_type') {
834
+ const nameNode = typeNode.childForFieldName('name');
835
+ if (nameNode !== null)
836
+ return extractAdlSimpleTypeName(nameNode);
837
+ const id = findFirstDescendantOfType(typeNode, 'type_identifier');
838
+ return id !== null ? id.text : '';
839
+ }
801
840
  if (typeNode.type === 'qualified_identifier') {
802
841
  const nameNode = typeNode.childForFieldName('name');
803
842
  if (nameNode !== null)
@@ -805,9 +844,112 @@ function extractAdlSimpleTypeName(typeNode) {
805
844
  const id = findFirstDescendantOfType(typeNode, 'type_identifier');
806
845
  return id !== null ? id.text : '';
807
846
  }
808
- // template_type (e.g. `vector<int>`), function pointers, decltype — V1 excludes.
847
+ // Function pointers, decltype, etc — unsupported for ADL participation.
848
+ return '';
849
+ }
850
+ function extractAdlTypeNamespace(typeNode) {
851
+ if (typeNode.type === 'type_descriptor') {
852
+ const innerType = typeNode.childForFieldName('type');
853
+ if (innerType !== null)
854
+ return extractAdlTypeNamespace(innerType);
855
+ for (let i = 0; i < typeNode.childCount; i++) {
856
+ const child = typeNode.child(i);
857
+ if (child === null)
858
+ continue;
859
+ if (child.type === 'qualified_identifier' ||
860
+ child.type === 'template_type' ||
861
+ child.type === 'type_identifier') {
862
+ return extractAdlTypeNamespace(child);
863
+ }
864
+ }
865
+ return '';
866
+ }
867
+ if (typeNode.type === 'template_type') {
868
+ const nameNode = typeNode.childForFieldName('name');
869
+ return nameNode !== null ? extractAdlTypeNamespace(nameNode) : '';
870
+ }
871
+ if (typeNode.type === 'qualified_identifier') {
872
+ const scope = typeNode.childForFieldName('scope');
873
+ if (scope !== null)
874
+ return normalizeCppNamespaceQName(scope.text);
875
+ return extractNamespaceFromQualifiedText(typeNode.text);
876
+ }
809
877
  return '';
810
878
  }
879
+ function extractAdlTemplateInfo(typeNode) {
880
+ const templateTypeNode = findTemplateTypeNode(typeNode);
881
+ if (templateTypeNode === null) {
882
+ return {
883
+ templateSimpleClassName: '',
884
+ templateNamespace: '',
885
+ templateArgClassNames: [],
886
+ templateArgNamespaces: [],
887
+ };
888
+ }
889
+ const templateArgClassNames = [];
890
+ const templateArgNamespaces = [];
891
+ collectAdlTemplateArgs(templateTypeNode, 0, templateArgClassNames, templateArgNamespaces);
892
+ return {
893
+ templateSimpleClassName: extractAdlSimpleTypeName(templateTypeNode),
894
+ templateNamespace: extractAdlTypeNamespace(typeNode),
895
+ templateArgClassNames,
896
+ templateArgNamespaces,
897
+ };
898
+ }
899
+ function collectAdlTemplateArgs(templateTypeNode, depth, outClassNames, outNamespaces) {
900
+ if (depth >= ADL_TEMPLATE_RECURSION_MAX_DEPTH)
901
+ return;
902
+ if (templateTypeNode.type !== 'template_type')
903
+ return;
904
+ const argList = templateTypeNode.childForFieldName('arguments') ??
905
+ findChildOfType(templateTypeNode, ['template_argument_list']);
906
+ if (argList === null)
907
+ return;
908
+ for (let i = 0; i < argList.namedChildCount; i++) {
909
+ const arg = argList.namedChild(i);
910
+ if (arg === null || arg.type !== 'type_descriptor')
911
+ continue;
912
+ const simpleClassName = extractAdlSimpleTypeName(arg);
913
+ if (simpleClassName.length > 0)
914
+ outClassNames.push(simpleClassName);
915
+ const ns = extractAdlTypeNamespace(arg);
916
+ if (ns.length > 0)
917
+ outNamespaces.push(ns);
918
+ const nestedType = arg.childForFieldName('type');
919
+ const nestedTemplate = nestedType !== null ? findTemplateTypeNode(nestedType) : null;
920
+ if (nestedTemplate !== null) {
921
+ collectAdlTemplateArgs(nestedTemplate, depth + 1, outClassNames, outNamespaces);
922
+ }
923
+ }
924
+ }
925
+ function findTemplateTypeNode(typeNode) {
926
+ if (typeNode.type === 'template_type')
927
+ return typeNode;
928
+ if (typeNode.type === 'type_descriptor') {
929
+ const innerType = typeNode.childForFieldName('type');
930
+ if (innerType !== null)
931
+ return findTemplateTypeNode(innerType);
932
+ return null;
933
+ }
934
+ if (typeNode.type === 'qualified_identifier') {
935
+ const nameNode = typeNode.childForFieldName('name');
936
+ if (nameNode !== null)
937
+ return findTemplateTypeNode(nameNode);
938
+ return null;
939
+ }
940
+ return null;
941
+ }
942
+ function normalizeCppNamespaceQName(text) {
943
+ const normalized = text.replace(/^::/, '').replace(/::$/, '').replace(/::/g, '.');
944
+ return normalized;
945
+ }
946
+ function extractNamespaceFromQualifiedText(text) {
947
+ const cleaned = text.replace(/\s+/g, '');
948
+ const idx = cleaned.lastIndexOf('::');
949
+ if (idx <= 0)
950
+ return '';
951
+ return normalizeCppNamespaceQName(cleaned.slice(0, idx));
952
+ }
811
953
  /**
812
954
  * Check if a C++ function_definition or declaration has `static` storage class.
813
955
  */
@@ -188,8 +188,10 @@ export const cppScopeResolver = {
188
188
  // C++ argument-dependent / Koenig lookup (U2 of plan 2026-05-13-001).
189
189
  // Fires after `findCallableBindingInScope` returns undefined; surfaces
190
190
  // candidates from the associated namespaces of class-typed arguments.
191
- // V1 limitation: only direct enclosing-namespace closure for value
192
- // class-typed args; pointer/reference/template-spec args excluded.
191
+ // Current boundary: class-typed value/pointer/reference args and template
192
+ // specializations with explicit type arguments contribute associated
193
+ // namespaces. Function-pointer args, base-class associated namespaces,
194
+ // and full ordinary+ADL merge remain excluded.
193
195
  resolveAdlCandidates: (site, callerParsed, scopes, parsedFiles) => {
194
196
  // `using ns::name;` introduces `name` into ordinary unqualified lookup.
195
197
  // For template-class method bodies, lexical scope walks can miss this
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.5-rc.40",
3
+ "version": "1.6.5-rc.41",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",