gitnexus 1.6.5-rc.37 → 1.6.5-rc.39
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/adl.d.ts +15 -19
- package/dist/core/ingestion/languages/cpp/adl.js +13 -14
- package/dist/core/ingestion/languages/cpp/captures.js +30 -20
- package/dist/core/ingestion/languages/cpp/scope-resolver.js +31 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +11 -0
- 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 +66 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* C++ argument-dependent lookup (ADL / Koenig lookup)
|
|
2
|
+
* C++ argument-dependent lookup (ADL / Koenig lookup).
|
|
3
3
|
*
|
|
4
4
|
* When ordinary unqualified lookup fails for a free-call site, ADL also
|
|
5
5
|
* considers candidates declared in the **associated namespaces** of the
|
|
@@ -13,17 +13,18 @@
|
|
|
13
13
|
* `using` anything. With V1 ADL: `audit::record` is discovered via
|
|
14
14
|
* `audit::Event`'s associated namespace.
|
|
15
15
|
*
|
|
16
|
-
* ##
|
|
16
|
+
* ## Current boundary
|
|
17
17
|
*
|
|
18
|
-
*
|
|
18
|
+
* The current implementation covers ONE associated-entity rule: an argument that's a directly-named
|
|
19
19
|
* class type (`audit::Event e`) contributes its **direct enclosing
|
|
20
|
-
* namespace** to the candidate set.
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
20
|
+
* namespace** to the candidate set. V2 extends that one step to
|
|
21
|
+
* pointer-typed and reference-typed class args (`audit::Event* p`,
|
|
22
|
+
* `audit::Event& r`, `audit::Event&& rr`): they contribute the pointee /
|
|
23
|
+
* referred class's enclosing namespace too. Function-pointer arguments,
|
|
24
|
+
* template specializations, base-class associated namespaces, and the
|
|
25
|
+
* rest of the full closure are still deliberately excluded.
|
|
25
26
|
*
|
|
26
|
-
*
|
|
27
|
+
* The current implementation also short-circuits to ADL only when ordinary lookup is empty
|
|
27
28
|
* (`findCallableBindingInScope` returned undefined). ISO C++ would
|
|
28
29
|
* normally merge ADL candidates with ordinary-lookup candidates and
|
|
29
30
|
* run overload resolution over the union; V1 defers that merge to V2.
|
|
@@ -54,19 +55,14 @@
|
|
|
54
55
|
import type { ParsedFile, SymbolDefinition } from '../../../../_shared/index.js';
|
|
55
56
|
import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js';
|
|
56
57
|
/**
|
|
57
|
-
* Per-argument shape information collected at capture time. ADL
|
|
58
|
-
*
|
|
59
|
-
*
|
|
58
|
+
* Per-argument shape information collected at capture time. ADL fires for
|
|
59
|
+
* arguments where `simpleClassName !== ''`, including class pointers and
|
|
60
|
+
* references whose declarator chain resolves to a named class type.
|
|
60
61
|
*/
|
|
61
62
|
export interface CppAdlArgInfo {
|
|
62
63
|
/** Simple class-like type name (last segment of qualified name); empty
|
|
63
64
|
* for primitives, literals, function pointers, template specs, etc. */
|
|
64
65
|
readonly simpleClassName: string;
|
|
65
|
-
/** True when the variable's declarator was a `pointer_declarator`. V1
|
|
66
|
-
* excludes pointer-typed args (closure rules deferred to V2). */
|
|
67
|
-
readonly isPointer: boolean;
|
|
68
|
-
/** True when the variable's declarator was a `reference_declarator`. */
|
|
69
|
-
readonly isReference: boolean;
|
|
70
66
|
}
|
|
71
67
|
/** Sentinel returned by `pickCppAdlCandidates` when ADL surfaces multiple
|
|
72
68
|
* candidates that share normalized parameter types — the caller MUST
|
|
@@ -105,8 +101,8 @@ export declare function populateCppAssociatedNamespaces(parsed: ParsedFile): voi
|
|
|
105
101
|
*
|
|
106
102
|
* Fires only when:
|
|
107
103
|
* - the call site is not in `noAdlSites` (parenthesized form), AND
|
|
108
|
-
* - at least one argument
|
|
109
|
-
*
|
|
104
|
+
* - at least one argument resolves to a named class type (value,
|
|
105
|
+
* pointer, or reference; but not function pointer, literal, or primitive).
|
|
110
106
|
*/
|
|
111
107
|
export declare function pickCppAdlCandidates(site: {
|
|
112
108
|
readonly name: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* C++ argument-dependent lookup (ADL / Koenig lookup)
|
|
2
|
+
* C++ argument-dependent lookup (ADL / Koenig lookup).
|
|
3
3
|
*
|
|
4
4
|
* When ordinary unqualified lookup fails for a free-call site, ADL also
|
|
5
5
|
* considers candidates declared in the **associated namespaces** of the
|
|
@@ -13,17 +13,18 @@
|
|
|
13
13
|
* `using` anything. With V1 ADL: `audit::record` is discovered via
|
|
14
14
|
* `audit::Event`'s associated namespace.
|
|
15
15
|
*
|
|
16
|
-
* ##
|
|
16
|
+
* ## Current boundary
|
|
17
17
|
*
|
|
18
|
-
*
|
|
18
|
+
* The current implementation covers ONE associated-entity rule: an argument that's a directly-named
|
|
19
19
|
* class type (`audit::Event e`) contributes its **direct enclosing
|
|
20
|
-
* namespace** to the candidate set.
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
20
|
+
* namespace** to the candidate set. V2 extends that one step to
|
|
21
|
+
* pointer-typed and reference-typed class args (`audit::Event* p`,
|
|
22
|
+
* `audit::Event& r`, `audit::Event&& rr`): they contribute the pointee /
|
|
23
|
+
* referred class's enclosing namespace too. Function-pointer arguments,
|
|
24
|
+
* template specializations, base-class associated namespaces, and the
|
|
25
|
+
* rest of the full closure are still deliberately excluded.
|
|
25
26
|
*
|
|
26
|
-
*
|
|
27
|
+
* The current implementation also short-circuits to ADL only when ordinary lookup is empty
|
|
27
28
|
* (`findCallableBindingInScope` returned undefined). ISO C++ would
|
|
28
29
|
* normally merge ADL candidates with ordinary-lookup candidates and
|
|
29
30
|
* run overload resolution over the union; V1 defers that merge to V2.
|
|
@@ -118,8 +119,8 @@ export function populateCppAssociatedNamespaces(parsed) {
|
|
|
118
119
|
*
|
|
119
120
|
* Fires only when:
|
|
120
121
|
* - the call site is not in `noAdlSites` (parenthesized form), AND
|
|
121
|
-
* - at least one argument
|
|
122
|
-
*
|
|
122
|
+
* - at least one argument resolves to a named class type (value,
|
|
123
|
+
* pointer, or reference; but not function pointer, literal, or primitive).
|
|
123
124
|
*/
|
|
124
125
|
export function pickCppAdlCandidates(site, callerParsed, scopes, parsedFiles) {
|
|
125
126
|
const key = siteKey(callerParsed.filePath, site.atRange.startLine, site.atRange.startCol);
|
|
@@ -128,13 +129,11 @@ export function pickCppAdlCandidates(site, callerParsed, scopes, parsedFiles) {
|
|
|
128
129
|
const args = argInfoBySite.get(key);
|
|
129
130
|
if (args === undefined || args.length === 0)
|
|
130
131
|
return undefined;
|
|
131
|
-
// Collect associated namespace QNames from every
|
|
132
|
+
// Collect associated namespace QNames from every participating class-typed arg.
|
|
132
133
|
const associatedNamespaces = new Set();
|
|
133
134
|
for (const arg of args) {
|
|
134
135
|
if (arg.simpleClassName === '')
|
|
135
136
|
continue;
|
|
136
|
-
if (arg.isPointer || arg.isReference)
|
|
137
|
-
continue;
|
|
138
137
|
const classDef = findCppClassDefBySimpleName(arg.simpleClassName, scopes);
|
|
139
138
|
if (classDef === undefined)
|
|
140
139
|
continue;
|
|
@@ -657,14 +657,15 @@ function isParenthesizedFunctionCall(callNode) {
|
|
|
657
657
|
}
|
|
658
658
|
/**
|
|
659
659
|
* Per-argument ADL classification: walk each argument of a free call and
|
|
660
|
-
* decide whether it
|
|
661
|
-
*
|
|
662
|
-
* pointer, template specialization
|
|
660
|
+
* decide whether it resolves to a directly-named class or class-pointer
|
|
661
|
+
* type (ADL fires) or to an excluded shape such as a reference, function
|
|
662
|
+
* pointer, primitive, literal, or template specialization.
|
|
663
663
|
*
|
|
664
|
-
*
|
|
665
|
-
*
|
|
666
|
-
*
|
|
667
|
-
*
|
|
664
|
+
* Class-typed values and class pointers (`N::S`, `N::S*`, `N::S**`) all
|
|
665
|
+
* preserve the pointee class name for associated-namespace lookup.
|
|
666
|
+
* Function pointers remain excluded even when their return type names a
|
|
667
|
+
* class, because the associated entity is the pointed-to function type,
|
|
668
|
+
* not the return type.
|
|
668
669
|
*/
|
|
669
670
|
function inferCppCallAdlArgs(callNode) {
|
|
670
671
|
const argList = callNode.childForFieldName('arguments');
|
|
@@ -681,7 +682,7 @@ function inferCppCallAdlArgs(callNode) {
|
|
|
681
682
|
}
|
|
682
683
|
return out;
|
|
683
684
|
}
|
|
684
|
-
const EMPTY_ADL_ARG = { simpleClassName: ''
|
|
685
|
+
const EMPTY_ADL_ARG = { simpleClassName: '' };
|
|
685
686
|
function classifyAdlArg(argNode) {
|
|
686
687
|
// Literals and primitive-shaped expressions never have associated namespaces.
|
|
687
688
|
if (argNode.type === 'number_literal' ||
|
|
@@ -727,24 +728,29 @@ function lookupAdlIdentifierType(identNode) {
|
|
|
727
728
|
continue;
|
|
728
729
|
// Unwrap declarator chain to find pointer/reference markers and the
|
|
729
730
|
// variable name. `init_declarator > pointer_declarator > identifier`
|
|
730
|
-
// means pointer-typed;
|
|
731
|
-
//
|
|
732
|
-
|
|
733
|
-
|
|
731
|
+
// means pointer-typed; repeated pointer wrappers still count as pointer
|
|
732
|
+
// typed; `init_declarator > reference_declarator > ...` (or
|
|
733
|
+
// `rvalue_reference_declarator`) means reference-typed; bare
|
|
734
|
+
// `init_declarator > identifier` is value.
|
|
735
|
+
// Function-pointer wrappers (`pointer_declarator > function_declarator`)
|
|
736
|
+
// must not contribute ADL associated namespaces.
|
|
737
|
+
let isFunctionPointer = false;
|
|
734
738
|
let inner = declarator;
|
|
735
739
|
let nameText = null;
|
|
736
740
|
let safety = 16; // bound walk depth defensively
|
|
737
741
|
while (safety-- > 0) {
|
|
738
742
|
if (inner.type === 'pointer_declarator') {
|
|
739
|
-
|
|
743
|
+
if (findFirstDescendantOfType(inner, 'function_declarator') !== null) {
|
|
744
|
+
isFunctionPointer = true;
|
|
745
|
+
break;
|
|
746
|
+
}
|
|
740
747
|
const next = inner.childForFieldName('declarator');
|
|
741
748
|
if (next === null)
|
|
742
749
|
break;
|
|
743
750
|
inner = next;
|
|
744
751
|
continue;
|
|
745
752
|
}
|
|
746
|
-
if (inner.type === 'reference_declarator') {
|
|
747
|
-
isReference = true;
|
|
753
|
+
if (inner.type === 'reference_declarator' || inner.type === 'rvalue_reference_declarator') {
|
|
748
754
|
// reference_declarator has a single child (the inner declarator).
|
|
749
755
|
let next = null;
|
|
750
756
|
for (let j = 0; j < inner.namedChildCount; j++) {
|
|
@@ -766,21 +772,25 @@ function lookupAdlIdentifierType(identNode) {
|
|
|
766
772
|
inner = next;
|
|
767
773
|
continue;
|
|
768
774
|
}
|
|
775
|
+
if (inner.type === 'function_declarator') {
|
|
776
|
+
isFunctionPointer = true;
|
|
777
|
+
break;
|
|
778
|
+
}
|
|
769
779
|
// Reached the leaf — usually `identifier`. Take its text.
|
|
770
780
|
nameText = inner.text;
|
|
771
781
|
break;
|
|
772
782
|
}
|
|
773
|
-
if (nameText !== varName)
|
|
783
|
+
if (isFunctionPointer || nameText !== varName)
|
|
774
784
|
continue;
|
|
775
785
|
const simpleClassName = extractAdlSimpleTypeName(typeNode);
|
|
776
|
-
return { simpleClassName
|
|
786
|
+
return { simpleClassName };
|
|
777
787
|
}
|
|
778
788
|
return EMPTY_ADL_ARG;
|
|
779
789
|
}
|
|
780
790
|
/** Extract the simple class-like type name from a `type:` field node.
|
|
781
|
-
* Returns '' for primitives, template specializations,
|
|
782
|
-
*
|
|
783
|
-
*
|
|
791
|
+
* Returns '' for primitives, template specializations, and any other
|
|
792
|
+
* unsupported type-only shape. Function pointers are filtered at the
|
|
793
|
+
* declarator level in `lookupAdlIdentifierType`. */
|
|
784
794
|
function extractAdlSimpleTypeName(typeNode) {
|
|
785
795
|
if (typeNode.type === 'primitive_type')
|
|
786
796
|
return '';
|
|
@@ -12,6 +12,7 @@ import { populateCppDependentBases, clearCppDependentBases, isCppDependentBaseMe
|
|
|
12
12
|
import { populateCppAssociatedNamespaces, clearCppAdlState, pickCppAdlCandidates, ADL_AMBIGUOUS, } from './adl.js';
|
|
13
13
|
import { clearCppInlineNamespaces, populateCppInlineNamespaceScopes, resolveCppQualifiedNamespaceMember, } from './inline-namespaces.js';
|
|
14
14
|
import { populateCppRangeBindings } from './range-bindings.js';
|
|
15
|
+
import { isOverloadAmbiguousAfterNormalization, narrowOverloadCandidates, } from '../../scope-resolution/passes/overload-narrowing.js';
|
|
15
16
|
/**
|
|
16
17
|
* C++ `ScopeResolver` registered in `SCOPE_RESOLVERS` and consumed by
|
|
17
18
|
* the generic `runScopeResolution` orchestrator (RFC #909 Ring 3).
|
|
@@ -145,6 +146,8 @@ export const cppScopeResolver = {
|
|
|
145
146
|
// for cross-file propagation and compound-receiver chain resolution.
|
|
146
147
|
// cppBindingScopeFor hoists @type-binding.return to Module scope.
|
|
147
148
|
hoistTypeBindingsToModule: true,
|
|
149
|
+
// Enable receiver-bound explicit-`this` fallback only for C++.
|
|
150
|
+
resolveThisViaEnclosingClass: true,
|
|
148
151
|
// The `isFileLocalDef` hook on the global free-call fallback names
|
|
149
152
|
// file-local linkage historically, but semantically gates "logically
|
|
150
153
|
// invisible cross-file" defs. C++ extends this to also reject class-
|
|
@@ -188,6 +191,34 @@ export const cppScopeResolver = {
|
|
|
188
191
|
// V1 limitation: only direct enclosing-namespace closure for value
|
|
189
192
|
// class-typed args; pointer/reference/template-spec args excluded.
|
|
190
193
|
resolveAdlCandidates: (site, callerParsed, scopes, parsedFiles) => {
|
|
194
|
+
// `using ns::name;` introduces `name` into ordinary unqualified lookup.
|
|
195
|
+
// For template-class method bodies, lexical scope walks can miss this
|
|
196
|
+
// named-using visibility; recover by resolving the imported namespace
|
|
197
|
+
// member directly when the local call name matches a named using import.
|
|
198
|
+
const usingNamedHits = [];
|
|
199
|
+
const seenUsing = new Set();
|
|
200
|
+
for (const imp of callerParsed.parsedImports) {
|
|
201
|
+
if (imp.kind !== 'named')
|
|
202
|
+
continue;
|
|
203
|
+
if (imp.localName !== site.name)
|
|
204
|
+
continue;
|
|
205
|
+
const member = resolveCppQualifiedNamespaceMember(imp.targetRaw, imp.importedName, parsedFiles, scopes);
|
|
206
|
+
if (member === undefined)
|
|
207
|
+
continue;
|
|
208
|
+
if (seenUsing.has(member.nodeId))
|
|
209
|
+
continue;
|
|
210
|
+
seenUsing.add(member.nodeId);
|
|
211
|
+
usingNamedHits.push(member);
|
|
212
|
+
}
|
|
213
|
+
if (usingNamedHits.length > 0) {
|
|
214
|
+
const narrowed = narrowOverloadCandidates(usingNamedHits, site.arity, site.argumentTypes);
|
|
215
|
+
if (isOverloadAmbiguousAfterNormalization(narrowed, site.arity))
|
|
216
|
+
return 'ambiguous';
|
|
217
|
+
if (narrowed.length === 1)
|
|
218
|
+
return narrowed[0];
|
|
219
|
+
if (narrowed.length > 1)
|
|
220
|
+
return 'ambiguous';
|
|
221
|
+
}
|
|
191
222
|
const result = pickCppAdlCandidates(site, callerParsed, scopes, parsedFiles);
|
|
192
223
|
if (result === ADL_AMBIGUOUS)
|
|
193
224
|
return 'ambiguous';
|
|
@@ -547,6 +547,17 @@ export interface ScopeResolver {
|
|
|
547
547
|
* remaining cases.
|
|
548
548
|
*/
|
|
549
549
|
readonly resolveQualifiedReceiverMember?: (receiverName: string, memberName: string, callerScope: ScopeId, scopes: ScopeResolutionIndexes, parsedFiles: readonly ParsedFile[]) => SymbolDefinition | undefined;
|
|
550
|
+
/**
|
|
551
|
+
* Enable the receiver-bound Case 0.5 fallback for explicit `this`
|
|
552
|
+
* receivers (`this->m()` / `this.m()`) that resolves against the
|
|
553
|
+
* enclosing class + MRO even when no explicit `this` typeBinding is
|
|
554
|
+
* present in scope.
|
|
555
|
+
*
|
|
556
|
+
* Keep disabled for languages where the existing type-binding path
|
|
557
|
+
* (Case 4) already handles `this` correctly and overload ambiguity
|
|
558
|
+
* suppression must remain unchanged.
|
|
559
|
+
*/
|
|
560
|
+
readonly resolveThisViaEnclosingClass?: boolean;
|
|
550
561
|
/**
|
|
551
562
|
* Optional post-finalize hook to inject cross-file bindings that
|
|
552
563
|
* aren't modeled via explicit imports. Runs after
|
|
@@ -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'>;
|
|
44
|
+
type ReceiverBoundProviderSubset = Pick<ScopeResolver, 'isSuperReceiver' | 'isSuperReceiverInContext' | 'fieldFallbackOnMethodLookup' | 'collapseMemberCallsByCallerTarget' | 'unwrapCollectionAccessor' | 'hoistTypeBindingsToModule' | 'resolveQualifiedReceiverMember' | 'resolveThisViaEnclosingClass'>;
|
|
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
|
|
@@ -232,6 +232,72 @@ export function emitReceiverBoundCalls(graph, scopes, parsedFiles, nodeLookup, h
|
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
|
+
// ── Case 0.5: implicit `this` receiver ───────────────────────
|
|
236
|
+
// C++ `this->member()` (and same-shape receivers in other OO
|
|
237
|
+
// languages) should resolve against the enclosing class + MRO
|
|
238
|
+
// even when there is no explicit `this` typeBinding in scope.
|
|
239
|
+
if (provider.resolveThisViaEnclosingClass === true && receiverName === 'this') {
|
|
240
|
+
const enclosingClass = findEnclosingClassDef(site.inScope, scopes);
|
|
241
|
+
if (enclosingClass !== undefined) {
|
|
242
|
+
const chain = [
|
|
243
|
+
enclosingClass.nodeId,
|
|
244
|
+
...scopes.methodDispatch.mroFor(enclosingClass.nodeId),
|
|
245
|
+
];
|
|
246
|
+
let memberDef;
|
|
247
|
+
let ambiguous = false;
|
|
248
|
+
let hiddenByName = false;
|
|
249
|
+
for (const ownerId of chain) {
|
|
250
|
+
const methodOverloads = model.methods.lookupAllByOwner(ownerId, memberName);
|
|
251
|
+
if (methodOverloads.length > 0) {
|
|
252
|
+
const narrowed = narrowOverloadCandidates(methodOverloads, site.arity, site.argumentTypes);
|
|
253
|
+
if (isOverloadAmbiguousAfterNormalization(narrowed, site.arity)) {
|
|
254
|
+
ambiguous = true;
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
if (narrowed.length === 0) {
|
|
258
|
+
// C++ name hiding: if the derived class declares `f`, base-class
|
|
259
|
+
// overloads named `f` are hidden for member lookup
|
|
260
|
+
// ([basic.lookup.classref]). A non-viable derived overload set
|
|
261
|
+
// therefore terminates lookup instead of falling through to base.
|
|
262
|
+
hiddenByName = true;
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
memberDef = narrowed[0] ?? methodOverloads[0];
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
// Field/property lookup intentionally runs only after the method
|
|
269
|
+
// lookup above: in C++ member-name lookup, functions with this
|
|
270
|
+
// name hide same-named base members; we therefore prefer method
|
|
271
|
+
// candidates first and only target a field when no methods with
|
|
272
|
+
// this name exist on the current owner.
|
|
273
|
+
memberDef = model.fields.lookupFieldByOwner(ownerId, memberName);
|
|
274
|
+
if (memberDef !== undefined) {
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (ambiguous) {
|
|
279
|
+
handledSites.add(siteKey);
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
if (hiddenByName) {
|
|
283
|
+
handledSites.add(siteKey);
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
if (memberDef !== undefined) {
|
|
287
|
+
const reason = site.kind === 'write' || site.kind === 'read'
|
|
288
|
+
? site.kind
|
|
289
|
+
: memberDef.filePath !== parsed.filePath
|
|
290
|
+
? 'import-resolved'
|
|
291
|
+
: 'global';
|
|
292
|
+
const confidence = site.kind === 'write' || site.kind === 'read' ? 1.0 : 0.85;
|
|
293
|
+
const ok = tryEmitEdge(graph, scopes, nodeLookup, site, memberDef, reason, seen, confidence, collapse);
|
|
294
|
+
if (ok)
|
|
295
|
+
emitted++;
|
|
296
|
+
handledSites.add(siteKey);
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
235
301
|
// ── Case 1: namespace receiver ───────────────────────────────
|
|
236
302
|
const targetFiles = namespaceTargets.get(receiverName);
|
|
237
303
|
if (targetFiles !== undefined) {
|
package/package.json
CHANGED