gitnexus 1.6.5-rc.44 → 1.6.5-rc.45
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/core/ingestion/languages/cpp/inline-namespaces.d.ts +3 -3
- package/dist/core/ingestion/languages/cpp/inline-namespaces.js +49 -15
- package/dist/core/ingestion/languages/cpp/scope-resolver.js +1 -1
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +4 -3
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +6 -0
- package/package.json +1 -1
|
@@ -60,8 +60,8 @@ export declare function isCppInlineNamespaceScope(scopeId: ScopeId): boolean;
|
|
|
60
60
|
* Returns the most specific (innermost) match — for `outer::foo()`
|
|
61
61
|
* where `inline namespace v1` declares `foo`, returns `v1::foo`. When
|
|
62
62
|
* multiple inline-namespace children declare the same name, ISO C++
|
|
63
|
-
* leaves the call ambiguous;
|
|
64
|
-
*
|
|
63
|
+
* leaves the call ambiguous; returns `'ambiguous'` so the caller
|
|
64
|
+
* suppresses edge emission rather than picking arbitrarily (#1564).
|
|
65
65
|
*/
|
|
66
|
-
export declare function resolveCppQualifiedNamespaceMember(receiverName: string, memberName: string, parsedFiles: readonly ParsedFile[], _scopes: ScopeResolutionIndexes): SymbolDefinition | undefined;
|
|
66
|
+
export declare function resolveCppQualifiedNamespaceMember(receiverName: string, memberName: string, parsedFiles: readonly ParsedFile[], _scopes: ScopeResolutionIndexes): SymbolDefinition | 'ambiguous' | undefined;
|
|
67
67
|
export {};
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
* `std::vector` qualified calls resolve to the inline-namespace
|
|
27
27
|
* declaration transparently.
|
|
28
28
|
*/
|
|
29
|
+
import { isOverloadAmbiguousAfterNormalization, narrowOverloadCandidates, } from '../../scope-resolution/passes/overload-narrowing.js';
|
|
29
30
|
const inlineNamespaceRangesByFile = new Map();
|
|
30
31
|
const inlineNamespaceScopeIds = new Set();
|
|
31
32
|
function rangeKey(r) {
|
|
@@ -80,10 +81,12 @@ export function isCppInlineNamespaceScope(scopeId) {
|
|
|
80
81
|
* Returns the most specific (innermost) match — for `outer::foo()`
|
|
81
82
|
* where `inline namespace v1` declares `foo`, returns `v1::foo`. When
|
|
82
83
|
* multiple inline-namespace children declare the same name, ISO C++
|
|
83
|
-
* leaves the call ambiguous;
|
|
84
|
-
*
|
|
84
|
+
* leaves the call ambiguous; returns `'ambiguous'` so the caller
|
|
85
|
+
* suppresses edge emission rather than picking arbitrarily (#1564).
|
|
85
86
|
*/
|
|
86
87
|
export function resolveCppQualifiedNamespaceMember(receiverName, memberName, parsedFiles, _scopes) {
|
|
88
|
+
const allHits = [];
|
|
89
|
+
const seenNodeId = new Set();
|
|
87
90
|
for (const parsed of parsedFiles) {
|
|
88
91
|
const scopesById = new Map();
|
|
89
92
|
for (const sc of parsed.scopes)
|
|
@@ -97,27 +100,58 @@ export function resolveCppQualifiedNamespaceMember(receiverName, memberName, par
|
|
|
97
100
|
const nsName = nsDef.qualifiedName?.split('.').pop() ?? nsDef.qualifiedName ?? '';
|
|
98
101
|
if (nsName !== receiverName)
|
|
99
102
|
continue;
|
|
100
|
-
// Found a matching namespace scope in this file. Collect
|
|
101
|
-
//
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
// Found a matching namespace scope in this file. Collect ALL
|
|
104
|
+
// members transitively through any inline-namespace children.
|
|
105
|
+
const hits = findMemberInNamespaceTransitive(scope, scopesById, memberName);
|
|
106
|
+
for (const hit of hits) {
|
|
107
|
+
if (seenNodeId.has(hit.nodeId))
|
|
108
|
+
continue;
|
|
109
|
+
seenNodeId.add(hit.nodeId);
|
|
110
|
+
allHits.push(hit);
|
|
111
|
+
}
|
|
105
112
|
}
|
|
106
113
|
}
|
|
107
|
-
|
|
114
|
+
if (allHits.length === 0)
|
|
115
|
+
return undefined;
|
|
116
|
+
if (allHits.length === 1)
|
|
117
|
+
return allHits[0];
|
|
118
|
+
// Multi-candidate: the `resolveQualifiedReceiverMember` hook has no
|
|
119
|
+
// access to call-site arity or argument types, so
|
|
120
|
+
// `narrowOverloadCandidates` cannot actually narrow here — the call
|
|
121
|
+
// with `(allHits, undefined, undefined)` is effectively a pass-through.
|
|
122
|
+
// We retain it so that `isOverloadAmbiguousAfterNormalization` can
|
|
123
|
+
// still detect int/long-style normalization collisions on this path,
|
|
124
|
+
// but for any multi-hit case where candidates have genuinely distinct
|
|
125
|
+
// signatures (e.g. `foo(int)` vs `foo(double)` in different inline
|
|
126
|
+
// children), we conservatively suppress rather than pick arbitrarily.
|
|
127
|
+
// A future enhancement could thread call-site argument info through
|
|
128
|
+
// the `resolveQualifiedReceiverMember` contract to enable real
|
|
129
|
+
// narrowing here.
|
|
130
|
+
const narrowed = narrowOverloadCandidates(allHits, undefined, undefined);
|
|
131
|
+
if (narrowed.length === 1)
|
|
132
|
+
return narrowed[0];
|
|
133
|
+
if (narrowed.length === 0)
|
|
134
|
+
return undefined;
|
|
135
|
+
if (isOverloadAmbiguousAfterNormalization(narrowed, undefined))
|
|
136
|
+
return 'ambiguous';
|
|
137
|
+
// Multiple surviving candidates (distinct signatures) — conservative
|
|
138
|
+
// suppress because we lack call-site info to disambiguate.
|
|
139
|
+
return 'ambiguous';
|
|
108
140
|
}
|
|
109
141
|
/** Recursively search a namespace scope and any inline-namespace
|
|
110
|
-
* descendants for
|
|
142
|
+
* descendants for callable defs with the given simple name. Non-inline
|
|
111
143
|
* nested namespaces are NOT traversed — they require explicit
|
|
112
|
-
* qualification (`outer::nested::foo`).
|
|
144
|
+
* qualification (`outer::nested::foo`). Returns ALL matches so the
|
|
145
|
+
* caller can detect same-name ambiguity across inline children (#1564). */
|
|
113
146
|
function findMemberInNamespaceTransitive(scope, scopesById, memberName) {
|
|
147
|
+
const results = [];
|
|
114
148
|
// Check this scope's own ownedDefs first.
|
|
115
149
|
for (const def of scope.ownedDefs) {
|
|
116
150
|
if (def.type !== 'Function' && def.type !== 'Method' && def.type !== 'Constructor')
|
|
117
151
|
continue;
|
|
118
152
|
const simple = def.qualifiedName?.split('.').pop() ?? def.qualifiedName ?? '';
|
|
119
153
|
if (simple === memberName)
|
|
120
|
-
|
|
154
|
+
results.push(def);
|
|
121
155
|
}
|
|
122
156
|
// Descend into inline-namespace children.
|
|
123
157
|
for (const childScope of scopesById.values()) {
|
|
@@ -127,11 +161,11 @@ function findMemberInNamespaceTransitive(scope, scopesById, memberName) {
|
|
|
127
161
|
continue;
|
|
128
162
|
if (!inlineNamespaceScopeIds.has(childScope.id))
|
|
129
163
|
continue;
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
164
|
+
const childHits = findMemberInNamespaceTransitive(childScope, scopesById, memberName);
|
|
165
|
+
for (const hit of childHits)
|
|
166
|
+
results.push(hit);
|
|
133
167
|
}
|
|
134
|
-
return
|
|
168
|
+
return results;
|
|
135
169
|
}
|
|
136
170
|
function findNamespaceDefInScope(scope) {
|
|
137
171
|
for (const def of scope.ownedDefs) {
|
|
@@ -205,7 +205,7 @@ export const cppScopeResolver = {
|
|
|
205
205
|
if (imp.localName !== site.name)
|
|
206
206
|
continue;
|
|
207
207
|
const member = resolveCppQualifiedNamespaceMember(imp.targetRaw, imp.importedName, parsedFiles, scopes);
|
|
208
|
-
if (member === undefined)
|
|
208
|
+
if (member === undefined || member === 'ambiguous')
|
|
209
209
|
continue;
|
|
210
210
|
if (seenUsing.has(member.nodeId))
|
|
211
211
|
continue;
|
|
@@ -542,10 +542,11 @@ export interface ScopeResolver {
|
|
|
542
542
|
*
|
|
543
543
|
* Receiver-bound-calls invokes this hook AFTER Case 1 (namespace
|
|
544
544
|
* imports) and AFTER Case 2 (class-name receiver) fail to resolve.
|
|
545
|
-
* Returns the target def,
|
|
546
|
-
*
|
|
545
|
+
* Returns the target def, `'ambiguous'` when multiple inline-namespace
|
|
546
|
+
* children declare the same name (suppresses edge emission), or
|
|
547
|
+
* `undefined` to fall through to the remaining cases.
|
|
547
548
|
*/
|
|
548
|
-
readonly resolveQualifiedReceiverMember?: (receiverName: string, memberName: string, callerScope: ScopeId, scopes: ScopeResolutionIndexes, parsedFiles: readonly ParsedFile[]) => SymbolDefinition | undefined;
|
|
549
|
+
readonly resolveQualifiedReceiverMember?: (receiverName: string, memberName: string, callerScope: ScopeId, scopes: ScopeResolutionIndexes, parsedFiles: readonly ParsedFile[]) => SymbolDefinition | 'ambiguous' | undefined;
|
|
549
550
|
/**
|
|
550
551
|
* Enable the receiver-bound Case 0.5 fallback for explicit `this`
|
|
551
552
|
* receivers (`this->m()` / `this.m()`) that resolves against the
|
|
@@ -324,6 +324,12 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
|
|
|
324
324
|
// class with the same simple name.
|
|
325
325
|
if (provider.resolveQualifiedReceiverMember !== undefined) {
|
|
326
326
|
const memberDef = provider.resolveQualifiedReceiverMember(receiverName, memberName, site.inScope, scopes, parsedFiles);
|
|
327
|
+
if (memberDef === 'ambiguous') {
|
|
328
|
+
// Same-name ambiguity across inline-namespace children (#1564):
|
|
329
|
+
// suppress edge emission, mark site handled.
|
|
330
|
+
handledSites.add(siteKey);
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
327
333
|
if (memberDef !== undefined) {
|
|
328
334
|
const ok = tryEmitEdge(graph, scopes, nodeLookup, site, memberDef, memberDef.filePath !== parsed.filePath ? 'import-resolved' : 'global', seen, 0.85, collapse);
|
|
329
335
|
if (ok)
|
package/package.json
CHANGED