gitnexus 1.6.5 → 1.6.6-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_shared/index.d.ts +2 -2
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/index.js.map +1 -1
- package/dist/_shared/scope-resolution/registries/context.d.ts +37 -0
- package/dist/_shared/scope-resolution/registries/context.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/registries/context.js.map +1 -1
- package/dist/_shared/scope-resolution/registries/lookup-core.d.ts +4 -2
- package/dist/_shared/scope-resolution/registries/lookup-core.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/registries/lookup-core.js +8 -23
- package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -1
- package/dist/_shared/scope-resolution/symbol-definition.d.ts +20 -0
- package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
- package/dist/cli/analyze.js +65 -3
- package/dist/cli/eval-server.d.ts +14 -3
- package/dist/cli/eval-server.js +79 -9
- package/dist/cli/index.js +3 -1
- package/dist/cli/serve.js +6 -1
- package/dist/cli/wiki.d.ts +1 -0
- package/dist/cli/wiki.js +32 -8
- package/dist/core/ingestion/language-provider.d.ts +29 -0
- package/dist/core/ingestion/languages/c-cpp.js +46 -0
- package/dist/core/ingestion/languages/cpp/arity-metadata.d.ts +17 -0
- package/dist/core/ingestion/languages/cpp/arity-metadata.js +51 -2
- package/dist/core/ingestion/languages/cpp/arity.d.ts +4 -1
- package/dist/core/ingestion/languages/cpp/arity.js +4 -1
- package/dist/core/ingestion/languages/cpp/captures.js +73 -0
- package/dist/core/ingestion/languages/cpp/constraint-extractor.d.ts +73 -0
- package/dist/core/ingestion/languages/cpp/constraint-extractor.js +308 -0
- package/dist/core/ingestion/languages/cpp/constraint-filter.d.ts +31 -0
- package/dist/core/ingestion/languages/cpp/constraint-filter.js +135 -0
- package/dist/core/ingestion/languages/cpp/scope-resolver.js +6 -0
- package/dist/core/ingestion/languages/cpp/type-classifier.d.ts +26 -0
- package/dist/core/ingestion/languages/cpp/type-classifier.js +49 -0
- package/dist/core/ingestion/model/field-registry.d.ts +17 -3
- package/dist/core/ingestion/model/field-registry.js +19 -4
- package/dist/core/ingestion/model/owned-members-lookup.d.ts +19 -0
- package/dist/core/ingestion/model/owned-members-lookup.js +43 -0
- package/dist/core/ingestion/model/symbol-table.d.ts +2 -1
- package/dist/core/ingestion/model/symbol-table.js +3 -0
- package/dist/core/ingestion/model/type-registry.d.ts +9 -0
- package/dist/core/ingestion/model/type-registry.js +18 -0
- package/dist/core/ingestion/parsing-processor.js +35 -2
- package/dist/core/ingestion/resolve-references.d.ts +3 -1
- package/dist/core/ingestion/resolve-references.js +5 -1
- package/dist/core/ingestion/scope-extractor.js +63 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +21 -1
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.d.ts +1 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +14 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +12 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +11 -1
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +83 -28
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +30 -7
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +49 -18
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +1 -1
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +10 -4
- package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.d.ts +4 -2
- package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +48 -9
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +3 -0
- package/dist/core/ingestion/utils/template-arguments.d.ts +19 -0
- package/dist/core/ingestion/utils/template-arguments.js +30 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +2 -1
- package/dist/core/ingestion/workers/parse-worker.js +1 -0
- package/dist/core/lbug/lbug-adapter.d.ts +3 -1
- package/dist/core/lbug/lbug-adapter.js +33 -19
- package/dist/core/lbug/lbug-config.d.ts +1 -1
- package/dist/core/lbug/lbug-config.js +1 -1
- package/dist/core/lbug/pool-adapter.d.ts +0 -7
- package/dist/core/lbug/pool-adapter.js +10 -35
- package/dist/core/lbug/query-params.d.ts +1 -0
- package/dist/core/lbug/query-params.js +21 -0
- package/dist/core/search/bm25-index.js +4 -6
- package/dist/core/wiki/generator.d.ts +13 -0
- package/dist/core/wiki/generator.js +45 -4
- package/dist/core/wiki/llm-client.d.ts +1 -1
- package/dist/core/wiki/llm-client.js +23 -6
- package/dist/mcp/local/local-backend.d.ts +18 -3
- package/dist/mcp/local/local-backend.js +105 -11
- package/dist/mcp/tools.js +10 -0
- package/dist/server/api.d.ts +3 -0
- package/dist/server/api.js +36 -24
- package/package.json +1 -1
|
@@ -22,6 +22,11 @@ import { isOverloadAmbiguousAfterNormalization, narrowOverloadCandidates, } from
|
|
|
22
22
|
export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _referenceIndex, handledSites, model, workspaceIndex, options = {}) {
|
|
23
23
|
let emitted = 0;
|
|
24
24
|
const seen = new Set();
|
|
25
|
+
// Build an O(1) simple-name -> callable defs index over scopes.defs once
|
|
26
|
+
// per pass so pickUniqueGlobalCallable doesn't re-scan defs.byId.values()
|
|
27
|
+
// per call site. Same name + callable-kind filter that the previous scan
|
|
28
|
+
// applied (see pickUniqueGlobalCallable JSDoc). Cost: O(|defs|) once.
|
|
29
|
+
const globalCallablesBySimpleName = buildGlobalCallableIndex(scopes);
|
|
25
30
|
for (const parsed of parsedFiles) {
|
|
26
31
|
for (const site of parsed.referenceSites) {
|
|
27
32
|
if (site.kind !== 'call')
|
|
@@ -45,7 +50,10 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
|
|
|
45
50
|
// the same name in a single class, choose the best match by
|
|
46
51
|
// arity + argument types.
|
|
47
52
|
if (fnDef === undefined) {
|
|
48
|
-
fnDef = pickImplicitThisOverload(site, scopes, workspaceIndex, model,
|
|
53
|
+
fnDef = pickImplicitThisOverload(site, scopes, workspaceIndex, model, {
|
|
54
|
+
conversionRankFn: options.conversionRankFn,
|
|
55
|
+
constraintCompatibility: options.constraintCompatibility,
|
|
56
|
+
});
|
|
49
57
|
}
|
|
50
58
|
// Scope-chain callable lookup. First-match preserves scope-chain
|
|
51
59
|
// precedence (local shadows import). When a conversion-rank function
|
|
@@ -63,7 +71,10 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
|
|
|
63
71
|
if (fnDef !== undefined && options.conversionRankFn !== undefined) {
|
|
64
72
|
const allCallables = findAllCallableBindingsInScope(site.inScope, site.name, scopes);
|
|
65
73
|
if (allCallables.length > 1) {
|
|
66
|
-
const narrowed = narrowOverloadCandidates(allCallables, site.arity, site.argumentTypes,
|
|
74
|
+
const narrowed = narrowOverloadCandidates(allCallables, site.arity, site.argumentTypes, {
|
|
75
|
+
conversionRankFn: options.conversionRankFn,
|
|
76
|
+
constraintCompatibility: options.constraintCompatibility,
|
|
77
|
+
});
|
|
67
78
|
if (narrowed.length === 1) {
|
|
68
79
|
fnDef = narrowed[0];
|
|
69
80
|
}
|
|
@@ -97,36 +108,49 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
|
|
|
97
108
|
argumentTypes: site.argumentTypes,
|
|
98
109
|
atRange: { startLine: site.atRange.startLine, startCol: site.atRange.startCol },
|
|
99
110
|
}, parsed, scopes, parsedFiles);
|
|
100
|
-
|
|
101
|
-
// with conversion-rank scoring when multiple overloads exist.
|
|
102
|
-
// Single candidate or empty falls through to first-match.
|
|
111
|
+
const siteKey = `${parsed.filePath}:${site.atRange.startLine}:${site.atRange.startCol}`;
|
|
103
112
|
if (adl === undefined || adl.length === 0) {
|
|
104
|
-
|
|
113
|
+
// No ADL contribution. Default behavior: `ordinary[0]` —
|
|
114
|
+
// scope-chain walk preserves local-shadows-import precedence.
|
|
115
|
+
//
|
|
116
|
+
// Narrowing kicks in when either disambiguation signal is
|
|
117
|
+
// present: any candidate carries `templateConstraints`
|
|
118
|
+
// (SFINAE / `requires`-clause guarded templates, #1579), OR
|
|
119
|
+
// a conversion-rank function is provided (#1606 / #1578).
|
|
120
|
+
// Both hooks are threaded into `narrowOverloadCandidates`
|
|
121
|
+
// via the unified `OverloadNarrowingHookCtx`.
|
|
122
|
+
const hasConstraints = ordinary.some((d) => d.templateConstraints !== undefined);
|
|
123
|
+
const canNarrow = hasConstraints || options.conversionRankFn !== undefined;
|
|
124
|
+
if (ordinary.length <= 1 || !canNarrow) {
|
|
105
125
|
fnDef = ordinary[0];
|
|
106
126
|
}
|
|
107
127
|
else {
|
|
108
|
-
const
|
|
109
|
-
|
|
128
|
+
const narrowed = narrowOverloadCandidates(ordinary, site.arity, site.argumentTypes, {
|
|
129
|
+
conversionRankFn: options.conversionRankFn,
|
|
130
|
+
constraintCompatibility: options.constraintCompatibility,
|
|
131
|
+
});
|
|
110
132
|
if (narrowed.length === 1) {
|
|
111
133
|
fnDef = narrowed[0];
|
|
112
134
|
}
|
|
113
|
-
else if (narrowed.length
|
|
114
|
-
|
|
115
|
-
|
|
135
|
+
else if (narrowed.length === 0) {
|
|
136
|
+
handledSites.add(siteKey);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// >1 survivors: same-file → suppress (true overloads,
|
|
141
|
+
// "degrade not lie" — no edge beats a wrong one, and
|
|
142
|
+
// SFINAE-ambiguous calls land here). Cross-file →
|
|
143
|
+
// first-match (shadowing semantics).
|
|
116
144
|
const sameFile = narrowed.every((d) => d.filePath === narrowed[0].filePath);
|
|
117
145
|
if (sameFile) {
|
|
118
146
|
handledSites.add(siteKey);
|
|
119
147
|
continue;
|
|
120
148
|
}
|
|
121
|
-
fnDef = ordinary[0];
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
fnDef = ordinary[0]; // narrowed empty → first-match
|
|
149
|
+
fnDef = ordinary[0];
|
|
125
150
|
}
|
|
126
151
|
}
|
|
127
152
|
}
|
|
128
153
|
else {
|
|
129
|
-
const siteKey = `${parsed.filePath}:${site.atRange.startLine}:${site.atRange.startCol}`;
|
|
130
154
|
const merged = [];
|
|
131
155
|
const seenMerge = new Set();
|
|
132
156
|
const push = (defs) => {
|
|
@@ -139,7 +163,10 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
|
|
|
139
163
|
};
|
|
140
164
|
push(ordinary);
|
|
141
165
|
push(adl);
|
|
142
|
-
const narrowed = narrowOverloadCandidates(merged, site.arity, site.argumentTypes,
|
|
166
|
+
const narrowed = narrowOverloadCandidates(merged, site.arity, site.argumentTypes, {
|
|
167
|
+
conversionRankFn: options.conversionRankFn,
|
|
168
|
+
constraintCompatibility: options.constraintCompatibility,
|
|
169
|
+
});
|
|
143
170
|
if (narrowed.length === 1) {
|
|
144
171
|
fnDef = narrowed[0];
|
|
145
172
|
}
|
|
@@ -165,7 +192,7 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
|
|
|
165
192
|
// the caller does not import the target package. Same-package calls are
|
|
166
193
|
// usually caught by nearest-scope lookup before reaching here.
|
|
167
194
|
if (fnDef === undefined && options.allowGlobalFallback === true) {
|
|
168
|
-
fnDef = pickUniqueGlobalCallable(site.name, model,
|
|
195
|
+
fnDef = pickUniqueGlobalCallable(site.name, model, globalCallablesBySimpleName, parsed.filePath, options.isFileLocalDef, site.arity, options.isCallableVisibleFromCaller !== undefined
|
|
169
196
|
? (candidate) => options.isCallableVisibleFromCaller({
|
|
170
197
|
callerParsed: parsed,
|
|
171
198
|
candidate,
|
|
@@ -205,15 +232,36 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
|
|
|
205
232
|
}
|
|
206
233
|
return emitted;
|
|
207
234
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
235
|
+
/**
|
|
236
|
+
* Build a `simpleName -> callable defs` index from `scopes.defs` once per
|
|
237
|
+
* pass. Mirrors the filter the old per-site scan applied: Function /
|
|
238
|
+
* Method / Constructor, keyed by the last `.`-segment of `qualifiedName`
|
|
239
|
+
* (falling back to the qualifiedName itself when undotted). Used by
|
|
240
|
+
* `pickUniqueGlobalCallable` so every free-call fallback site is O(1)
|
|
241
|
+
* instead of O(|defs|).
|
|
242
|
+
*/
|
|
243
|
+
function buildGlobalCallableIndex(scopes) {
|
|
244
|
+
const out = new Map();
|
|
211
245
|
for (const def of scopes.defs.byId.values()) {
|
|
212
|
-
const simple = def.qualifiedName?.split('.').pop() ?? def.qualifiedName;
|
|
213
|
-
if (simple !== name)
|
|
214
|
-
continue;
|
|
215
246
|
if (def.type !== 'Function' && def.type !== 'Method' && def.type !== 'Constructor')
|
|
216
247
|
continue;
|
|
248
|
+
const qualified = def.qualifiedName;
|
|
249
|
+
if (qualified === undefined || qualified.length === 0)
|
|
250
|
+
continue;
|
|
251
|
+
const dot = qualified.lastIndexOf('.');
|
|
252
|
+
const simple = dot === -1 ? qualified : qualified.slice(dot + 1);
|
|
253
|
+
const bucket = out.get(simple);
|
|
254
|
+
if (bucket)
|
|
255
|
+
bucket.push(def);
|
|
256
|
+
else
|
|
257
|
+
out.set(simple, [def]);
|
|
258
|
+
}
|
|
259
|
+
return out;
|
|
260
|
+
}
|
|
261
|
+
function pickUniqueGlobalCallable(name, model, globalCallablesBySimpleName, callerFilePath, isFileLocalDef, callArity, isCallerVisible, callArgTypes, conversionRankFn) {
|
|
262
|
+
const scopeDefs = [];
|
|
263
|
+
const scopeSeen = new Set();
|
|
264
|
+
for (const def of globalCallablesBySimpleName.get(name) ?? []) {
|
|
217
265
|
// Skip file-local defs (e.g. C `static` functions) that live in a
|
|
218
266
|
// different file from the caller — they are logically invisible.
|
|
219
267
|
if (isFileLocalDef !== undefined && def.filePath !== callerFilePath && isFileLocalDef(def)) {
|
|
@@ -248,7 +296,9 @@ function pickUniqueGlobalCallable(name, model, scopes, callerFilePath, isFileLoc
|
|
|
248
296
|
// best-rank candidate when exact-type or conversion-rank scoring can
|
|
249
297
|
// disambiguate (e.g., `f(int)` vs `f(double)` called with `f(2.5)`).
|
|
250
298
|
if (scopeDefs.length > 1) {
|
|
251
|
-
const narrowed = narrowOverloadCandidates(scopeDefs, callArity, callArgTypes,
|
|
299
|
+
const narrowed = narrowOverloadCandidates(scopeDefs, callArity, callArgTypes, {
|
|
300
|
+
conversionRankFn,
|
|
301
|
+
});
|
|
252
302
|
if (narrowed.length === 1)
|
|
253
303
|
return narrowed[0];
|
|
254
304
|
}
|
|
@@ -286,7 +336,9 @@ function pickUniqueGlobalCallable(name, model, scopes, callerFilePath, isFileLoc
|
|
|
286
336
|
}
|
|
287
337
|
// Same argument-type + conversion-rank narrowing for the model pool.
|
|
288
338
|
if (defs.length > 1) {
|
|
289
|
-
const narrowed = narrowOverloadCandidates(defs, callArity, callArgTypes,
|
|
339
|
+
const narrowed = narrowOverloadCandidates(defs, callArity, callArgTypes, {
|
|
340
|
+
conversionRankFn,
|
|
341
|
+
});
|
|
290
342
|
if (narrowed.length === 1)
|
|
291
343
|
return narrowed[0];
|
|
292
344
|
}
|
|
@@ -345,7 +397,7 @@ function pickConstructorOrClass(classDef, workspaceIndex) {
|
|
|
345
397
|
* Exported for unit testing — language-agnostic logic, exercised
|
|
346
398
|
* via synthetic stubs in `pick-implicit-this-overload.test.ts`. The
|
|
347
399
|
* production call site is `applyFreeCallFallback` immediately above. */
|
|
348
|
-
export function pickImplicitThisOverload(site, scopes, workspaceIndex, model,
|
|
400
|
+
export function pickImplicitThisOverload(site, scopes, workspaceIndex, model, hookCtx) {
|
|
349
401
|
// Find the enclosing Class scope by walking parents.
|
|
350
402
|
let curId = site.inScope;
|
|
351
403
|
let classScopeId;
|
|
@@ -374,7 +426,10 @@ export function pickImplicitThisOverload(site, scopes, workspaceIndex, model, co
|
|
|
374
426
|
// ambiguous narrowing (multiple compatible candidates with no
|
|
375
427
|
// disambiguating signal) leaves the call unresolved rather than
|
|
376
428
|
// routing to an arbitrary first overload by registration order.
|
|
377
|
-
const candidates = narrowOverloadCandidates(overloads, site.arity, site.argumentTypes,
|
|
429
|
+
const candidates = narrowOverloadCandidates(overloads, site.arity, site.argumentTypes, {
|
|
430
|
+
conversionRankFn: hookCtx?.conversionRankFn,
|
|
431
|
+
constraintCompatibility: hookCtx?.constraintCompatibility,
|
|
432
|
+
});
|
|
378
433
|
if (candidates.length !== 1)
|
|
379
434
|
return undefined;
|
|
380
435
|
return candidates[0];
|
|
@@ -25,14 +25,19 @@
|
|
|
25
25
|
* counts as a match. Mismatches disqualify. A non-empty typed
|
|
26
26
|
* result wins; otherwise return the arity-filtered candidates.
|
|
27
27
|
* 4b. When the exact-type filter from step 4 returns empty AND a
|
|
28
|
-
* `conversionRankFn` is provided, rank candidates
|
|
29
|
-
* dominance comparison (ISO C++ [over.ics.rank]):
|
|
30
|
-
* only when F1 is not worse for every arg and better
|
|
31
|
-
* least one. Non-dominated candidates are returned;
|
|
32
|
-
* survivors are genuinely ambiguous.
|
|
28
|
+
* `conversionRankFn` is provided (via `hookCtx`), rank candidates
|
|
29
|
+
* via pairwise dominance comparison (ISO C++ [over.ics.rank]):
|
|
30
|
+
* F1 beats F2 only when F1 is not worse for every arg and better
|
|
31
|
+
* for at least one. Non-dominated candidates are returned;
|
|
32
|
+
* multiple survivors are genuinely ambiguous.
|
|
33
|
+
* 4c. Final per-candidate constraint filter (SFINAE / `requires`).
|
|
34
|
+
* When `constraintCompatibility` is provided via `hookCtx`, drop
|
|
35
|
+
* candidates whose template constraints provably fail at the
|
|
36
|
+
* call site. Three-valued; `'unknown'` keeps the candidate
|
|
37
|
+
* (monotonicity).
|
|
33
38
|
* 5. Empty input returns empty output.
|
|
34
39
|
*/
|
|
35
|
-
import type { SymbolDefinition } from '../../../../_shared/index.js';
|
|
40
|
+
import type { ArityVerdict, Callsite, ConstraintContext, SymbolDefinition } from '../../../../_shared/index.js';
|
|
36
41
|
/**
|
|
37
42
|
* Per-slot conversion-rank function. Returns a numeric cost for
|
|
38
43
|
* converting `argType` to `paramType`:
|
|
@@ -45,7 +50,25 @@ import type { SymbolDefinition } from '../../../../_shared/index.js';
|
|
|
45
50
|
* on normalized type strings (output of the language's type normalizer).
|
|
46
51
|
*/
|
|
47
52
|
export type ConversionRankFn = (argType: string, paramType: string) => number;
|
|
48
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Optional hook bundle for narrowing extension points. Threaded in
|
|
55
|
+
* from `pickOverload` / `pickImplicitThisOverload` so per-language
|
|
56
|
+
* narrowing can layer in conversion-rank scoring (#1606) and
|
|
57
|
+
* constraint filtering (#1579) without changing the call signature
|
|
58
|
+
* at every site. Each hook is independently optional — leaving both
|
|
59
|
+
* undefined preserves the legacy arity + exact-type behavior.
|
|
60
|
+
*/
|
|
61
|
+
export interface OverloadNarrowingHookCtx {
|
|
62
|
+
/** Conversion-rank scoring fallback (step 4b). Engages when the
|
|
63
|
+
* exact-type filter rejects every candidate. */
|
|
64
|
+
readonly conversionRankFn?: ConversionRankFn;
|
|
65
|
+
/** Constraint filter (step 4c). Drops candidates whose template
|
|
66
|
+
* guards (SFINAE `enable_if_t`, C++20 `requires`, future Rust
|
|
67
|
+
* trait bounds, etc.) provably fail at the call site. Three-valued
|
|
68
|
+
* — `'unknown'` keeps the candidate (monotonicity). */
|
|
69
|
+
readonly constraintCompatibility?: (callsite: Callsite, def: SymbolDefinition, ctx: ConstraintContext) => ArityVerdict;
|
|
70
|
+
}
|
|
71
|
+
export declare function narrowOverloadCandidates(overloads: readonly SymbolDefinition[], argCount: number | undefined, argTypes: readonly string[] | undefined, hookCtx?: OverloadNarrowingHookCtx): readonly SymbolDefinition[];
|
|
49
72
|
/**
|
|
50
73
|
* Detect when >1 candidate share identical `parameterTypes` after the
|
|
51
74
|
* per-language normalizer has collapsed distinct underlying types. This
|
|
@@ -25,14 +25,19 @@
|
|
|
25
25
|
* counts as a match. Mismatches disqualify. A non-empty typed
|
|
26
26
|
* result wins; otherwise return the arity-filtered candidates.
|
|
27
27
|
* 4b. When the exact-type filter from step 4 returns empty AND a
|
|
28
|
-
* `conversionRankFn` is provided, rank candidates
|
|
29
|
-
* dominance comparison (ISO C++ [over.ics.rank]):
|
|
30
|
-
* only when F1 is not worse for every arg and better
|
|
31
|
-
* least one. Non-dominated candidates are returned;
|
|
32
|
-
* survivors are genuinely ambiguous.
|
|
28
|
+
* `conversionRankFn` is provided (via `hookCtx`), rank candidates
|
|
29
|
+
* via pairwise dominance comparison (ISO C++ [over.ics.rank]):
|
|
30
|
+
* F1 beats F2 only when F1 is not worse for every arg and better
|
|
31
|
+
* for at least one. Non-dominated candidates are returned;
|
|
32
|
+
* multiple survivors are genuinely ambiguous.
|
|
33
|
+
* 4c. Final per-candidate constraint filter (SFINAE / `requires`).
|
|
34
|
+
* When `constraintCompatibility` is provided via `hookCtx`, drop
|
|
35
|
+
* candidates whose template constraints provably fail at the
|
|
36
|
+
* call site. Three-valued; `'unknown'` keeps the candidate
|
|
37
|
+
* (monotonicity).
|
|
33
38
|
* 5. Empty input returns empty output.
|
|
34
39
|
*/
|
|
35
|
-
export function narrowOverloadCandidates(overloads, argCount, argTypes,
|
|
40
|
+
export function narrowOverloadCandidates(overloads, argCount, argTypes, hookCtx) {
|
|
36
41
|
if (overloads.length === 0)
|
|
37
42
|
return [];
|
|
38
43
|
const arityMatches = argCount === undefined
|
|
@@ -67,6 +72,7 @@ export function narrowOverloadCandidates(overloads, argCount, argTypes, conversi
|
|
|
67
72
|
// args).
|
|
68
73
|
const anyUnknownBounds = overloads.some((d) => d.parameterCount === undefined && d.requiredParameterCount === undefined);
|
|
69
74
|
const candidates = arityMatches.length > 0 ? arityMatches : anyUnknownBounds ? overloads : [];
|
|
75
|
+
let result = candidates;
|
|
70
76
|
if (argTypes !== undefined && argTypes.length > 0) {
|
|
71
77
|
const typed = candidates.filter((d) => {
|
|
72
78
|
const params = d.parameterTypes;
|
|
@@ -80,21 +86,46 @@ export function narrowOverloadCandidates(overloads, argCount, argTypes, conversi
|
|
|
80
86
|
}
|
|
81
87
|
return true;
|
|
82
88
|
});
|
|
83
|
-
if (typed.length > 0)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
if (typed.length > 0) {
|
|
90
|
+
result = typed;
|
|
91
|
+
}
|
|
92
|
+
else if (hookCtx?.conversionRankFn !== undefined) {
|
|
93
|
+
// ── Conversion-rank scoring (step 4b) ──────────────────────────
|
|
94
|
+
// The exact-type filter rejected every candidate. Rank via
|
|
95
|
+
// pairwise dominance: F1 beats F2 only when F1 is not worse for
|
|
96
|
+
// every arg and better for at least one. Non-dominated candidates
|
|
97
|
+
// are returned; multiple survivors are genuinely ambiguous. When
|
|
98
|
+
// ranking also yields empty, fall through to the arity-filtered
|
|
99
|
+
// `candidates` set — matches pre-#1606 behavior.
|
|
100
|
+
const ranked = rankByConversion(candidates, argTypes, hookCtx.conversionRankFn);
|
|
93
101
|
if (ranked.length > 0)
|
|
94
|
-
|
|
102
|
+
result = ranked;
|
|
95
103
|
}
|
|
96
104
|
}
|
|
97
|
-
|
|
105
|
+
// Constraint filter (step 4c; Tier-A — SFINAE / `requires` clauses).
|
|
106
|
+
// Runs after arity, exact-type, and conversion-rank filters so the
|
|
107
|
+
// hook only sees candidates already viable on the other axes.
|
|
108
|
+
// Three-valued: `'compatible'` and `'unknown'` keep the candidate
|
|
109
|
+
// (monotonicity — adding a predicate must never cause a wrong edge);
|
|
110
|
+
// only `'incompatible'` drops it. Candidates without
|
|
111
|
+
// `templateConstraints` are always kept.
|
|
112
|
+
//
|
|
113
|
+
// No fallback to the unconstrained set when this filter empties the
|
|
114
|
+
// candidate list: a fully-`'incompatible'` verdict is authoritative.
|
|
115
|
+
// The downstream `OVERLOAD_AMBIGUOUS` sentinel still guards the empty
|
|
116
|
+
// case, so a buggy hook that wrongly returns `'incompatible'` for
|
|
117
|
+
// every candidate degrades to today's "suppress edge" behavior rather
|
|
118
|
+
// than emitting a wrong edge.
|
|
119
|
+
if (hookCtx?.constraintCompatibility !== undefined && argCount !== undefined) {
|
|
120
|
+
const callsite = { arity: argCount };
|
|
121
|
+
const ctx = argTypes !== undefined ? { argumentTypes: argTypes } : {};
|
|
122
|
+
result = result.filter((def) => {
|
|
123
|
+
if (def.templateConstraints === undefined)
|
|
124
|
+
return true;
|
|
125
|
+
return hookCtx.constraintCompatibility(callsite, def, ctx) !== 'incompatible';
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return result;
|
|
98
129
|
}
|
|
99
130
|
/**
|
|
100
131
|
* Pairwise dominance comparison (ISO C++ [over.ics.rank]).
|
|
@@ -41,7 +41,7 @@ import type { WorkspaceResolutionIndex } from '../workspace-index.js';
|
|
|
41
41
|
/** Subset of `ScopeResolver` consumed by this pass. Accepting the
|
|
42
42
|
* subset rather than the full provider keeps tests and partial
|
|
43
43
|
* refactors lighter — callers only need to populate what we read. */
|
|
44
|
-
type ReceiverBoundProviderSubset = Pick<ScopeResolver, 'isSuperReceiver' | 'isSuperReceiverInContext' | 'fieldFallbackOnMethodLookup' | 'collapseMemberCallsByCallerTarget' | 'unwrapCollectionAccessor' | 'hoistTypeBindingsToModule' | 'resolveQualifiedReceiverMember' | 'resolveThisViaEnclosingClass' | 'conversionRankFn'>;
|
|
44
|
+
type ReceiverBoundProviderSubset = Pick<ScopeResolver, 'isSuperReceiver' | 'isSuperReceiverInContext' | 'fieldFallbackOnMethodLookup' | 'collapseMemberCallsByCallerTarget' | 'unwrapCollectionAccessor' | 'hoistTypeBindingsToModule' | 'resolveQualifiedReceiverMember' | 'resolveThisViaEnclosingClass' | 'conversionRankFn' | 'constraintCompatibility'>;
|
|
45
45
|
export declare function emitReceiverBoundCalls(graph: KnowledgeGraph, scopes: ScopeResolutionIndexes, parsedFiles: readonly ParsedFile[], nodeLookup: GraphNodeLookup, handledSites: Set<string>, provider: ReceiverBoundProviderSubset, index: WorkspaceResolutionIndex, model: SemanticModel): number;
|
|
46
46
|
/**
|
|
47
47
|
* Sentinel returned by `pickOverload` when narrowing leaves >1 candidate
|
|
@@ -249,7 +249,10 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
|
|
|
249
249
|
for (const ownerId of chain) {
|
|
250
250
|
const methodOverloads = model.methods.lookupAllByOwner(ownerId, memberName);
|
|
251
251
|
if (methodOverloads.length > 0) {
|
|
252
|
-
const narrowed = narrowOverloadCandidates(methodOverloads, site.arity, site.argumentTypes,
|
|
252
|
+
const narrowed = narrowOverloadCandidates(methodOverloads, site.arity, site.argumentTypes, {
|
|
253
|
+
conversionRankFn: provider.conversionRankFn,
|
|
254
|
+
constraintCompatibility: provider.constraintCompatibility,
|
|
255
|
+
});
|
|
253
256
|
if (isOverloadAmbiguousAfterNormalization(narrowed, site.arity)) {
|
|
254
257
|
ambiguous = true;
|
|
255
258
|
break;
|
|
@@ -467,7 +470,7 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
|
|
|
467
470
|
let memberDef;
|
|
468
471
|
let ambiguous = false;
|
|
469
472
|
for (const ownerId of chain) {
|
|
470
|
-
const picked = pickOverload(ownerId, memberName, site, model, provider
|
|
473
|
+
const picked = pickOverload(ownerId, memberName, site, model, provider);
|
|
471
474
|
if (picked === OVERLOAD_AMBIGUOUS) {
|
|
472
475
|
ambiguous = true;
|
|
473
476
|
break;
|
|
@@ -518,7 +521,7 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
|
|
|
518
521
|
* types when multiple overloads share the name. Falls back to the
|
|
519
522
|
* first-seen def (legacy `findOwnedMember` semantics) when there's
|
|
520
523
|
* no narrowing signal or when `argumentTypes` is unavailable. */
|
|
521
|
-
function pickOverload(ownerId, memberName, site, model,
|
|
524
|
+
function pickOverload(ownerId, memberName, site, model, provider) {
|
|
522
525
|
const overloads = model.methods.lookupAllByOwner(ownerId, memberName);
|
|
523
526
|
if (overloads.length === 0) {
|
|
524
527
|
// Non-callable member (field / property / variable) — ACCESSES
|
|
@@ -528,7 +531,10 @@ function pickOverload(ownerId, memberName, site, model, conversionRankFn) {
|
|
|
528
531
|
}
|
|
529
532
|
if (overloads.length === 1)
|
|
530
533
|
return overloads[0];
|
|
531
|
-
const candidates = narrowOverloadCandidates(overloads, site.arity, site.argumentTypes,
|
|
534
|
+
const candidates = narrowOverloadCandidates(overloads, site.arity, site.argumentTypes, {
|
|
535
|
+
conversionRankFn: provider.conversionRankFn,
|
|
536
|
+
constraintCompatibility: provider.constraintCompatibility,
|
|
537
|
+
});
|
|
532
538
|
// When narrowing leaves >1 candidate that share identical normalized
|
|
533
539
|
// parameter-types (e.g., C++ `f(int)` vs `f(long)` both collapsed to
|
|
534
540
|
// `['int']` by `normalizeCppParamType`), suppress the edge entirely.
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
* undefined `ownerId` is reachable via either:
|
|
19
19
|
* - `model.methods.lookupAllByOwner(ownerId, simpleName)` — if the
|
|
20
20
|
* def is a Method / Function / Constructor, OR
|
|
21
|
-
* - `model.fields.
|
|
22
|
-
* def is a Property / Variable.
|
|
21
|
+
* - `model.fields.lookupAllByOwner(ownerId, simpleName)` — if the
|
|
22
|
+
* def is a Property / Variable / Const / Static.
|
|
23
23
|
*
|
|
24
24
|
* This invariant is the foundation of Contract Invariant I9
|
|
25
25
|
* (`contract/scope-resolver.ts`): scope-resolution passes MUST read
|
|
@@ -47,6 +47,8 @@ export interface ReconcileStats {
|
|
|
47
47
|
readonly methodsRegistered: number;
|
|
48
48
|
/** Property/Variable defs registered into FieldRegistry. */
|
|
49
49
|
readonly fieldsRegistered: number;
|
|
50
|
+
/** Class-like nested type defs registered into TypeRegistry by owner. */
|
|
51
|
+
readonly nestedTypesRegistered: number;
|
|
50
52
|
/** Defs already present (idempotent skip). */
|
|
51
53
|
readonly skippedAlreadyPresent: number;
|
|
52
54
|
}
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
* undefined `ownerId` is reachable via either:
|
|
19
19
|
* - `model.methods.lookupAllByOwner(ownerId, simpleName)` — if the
|
|
20
20
|
* def is a Method / Function / Constructor, OR
|
|
21
|
-
* - `model.fields.
|
|
22
|
-
* def is a Property / Variable.
|
|
21
|
+
* - `model.fields.lookupAllByOwner(ownerId, simpleName)` — if the
|
|
22
|
+
* def is a Property / Variable / Const / Static.
|
|
23
23
|
*
|
|
24
24
|
* This invariant is the foundation of Contract Invariant I9
|
|
25
25
|
* (`contract/scope-resolver.ts`): scope-resolution passes MUST read
|
|
@@ -41,9 +41,25 @@
|
|
|
41
41
|
* follow-up plan.
|
|
42
42
|
*/
|
|
43
43
|
import { simpleQualifiedName } from '../graph-bridge/ids.js';
|
|
44
|
+
const NESTED_TYPE_KINDS = new Set([
|
|
45
|
+
'Class',
|
|
46
|
+
'Interface',
|
|
47
|
+
'Enum',
|
|
48
|
+
'Struct',
|
|
49
|
+
'Union',
|
|
50
|
+
'Trait',
|
|
51
|
+
'TypeAlias',
|
|
52
|
+
'Typedef',
|
|
53
|
+
'Record',
|
|
54
|
+
'Delegate',
|
|
55
|
+
'Annotation',
|
|
56
|
+
'Template',
|
|
57
|
+
'Namespace',
|
|
58
|
+
]);
|
|
44
59
|
export function reconcileOwnership(parsedFiles, model) {
|
|
45
60
|
let methodsRegistered = 0;
|
|
46
61
|
let fieldsRegistered = 0;
|
|
62
|
+
let nestedTypesRegistered = 0;
|
|
47
63
|
let skippedAlreadyPresent = 0;
|
|
48
64
|
for (const parsed of parsedFiles) {
|
|
49
65
|
for (const def of parsed.localDefs) {
|
|
@@ -62,18 +78,30 @@ export function reconcileOwnership(parsedFiles, model) {
|
|
|
62
78
|
model.methods.register(ownerId, simple, def);
|
|
63
79
|
methodsRegistered++;
|
|
64
80
|
}
|
|
65
|
-
else if (def.type === 'Property' ||
|
|
66
|
-
|
|
67
|
-
|
|
81
|
+
else if (def.type === 'Property' ||
|
|
82
|
+
def.type === 'Variable' ||
|
|
83
|
+
def.type === 'Const' ||
|
|
84
|
+
def.type === 'Static') {
|
|
85
|
+
const existing = model.fields.lookupAllByOwner(ownerId, simple);
|
|
86
|
+
if (existing.some((e) => e.nodeId === def.nodeId)) {
|
|
68
87
|
skippedAlreadyPresent++;
|
|
69
88
|
continue;
|
|
70
89
|
}
|
|
71
90
|
model.fields.register(ownerId, simple, def);
|
|
72
91
|
fieldsRegistered++;
|
|
73
92
|
}
|
|
93
|
+
else if (NESTED_TYPE_KINDS.has(def.type)) {
|
|
94
|
+
const existing = model.types.lookupAllByOwner(ownerId, simple);
|
|
95
|
+
if (existing.some((e) => e.nodeId === def.nodeId)) {
|
|
96
|
+
skippedAlreadyPresent++;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
model.types.registerByOwner(ownerId, simple, def);
|
|
100
|
+
nestedTypesRegistered++;
|
|
101
|
+
}
|
|
74
102
|
}
|
|
75
103
|
}
|
|
76
|
-
return { methodsRegistered, fieldsRegistered, skippedAlreadyPresent };
|
|
104
|
+
return { methodsRegistered, fieldsRegistered, nestedTypesRegistered, skippedAlreadyPresent };
|
|
77
105
|
}
|
|
78
106
|
/**
|
|
79
107
|
* Debug-mode parity validator. Runs only when
|
|
@@ -111,14 +139,25 @@ export function validateOwnershipParity(parsedFiles, model, onWarn) {
|
|
|
111
139
|
mismatches++;
|
|
112
140
|
}
|
|
113
141
|
}
|
|
114
|
-
else if (def.type === 'Property' ||
|
|
115
|
-
|
|
116
|
-
|
|
142
|
+
else if (def.type === 'Property' ||
|
|
143
|
+
def.type === 'Variable' ||
|
|
144
|
+
def.type === 'Const' ||
|
|
145
|
+
def.type === 'Static') {
|
|
146
|
+
const found = model.fields.lookupAllByOwner(ownerId, simple);
|
|
147
|
+
if (!found.some((d) => d.nodeId === def.nodeId)) {
|
|
117
148
|
onWarn(`semantic-model parity: ${def.type} ${def.nodeId} (${parsed.filePath}) ` +
|
|
118
149
|
`owned by ${ownerId} as "${simple}" not in FieldRegistry`);
|
|
119
150
|
mismatches++;
|
|
120
151
|
}
|
|
121
152
|
}
|
|
153
|
+
else if (NESTED_TYPE_KINDS.has(def.type)) {
|
|
154
|
+
const found = model.types.lookupAllByOwner(ownerId, simple);
|
|
155
|
+
if (!found.some((d) => d.nodeId === def.nodeId)) {
|
|
156
|
+
onWarn(`semantic-model parity: ${def.type} ${def.nodeId} (${parsed.filePath}) ` +
|
|
157
|
+
`owned by ${ownerId} as "${simple}" not in TypeRegistry owner index`);
|
|
158
|
+
mismatches++;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
122
161
|
}
|
|
123
162
|
}
|
|
124
163
|
return mismatches;
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
*
|
|
23
23
|
* Plan: `docs/plans/2026-04-20-001-refactor-emit-pipeline-generalization-plan.md`.
|
|
24
24
|
*/
|
|
25
|
+
import { lookupOwnedMembersByOwner } from '../../model/owned-members-lookup.js';
|
|
25
26
|
import { reconcileOwnership, validateOwnershipParity } from './reconcile-ownership.js';
|
|
26
27
|
import { validateBindingsImmutability } from './validate-bindings-immutability.js';
|
|
27
28
|
import { extractParsedFile } from '../../scope-extractor-bridge.js';
|
|
@@ -236,6 +237,7 @@ export function runScopeResolution(input, provider) {
|
|
|
236
237
|
const { referenceIndex, stats: resolveStats } = resolveReferenceSites({
|
|
237
238
|
scopes: indexes,
|
|
238
239
|
providers: registryProviders,
|
|
240
|
+
ownedMembersByOwner: (ownerDefId, memberName) => lookupOwnedMembersByOwner(readonlyModel, ownerDefId, memberName),
|
|
239
241
|
});
|
|
240
242
|
const tResolve = PROF ? process.hrtime.bigint() : 0n;
|
|
241
243
|
// ── Phase 4: emit graph edges (LOAD-BEARING ORDER — see I1) ────────────
|
|
@@ -250,6 +252,7 @@ export function runScopeResolution(input, provider) {
|
|
|
250
252
|
isCallableVisibleFromCaller: provider.isCallableVisibleFromCaller,
|
|
251
253
|
resolveAdlCandidates: provider.resolveAdlCandidates,
|
|
252
254
|
conversionRankFn: provider.conversionRankFn,
|
|
255
|
+
constraintCompatibility: provider.constraintCompatibility,
|
|
253
256
|
});
|
|
254
257
|
const { emitted, skipped } = emitReferencesViaLookup(graph, indexes, referenceIndex, nodeLookup, handledSites);
|
|
255
258
|
const importsEmitted = emitImportEdges(graph, indexes.imports, indexes.scopeTree, provider.importEdgeReason);
|
|
@@ -9,3 +9,22 @@
|
|
|
9
9
|
export declare function extractTemplateArguments(text: string): string[] | undefined;
|
|
10
10
|
export declare function stripTemplateArguments(text: string): string;
|
|
11
11
|
export declare function templateArgumentsIdTag(templateArguments?: readonly string[]): string;
|
|
12
|
+
/**
|
|
13
|
+
* Stable short hash for the opaque `SymbolDefinition.templateConstraints`
|
|
14
|
+
* payload (issue #1579). Two function-template overloads with identical
|
|
15
|
+
* `parameterTypes` but mutually-exclusive SFINAE constraints
|
|
16
|
+
* (`enable_if_t<is_integral_v<T>>` vs `enable_if_t<is_floating_point_v<T>>`)
|
|
17
|
+
* must produce distinct graph node IDs so the constraint-filter step
|
|
18
|
+
* has two candidates to narrow between. Without this they collapse to
|
|
19
|
+
* a single Function node and the SFINAE golden case can only emit one
|
|
20
|
+
* edge regardless of resolver fixes.
|
|
21
|
+
*
|
|
22
|
+
* FNV-1a 32-bit, base36 encoded. Deterministic; non-cryptographic — the
|
|
23
|
+
* tag's job is collision-avoidance among same-name overloads in one
|
|
24
|
+
* file, not security.
|
|
25
|
+
*/
|
|
26
|
+
export declare function constraintsHash(jsonText: string): string;
|
|
27
|
+
/** Build the `~c:<hash>` ID suffix from an opaque constraint payload.
|
|
28
|
+
* Returns empty string when the payload is absent so callers can
|
|
29
|
+
* string-concatenate unconditionally. */
|
|
30
|
+
export declare function templateConstraintsIdTag(payload: unknown): string;
|
|
@@ -63,3 +63,33 @@ export function templateArgumentsIdTag(templateArguments) {
|
|
|
63
63
|
return '';
|
|
64
64
|
return `~${templateArguments.join(',')}`;
|
|
65
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Stable short hash for the opaque `SymbolDefinition.templateConstraints`
|
|
68
|
+
* payload (issue #1579). Two function-template overloads with identical
|
|
69
|
+
* `parameterTypes` but mutually-exclusive SFINAE constraints
|
|
70
|
+
* (`enable_if_t<is_integral_v<T>>` vs `enable_if_t<is_floating_point_v<T>>`)
|
|
71
|
+
* must produce distinct graph node IDs so the constraint-filter step
|
|
72
|
+
* has two candidates to narrow between. Without this they collapse to
|
|
73
|
+
* a single Function node and the SFINAE golden case can only emit one
|
|
74
|
+
* edge regardless of resolver fixes.
|
|
75
|
+
*
|
|
76
|
+
* FNV-1a 32-bit, base36 encoded. Deterministic; non-cryptographic — the
|
|
77
|
+
* tag's job is collision-avoidance among same-name overloads in one
|
|
78
|
+
* file, not security.
|
|
79
|
+
*/
|
|
80
|
+
export function constraintsHash(jsonText) {
|
|
81
|
+
let h = 0x811c9dc5;
|
|
82
|
+
for (let i = 0; i < jsonText.length; i++) {
|
|
83
|
+
h ^= jsonText.charCodeAt(i);
|
|
84
|
+
h = Math.imul(h, 0x01000193);
|
|
85
|
+
}
|
|
86
|
+
return (h >>> 0).toString(36);
|
|
87
|
+
}
|
|
88
|
+
/** Build the `~c:<hash>` ID suffix from an opaque constraint payload.
|
|
89
|
+
* Returns empty string when the payload is absent so callers can
|
|
90
|
+
* string-concatenate unconditionally. */
|
|
91
|
+
export function templateConstraintsIdTag(payload) {
|
|
92
|
+
if (payload === undefined || payload === null)
|
|
93
|
+
return '';
|
|
94
|
+
return `~c:${constraintsHash(JSON.stringify(payload))}`;
|
|
95
|
+
}
|
|
@@ -3,7 +3,7 @@ import type { ExtractedHeritage } from '../model/heritage-map.js';
|
|
|
3
3
|
import { type MixedChainStep } from '../utils/call-analysis.js';
|
|
4
4
|
import type { ConstructorBinding } from '../type-env.js';
|
|
5
5
|
import type { NamedBinding } from '../named-bindings/types.js';
|
|
6
|
-
import type { NodeLabel } from '../../../_shared/index.js';
|
|
6
|
+
import type { NodeLabel, ParameterTypeClass } from '../../../_shared/index.js';
|
|
7
7
|
import type { ParsedFile } from '../../../_shared/index.js';
|
|
8
8
|
interface ParsedNode {
|
|
9
9
|
id: string;
|
|
@@ -38,6 +38,7 @@ interface ParsedSymbol {
|
|
|
38
38
|
parameterCount?: number;
|
|
39
39
|
requiredParameterCount?: number;
|
|
40
40
|
parameterTypes?: string[];
|
|
41
|
+
parameterTypeClasses?: ParameterTypeClass[];
|
|
41
42
|
returnType?: string;
|
|
42
43
|
declaredType?: string;
|
|
43
44
|
templateArguments?: string[];
|
|
@@ -1801,6 +1801,7 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1801
1801
|
parameterCount: methodProps.parameterCount,
|
|
1802
1802
|
requiredParameterCount: methodProps.requiredParameterCount,
|
|
1803
1803
|
parameterTypes: methodProps.parameterTypes,
|
|
1804
|
+
parameterTypeClasses: methodProps.parameterTypeClasses,
|
|
1804
1805
|
returnType: methodProps.returnType,
|
|
1805
1806
|
...(declaredType !== undefined ? { declaredType } : {}),
|
|
1806
1807
|
...(classTemplateArguments !== undefined && classTemplateArguments.length > 0
|