gitnexus 1.6.8-rc.47 → 1.6.8-rc.49

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.
Files changed (23) hide show
  1. package/dist/_shared/scope-resolution/symbol-definition.d.ts +2 -0
  2. package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
  3. package/dist/core/ingestion/languages/cpp/arity-metadata.js +35 -0
  4. package/dist/core/ingestion/languages/cpp/captures.js +24 -0
  5. package/dist/core/ingestion/languages/cpp/conversion-rank.d.ts +2 -0
  6. package/dist/core/ingestion/languages/cpp/conversion-rank.js +89 -0
  7. package/dist/core/ingestion/languages/cpp/inline-namespaces.js +7 -2
  8. package/dist/core/ingestion/languages/cpp/member-lookup.js +2 -1
  9. package/dist/core/ingestion/languages/cpp/scope-resolver.js +2 -1
  10. package/dist/core/ingestion/scope-extractor.js +9 -2
  11. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +9 -0
  12. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +3 -1
  13. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +9 -2
  14. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +4 -0
  15. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +9 -0
  16. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +1 -1
  17. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +4 -0
  18. package/dist/core/ingestion/scope-resolution/pipeline/run.js +1 -0
  19. package/dist/core/ingestion/type-extractors/c-cpp.js +21 -0
  20. package/dist/core/wiki/generator.js +3 -1
  21. package/dist/core/wiki/graph-queries.d.ts +6 -0
  22. package/dist/core/wiki/graph-queries.js +9 -1
  23. package/package.json +1 -1
@@ -18,6 +18,8 @@ export interface ParameterTypeClass {
18
18
  indirection: 'value' | 'lvalue-ref' | 'rvalue-ref' | 'pointer' | 'unknown';
19
19
  /** Number of pointer markers when indirection is `pointer`; otherwise 0. */
20
20
  pointerDepth: number;
21
+ /** Normalized top-level template arguments, when a language preserves them. */
22
+ templateArguments?: string[];
21
23
  }
22
24
  export interface SymbolDefinition {
23
25
  nodeId: string;
@@ -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,kBAAkB;IACjC,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,gBAAgB,GAAG,SAAS,CAAC;IACjE,4CAA4C;IAC5C,WAAW,EAAE,OAAO,GAAG,YAAY,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,CAAC;IAC3E,4EAA4E;IAC5E,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,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;4FACwF;IACxF,oBAAoB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC5C,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;;;;;yEAKqE;IACrE,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;4DAEwD;IACxD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;mEAE+D;IAC/D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;iEAO6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B"}
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,kBAAkB;IACjC,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,gBAAgB,GAAG,SAAS,CAAC;IACjE,4CAA4C;IAC5C,WAAW,EAAE,OAAO,GAAG,YAAY,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,CAAC;IAC3E,4EAA4E;IAC5E,YAAY,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,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;4FACwF;IACxF,oBAAoB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC5C,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;;;;;yEAKqE;IACrE,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;4DAEwD;IACxD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;mEAE+D;IAC/D,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;iEAO6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B"}
@@ -173,6 +173,7 @@ export function classifyCppParameterType(rawType, declaratorText, fullParameterT
173
173
  cv,
174
174
  indirection,
175
175
  pointerDepth,
176
+ ...templateArgumentsFor(`${source} ${rawType} ${declaratorText ?? ''}`),
176
177
  };
177
178
  }
178
179
  function unknownTypeClass(base) {
@@ -183,6 +184,40 @@ function unknownTypeClass(base) {
183
184
  pointerDepth: 0,
184
185
  };
185
186
  }
187
+ function templateArgumentsFor(rawType) {
188
+ const args = parseTopLevelTemplateArguments(rawType);
189
+ return args === undefined ? {} : { templateArguments: args };
190
+ }
191
+ function parseTopLevelTemplateArguments(rawType) {
192
+ const start = rawType.indexOf('<');
193
+ if (start < 0)
194
+ return undefined;
195
+ const args = [];
196
+ let depth = 0;
197
+ let argStart = start + 1;
198
+ for (let i = start + 1; i < rawType.length; i++) {
199
+ const ch = rawType[i];
200
+ if (ch === '<') {
201
+ depth++;
202
+ }
203
+ else if (ch === '>') {
204
+ if (depth === 0) {
205
+ const finalArg = rawType.slice(argStart, i).trim();
206
+ if (finalArg.length > 0)
207
+ args.push(normalizeCppParamType(finalArg));
208
+ return args.length > 0 ? args : undefined;
209
+ }
210
+ depth--;
211
+ }
212
+ else if (ch === ',' && depth === 0) {
213
+ const arg = rawType.slice(argStart, i).trim();
214
+ if (arg.length > 0)
215
+ args.push(normalizeCppParamType(arg));
216
+ argStart = i + 1;
217
+ }
218
+ }
219
+ return undefined;
220
+ }
186
221
  function findFuncDeclarator(node) {
187
222
  let decl = node.childForFieldName('declarator');
188
223
  if (decl === null) {
@@ -11,6 +11,7 @@ import { markCppAdlSiteArgs, markCppAdlSiteNoAdl } from './adl.js';
11
11
  import { markCppInlineNamespaceRange } from './inline-namespaces.js';
12
12
  import { extractCppTemplateConstraints } from './constraint-extractor.js';
13
13
  import { captureCppMemberLookupFacts } from './member-lookup.js';
14
+ import { CPP_BRACED_INIT_TYPE_PREFIX } from './conversion-rank.js';
14
15
  export function emitCppScopeCaptures(sourceText, filePath, cachedTree) {
15
16
  let tree = cachedTree;
16
17
  if (tree === undefined) {
@@ -906,6 +907,8 @@ function unknownTypeClass(base) {
906
907
  */
907
908
  function inferCppLiteralType(node) {
908
909
  switch (node.type) {
910
+ case 'initializer_list':
911
+ return inferCppBracedInitType(node);
909
912
  case 'number_literal': {
910
913
  const text = node.text;
911
914
  // Floating-point literals contain '.', 'e', 'E', or end with 'f'/'F'
@@ -934,6 +937,27 @@ function inferCppLiteralType(node) {
934
937
  return '';
935
938
  }
936
939
  }
940
+ function inferCppBracedInitType(node) {
941
+ const elementTypes = [];
942
+ for (let i = 0; i < node.childCount; i++) {
943
+ const child = node.child(i);
944
+ if (child === null)
945
+ continue;
946
+ if (child.type === ',' || child.type === '{' || child.type === '}')
947
+ continue;
948
+ const elementType = inferCppLiteralType(child);
949
+ if (elementType === '' || elementType.startsWith(CPP_BRACED_INIT_TYPE_PREFIX)) {
950
+ return `${CPP_BRACED_INIT_TYPE_PREFIX}unknown:${elementTypes.length + 1}`;
951
+ }
952
+ elementTypes.push(elementType);
953
+ }
954
+ if (elementTypes.length === 0)
955
+ return `${CPP_BRACED_INIT_TYPE_PREFIX}unknown:0`;
956
+ const first = elementTypes[0];
957
+ return elementTypes.every((type) => type === first)
958
+ ? `${CPP_BRACED_INIT_TYPE_PREFIX}${first}:${elementTypes.length}`
959
+ : `${CPP_BRACED_INIT_TYPE_PREFIX}unknown:${elementTypes.length}`;
960
+ }
937
961
  /**
938
962
  * Look up the declared type of a variable by scanning sibling declarations
939
963
  * in the enclosing compound_statement (function body). Handles:
@@ -20,6 +20,8 @@
20
20
  * their own `ConversionRankFn` in the future.
21
21
  */
22
22
  import type { ParameterTypeClass } from '../../../../_shared/index.js';
23
+ export declare const CPP_BRACED_INIT_TYPE_PREFIX = "braced-init:";
24
+ export declare const CPP_CONVERSION_ONLY_ARG_TYPE_PREFIXES: readonly ["braced-init:"];
23
25
  /**
24
26
  * Return the conversion rank from `argType` to `paramType`.
25
27
  *
@@ -19,6 +19,7 @@
19
19
  * This function is intentionally C++-specific. Other languages may define
20
20
  * their own `ConversionRankFn` in the future.
21
21
  */
22
+ import { normalizeCppParamType } from './arity-metadata.js';
22
23
  import { hasCppUserDefinedConversion } from './user-defined-conversions.js';
23
24
  /** Set of normalized arithmetic types that support implicit conversion. */
24
25
  const ARITHMETIC = new Set(['int', 'double', 'char', 'bool']);
@@ -27,6 +28,22 @@ const INTEGRAL_PROMOTION = new Map([
27
28
  ['char', 'int'],
28
29
  ['bool', 'int'],
29
30
  ]);
31
+ export const CPP_BRACED_INIT_TYPE_PREFIX = 'braced-init:';
32
+ export const CPP_CONVERSION_ONLY_ARG_TYPE_PREFIXES = [CPP_BRACED_INIT_TYPE_PREFIX];
33
+ const BRACED_INIT_CONTAINER_TYPES = new Set([
34
+ 'array',
35
+ 'deque',
36
+ 'list',
37
+ 'set',
38
+ 'std::array',
39
+ 'std::deque',
40
+ 'std::list',
41
+ 'std::set',
42
+ 'std::unordered_set',
43
+ 'std::vector',
44
+ 'unordered_set',
45
+ 'vector',
46
+ ]);
30
47
  /**
31
48
  * Return the conversion rank from `argType` to `paramType`.
32
49
  *
@@ -36,6 +53,17 @@ const INTEGRAL_PROMOTION = new Map([
36
53
  * for mismatch.
37
54
  */
38
55
  export function cppConversionRank(argType, paramType, argTypeClass, paramTypeClass) {
56
+ const bracedInitType = parseBracedInitArgType(argType);
57
+ if (bracedInitType !== undefined) {
58
+ if (bracedInitType.elementType === 'unknown')
59
+ return Infinity;
60
+ if (bracedInitType.elementCount === 1) {
61
+ const scalarRank = cppConversionRank(bracedInitType.elementType, paramType, undefined, paramTypeClass);
62
+ if (isFinite(scalarRank))
63
+ return scalarRank;
64
+ }
65
+ return bracedInitConversionRank(paramType, bracedInitType, paramTypeClass);
66
+ }
39
67
  if (argType === paramType) {
40
68
  return exactShapeCompatible(argTypeClass, paramTypeClass) ? 0 : Infinity;
41
69
  }
@@ -57,6 +85,67 @@ export function cppConversionRank(argType, paramType, argTypeClass, paramTypeCla
57
85
  return 4;
58
86
  return Infinity;
59
87
  }
88
+ function parseBracedInitArgType(argType) {
89
+ if (!argType.startsWith(CPP_BRACED_INIT_TYPE_PREFIX))
90
+ return undefined;
91
+ const payload = argType.slice(CPP_BRACED_INIT_TYPE_PREFIX.length);
92
+ if (payload === '')
93
+ return undefined;
94
+ const separator = payload.lastIndexOf(':');
95
+ if (separator > 0) {
96
+ const countText = payload.slice(separator + 1);
97
+ if (/^\d+$/.test(countText)) {
98
+ return {
99
+ elementType: payload.slice(0, separator),
100
+ elementCount: Number(countText),
101
+ };
102
+ }
103
+ }
104
+ return { elementType: payload };
105
+ }
106
+ function bracedInitConversionRank(paramType, argType, paramTypeClass) {
107
+ const targetBase = bracedInitTargetBase(paramType);
108
+ if (targetBase === 'initializer_list' || targetBase === 'std::initializer_list') {
109
+ return bracedInitValueTypeMatches(paramType, argType, paramTypeClass) ? 0 : Infinity;
110
+ }
111
+ if (BRACED_INIT_CONTAINER_TYPES.has(targetBase)) {
112
+ return bracedInitValueTypeMatches(paramType, argType, paramTypeClass) ? 4 : Infinity;
113
+ }
114
+ return Infinity;
115
+ }
116
+ function bracedInitValueTypeMatches(paramType, argType, paramTypeClass) {
117
+ const valueType = bracedInitTargetValueType(paramType, paramTypeClass);
118
+ if (valueType === undefined)
119
+ return false;
120
+ return isFinite(cppConversionRank(argType.elementType, valueType));
121
+ }
122
+ function bracedInitTargetValueType(paramType, paramTypeClass) {
123
+ return firstTemplateArgument(paramType) ?? paramTypeClass?.templateArguments?.[0];
124
+ }
125
+ function firstTemplateArgument(rawType) {
126
+ const start = rawType.indexOf('<');
127
+ if (start < 0)
128
+ return undefined;
129
+ let depth = 0;
130
+ for (let i = start + 1; i < rawType.length; i++) {
131
+ const ch = rawType[i];
132
+ if (ch === '<') {
133
+ depth++;
134
+ }
135
+ else if (ch === '>') {
136
+ if (depth === 0)
137
+ return bracedInitTargetBase(rawType.slice(start + 1, i));
138
+ depth--;
139
+ }
140
+ else if (ch === ',' && depth === 0) {
141
+ return bracedInitTargetBase(rawType.slice(start + 1, i));
142
+ }
143
+ }
144
+ return undefined;
145
+ }
146
+ function bracedInitTargetBase(paramType) {
147
+ return normalizeCppParamType(paramType);
148
+ }
60
149
  function isPointer(typeClass) {
61
150
  return typeClass?.indirection === 'pointer' && typeClass.pointerDepth > 0;
62
151
  }
@@ -27,7 +27,7 @@
27
27
  * declaration transparently.
28
28
  */
29
29
  import { isOverloadAmbiguousAfterNormalization, narrowOverloadCandidates, } from '../../scope-resolution/passes/overload-narrowing.js';
30
- import { cppConversionRank } from './conversion-rank.js';
30
+ import { CPP_CONVERSION_ONLY_ARG_TYPE_PREFIXES, cppConversionRank } from './conversion-rank.js';
31
31
  const inlineNamespaceRangesByFile = new Map();
32
32
  const inlineNamespaceScopeIds = new Set();
33
33
  function rangeKey(r) {
@@ -142,7 +142,12 @@ export function resolveCppQualifiedNamespaceMember(receiverName, memberName, par
142
142
  // can disambiguate via exact-type match and, when available, conversion-rank
143
143
  // scoring (`cppConversionRank`). Same-signature ambiguity is still detected
144
144
  // by `isOverloadAmbiguousAfterNormalization` below.
145
- const narrowed = narrowOverloadCandidates(allHits, callsite?.arity, callsite?.argumentTypes, callsite !== undefined ? { conversionRankFn: cppConversionRank } : undefined);
145
+ const narrowed = narrowOverloadCandidates(allHits, callsite?.arity, callsite?.argumentTypes, callsite !== undefined
146
+ ? {
147
+ conversionRankFn: cppConversionRank,
148
+ conversionOnlyArgTypePrefixes: CPP_CONVERSION_ONLY_ARG_TYPE_PREFIXES,
149
+ }
150
+ : undefined);
146
151
  if (narrowed.length === 1)
147
152
  return narrowed[0];
148
153
  if (narrowed.length === 0)
@@ -3,7 +3,7 @@ import { buildMro, defaultLinearize } from '../../scope-resolution/passes/mro.js
3
3
  import { isOverloadAmbiguousAfterNormalization, narrowOverloadCandidates, } from '../../scope-resolution/passes/overload-narrowing.js';
4
4
  import { isClassLike } from '../../scope-resolution/scope/walkers.js';
5
5
  import { cppConstraintCompatibility } from './constraint-filter.js';
6
- import { cppConversionRank } from './conversion-rank.js';
6
+ import { CPP_CONVERSION_ONLY_ARG_TYPE_PREFIXES, cppConversionRank } from './conversion-rank.js';
7
7
  const capturedByFile = new Map();
8
8
  let directParentsByDefId = new Map();
9
9
  let virtualEdges = new Set();
@@ -193,6 +193,7 @@ function chooseOverload(candidates, callsite) {
193
193
  const narrowed = narrowOverloadCandidates(candidates, callsite.arity, callsite.argumentTypes, {
194
194
  argumentTypeClasses: callsite.argumentTypeClasses,
195
195
  conversionRankFn: cppConversionRank,
196
+ conversionOnlyArgTypePrefixes: CPP_CONVERSION_ONLY_ARG_TYPE_PREFIXES,
196
197
  constraintCompatibility: cppConstraintCompatibility,
197
198
  });
198
199
  if (narrowed.length === 1)
@@ -3,7 +3,7 @@ import { SupportedLanguages } from '../../../../_shared/index.js';
3
3
  import { populateClassOwnedMembers, tagNamespacePrefixes, } from '../../scope-resolution/scope/walkers.js';
4
4
  import { cppProvider } from '../c-cpp.js';
5
5
  import { cppArityCompatibility } from './arity.js';
6
- import { cppConversionRank } from './conversion-rank.js';
6
+ import { CPP_CONVERSION_ONLY_ARG_TYPE_PREFIXES, cppConversionRank } from './conversion-rank.js';
7
7
  import { cppMergeBindings } from './merge-bindings.js';
8
8
  import { resolveCppImportTarget } from './import-target.js';
9
9
  import { scanCppHeaderFiles } from './header-scan.js';
@@ -205,6 +205,7 @@ export const cppScopeResolver = {
205
205
  // Disambiguates `f(int)` vs `f(double)` called with `f(2.5)` by scoring
206
206
  // each candidate's conversion cost; exact match wins over standard conversion.
207
207
  conversionRankFn: cppConversionRank,
208
+ conversionOnlyArgTypePrefixes: CPP_CONVERSION_ONLY_ARG_TYPE_PREFIXES,
208
209
  // Range-for element type inference: for (auto& user : users) → bind user to User
209
210
  populateRangeBindings: populateCppRangeBindings,
210
211
  // C++ method return-type bindings need to be visible from module scope
@@ -477,12 +477,19 @@ function parseJsonParameterTypeClassesCapture(cap) {
477
477
  if (typeof o.pointerDepth !== 'number' || !Number.isFinite(o.pointerDepth)) {
478
478
  return undefined;
479
479
  }
480
- out.push({
480
+ const shape = {
481
481
  base: o.base,
482
482
  cv: o.cv,
483
483
  indirection: o.indirection,
484
484
  pointerDepth: o.pointerDepth,
485
- });
485
+ };
486
+ if (Array.isArray(o.templateArguments)) {
487
+ if (!o.templateArguments.every((x) => typeof x === 'string')) {
488
+ return undefined;
489
+ }
490
+ shape.templateArguments = [...o.templateArguments];
491
+ }
492
+ out.push(shape);
486
493
  }
487
494
  return out;
488
495
  }
@@ -618,6 +618,15 @@ export interface ScopeResolver {
618
618
  * `cppConversionRank`; other languages define their own if needed.
619
619
  */
620
620
  readonly conversionRankFn?: ConversionRankFn;
621
+ /**
622
+ * Optional per-language argument-type prefixes for conversion-only
623
+ * argument sentinels. When ranking cannot find any viable candidate
624
+ * for a multi-overload set containing one of these sentinels, shared
625
+ * narrowing suppresses the ambiguous set instead of falling back to
626
+ * arity-only candidates. Languages without such sentinels leave this
627
+ * undefined.
628
+ */
629
+ readonly conversionOnlyArgTypePrefixes?: readonly string[];
621
630
  /**
622
631
  * Optional predicate to identify definitions with file-local linkage
623
632
  * (e.g. C `static` functions). When provided, `pickUniqueGlobalCallable`
@@ -49,6 +49,7 @@ export declare function emitFreeCallFallback(graph: KnowledgeGraph, scopes: Scop
49
49
  };
50
50
  }, callerParsed: ParsedFile, scopes: ScopeResolutionIndexes, parsedFiles: readonly ParsedFile[]) => readonly SymbolDefinition[] | undefined;
51
51
  readonly conversionRankFn?: ConversionRankFn;
52
+ readonly conversionOnlyArgTypePrefixes?: readonly string[];
52
53
  /** Optional per-language constraint hook threaded into
53
54
  * `narrowOverloadCandidates`. Drops candidates whose template
54
55
  * constraints (e.g. C++ `enable_if_t`, C++20 `requires`) provably
@@ -99,7 +100,7 @@ export declare function buildGlobalClassIndex(scopes: ScopeResolutionIndexes): R
99
100
  * order. Exported for unit testing — the `scopeDefsCache` equivalence is
100
101
  * exercised via synthetic stubs in `pick-unique-global-callable.test.ts`.
101
102
  */
102
- export declare function pickUniqueGlobalCallable(name: string, model: SemanticModel, globalCallablesBySimpleName: ReadonlyMap<string, readonly SymbolDefinition[]>, callerFilePath: string, isFileLocalDef?: (def: SymbolDefinition) => boolean, callArity?: number, isCallerVisible?: (candidate: SymbolDefinition) => boolean, callArgTypes?: readonly string[], callArgTypeClasses?: readonly ParameterTypeClass[], conversionRankFn?: ConversionRankFn, scopeDefsCache?: Map<string, readonly SymbolDefinition[]>): SymbolDefinition | undefined;
103
+ export declare function pickUniqueGlobalCallable(name: string, model: SemanticModel, globalCallablesBySimpleName: ReadonlyMap<string, readonly SymbolDefinition[]>, callerFilePath: string, isFileLocalDef?: (def: SymbolDefinition) => boolean, callArity?: number, isCallerVisible?: (candidate: SymbolDefinition) => boolean, callArgTypes?: readonly string[], callArgTypeClasses?: readonly ParameterTypeClass[], conversionRankFn?: ConversionRankFn, scopeDefsCache?: Map<string, readonly SymbolDefinition[]>, conversionOnlyArgTypePrefixes?: readonly string[]): SymbolDefinition | undefined;
103
104
  /** Find a unique workspace-wide class-like def by simple name, for a
104
105
  * constructor-form call `Type(...)` whose type lives outside the call
105
106
  * site's lexical bindings (a sibling/imported file). Returns the def
@@ -142,5 +143,6 @@ export declare function pickImplicitThisOverload(site: {
142
143
  readonly argumentTypeClasses?: readonly import('../../../../_shared/index.js').ParameterTypeClass[];
143
144
  }, scopes: ScopeResolutionIndexes, workspaceIndex: WorkspaceResolutionIndex, model: SemanticModel, hookCtx?: {
144
145
  readonly conversionRankFn?: ConversionRankFn;
146
+ readonly conversionOnlyArgTypePrefixes?: readonly string[];
145
147
  readonly constraintCompatibility?: ScopeResolver['constraintCompatibility'];
146
148
  }): SymbolDefinition | undefined;
@@ -89,6 +89,7 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
89
89
  if (fnDef === undefined) {
90
90
  fnDef = pickImplicitThisOverload(site, scopes, workspaceIndex, model, {
91
91
  conversionRankFn: options.conversionRankFn,
92
+ conversionOnlyArgTypePrefixes: options.conversionOnlyArgTypePrefixes,
92
93
  constraintCompatibility: options.constraintCompatibility,
93
94
  });
94
95
  fnDefFromImplicitThis = fnDef !== undefined;
@@ -112,6 +113,7 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
112
113
  const narrowed = narrowOverloadCandidates(allCallables, site.arity, site.argumentTypes, {
113
114
  argumentTypeClasses: site.argumentTypeClasses,
114
115
  conversionRankFn: options.conversionRankFn,
116
+ conversionOnlyArgTypePrefixes: options.conversionOnlyArgTypePrefixes,
115
117
  constraintCompatibility: options.constraintCompatibility,
116
118
  });
117
119
  if (narrowed.length === 1) {
@@ -190,6 +192,7 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
190
192
  const narrowed = narrowOverloadCandidates(ordinary, site.arity, site.argumentTypes, {
191
193
  argumentTypeClasses: site.argumentTypeClasses,
192
194
  conversionRankFn: options.conversionRankFn,
195
+ conversionOnlyArgTypePrefixes: options.conversionOnlyArgTypePrefixes,
193
196
  constraintCompatibility: options.constraintCompatibility,
194
197
  });
195
198
  if (narrowed.length === 1) {
@@ -240,6 +243,7 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
240
243
  const narrowed = narrowOverloadCandidates(merged, site.arity, site.argumentTypes, {
241
244
  argumentTypeClasses: site.argumentTypeClasses,
242
245
  conversionRankFn: options.conversionRankFn,
246
+ conversionOnlyArgTypePrefixes: options.conversionOnlyArgTypePrefixes,
243
247
  constraintCompatibility: options.constraintCompatibility,
244
248
  });
245
249
  if (narrowed.length === 1) {
@@ -285,7 +289,7 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
285
289
  callerScope: site.inScope,
286
290
  scopes,
287
291
  })
288
- : undefined, site.argumentTypes, site.argumentTypeClasses, options.conversionRankFn, scopeDefsCache);
292
+ : undefined, site.argumentTypes, site.argumentTypeClasses, options.conversionRankFn, scopeDefsCache, options.conversionOnlyArgTypePrefixes);
289
293
  }
290
294
  if (fnDef === undefined)
291
295
  continue;
@@ -442,7 +446,7 @@ export function buildGlobalClassIndex(scopes) {
442
446
  * order. Exported for unit testing — the `scopeDefsCache` equivalence is
443
447
  * exercised via synthetic stubs in `pick-unique-global-callable.test.ts`.
444
448
  */
445
- export function pickUniqueGlobalCallable(name, model, globalCallablesBySimpleName, callerFilePath, isFileLocalDef, callArity, isCallerVisible, callArgTypes, callArgTypeClasses, conversionRankFn, scopeDefsCache) {
449
+ export function pickUniqueGlobalCallable(name, model, globalCallablesBySimpleName, callerFilePath, isFileLocalDef, callArity, isCallerVisible, callArgTypes, callArgTypeClasses, conversionRankFn, scopeDefsCache, conversionOnlyArgTypePrefixes) {
446
450
  // The scope-index candidate list is a pure function of (name, callerFilePath):
447
451
  // the same-name bucket is fixed for the pass, the file-local filter depends
448
452
  // only on the candidate + callerFilePath, and the logical-key dedup is
@@ -504,6 +508,7 @@ export function pickUniqueGlobalCallable(name, model, globalCallablesBySimpleNam
504
508
  const narrowed = narrowOverloadCandidates(scopeDefs, callArity, callArgTypes, {
505
509
  argumentTypeClasses: callArgTypeClasses,
506
510
  conversionRankFn,
511
+ conversionOnlyArgTypePrefixes,
507
512
  });
508
513
  if (narrowed.length === 1)
509
514
  return narrowed[0];
@@ -545,6 +550,7 @@ export function pickUniqueGlobalCallable(name, model, globalCallablesBySimpleNam
545
550
  const narrowed = narrowOverloadCandidates(defs, callArity, callArgTypes, {
546
551
  argumentTypeClasses: callArgTypeClasses,
547
552
  conversionRankFn,
553
+ conversionOnlyArgTypePrefixes,
548
554
  });
549
555
  if (narrowed.length === 1)
550
556
  return narrowed[0];
@@ -687,6 +693,7 @@ export function pickImplicitThisOverload(site, scopes, workspaceIndex, model, ho
687
693
  const candidates = narrowOverloadCandidates(overloads, site.arity, site.argumentTypes, {
688
694
  argumentTypeClasses: site.argumentTypeClasses,
689
695
  conversionRankFn: hookCtx?.conversionRankFn,
696
+ conversionOnlyArgTypePrefixes: hookCtx?.conversionOnlyArgTypePrefixes,
690
697
  constraintCompatibility: hookCtx?.constraintCompatibility,
691
698
  });
692
699
  if (candidates.length !== 1)
@@ -69,6 +69,10 @@ export interface OverloadNarrowingHookCtx {
69
69
  /** Conversion-rank scoring fallback (step 4b). Engages when the
70
70
  * exact-type filter rejects every candidate. */
71
71
  readonly conversionRankFn?: ConversionRankFn;
72
+ /** Per-language argument-type prefixes whose conversion-rank failures
73
+ * should suppress genuinely ambiguous multi-overload sets instead of
74
+ * falling back to arity-only candidates. */
75
+ readonly conversionOnlyArgTypePrefixes?: readonly string[];
72
76
  /** Constraint filter (step 4c). Drops candidates whose template
73
77
  * guards (SFINAE `enable_if_t`, C++20 `requires`, future Rust
74
78
  * trait bounds, etc.) provably fail at the call site. Three-valued
@@ -106,6 +106,10 @@ export function narrowOverloadCandidates(overloads, argCount, argTypes, hookCtx)
106
106
  const ranked = rankByConversion(candidates, argTypes, hookCtx.conversionRankFn, hookCtx.argumentTypeClasses);
107
107
  if (ranked.length > 0)
108
108
  result = ranked;
109
+ else if (candidates.length > 1 &&
110
+ hasConversionOnlyArgType(argTypes, hookCtx.conversionOnlyArgTypePrefixes)) {
111
+ result = [];
112
+ }
109
113
  }
110
114
  }
111
115
  // Constraint filter (step 4c; Tier-A — SFINAE / `requires` clauses).
@@ -145,6 +149,11 @@ export function narrowOverloadCandidates(overloads, argCount, argTypes, hookCtx)
145
149
  }
146
150
  return result;
147
151
  }
152
+ function hasConversionOnlyArgType(argTypes, prefixes) {
153
+ if (prefixes === undefined || prefixes.length === 0)
154
+ return false;
155
+ return argTypes.some((type) => prefixes.some((prefix) => type.startsWith(prefix)));
156
+ }
148
157
  function exactTypeSlotMatches(argType, paramType, argTypeClass, paramTypeClass) {
149
158
  if (argType !== paramType)
150
159
  return false;
@@ -47,7 +47,7 @@ import type { ResolutionOutcomeRecorder } from '../resolution-outcome.js';
47
47
  /** Subset of `ScopeResolver` consumed by this pass. Accepting the
48
48
  * subset rather than the full provider keeps tests and partial
49
49
  * refactors lighter — callers only need to populate what we read. */
50
- type ReceiverBoundProviderSubset = Pick<ScopeResolver, 'isSuperReceiver' | 'isSuperReceiverInContext' | 'fieldFallbackOnMethodLookup' | 'collapseMemberCallsByCallerTarget' | 'unwrapCollectionAccessor' | 'hoistTypeBindingsToModule' | 'resolveQualifiedReceiverMember' | 'resolveReceiverMember' | 'resolveThisViaEnclosingClass' | 'conversionRankFn' | 'constraintCompatibility' | 'isStaticOnly'>;
50
+ type ReceiverBoundProviderSubset = Pick<ScopeResolver, 'isSuperReceiver' | 'isSuperReceiverInContext' | 'fieldFallbackOnMethodLookup' | 'collapseMemberCallsByCallerTarget' | 'unwrapCollectionAccessor' | 'hoistTypeBindingsToModule' | 'resolveQualifiedReceiverMember' | 'resolveReceiverMember' | 'resolveThisViaEnclosingClass' | 'conversionRankFn' | 'conversionOnlyArgTypePrefixes' | 'constraintCompatibility' | 'isStaticOnly'>;
51
51
  export declare function emitReceiverBoundCalls(graph: KnowledgeGraph, scopes: ScopeResolutionIndexes, parsedFiles: readonly ParsedFile[], nodeLookup: GraphNodeLookup, handledSites: Set<string>, provider: ReceiverBoundProviderSubset, index: WorkspaceResolutionIndex, model: SemanticModel, options?: {
52
52
  readonly recordResolutionOutcome?: ResolutionOutcomeRecorder;
53
53
  }): number;
@@ -352,6 +352,7 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
352
352
  const narrowed = narrowOverloadCandidates(methodOverloads, site.arity, site.argumentTypes, {
353
353
  argumentTypeClasses: site.argumentTypeClasses,
354
354
  conversionRankFn: provider.conversionRankFn,
355
+ conversionOnlyArgTypePrefixes: provider.conversionOnlyArgTypePrefixes,
355
356
  constraintCompatibility: provider.constraintCompatibility,
356
357
  });
357
358
  if (isOverloadAmbiguousAfterNormalization(narrowed, site.arity)) {
@@ -867,6 +868,7 @@ function pickOverload(ownerId, memberName, site, model, provider) {
867
868
  const candidates = narrowOverloadCandidates(overloads, site.arity, site.argumentTypes, {
868
869
  argumentTypeClasses: site.argumentTypeClasses,
869
870
  conversionRankFn: provider.conversionRankFn,
871
+ conversionOnlyArgTypePrefixes: provider.conversionOnlyArgTypePrefixes,
870
872
  constraintCompatibility: provider.constraintCompatibility,
871
873
  });
872
874
  // When narrowing leaves >1 candidate that share identical normalized
@@ -967,6 +969,7 @@ function pickFirstNonStaticOnly(ownerId, memberName, site, model, provider) {
967
969
  const candidates = narrowOverloadCandidates(overloads, site.arity, site.argumentTypes, {
968
970
  argumentTypeClasses: site.argumentTypeClasses,
969
971
  conversionRankFn: provider.conversionRankFn,
972
+ conversionOnlyArgTypePrefixes: provider.conversionOnlyArgTypePrefixes,
970
973
  constraintCompatibility: provider.constraintCompatibility,
971
974
  });
972
975
  // Same ambiguity handling as `pickOverload`: when normalization
@@ -1001,6 +1004,7 @@ function recordReceiverOverloadSuppression(record, filePath, site, ownerId, memb
1001
1004
  const candidates = narrowOverloadCandidates(overloads, site.arity, site.argumentTypes, {
1002
1005
  argumentTypeClasses: site.argumentTypeClasses,
1003
1006
  conversionRankFn: provider.conversionRankFn,
1007
+ conversionOnlyArgTypePrefixes: provider.conversionOnlyArgTypePrefixes,
1004
1008
  constraintCompatibility: provider.constraintCompatibility,
1005
1009
  });
1006
1010
  const reason = isOverloadAmbiguousAfterNormalization(candidates, site.arity)
@@ -446,6 +446,7 @@ export function runScopeResolution(input, provider) {
446
446
  isCallableVisibleFromCaller: provider.isCallableVisibleFromCaller,
447
447
  resolveAdlCandidates: provider.resolveAdlCandidates,
448
448
  conversionRankFn: provider.conversionRankFn,
449
+ conversionOnlyArgTypePrefixes: provider.conversionOnlyArgTypePrefixes,
449
450
  constraintCompatibility: provider.constraintCompatibility,
450
451
  recordResolutionOutcome,
451
452
  });
@@ -1,4 +1,5 @@
1
1
  import { extractSimpleTypeName, extractVarName, resolveIterableElementType, methodToTypeArgPosition, } from './shared.js';
2
+ import { CPP_BRACED_INIT_TYPE_PREFIX } from '../languages/cpp/conversion-rank.js';
2
3
  const DECLARATION_NODE_TYPES = new Set(['declaration']);
3
4
  /** Smart pointer factory function names that create a typed object. */
4
5
  const SMART_PTR_FACTORIES = new Set(['make_shared', 'make_unique', 'make_shared_for_overwrite']);
@@ -447,6 +448,8 @@ const extractForLoopBinding = (node, { scopeEnv, declarationTypeNodes, scope })
447
448
  /** Infer the type of a literal AST node for C++ overload disambiguation. */
448
449
  const inferLiteralType = (node) => {
449
450
  switch (node.type) {
451
+ case 'initializer_list':
452
+ return inferBracedInitLiteralType(node);
450
453
  case 'number_literal': {
451
454
  const t = node.text;
452
455
  // Float suffixes
@@ -475,6 +478,24 @@ const inferLiteralType = (node) => {
475
478
  return undefined;
476
479
  }
477
480
  };
481
+ function inferBracedInitLiteralType(node) {
482
+ const elementTypes = [];
483
+ for (const child of node.children) {
484
+ if (child.type === ',' || child.type === '{' || child.type === '}')
485
+ continue;
486
+ const elementType = inferLiteralType(child);
487
+ if (elementType === undefined || elementType.startsWith(CPP_BRACED_INIT_TYPE_PREFIX)) {
488
+ return `${CPP_BRACED_INIT_TYPE_PREFIX}unknown:${elementTypes.length + 1}`;
489
+ }
490
+ elementTypes.push(elementType);
491
+ }
492
+ if (elementTypes.length === 0)
493
+ return `${CPP_BRACED_INIT_TYPE_PREFIX}unknown:0`;
494
+ const first = elementTypes[0];
495
+ return elementTypes.every((type) => type === first)
496
+ ? `${CPP_BRACED_INIT_TYPE_PREFIX}${first}:${elementTypes.length}`
497
+ : `${CPP_BRACED_INIT_TYPE_PREFIX}unknown:${elementTypes.length}`;
498
+ }
478
499
  /** C++: detect constructor type from smart pointer factory calls (make_shared<Dog>()).
479
500
  * Extracts the template type argument as the constructor type for virtual dispatch. */
480
501
  const detectCppConstructorType = (node, classNames) => {
@@ -12,7 +12,7 @@
12
12
  import fs from 'fs/promises';
13
13
  import path from 'path';
14
14
  import { execSync, execFileSync } from 'child_process';
15
- import { initWikiDb, closeWikiDb, touchWikiDb, getFilesWithExports, getAllFiles, getIntraModuleCallEdges, getInterModuleCallEdges, getProcessesForFiles, getAllProcesses, getInterModuleEdgesForOverview, } from './graph-queries.js';
15
+ import { initWikiDb, closeWikiDb, touchWikiDb, pinWikiDb, getFilesWithExports, getAllFiles, getIntraModuleCallEdges, getInterModuleCallEdges, getProcessesForFiles, getAllProcesses, getInterModuleEdgesForOverview, } from './graph-queries.js';
16
16
  import { generateHTMLViewer } from './html-viewer.js';
17
17
  import { sanitizeMermaidMarkdown } from './mermaid-sanitizer.js';
18
18
  import { callLLM, estimateTokens, } from './llm-client.js';
@@ -183,6 +183,7 @@ export class WikiGenerator {
183
183
  }
184
184
  // Init graph
185
185
  this.onProgress('init', 2, 'Connecting to knowledge graph...');
186
+ const releaseWikiDbPin = pinWikiDb();
186
187
  await initWikiDb(this.lbugPath);
187
188
  let result;
188
189
  try {
@@ -201,6 +202,7 @@ export class WikiGenerator {
201
202
  }
202
203
  }
203
204
  finally {
205
+ releaseWikiDbPin();
204
206
  await closeWikiDb();
205
207
  }
206
208
  // Always generate the HTML viewer after wiki content changes
@@ -8,6 +8,12 @@
8
8
  * Touch the wiki DB connection to prevent idle timeout during long LLM calls.
9
9
  */
10
10
  export declare function touchWikiDb(): void;
11
+ /**
12
+ * Keep the wiki DB resident for a full generation run. Wiki generation can spend
13
+ * minutes inside LLM calls, and the pooled DB must survive both idle cleanup and
14
+ * unrelated LRU pressure until the run reaches its final graph queries.
15
+ */
16
+ export declare function pinWikiDb(): () => void;
11
17
  export interface FileWithExports {
12
18
  filePath: string;
13
19
  symbols: Array<{
@@ -4,7 +4,7 @@
4
4
  * Encapsulated Cypher queries against the GitNexus knowledge graph.
5
5
  * Uses the MCP-style pooled lbug-adapter for connection management.
6
6
  */
7
- import { initLbug, executeQuery, closeLbug, touchRepo } from '../lbug/pool-adapter.js';
7
+ import { initLbug, executeQuery, closeLbug, touchRepo, pinRepo } from '../lbug/pool-adapter.js';
8
8
  const REPO_ID = '__wiki__';
9
9
  /**
10
10
  * Touch the wiki DB connection to prevent idle timeout during long LLM calls.
@@ -12,6 +12,14 @@ const REPO_ID = '__wiki__';
12
12
  export function touchWikiDb() {
13
13
  touchRepo(REPO_ID);
14
14
  }
15
+ /**
16
+ * Keep the wiki DB resident for a full generation run. Wiki generation can spend
17
+ * minutes inside LLM calls, and the pooled DB must survive both idle cleanup and
18
+ * unrelated LRU pressure until the run reaches its final graph queries.
19
+ */
20
+ export function pinWikiDb() {
21
+ return pinRepo(REPO_ID);
22
+ }
15
23
  /**
16
24
  * Initialize the LadybugDB connection for wiki generation.
17
25
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.8-rc.47",
3
+ "version": "1.6.8-rc.49",
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",