gitnexus 1.6.6-rc.12 → 1.6.6-rc.13

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.
@@ -20,6 +20,7 @@
20
20
  * resolution step that reads this record and produces a `Reference`
21
21
  * (defined in `./types.ts`).
22
22
  */
23
+ import type { ParameterTypeClass } from './symbol-definition.js';
23
24
  import type { Range, ScopeId } from './types.js';
24
25
  /**
25
26
  * What kind of usage this reference represents — the graph-edge kind
@@ -71,5 +72,12 @@ export interface ReferenceSite {
71
72
  * (C#: `42` → `'int'`, `"alice"` → `'string'`).
72
73
  */
73
74
  readonly argumentTypes?: readonly string[];
75
+ /**
76
+ * Optional per-argument type-shape sidecar for languages that need
77
+ * cv/ref/pointer distinctions during constraint filtering. This is
78
+ * intentionally separate from `argumentTypes`, which stays normalized
79
+ * for existing overload narrowing and conversion-rank logic.
80
+ */
81
+ readonly argumentTypeClasses?: readonly ParameterTypeClass[];
74
82
  }
75
83
  //# sourceMappingURL=reference-site.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reference-site.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/reference-site.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,MAAM,GACN,OAAO,GACP,gBAAgB,GAChB,UAAU,GACV,YAAY,CAAC;AAEjB;;;;;;;;;GASG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,aAAa,GAAG,OAAO,CAAC;AAEnE,MAAM,WAAW,aAAa;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,kCAAkC;IAClC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5C"}
1
+ {"version":3,"file":"reference-site.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/reference-site.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,MAAM,GACN,OAAO,GACP,gBAAgB,GAChB,UAAU,GACV,YAAY,CAAC;AAEjB;;;;;;;;;GASG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,aAAa,GAAG,OAAO,CAAC;AAEnE,MAAM,WAAW,aAAa;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,kCAAkC;IAClC,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;CAC9D"}
@@ -12,7 +12,7 @@
12
12
  * reaches into the CLI package.
13
13
  */
14
14
  import type { NodeLabel } from '../../graph/types.js';
15
- import type { SymbolDefinition } from '../symbol-definition.js';
15
+ import type { ParameterTypeClass, SymbolDefinition } from '../symbol-definition.js';
16
16
  import type { Callsite, DefId } from '../types.js';
17
17
  import type { DefIndex } from '../def-index.js';
18
18
  import type { QualifiedNameIndex } from '../qualified-name-index.js';
@@ -54,6 +54,13 @@ export interface ConstraintContext {
54
54
  * `narrowOverloadCandidates`' `argTypes` parameter.
55
55
  */
56
56
  readonly argumentTypes?: readonly string[];
57
+ /**
58
+ * Optional shape-preserving sidecar aligned with `argumentTypes`.
59
+ * Unknown or unsupported slots should be omitted by producers or
60
+ * marked with `indirection: 'unknown'`; consumers must preserve the
61
+ * monotonic fallback and return 'unknown' instead of guessing.
62
+ */
63
+ readonly argumentTypeClasses?: readonly ParameterTypeClass[];
57
64
  }
58
65
  /**
59
66
  * Per-owner membership view plugged into `LookupParams.ownerScopedContributor`.
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/scope-resolution/registries/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAIvE,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,kBAAkB,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,gBAAgB,GAAG,YAAY,CAAC;IAE7E;;;;;;;;;;OAUG;IACH,uBAAuB,CAAC,CACtB,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,iBAAiB,GACrB,YAAY,CAAC;CACjB;AAED,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,SAAS,GAAG,cAAc,CAAC;AAErE;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5C;AAID;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,sBAAsB;IACrC,sEAAsE;IACtE,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC;IAC3B;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,gBAAgB,EAAE,CAAC;CACnD;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,yBAAyB,GAAG,CACtC,UAAU,EAAE,KAAK,EACjB,UAAU,EAAE,MAAM,KACf,SAAS,gBAAgB,EAAE,CAAC;AAIjC,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,kBAAkB,CAAC;IAC5C,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC;IACxC,QAAQ,CAAC,mBAAmB,EAAE,yBAAyB,CAAC;IACxD;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,mBAAmB,CAAC;IAC9C,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;CACvC;AAOD,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAc1C,CAAC;AAEH,eAAO,MAAM,YAAY,EAAE,SAAS,SAAS,EAI3C,CAAC;AAEH,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAK1C,CAAC"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/scope-resolution/registries/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACpF,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAIvE,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,kBAAkB,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,gBAAgB,GAAG,YAAY,CAAC;IAE7E;;;;;;;;;;OAUG;IACH,uBAAuB,CAAC,CACtB,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,iBAAiB,GACrB,YAAY,CAAC;CACjB;AAED,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,SAAS,GAAG,cAAc,CAAC;AAErE;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;CAC9D;AAID;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,sBAAsB;IACrC,sEAAsE;IACtE,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC;IAC3B;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,gBAAgB,EAAE,CAAC;CACnD;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,yBAAyB,GAAG,CACtC,UAAU,EAAE,KAAK,EACjB,UAAU,EAAE,MAAM,KACf,SAAS,gBAAgB,EAAE,CAAC;AAIjC,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,kBAAkB,CAAC;IAC5C,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC;IACxC,QAAQ,CAAC,mBAAmB,EAAE,yBAAyB,CAAC;IACxD;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,mBAAmB,CAAC;IAC9C,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;CACvC;AAOD,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAc1C,CAAC;AAEH,eAAO,MAAM,YAAY,EAAE,SAAS,SAAS,EAI3C,CAAC;AAEH,eAAO,MAAM,WAAW,EAAE,SAAS,SAAS,EAK1C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/scope-resolution/registries/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAgHH,8EAA8E;AAC9E,EAAE;AACF,0EAA0E;AAC1E,6DAA6D;AAE7D,MAAM,CAAC,MAAM,WAAW,GAAyB,MAAM,CAAC,MAAM,CAAC;IAC7D,OAAO;IACP,WAAW;IACX,MAAM;IACN,QAAQ;IACR,OAAO;IACP,OAAO;IACP,WAAW;IACX,SAAS;IACT,QAAQ;IACR,UAAU;IACV,YAAY;IACZ,UAAU;IACV,WAAW;CACZ,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAyB,MAAM,CAAC,MAAM,CAAC;IAC9D,QAAQ;IACR,UAAU;IACV,aAAa;CACd,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,WAAW,GAAyB,MAAM,CAAC,MAAM,CAAC;IAC7D,UAAU;IACV,UAAU;IACV,OAAO;IACP,QAAQ;CACT,CAAC,CAAC"}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/scope-resolution/registries/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAuHH,8EAA8E;AAC9E,EAAE;AACF,0EAA0E;AAC1E,6DAA6D;AAE7D,MAAM,CAAC,MAAM,WAAW,GAAyB,MAAM,CAAC,MAAM,CAAC;IAC7D,OAAO;IACP,WAAW;IACX,MAAM;IACN,QAAQ;IACR,OAAO;IACP,OAAO;IACP,WAAW;IACX,SAAS;IACT,QAAQ;IACR,UAAU;IACV,YAAY;IACZ,UAAU;IACV,WAAW;CACZ,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAyB,MAAM,CAAC,MAAM,CAAC;IAC9D,QAAQ;IACR,UAAU;IACV,aAAa;CACd,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,WAAW,GAAyB,MAAM,CAAC,MAAM,CAAC;IAC7D,UAAU;IACV,UAAU;IACV,OAAO;IACP,QAAQ;CACT,CAAC,CAAC"}
@@ -3,7 +3,7 @@ import { getCppParser, getCppScopeQuery } from './query.js';
3
3
  import { getTreeSitterBufferSize } from '../../constants.js';
4
4
  import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
5
5
  import { splitCppInclude, splitCppUsingDecl } from './import-decomposer.js';
6
- import { computeCppDeclarationArity, computeCppCallArity } from './arity-metadata.js';
6
+ import { classifyCppParameterType, computeCppDeclarationArity, computeCppCallArity, } from './arity-metadata.js';
7
7
  import { markCppAnonymousNamespaceRange, markFileLocal } from './file-local-linkage.js';
8
8
  import { markCppDependentBase } from './two-phase-lookup.js';
9
9
  import { markCppAdlSiteArgs, markCppAdlSiteNoAdl } from './adl.js';
@@ -159,6 +159,10 @@ export function emitCppScopeCaptures(sourceText, filePath, cachedTree) {
159
159
  if (argTypes !== undefined && argTypes.length > 0) {
160
160
  grouped['@reference.parameter-types'] = syntheticCapture('@reference.parameter-types', cNode, JSON.stringify(argTypes));
161
161
  }
162
+ const argTypeClasses = inferCppCallArgTypeClasses(cNode);
163
+ if (argTypeClasses !== undefined && argTypeClasses.length > 0) {
164
+ grouped['@reference.parameter-type-classes'] = syntheticCapture('@reference.parameter-type-classes', cNode, JSON.stringify(argTypeClasses));
165
+ }
162
166
  }
163
167
  }
164
168
  // ── Inline namespace detection ──────────────────────────────────
@@ -612,6 +616,36 @@ function inferCppCallArgTypes(node) {
612
616
  }
613
617
  return types.length > 0 ? types : undefined;
614
618
  }
619
+ function inferCppCallArgTypeClasses(node) {
620
+ const argList = node.childForFieldName('arguments');
621
+ if (argList === null)
622
+ return undefined;
623
+ const classes = [];
624
+ for (let i = 0; i < argList.childCount; i++) {
625
+ const child = argList.child(i);
626
+ if (child === null)
627
+ continue;
628
+ if (child.type === ',' || child.type === '(' || child.type === ')')
629
+ continue;
630
+ const litType = inferCppLiteralType(child);
631
+ if (litType !== '') {
632
+ classes.push(valueTypeClass(litType));
633
+ }
634
+ else if (child.type === 'identifier') {
635
+ classes.push(lookupDeclaredTypeClassForIdentifier(child));
636
+ }
637
+ else {
638
+ classes.push(unknownTypeClass('unknown'));
639
+ }
640
+ }
641
+ return classes.length > 0 ? classes : undefined;
642
+ }
643
+ function valueTypeClass(base) {
644
+ return { base, cv: 'none', indirection: 'value', pointerDepth: 0 };
645
+ }
646
+ function unknownTypeClass(base) {
647
+ return { base, cv: 'unknown', indirection: 'unknown', pointerDepth: 0 };
648
+ }
615
649
  /**
616
650
  * Infer the canonical type name of a C++ literal AST node.
617
651
  * Returns empty string for non-literal / unknown nodes.
@@ -674,6 +708,9 @@ function lookupDeclaredTypeForIdentifier(identNode) {
674
708
  }
675
709
  if (scope === null)
676
710
  return '';
711
+ const paramType = lookupFunctionParameterType(scope, varName);
712
+ if (paramType !== '')
713
+ return paramType;
677
714
  // Scan declarations in the scope for a matching variable name
678
715
  for (let i = 0; i < scope.childCount; i++) {
679
716
  const stmt = scope.child(i);
@@ -689,18 +726,113 @@ function lookupDeclaredTypeForIdentifier(identNode) {
689
726
  const declarator = stmt.childForFieldName('declarator');
690
727
  if (declarator === null)
691
728
  continue;
692
- if (declarator.type === 'init_declarator') {
693
- const nameChild = declarator.childForFieldName('declarator');
694
- if (nameChild !== null && nameChild.text === varName) {
695
- return normalizeCppTypeText(typeNode.text);
696
- }
697
- }
698
- else if (declarator.text === varName) {
729
+ const nameChild = declaredNameNode(declarator);
730
+ if (nameChild !== null && extractDeclaratorLeafName(nameChild) === varName) {
699
731
  return normalizeCppTypeText(typeNode.text);
700
732
  }
701
733
  }
702
734
  return '';
703
735
  }
736
+ function lookupDeclaredTypeClassForIdentifier(identNode) {
737
+ const varName = identNode.text;
738
+ let scope = identNode.parent;
739
+ while (scope !== null &&
740
+ scope.type !== 'compound_statement' &&
741
+ scope.type !== 'translation_unit') {
742
+ scope = scope.parent;
743
+ }
744
+ if (scope === null)
745
+ return unknownTypeClass('unknown');
746
+ const paramTypeClass = lookupFunctionParameterTypeClass(scope, varName, identNode);
747
+ if (paramTypeClass !== undefined)
748
+ return paramTypeClass;
749
+ for (let i = 0; i < scope.childCount; i++) {
750
+ const stmt = scope.child(i);
751
+ if (stmt === null || stmt.type !== 'declaration')
752
+ continue;
753
+ const typeNode = stmt.childForFieldName('type');
754
+ if (typeNode === null)
755
+ continue;
756
+ if (typeNode.type === 'placeholder_type_specifier')
757
+ continue;
758
+ const declarator = stmt.childForFieldName('declarator');
759
+ if (declarator === null)
760
+ continue;
761
+ const nameChild = declaredNameNode(declarator);
762
+ if (nameChild === null || extractDeclaratorLeafName(nameChild) !== varName)
763
+ continue;
764
+ const typeClass = classifyCppParameterType(typeNode.text, nameChild.text, stmt.text.replace(/;\s*$/, ''));
765
+ if (isKnownEnumName(identNode, typeClass.base)) {
766
+ return { ...typeClass, base: `enum:${typeClass.base}` };
767
+ }
768
+ return typeClass;
769
+ }
770
+ return unknownTypeClass('unknown');
771
+ }
772
+ function lookupFunctionParameterType(scope, varName) {
773
+ const param = findEnclosingFunctionParameter(scope, varName);
774
+ if (param === null)
775
+ return '';
776
+ const typeNode = param.childForFieldName('type');
777
+ if (typeNode === null)
778
+ return '';
779
+ return normalizeCppTypeText(typeNode.text);
780
+ }
781
+ function lookupFunctionParameterTypeClass(scope, varName, identNode) {
782
+ const param = findEnclosingFunctionParameter(scope, varName);
783
+ if (param === null)
784
+ return undefined;
785
+ const typeNode = param.childForFieldName('type');
786
+ if (typeNode === null)
787
+ return undefined;
788
+ const declarator = param.childForFieldName('declarator');
789
+ if (declarator === null)
790
+ return undefined;
791
+ const typeClass = classifyCppParameterType(typeNode.text, declarator.text, param.text);
792
+ if (isKnownEnumName(identNode, typeClass.base)) {
793
+ return { ...typeClass, base: `enum:${typeClass.base}` };
794
+ }
795
+ return typeClass;
796
+ }
797
+ function findEnclosingFunctionParameter(scope, varName) {
798
+ let node = scope.parent;
799
+ while (node !== null) {
800
+ if (node.type === 'function_definition' || node.type === 'function_declarator') {
801
+ const fnDecl = node.type === 'function_declarator'
802
+ ? node
803
+ : findFirstDescendantOfType(node, 'function_declarator');
804
+ const params = fnDecl?.childForFieldName('parameters') ?? null;
805
+ if (params !== null) {
806
+ for (let i = 0; i < params.namedChildCount; i++) {
807
+ const param = params.namedChild(i);
808
+ if (param === null || param.type !== 'parameter_declaration')
809
+ continue;
810
+ const declarator = param.childForFieldName('declarator');
811
+ if (declarator !== null && extractDeclaratorLeafName(declarator) === varName) {
812
+ return param;
813
+ }
814
+ }
815
+ }
816
+ return null;
817
+ }
818
+ node = node.parent;
819
+ }
820
+ return null;
821
+ }
822
+ function declaredNameNode(declarator) {
823
+ if (declarator.type !== 'init_declarator')
824
+ return declarator;
825
+ for (let i = 0; i < declarator.namedChildCount; i++) {
826
+ const child = declarator.namedChild(i);
827
+ if (child === null)
828
+ continue;
829
+ if (child.type === 'identifier')
830
+ return child;
831
+ if (child.type.endsWith('_declarator'))
832
+ return child;
833
+ }
834
+ return declarator.childForFieldName('declarator');
835
+ }
704
836
  /** Normalize a type-specifier text for argument type matching.
705
837
  * Strips qualifiers (const, volatile), namespace prefixes (std::),
706
838
  * and pointer/reference markers. */
@@ -711,6 +843,28 @@ function normalizeCppTypeText(text) {
711
843
  t = t.replace(/[*&]/g, '').trim();
712
844
  return t;
713
845
  }
846
+ function isKnownEnumName(node, typeName) {
847
+ if (typeName === '' || typeName === 'unknown')
848
+ return false;
849
+ let root = node;
850
+ while (root.parent !== null)
851
+ root = root.parent;
852
+ const stack = [root];
853
+ while (stack.length > 0) {
854
+ const cur = stack.pop();
855
+ if (cur.type === 'enum_specifier') {
856
+ const name = cur.childForFieldName('name');
857
+ if (name?.text === typeName)
858
+ return true;
859
+ }
860
+ for (let i = 0; i < cur.childCount; i++) {
861
+ const child = cur.child(i);
862
+ if (child !== null)
863
+ stack.push(child);
864
+ }
865
+ }
866
+ return false;
867
+ }
714
868
  /**
715
869
  * Detect whether a `namespace_definition` AST node is inline.
716
870
  * Tree-sitter-cpp exposes the `inline` keyword as an anonymous child
@@ -1166,7 +1320,9 @@ function extractDeclaratorLeafName(node) {
1166
1320
  // Common wrapper nodes — follow the 'declarator' field when present.
1167
1321
  const next = cur.childForFieldName('declarator') ??
1168
1322
  // parenthesized_declarator: single named child
1169
- (cur.type === 'parenthesized_declarator' ? cur.namedChild(0) : null);
1323
+ (cur.type === 'parenthesized_declarator' || cur.type.endsWith('_declarator')
1324
+ ? cur.namedChild(0)
1325
+ : null);
1170
1326
  if (next === null)
1171
1327
  return null;
1172
1328
  cur = next;
@@ -21,13 +21,9 @@
21
21
  */
22
22
  import { classifyType } from './type-classifier.js';
23
23
  /**
24
- * Curated Tier-A predicate registry — the four canonical
25
- * `<type_traits>` variable templates whose truth tables are closed-form
26
- * over our coarse `TypeClass` enum.
27
- *
28
- * Deferred predicates that need a cv/ref/pointer sidecar on
29
- * `normalizeCppParamType` (today the normalizer strips those markers
30
- * before storage) live in #1579 as one-line follow-up adds.
24
+ * Curated Tier-A predicate registry. Predicates that depend on pointer,
25
+ * reference, or cv shape consult `ConstraintContext.argumentTypeClasses`.
26
+ * Missing or unsupported shape returns 'unknown' to preserve monotonicity.
31
27
  */
32
28
  // ISO `<type_traits>` treats `bool`, `char`, and the signed/unsigned char
33
29
  // variants as integral types (§21.3.4 Table 48), so `is_integral_v<bool>`
@@ -39,40 +35,117 @@ function isIntegralClass(c) {
39
35
  return c === 'integral' || c === 'bool' || c === 'char';
40
36
  }
41
37
  const REGISTRY = new Map([
42
- ['is_integral_v', (cls) => verdictFromBool(isIntegralClass(cls[0]), cls)],
43
- ['is_floating_point_v', (cls) => verdictFromBool(cls[0] === 'floating', cls)],
38
+ [
39
+ 'is_void_v',
40
+ (args) => unaryVerdict(args, (arg) => isPlainValue(arg) && arg.typeClass === 'void'),
41
+ ],
42
+ [
43
+ 'is_integral_v',
44
+ (args) => unaryVerdict(args, (arg) => isPlainValue(arg) && isIntegralClass(arg.typeClass)),
45
+ ],
46
+ [
47
+ 'is_floating_point_v',
48
+ (args) => unaryVerdict(args, (arg) => isPlainValue(arg) && arg.typeClass === 'floating'),
49
+ ],
44
50
  [
45
51
  'is_arithmetic_v',
46
- (cls) => verdictFromBool(isIntegralClass(cls[0]) || cls[0] === 'floating', cls),
52
+ (args) => unaryVerdict(args, (arg) => isPlainValue(arg) && (isIntegralClass(arg.typeClass) || arg.typeClass === 'floating')),
53
+ ],
54
+ [
55
+ 'is_enum_v',
56
+ (args) => unaryVerdict(args, (arg) => isPlainValue(arg) && arg.typeClass === 'enum'),
57
+ ],
58
+ [
59
+ 'is_class_v',
60
+ (args) => unaryVerdict(args, (arg) => isPlainValue(arg) && arg.typeClass === 'class'),
61
+ ],
62
+ [
63
+ 'is_pointer_v',
64
+ (args) => unaryShapeVerdict(args, (shape) => shape.indirection === 'pointer' && shape.pointerDepth > 0),
65
+ ],
66
+ [
67
+ 'is_reference_v',
68
+ (args) => unaryShapeVerdict(args, (shape) => shape.indirection === 'lvalue-ref' || shape.indirection === 'rvalue-ref'),
69
+ ],
70
+ [
71
+ 'is_const_v',
72
+ (args) => unaryShapeVerdict(args, (shape) => shape.cv === 'const' || shape.cv === 'const volatile', {
73
+ requireTopLevelCv: true,
74
+ }),
75
+ ],
76
+ [
77
+ 'is_volatile_v',
78
+ (args) => unaryShapeVerdict(args, (shape) => shape.cv === 'volatile' || shape.cv === 'const volatile', {
79
+ requireTopLevelCv: true,
80
+ }),
47
81
  ],
48
- // NOTE: cv-qualifiers are stripped by `normalizeCppParamType` before the
49
- // type token reaches `classifyType`, so `is_same_v<const T, T>` returns
50
- // `'compatible'` instead of the ISO-correct `false`. Tracked under the
51
- // cv-sidecar refactor in #1579's "Out of scope" list; until that lands
52
- // this approximation matches the common `is_same_v<T, ConcreteType>`
53
- // dispatch idiom and silently degrades on cv-distinct compares.
54
82
  [
55
83
  'is_same_v',
56
- (cls) => {
57
- if (cls.length < 2 || cls[0] === 'unknown' || cls[1] === 'unknown')
84
+ (args) => {
85
+ if (args.length < 2 || args[0].typeClass === 'unknown' || args[1].typeClass === 'unknown') {
58
86
  return 'unknown';
59
- return cls[0] === cls[1] ? 'compatible' : 'incompatible';
87
+ }
88
+ return args[0].typeClass === args[1].typeClass ? 'compatible' : 'incompatible';
60
89
  },
61
90
  ],
62
91
  ]);
63
- function verdictFromBool(predicate, cls) {
64
- if (cls[0] === 'unknown')
92
+ function unaryVerdict(args, predicate) {
93
+ const arg = args[0];
94
+ if (arg === undefined || arg.typeClass === 'unknown')
65
95
  return 'unknown';
66
- return predicate ? 'compatible' : 'incompatible';
96
+ return predicate(arg) ? 'compatible' : 'incompatible';
97
+ }
98
+ function unaryShapeVerdict(args, predicate, options = {}) {
99
+ const arg = args[0];
100
+ if (arg === undefined || arg.typeClass === 'unknown')
101
+ return 'unknown';
102
+ const shape = arg.shape;
103
+ if (shape === undefined || shape.indirection === 'unknown' || shape.cv === 'unknown') {
104
+ return 'unknown';
105
+ }
106
+ if (options.requireTopLevelCv === true && shape.indirection === 'pointer') {
107
+ return 'unknown';
108
+ }
109
+ return predicate(shape) ? 'compatible' : 'incompatible';
110
+ }
111
+ function isPlainValue(arg) {
112
+ const shape = arg.shape;
113
+ if (shape === undefined)
114
+ return true;
115
+ return shape.indirection === 'value';
116
+ }
117
+ function classifyConstraintArg(token, shape) {
118
+ if (shape !== undefined && shape.base.startsWith('enum:')) {
119
+ return { typeClass: 'enum', shape };
120
+ }
121
+ const typeClass = token === undefined || token === '' ? 'unknown' : classifyType(token);
122
+ return { typeClass, ...(shape !== undefined ? { shape } : {}) };
123
+ }
124
+ function tokenForArg(ctx, argIdx) {
125
+ const shape = ctx.argumentTypeClasses?.[argIdx];
126
+ if (shape?.base.startsWith('enum:'))
127
+ return shape.base;
128
+ return ctx.argumentTypes?.[argIdx];
129
+ }
130
+ function shapeForTemplateParam(ctx, paramName, argIdx, def) {
131
+ const argShape = ctx.argumentTypeClasses?.[argIdx];
132
+ if (argShape === undefined)
133
+ return undefined;
134
+ const paramShape = def?.parameterTypeClasses?.[argIdx];
135
+ if (paramShape === undefined)
136
+ return argShape;
137
+ if (paramShape.base === paramName && paramShape.indirection === 'value')
138
+ return argShape;
139
+ return undefined;
67
140
  }
68
141
  /** Public surface — registered as `ScopeResolver.constraintCompatibility`. */
69
142
  export function cppConstraintCompatibility(_callsite, def, ctx) {
70
143
  const payload = def.templateConstraints;
71
144
  if (payload === undefined)
72
145
  return 'unknown';
73
- return evaluate(payload.expr, payload, ctx);
146
+ return evaluate(payload.expr, payload, ctx, def);
74
147
  }
75
- function evaluate(expr, payload, ctx) {
148
+ function evaluate(expr, payload, ctx, def) {
76
149
  switch (expr.kind) {
77
150
  case 'unknown':
78
151
  return 'unknown';
@@ -83,18 +156,15 @@ function evaluate(expr, payload, ctx) {
83
156
  const classes = expr.args.map((paramName) => {
84
157
  const argIdx = payload.paramArgIndex[paramName];
85
158
  if (argIdx === undefined)
86
- return 'unknown';
87
- const token = ctx.argumentTypes?.[argIdx];
88
- if (token === undefined || token === '')
89
- return 'unknown';
90
- return classifyType(token);
159
+ return { typeClass: 'unknown' };
160
+ return classifyConstraintArg(tokenForArg(ctx, argIdx), shapeForTemplateParam(ctx, paramName, argIdx, def));
91
161
  });
92
162
  return evaluator(classes);
93
163
  }
94
164
  case 'and': {
95
165
  let result = 'compatible';
96
166
  for (const child of expr.children) {
97
- const v = evaluate(child, payload, ctx);
167
+ const v = evaluate(child, payload, ctx, def);
98
168
  if (v === 'incompatible')
99
169
  return 'incompatible';
100
170
  if (v === 'unknown')
@@ -105,7 +175,7 @@ function evaluate(expr, payload, ctx) {
105
175
  case 'or': {
106
176
  let result = 'incompatible';
107
177
  for (const child of expr.children) {
108
- const v = evaluate(child, payload, ctx);
178
+ const v = evaluate(child, payload, ctx, def);
109
179
  if (v === 'compatible')
110
180
  return 'compatible';
111
181
  if (v === 'unknown')
@@ -114,7 +184,7 @@ function evaluate(expr, payload, ctx) {
114
184
  return result;
115
185
  }
116
186
  case 'not': {
117
- const v = evaluate(expr.child, payload, ctx);
187
+ const v = evaluate(expr.child, payload, ctx, def);
118
188
  if (v === 'compatible')
119
189
  return 'incompatible';
120
190
  if (v === 'incompatible')
@@ -7,20 +7,20 @@
7
7
  * the call-site inference in `captures.ts`) to one of the categories
8
8
  * the `<type_traits>` predicate registry uses for SFINAE filtering.
9
9
  *
10
- * Intentionally coarse: cv / pointer / reference qualifiers are stripped
11
- * upstream by `normalizeCppParamType`. Tier-A predicates
12
- * (`is_integral_v`, `is_floating_point_v`, `is_arithmetic_v`, `is_same_v`)
13
- * are insensitive to those modifiers per ISO `<type_traits>` semantics
14
- * ("including any cv-qualified variants").
10
+ * `argumentTypes` remain normalized for overload narrowing, while
11
+ * constraint predicates that need cv/ref/pointer shape read the parallel
12
+ * `argumentTypeClasses` sidecar. Unknown shapes must stay unknown rather
13
+ * than being guessed as incompatible.
15
14
  */
16
- export type TypeClass = 'integral' | 'floating' | 'bool' | 'char' | 'string' | 'null' | 'class' | 'unknown';
15
+ export type TypeClass = 'integral' | 'floating' | 'bool' | 'char' | 'string' | 'null' | 'void' | 'enum' | 'class' | 'pointer' | 'reference' | 'unknown';
17
16
  /**
18
17
  * Classify a normalized C++ type token. The mapping mirrors the literal-
19
18
  * inference table in `captures.ts:inferCppLiteralType` plus the std::
20
19
  * normalization in `arity-metadata.ts:normalizeCppParamType`.
21
20
  *
22
- * Caller note: token must already be normalized (no `const`, no `&` / `*`,
23
- * no `std::` prefix). Tokens passed via `ConstraintContext.argumentTypes`
24
- * coming from `inferCppCallArgTypes` satisfy this.
21
+ * Caller note: token should be normalized for overload matching. Enum
22
+ * tokens produced by the C++ adapter use the internal `enum:<Name>`
23
+ * prefix so `is_enum_v` does not have to guess that every user token is
24
+ * class-like.
25
25
  */
26
26
  export declare function classifyType(token: string): TypeClass;
@@ -7,25 +7,29 @@
7
7
  * the call-site inference in `captures.ts`) to one of the categories
8
8
  * the `<type_traits>` predicate registry uses for SFINAE filtering.
9
9
  *
10
- * Intentionally coarse: cv / pointer / reference qualifiers are stripped
11
- * upstream by `normalizeCppParamType`. Tier-A predicates
12
- * (`is_integral_v`, `is_floating_point_v`, `is_arithmetic_v`, `is_same_v`)
13
- * are insensitive to those modifiers per ISO `<type_traits>` semantics
14
- * ("including any cv-qualified variants").
10
+ * `argumentTypes` remain normalized for overload narrowing, while
11
+ * constraint predicates that need cv/ref/pointer shape read the parallel
12
+ * `argumentTypeClasses` sidecar. Unknown shapes must stay unknown rather
13
+ * than being guessed as incompatible.
15
14
  */
16
15
  /**
17
16
  * Classify a normalized C++ type token. The mapping mirrors the literal-
18
17
  * inference table in `captures.ts:inferCppLiteralType` plus the std::
19
18
  * normalization in `arity-metadata.ts:normalizeCppParamType`.
20
19
  *
21
- * Caller note: token must already be normalized (no `const`, no `&` / `*`,
22
- * no `std::` prefix). Tokens passed via `ConstraintContext.argumentTypes`
23
- * coming from `inferCppCallArgTypes` satisfy this.
20
+ * Caller note: token should be normalized for overload matching. Enum
21
+ * tokens produced by the C++ adapter use the internal `enum:<Name>`
22
+ * prefix so `is_enum_v` does not have to guess that every user token is
23
+ * class-like.
24
24
  */
25
25
  export function classifyType(token) {
26
26
  if (token.length === 0)
27
27
  return 'unknown';
28
+ if (token.startsWith('enum:'))
29
+ return 'enum';
28
30
  switch (token) {
31
+ case 'void':
32
+ return 'void';
29
33
  case 'int':
30
34
  return 'integral';
31
35
  case 'double':
@@ -692,6 +692,7 @@ function pass5CollectReferences(matches, positionIndex, filePath, referenceSites
692
692
  const explicitReceiver = extractExplicitReceiver(match);
693
693
  const arity = extractArity(match);
694
694
  const argumentTypes = extractArgumentTypes(match);
695
+ const argumentTypeClasses = parseJsonParameterTypeClassesCapture(match['@reference.parameter-type-classes']);
695
696
  const site = {
696
697
  name: nameCap.text,
697
698
  atRange: anchor.range,
@@ -701,6 +702,7 @@ function pass5CollectReferences(matches, positionIndex, filePath, referenceSites
701
702
  ...(explicitReceiver !== undefined ? { explicitReceiver } : {}),
702
703
  ...(arity !== undefined ? { arity } : {}),
703
704
  ...(argumentTypes !== undefined ? { argumentTypes } : {}),
705
+ ...(argumentTypeClasses !== undefined ? { argumentTypeClasses } : {}),
704
706
  };
705
707
  referenceSites.push(site);
706
708
  }
@@ -806,9 +808,11 @@ const KNOWN_SUB_TAGS = new Set([
806
808
  '@reference.receiver',
807
809
  '@reference.arity',
808
810
  '@reference.parameter-types',
811
+ '@reference.parameter-type-classes',
809
812
  '@declaration.parameter-count',
810
813
  '@declaration.required-parameter-count',
811
814
  '@declaration.parameter-types',
815
+ '@declaration.parameter-type-classes',
812
816
  '@declaration.template-constraints',
813
817
  ]);
814
818
  /**
@@ -70,6 +70,7 @@ export declare function pickImplicitThisOverload(site: {
70
70
  readonly name: string;
71
71
  readonly arity?: number;
72
72
  readonly argumentTypes?: readonly string[];
73
+ readonly argumentTypeClasses?: readonly import('../../../../_shared/index.js').ParameterTypeClass[];
73
74
  }, scopes: ScopeResolutionIndexes, workspaceIndex: WorkspaceResolutionIndex, model: SemanticModel, hookCtx?: {
74
75
  readonly conversionRankFn?: ConversionRankFn;
75
76
  readonly constraintCompatibility?: ScopeResolver['constraintCompatibility'];
@@ -72,6 +72,7 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
72
72
  const allCallables = findAllCallableBindingsInScope(site.inScope, site.name, scopes);
73
73
  if (allCallables.length > 1) {
74
74
  const narrowed = narrowOverloadCandidates(allCallables, site.arity, site.argumentTypes, {
75
+ argumentTypeClasses: site.argumentTypeClasses,
75
76
  conversionRankFn: options.conversionRankFn,
76
77
  constraintCompatibility: options.constraintCompatibility,
77
78
  });
@@ -126,6 +127,7 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
126
127
  }
127
128
  else {
128
129
  const narrowed = narrowOverloadCandidates(ordinary, site.arity, site.argumentTypes, {
130
+ argumentTypeClasses: site.argumentTypeClasses,
129
131
  conversionRankFn: options.conversionRankFn,
130
132
  constraintCompatibility: options.constraintCompatibility,
131
133
  });
@@ -164,6 +166,7 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
164
166
  push(ordinary);
165
167
  push(adl);
166
168
  const narrowed = narrowOverloadCandidates(merged, site.arity, site.argumentTypes, {
169
+ argumentTypeClasses: site.argumentTypeClasses,
167
170
  conversionRankFn: options.conversionRankFn,
168
171
  constraintCompatibility: options.constraintCompatibility,
169
172
  });
@@ -427,6 +430,7 @@ export function pickImplicitThisOverload(site, scopes, workspaceIndex, model, ho
427
430
  // disambiguating signal) leaves the call unresolved rather than
428
431
  // routing to an arbitrary first overload by registration order.
429
432
  const candidates = narrowOverloadCandidates(overloads, site.arity, site.argumentTypes, {
433
+ argumentTypeClasses: site.argumentTypeClasses,
430
434
  conversionRankFn: hookCtx?.conversionRankFn,
431
435
  constraintCompatibility: hookCtx?.constraintCompatibility,
432
436
  });
@@ -59,6 +59,8 @@ export type ConversionRankFn = (argType: string, paramType: string) => number;
59
59
  * undefined preserves the legacy arity + exact-type behavior.
60
60
  */
61
61
  export interface OverloadNarrowingHookCtx {
62
+ /** Shape-preserving per-argument sidecar aligned with `argTypes`. */
63
+ readonly argumentTypeClasses?: ConstraintContext['argumentTypeClasses'];
62
64
  /** Conversion-rank scoring fallback (step 4b). Engages when the
63
65
  * exact-type filter rejects every candidate. */
64
66
  readonly conversionRankFn?: ConversionRankFn;
@@ -118,7 +118,14 @@ export function narrowOverloadCandidates(overloads, argCount, argTypes, hookCtx)
118
118
  // than emitting a wrong edge.
119
119
  if (hookCtx?.constraintCompatibility !== undefined && argCount !== undefined) {
120
120
  const callsite = { arity: argCount };
121
- const ctx = argTypes !== undefined ? { argumentTypes: argTypes } : {};
121
+ const ctx = argTypes !== undefined
122
+ ? {
123
+ argumentTypes: argTypes,
124
+ ...(hookCtx.argumentTypeClasses !== undefined
125
+ ? { argumentTypeClasses: hookCtx.argumentTypeClasses }
126
+ : {}),
127
+ }
128
+ : {};
122
129
  result = result.filter((def) => {
123
130
  if (def.templateConstraints === undefined)
124
131
  return true;
@@ -250,6 +250,7 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
250
250
  const methodOverloads = model.methods.lookupAllByOwner(ownerId, memberName);
251
251
  if (methodOverloads.length > 0) {
252
252
  const narrowed = narrowOverloadCandidates(methodOverloads, site.arity, site.argumentTypes, {
253
+ argumentTypeClasses: site.argumentTypeClasses,
253
254
  conversionRankFn: provider.conversionRankFn,
254
255
  constraintCompatibility: provider.constraintCompatibility,
255
256
  });
@@ -532,6 +533,7 @@ function pickOverload(ownerId, memberName, site, model, provider) {
532
533
  if (overloads.length === 1)
533
534
  return overloads[0];
534
535
  const candidates = narrowOverloadCandidates(overloads, site.arity, site.argumentTypes, {
536
+ argumentTypeClasses: site.argumentTypeClasses,
535
537
  conversionRankFn: provider.conversionRankFn,
536
538
  constraintCompatibility: provider.constraintCompatibility,
537
539
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.6-rc.12",
3
+ "version": "1.6.6-rc.13",
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",