gitnexus 1.6.13-rc.18 → 1.6.13-rc.19
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 +1 -0
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/index.js.map +1 -1
- package/dist/_shared/scope-resolution/call-result-assignment-site.d.ts +14 -0
- package/dist/_shared/scope-resolution/call-result-assignment-site.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/call-result-assignment-site.js +2 -0
- package/dist/_shared/scope-resolution/call-result-assignment-site.js.map +1 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts +3 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
- package/dist/core/ingestion/languages/swift/captures.js +30 -2
- package/dist/core/ingestion/languages/swift/index.d.ts +1 -1
- package/dist/core/ingestion/languages/swift/index.js +1 -1
- package/dist/core/ingestion/languages/swift/interpret.d.ts +8 -0
- package/dist/core/ingestion/languages/swift/interpret.js +16 -1
- package/dist/core/ingestion/languages/swift/query.js +26 -0
- package/dist/core/ingestion/languages/swift/scope-resolver.d.ts +2 -1
- package/dist/core/ingestion/languages/swift/scope-resolver.js +90 -1
- package/dist/core/ingestion/scope-extractor.d.ts +7 -3
- package/dist/core/ingestion/scope-extractor.js +59 -13
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +5 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +10 -5
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +87 -14
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +11 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +109 -7
- package/dist/core/ingestion/scope-resolution/workspace-index-types.d.ts +6 -1
- package/dist/core/ingestion/scope-resolution/workspace-index.d.ts +3 -1
- package/dist/core/ingestion/scope-resolution/workspace-index.js +27 -2
- package/dist/storage/parse-cache.js +3 -1
- package/dist/storage/parsedfile-store.js +25 -2
- package/package.json +1 -1
package/dist/_shared/index.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export type { QualifiedNameIndex } from './scope-resolution/qualified-name-index
|
|
|
23
23
|
export { resolveTypeRef } from './scope-resolution/resolve-type-ref.js';
|
|
24
24
|
export type { ResolveTypeRefContext } from './scope-resolution/resolve-type-ref.js';
|
|
25
25
|
export type { ParsedFile } from './scope-resolution/parsed-file.js';
|
|
26
|
+
export type { CallResultAssignmentSite } from './scope-resolution/call-result-assignment-site.js';
|
|
26
27
|
export type { ReferenceSite, ReferenceKind, CallForm, MixedChainStep, } from './scope-resolution/reference-site.js';
|
|
27
28
|
export type { CallableFlowOperand, CallableFlowExpectedSignature, CallableFlowPassingMode, CallableFlowInvocationKind, CallableFlowSeedSite, CallableFlowCopySite, CallableFlowAliasSite, CallableFlowAddressSite, CallableFlowStoreSite, CallableFlowLoadSite, CallableFlowFormalSite, CallableFlowArgumentSite, CallableFlowInvokeSite, CallableFlowSite, } from './scope-resolution/callable-flow-site.js';
|
|
28
29
|
export { buildMethodDispatchIndex } from './scope-resolution/method-dispatch-index.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,mBAAmB;AACnB,OAAO,EACL,WAAW,EACX,cAAc,EACd,SAAS,EACT,oBAAoB,GACrB,MAAM,4BAA4B,CAAC;AAGpC,mBAAmB;AACnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EACL,uBAAuB,EACvB,6BAA6B,EAC7B,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AAGjC,sBAAsB;AACtB,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AA4C5E,8DAA8D;AAC9D,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AACnG,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AAGxE,yDAAyD;AACzD,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,+CAA+C,CAAC;AAGvD,sEAAsE;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAEhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AAEjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,4CAA4C,CAAC;AAGrF,gEAAgE;AAChE,yEAAyE;AACzE,2DAA2D;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,mBAAmB;AACnB,OAAO,EACL,WAAW,EACX,cAAc,EACd,SAAS,EACT,oBAAoB,GACrB,MAAM,4BAA4B,CAAC;AAGpC,mBAAmB;AACnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EACL,uBAAuB,EACvB,6BAA6B,EAC7B,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AAGjC,sBAAsB;AACtB,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AA4C5E,8DAA8D;AAC9D,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AACnG,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AAGxE,yDAAyD;AACzD,OAAO,EACL,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,+CAA+C,CAAC;AAGvD,sEAAsE;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAEhE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AAEjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,4CAA4C,CAAC;AAGrF,gEAAgE;AAChE,yEAAyE;AACzE,2DAA2D;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AA6BxE,oFAAoF;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,6CAA6C,CAAC;AAMvF,uEAAuE;AACvE,OAAO,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AAWpE,sEAAsE;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAErF,OAAO,EAAE,mBAAmB,EAAE,MAAM,kDAAkD,CAAC;AAKvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAKrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAErF,OAAO,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,mDAAmD,CAAC;AAEpF,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAEpG,OAAO,EACL,gCAAgC,EAChC,kBAAkB,GACnB,MAAM,6CAA6C,CAAC;AAErD,OAAO,EACL,WAAW,EACX,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,MAAM,0CAA0C,CAAC;AAUlD,2EAA2E;AAC3E,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAErF,OAAO,EACL,cAAc,EACd,cAAc,EACd,uBAAuB,GACxB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAG1E,8EAA8E;AAC9E,wEAAwE;AACxE,wEAAwE;AACxE,8DAA8D;AAC9D,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAEjG,OAAO,EACL,cAAc,EACd,4BAA4B,EAC5B,kBAAkB,EAClB,eAAe,EACf,sBAAsB,GACvB,MAAM,mCAAmC,CAAC;AAG3C,mDAAmD;AACnD,OAAO,EACL,+BAA+B,EAC/B,6BAA6B,EAC7B,4BAA4B,EAC5B,sBAAsB,EACtB,gBAAgB,EAChB,wBAAwB,EACxB,cAAc,GACf,MAAM,sCAAsC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Range, ScopeId } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Compact extraction-time identity for `lhs = callee()`.
|
|
4
|
+
*
|
|
5
|
+
* The call-site range uses the same call-expression anchor as reference
|
|
6
|
+
* resolution, allowing downstream passes to join this fact to the exact
|
|
7
|
+
* resolved callee id without relying on a possibly polluted type binding.
|
|
8
|
+
*/
|
|
9
|
+
export interface CallResultAssignmentSite {
|
|
10
|
+
readonly callSite: Range;
|
|
11
|
+
readonly inScope: ScopeId;
|
|
12
|
+
readonly lhs: string;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=call-result-assignment-site.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-result-assignment-site.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/call-result-assignment-site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-result-assignment-site.js","sourceRoot":"","sources":["../../src/scope-resolution/call-result-assignment-site.ts"],"names":[],"mappings":""}
|
|
@@ -55,6 +55,7 @@ import type { ParsedImport } from './types.js';
|
|
|
55
55
|
import type { SymbolDefinition } from './symbol-definition.js';
|
|
56
56
|
import type { ReferenceSite } from './reference-site.js';
|
|
57
57
|
import type { CallableFlowSite } from './callable-flow-site.js';
|
|
58
|
+
import type { CallResultAssignmentSite } from './call-result-assignment-site.js';
|
|
58
59
|
export interface ParsedFile {
|
|
59
60
|
readonly filePath: string;
|
|
60
61
|
/** `Scope.id` of the file's root `Module` scope. */
|
|
@@ -79,6 +80,8 @@ export interface ParsedFile {
|
|
|
79
80
|
* syntax remain source-compatible; consumers normalize absence to `[]`.
|
|
80
81
|
*/
|
|
81
82
|
readonly callableFlowSites?: readonly CallableFlowSite[];
|
|
83
|
+
/** Exact call-expression → assigned local identity for return-type replay. */
|
|
84
|
+
readonly callResultAssignmentSites?: readonly CallResultAssignmentSite[];
|
|
82
85
|
/**
|
|
83
86
|
* Opaque, language-private serialization of capture-time side-channel
|
|
84
87
|
* state that a provider's `emitScopeCaptures` populates into module-level
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parsed-file.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/parsed-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"parsed-file.d.ts","sourceRoot":"","sources":["../../src/scope-resolution/parsed-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAEjF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,oDAAoD;IACpD,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,SAAS,YAAY,EAAE,CAAC;IAChD;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAChD,QAAQ,CAAC,cAAc,EAAE,SAAS,aAAa,EAAE,CAAC;IAClD;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACzD,8EAA8E;IAC9E,QAAQ,CAAC,yBAAyB,CAAC,EAAE,SAAS,wBAAwB,EAAE,CAAC;IACzE;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAEtC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CACnC"}
|
|
@@ -37,6 +37,7 @@ import { swiftQualifiedBaseTail } from './base-type.js';
|
|
|
37
37
|
import { computeSwiftArityMetadata } from './arity-metadata.js';
|
|
38
38
|
import { findEnclosingTypeDeclaration, synthesizeSwiftReceiverBinding, } from './receiver-binding.js';
|
|
39
39
|
import { synthesizeSwiftSignatureBindings } from './signature-bindings.js';
|
|
40
|
+
import { swiftMethodConfig } from '../../method-extractors/configs/swift.js';
|
|
40
41
|
import { getSwiftParser, getSwiftScopeQuery } from './query.js';
|
|
41
42
|
import { preprocessSwiftConditionalDirectives } from './conditional-directive-preprocess.js';
|
|
42
43
|
import { recordCacheHit, recordCacheMiss } from './cache-stats.js';
|
|
@@ -174,6 +175,23 @@ export function emitSwiftScopeCaptures(sourceText, _filePath, cachedTree) {
|
|
|
174
175
|
}
|
|
175
176
|
continue;
|
|
176
177
|
}
|
|
178
|
+
// The query deliberately recognizes the compact `lhs = call()` shape;
|
|
179
|
+
// enforce "untyped lhs" here because tree-sitter queries cannot express
|
|
180
|
+
// absence of Swift's sibling type_annotation robustly. A typed declaration
|
|
181
|
+
// remains authoritative and must never enter return-type replay.
|
|
182
|
+
if (grouped['@call-result-assignment.call'] !== undefined) {
|
|
183
|
+
const callNode = nodeIfType(nodeMap['@call-result-assignment.call'], 'call_expression');
|
|
184
|
+
let property = callNode?.parent;
|
|
185
|
+
while (property?.type === 'await_expression' || property?.type === 'try_expression') {
|
|
186
|
+
property = property.parent;
|
|
187
|
+
}
|
|
188
|
+
if (property?.type !== 'property_declaration' ||
|
|
189
|
+
property.namedChildren.some((child) => child.type === 'type_annotation')) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
out.push(grouped);
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
177
195
|
// ── Field accesses: a `navigation_expression` (`obj.field`) is one of
|
|
178
196
|
// three things. Drop it when it's a call's callee (`u.save` in
|
|
179
197
|
// `u.save()` — the @reference.call.member query already covers that).
|
|
@@ -279,8 +297,13 @@ export function emitSwiftScopeCaptures(sourceText, _filePath, cachedTree) {
|
|
|
279
297
|
const fnNodeForArity = nodeIfType(nodeMap['@scope.function'] ??
|
|
280
298
|
nodeMap['@declaration.method'] ??
|
|
281
299
|
nodeMap['@declaration.constructor'], ...FUNCTION_NODE_TYPES);
|
|
282
|
-
if (fnNodeForArity !== null)
|
|
300
|
+
if (fnNodeForArity !== null) {
|
|
283
301
|
attachArityMetadata(grouped, fnNodeForArity);
|
|
302
|
+
const returnType = swiftMethodConfig.extractReturnType?.(fnNodeForArity);
|
|
303
|
+
if (returnType !== undefined && returnType !== '') {
|
|
304
|
+
grouped['@declaration.return-type'] = syntheticCapture('@declaration.return-type', fnNodeForArity, returnType);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
284
307
|
// Structural receiver chain for a call whose receiver is itself an
|
|
285
308
|
// expression, so resolution can type it by folding over structure
|
|
286
309
|
// instead of re-parsing the receiver's source text. Self-gating: a
|
|
@@ -304,8 +327,13 @@ export function emitSwiftScopeCaptures(sourceText, _filePath, cachedTree) {
|
|
|
304
327
|
const declTag = FUNCTION_DECL_TAGS.find((t) => grouped[t] !== undefined);
|
|
305
328
|
if (declTag !== undefined) {
|
|
306
329
|
const fnNode = nodeIfType(nodeMap[declTag], ...FUNCTION_NODE_TYPES);
|
|
307
|
-
if (fnNode !== null)
|
|
330
|
+
if (fnNode !== null) {
|
|
308
331
|
attachArityMetadata(grouped, fnNode);
|
|
332
|
+
const returnType = swiftMethodConfig.extractReturnType?.(fnNode);
|
|
333
|
+
if (returnType !== undefined && returnType !== '') {
|
|
334
|
+
grouped['@declaration.return-type'] = syntheticCapture('@declaration.return-type', fnNode, returnType);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
309
337
|
}
|
|
310
338
|
// ── Constructor calls: Swift has no `new`, so `Foo()` is a free call
|
|
311
339
|
// whose callee is a type. Re-tag an UpperCamelCase free-call callee as
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
*/
|
|
27
27
|
export { emitSwiftScopeCaptures } from './captures.js';
|
|
28
28
|
export { getSwiftCaptureCacheStats, resetSwiftCaptureCacheStats } from './cache-stats.js';
|
|
29
|
-
export { interpretSwiftImport, interpretSwiftTypeBinding } from './interpret.js';
|
|
29
|
+
export { interpretSwiftImport, interpretSwiftTypeBinding, normalizeSwiftTypeName, stripSwiftTypePreservingDecoration, } from './interpret.js';
|
|
30
30
|
export { swiftMergeBindings } from './merge-bindings.js';
|
|
31
31
|
export { swiftArityCompatibility } from './arity.js';
|
|
32
32
|
export { resolveSwiftImportTarget, type SwiftResolveContext } from './import-target.js';
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
*/
|
|
27
27
|
export { emitSwiftScopeCaptures } from './captures.js';
|
|
28
28
|
export { getSwiftCaptureCacheStats, resetSwiftCaptureCacheStats } from './cache-stats.js';
|
|
29
|
-
export { interpretSwiftImport, interpretSwiftTypeBinding } from './interpret.js';
|
|
29
|
+
export { interpretSwiftImport, interpretSwiftTypeBinding, normalizeSwiftTypeName, stripSwiftTypePreservingDecoration, } from './interpret.js';
|
|
30
30
|
export { swiftMergeBindings } from './merge-bindings.js';
|
|
31
31
|
export { swiftArityCompatibility } from './arity.js';
|
|
32
32
|
export { resolveSwiftImportTarget } from './import-target.js';
|
|
@@ -13,3 +13,11 @@
|
|
|
13
13
|
import type { CaptureMatch, ParsedImport, ParsedTypeBinding } from '../../../../_shared/index.js';
|
|
14
14
|
export declare function interpretSwiftImport(captures: CaptureMatch): ParsedImport | null;
|
|
15
15
|
export declare function interpretSwiftTypeBinding(captures: CaptureMatch): ParsedTypeBinding | null;
|
|
16
|
+
export declare function normalizeSwiftTypeName(text: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Type-preserving decoration only — used by `stripTypePreservingDecoration`
|
|
19
|
+
* for class lookup and declared-return replay. `User?` / `User!` → `User`.
|
|
20
|
+
* Arrays, generics, and nested `Foo.Bar` are left intact so a binding used
|
|
21
|
+
* for member lookup does not follow the element type or the trailing ident.
|
|
22
|
+
*/
|
|
23
|
+
export declare function stripSwiftTypePreservingDecoration(typeName: string): string | undefined;
|
|
@@ -40,7 +40,7 @@ export function interpretSwiftTypeBinding(captures) {
|
|
|
40
40
|
// `[User]` → User (array sugar)
|
|
41
41
|
// `Array<User>` / `Optional<User>` → User (single-arg generic)
|
|
42
42
|
// `Foundation.URL` → URL (qualifier)
|
|
43
|
-
const rawType =
|
|
43
|
+
const rawType = normalizeSwiftTypeName(typeCap.text);
|
|
44
44
|
let source = 'parameter-annotation';
|
|
45
45
|
if (captures['@type-binding.self'] !== undefined)
|
|
46
46
|
source = 'self';
|
|
@@ -54,6 +54,21 @@ export function interpretSwiftTypeBinding(captures) {
|
|
|
54
54
|
source = 'return-annotation';
|
|
55
55
|
return { boundName: nameCap.text, rawTypeName: rawType, source };
|
|
56
56
|
}
|
|
57
|
+
export function normalizeSwiftTypeName(text) {
|
|
58
|
+
return stripQualifier(stripGeneric(stripArraySugar(stripOptional(text.trim()))));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Type-preserving decoration only — used by `stripTypePreservingDecoration`
|
|
62
|
+
* for class lookup and declared-return replay. `User?` / `User!` → `User`.
|
|
63
|
+
* Arrays, generics, and nested `Foo.Bar` are left intact so a binding used
|
|
64
|
+
* for member lookup does not follow the element type or the trailing ident.
|
|
65
|
+
*/
|
|
66
|
+
export function stripSwiftTypePreservingDecoration(typeName) {
|
|
67
|
+
const trimmed = typeName.trim();
|
|
68
|
+
if (trimmed.endsWith('?') || trimmed.endsWith('!'))
|
|
69
|
+
return trimmed.slice(0, -1).trim();
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
57
72
|
/** `User?` / `User!` → `User`. */
|
|
58
73
|
function stripOptional(text) {
|
|
59
74
|
if (text.endsWith('?') || text.endsWith('!'))
|
|
@@ -186,6 +186,32 @@ const SWIFT_SCOPE_QUERY = `
|
|
|
186
186
|
(call_expression
|
|
187
187
|
(simple_identifier) @reference.name) @reference.call.free
|
|
188
188
|
|
|
189
|
+
;; Exact identity for \`let lhs = callee()\`. The call-expression anchor is
|
|
190
|
+
;; byte-identical to @reference.call.free / member for downstream position join.
|
|
191
|
+
(property_declaration
|
|
192
|
+
name: (pattern
|
|
193
|
+
bound_identifier: (simple_identifier) @call-result-assignment.lhs)
|
|
194
|
+
value: (call_expression) @call-result-assignment.call)
|
|
195
|
+
|
|
196
|
+
(property_declaration
|
|
197
|
+
name: (pattern
|
|
198
|
+
bound_identifier: (simple_identifier) @call-result-assignment.lhs)
|
|
199
|
+
value: (await_expression
|
|
200
|
+
(call_expression) @call-result-assignment.call))
|
|
201
|
+
|
|
202
|
+
(property_declaration
|
|
203
|
+
name: (pattern
|
|
204
|
+
bound_identifier: (simple_identifier) @call-result-assignment.lhs)
|
|
205
|
+
value: (try_expression
|
|
206
|
+
(call_expression) @call-result-assignment.call))
|
|
207
|
+
|
|
208
|
+
(property_declaration
|
|
209
|
+
name: (pattern
|
|
210
|
+
bound_identifier: (simple_identifier) @call-result-assignment.lhs)
|
|
211
|
+
value: (try_expression
|
|
212
|
+
(await_expression
|
|
213
|
+
(call_expression) @call-result-assignment.call)))
|
|
214
|
+
|
|
189
215
|
;; ── References — member / method calls: \`obj.method(...)\` ───────────
|
|
190
216
|
;; navigation_expression carries the receiver (target:) and the member
|
|
191
217
|
;; (suffix > navigation_suffix > simple_identifier). \`self\` is a
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
* re-keys an `extension Foo { … }` to a `class_declaration`-style def
|
|
15
15
|
* named `Foo`, so its members land on `Foo`'s scope and the shared
|
|
16
16
|
* `populateClassOwnedMembers` stamps them with `Foo`'s ownerId — the
|
|
17
|
-
* same mechanism C# uses for `partial class`.
|
|
17
|
+
* same mechanism C# uses for `partial class`. Cross-file extensions
|
|
18
|
+
* that mint no type def are reconciled by `populateWorkspaceOwners`.
|
|
18
19
|
* - **Labeled arguments** narrow by ARITY only (count-primary, labels
|
|
19
20
|
* soft) — see `arity.ts`. Label-precise dispatch is deferred to the
|
|
20
21
|
* type-binding layer.
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
* re-keys an `extension Foo { … }` to a `class_declaration`-style def
|
|
15
15
|
* named `Foo`, so its members land on `Foo`'s scope and the shared
|
|
16
16
|
* `populateClassOwnedMembers` stamps them with `Foo`'s ownerId — the
|
|
17
|
-
* same mechanism C# uses for `partial class`.
|
|
17
|
+
* same mechanism C# uses for `partial class`. Cross-file extensions
|
|
18
|
+
* that mint no type def are reconciled by `populateWorkspaceOwners`.
|
|
18
19
|
* - **Labeled arguments** narrow by ARITY only (count-primary, labels
|
|
19
20
|
* soft) — see `arity.ts`. Label-precise dispatch is deferred to the
|
|
20
21
|
* type-binding layer.
|
|
@@ -52,6 +53,8 @@ import { populateClassOwnedMembers, isClassLike } from '../../scope-resolution/s
|
|
|
52
53
|
import { resolveDefGraphId } from '../../scope-resolution/graph-bridge/ids.js';
|
|
53
54
|
import { swiftProvider } from '../swift.js';
|
|
54
55
|
import { swiftArityCompatibility, swiftMergeBindings, interpretSwiftImport, resolveSwiftImportTarget, populateSwiftTargetSiblings, emitSwiftImplicitImportEdges, mirrorSwiftSiblingTypeBindings, } from './index.js';
|
|
56
|
+
import { stripSwiftTypePreservingDecoration } from './interpret.js';
|
|
57
|
+
import { coerceSwiftTargets, groupSwiftFilesBySpmTarget } from './target-grouping.js';
|
|
55
58
|
import { swiftIsGlobalNameFallbackPlausible } from './name-fallback-visibility.js';
|
|
56
59
|
const ZERO_RANGE = { startLine: 0, startCol: 0, endLine: 0, endCol: 0 };
|
|
57
60
|
const swiftScopeResolver = {
|
|
@@ -77,11 +80,19 @@ const swiftScopeResolver = {
|
|
|
77
80
|
// Adapter: swiftArityCompatibility uses (def, callsite); contract is (callsite, def).
|
|
78
81
|
arityCompatibility: (callsite, def) => swiftArityCompatibility(def, callsite),
|
|
79
82
|
buildMro: (graph, parsedFiles, nodeLookup) => buildSwiftMro(graph, parsedFiles, nodeLookup),
|
|
83
|
+
implicitThisWalksMro: true,
|
|
84
|
+
stripTypePreservingDecoration: stripSwiftTypePreservingDecoration,
|
|
80
85
|
// Methods/properties/init are owned by their enclosing class/struct/
|
|
81
86
|
// extension(→extended type)/protocol. Extension members hoist for free
|
|
82
87
|
// because captures.ts re-keys the extension to a Class def named after
|
|
83
88
|
// the extended type.
|
|
84
89
|
populateOwners: (parsed) => populateClassOwnedMembers(parsed),
|
|
90
|
+
// An extension has its own Class scope but deliberately does not mint a
|
|
91
|
+
// second type def. Its members therefore leave the per-file owner walk with
|
|
92
|
+
// a qualified name (`ExtendedType.member`) but no ownerId. Reconcile those
|
|
93
|
+
// members after all files are available so extensions declared in sibling
|
|
94
|
+
// files work as well as extensions beside the original type.
|
|
95
|
+
populateWorkspaceOwners: populateSwiftExtensionOwners,
|
|
85
96
|
// `super.method()` dispatches through the superclass chain.
|
|
86
97
|
isSuperReceiver: (text) => text.trim() === 'super',
|
|
87
98
|
// Whole-module same-target visibility without `import`.
|
|
@@ -172,6 +183,84 @@ function buildSwiftMro(graph, parsedFiles, nodeLookup) {
|
|
|
172
183
|
}
|
|
173
184
|
return mro;
|
|
174
185
|
}
|
|
186
|
+
function populateSwiftExtensionOwners(parsedFiles, ctx) {
|
|
187
|
+
const filesByTarget = groupSwiftFilesBySpmTarget(parsedFiles, (parsed) => parsed.filePath, coerceSwiftTargets(ctx?.resolutionConfig));
|
|
188
|
+
for (const files of filesByTarget.values()) {
|
|
189
|
+
stampSwiftExtensionOwnersInTarget(files);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function stampSwiftExtensionOwnersInTarget(parsedFiles) {
|
|
193
|
+
const ownersByName = new Map();
|
|
194
|
+
for (const parsed of parsedFiles) {
|
|
195
|
+
for (const def of parsed.localDefs) {
|
|
196
|
+
if (!isClassLike(def.type) || def.qualifiedName === undefined)
|
|
197
|
+
continue;
|
|
198
|
+
const bucket = ownersByName.get(def.qualifiedName);
|
|
199
|
+
if (bucket === undefined)
|
|
200
|
+
ownersByName.set(def.qualifiedName, [def]);
|
|
201
|
+
else
|
|
202
|
+
bucket.push(def);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Extension members are Function-owned defs whose parent Class minted no
|
|
206
|
+
// type def. Nested locals are Function-owned defs whose parent is another
|
|
207
|
+
// Function — leave those ownerless so they cannot enter implicit-self CALLS.
|
|
208
|
+
for (const parsed of parsedFiles) {
|
|
209
|
+
const byId = new Map(parsed.scopes.map((scope) => [scope.id, scope]));
|
|
210
|
+
for (const scope of parsed.scopes) {
|
|
211
|
+
if (scope.kind !== 'Function')
|
|
212
|
+
continue;
|
|
213
|
+
const parent = scope.parent === null ? undefined : byId.get(scope.parent);
|
|
214
|
+
if (parent?.kind !== 'Class')
|
|
215
|
+
continue;
|
|
216
|
+
// A type-decl Class owns the type that opened it (same start line).
|
|
217
|
+
// Nested types inside an `extension` are also class-like and live on
|
|
218
|
+
// that Class scope — they are not the extended type, so they must
|
|
219
|
+
// not suppress stamping `func added` onto `Foo`.
|
|
220
|
+
if (parent.ownedDefs.some((d) => isClassLike(d.type) && defDeclaresThisClassScope(parent, d)))
|
|
221
|
+
continue;
|
|
222
|
+
for (const def of scope.ownedDefs) {
|
|
223
|
+
if (def.ownerId !== undefined || def.qualifiedName === undefined)
|
|
224
|
+
continue;
|
|
225
|
+
const dot = def.qualifiedName.lastIndexOf('.');
|
|
226
|
+
if (dot <= 0)
|
|
227
|
+
continue;
|
|
228
|
+
const owner = uniqueOwnerForExtensionPrefix(ownersByName, def.qualifiedName.slice(0, dot));
|
|
229
|
+
if (owner !== undefined) {
|
|
230
|
+
def.ownerId = owner.nodeId;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function defDeclaresThisClassScope(parent, def) {
|
|
237
|
+
const line = /#(\d+):/.exec(def.nodeId);
|
|
238
|
+
if (line === null)
|
|
239
|
+
return true;
|
|
240
|
+
return Number(line[1]) === parent.range.startLine;
|
|
241
|
+
}
|
|
242
|
+
function uniqueOwnerForExtensionPrefix(ownersByName, prefix) {
|
|
243
|
+
const seen = new Set();
|
|
244
|
+
const matches = [];
|
|
245
|
+
const consider = (defs) => {
|
|
246
|
+
if (defs === undefined)
|
|
247
|
+
return;
|
|
248
|
+
for (const def of defs) {
|
|
249
|
+
if (seen.has(def.nodeId))
|
|
250
|
+
continue;
|
|
251
|
+
seen.add(def.nodeId);
|
|
252
|
+
matches.push(def);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
consider(ownersByName.get(prefix));
|
|
256
|
+
if (!prefix.includes('.')) {
|
|
257
|
+
for (const [qn, defs] of ownersByName) {
|
|
258
|
+
if (qn !== prefix && qn.endsWith('.' + prefix))
|
|
259
|
+
consider(defs);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return matches.length === 1 ? matches[0] : undefined;
|
|
263
|
+
}
|
|
175
264
|
function closeProtocols(seeds, directImpls) {
|
|
176
265
|
const out = [];
|
|
177
266
|
const seen = new Set();
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* (RFC §5.3 + §3.2 Phase 1; Ring 2 PKG #919).
|
|
5
5
|
*
|
|
6
6
|
* Exactly one entry point: `extract(matches, filePath, provider) → ParsedFile`.
|
|
7
|
-
* Runs a
|
|
7
|
+
* Runs a seven-pass pipeline over the matches. Each pass is internal; the
|
|
8
8
|
* public contract is the output `ParsedFile`.
|
|
9
9
|
*
|
|
10
10
|
* ## Design principles
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* don't overlap) are enforced by `buildScopeTree` from Ring 2 SHARED
|
|
23
23
|
* (#912). Malformed inputs throw `ScopeTreeInvariantError`.
|
|
24
24
|
*
|
|
25
|
-
* ## The
|
|
25
|
+
* ## The seven passes
|
|
26
26
|
*
|
|
27
27
|
* 1. **Build scope tree.** Walk `@scope.*` matches. For each, consult
|
|
28
28
|
* `provider.resolveScopeKind` (default: suffix of the capture name).
|
|
@@ -60,6 +60,10 @@
|
|
|
60
60
|
* one `ReferenceSite` per match. Classify call form via
|
|
61
61
|
* `provider.classifyCallForm` (default: the capture's sub-tag if
|
|
62
62
|
* present; else `'free'`).
|
|
63
|
+
* 6. **Collect callable-value-flow facts.** Independent of Pass 5 so
|
|
64
|
+
* existing reference-site extraction stays byte-identical.
|
|
65
|
+
* 7. **Preserve call-result assignment identity.** Untyped
|
|
66
|
+
* `let lhs = call()` facts used by exact-callee return-type replay.
|
|
63
67
|
*
|
|
64
68
|
* ## What gets attached where
|
|
65
69
|
*
|
|
@@ -90,7 +94,7 @@ import type { LanguageProvider } from './language-provider.js';
|
|
|
90
94
|
*/
|
|
91
95
|
export type ScopeExtractorHooks = Pick<LanguageProvider, 'resolveScopeKind' | 'scopeOwnsReceivers' | 'bindingScopeFor' | 'interpretImport' | 'importsExecuteWhereWritten' | 'interpretTypeBinding' | 'classifyCallForm'>;
|
|
92
96
|
/**
|
|
93
|
-
* Drive the
|
|
97
|
+
* Drive the seven extraction passes and return a `ParsedFile`.
|
|
94
98
|
*
|
|
95
99
|
* Throws `ScopeTreeInvariantError` (from #912) when the provider emits
|
|
96
100
|
* captures that violate structural scope invariants (e.g., overlapping
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* (RFC §5.3 + §3.2 Phase 1; Ring 2 PKG #919).
|
|
5
5
|
*
|
|
6
6
|
* Exactly one entry point: `extract(matches, filePath, provider) → ParsedFile`.
|
|
7
|
-
* Runs a
|
|
7
|
+
* Runs a seven-pass pipeline over the matches. Each pass is internal; the
|
|
8
8
|
* public contract is the output `ParsedFile`.
|
|
9
9
|
*
|
|
10
10
|
* ## Design principles
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* don't overlap) are enforced by `buildScopeTree` from Ring 2 SHARED
|
|
23
23
|
* (#912). Malformed inputs throw `ScopeTreeInvariantError`.
|
|
24
24
|
*
|
|
25
|
-
* ## The
|
|
25
|
+
* ## The seven passes
|
|
26
26
|
*
|
|
27
27
|
* 1. **Build scope tree.** Walk `@scope.*` matches. For each, consult
|
|
28
28
|
* `provider.resolveScopeKind` (default: suffix of the capture name).
|
|
@@ -60,6 +60,10 @@
|
|
|
60
60
|
* one `ReferenceSite` per match. Classify call form via
|
|
61
61
|
* `provider.classifyCallForm` (default: the capture's sub-tag if
|
|
62
62
|
* present; else `'free'`).
|
|
63
|
+
* 6. **Collect callable-value-flow facts.** Independent of Pass 5 so
|
|
64
|
+
* existing reference-site extraction stays byte-identical.
|
|
65
|
+
* 7. **Preserve call-result assignment identity.** Untyped
|
|
66
|
+
* `let lhs = call()` facts used by exact-callee return-type replay.
|
|
63
67
|
*
|
|
64
68
|
* ## What gets attached where
|
|
65
69
|
*
|
|
@@ -79,7 +83,7 @@ import { extractTemplateArguments, stripTrailingCallSuffix, typeApplicationArgum
|
|
|
79
83
|
import { parseTypeParameterList } from './utils/type-parameters.js';
|
|
80
84
|
// ─── Public entry point ─────────────────────────────────────────────────────
|
|
81
85
|
/**
|
|
82
|
-
* Drive the
|
|
86
|
+
* Drive the seven extraction passes and return a `ParsedFile`.
|
|
83
87
|
*
|
|
84
88
|
* Throws `ScopeTreeInvariantError` (from #912) when the provider emits
|
|
85
89
|
* captures that violate structural scope invariants (e.g., overlapping
|
|
@@ -137,6 +141,9 @@ export function extract(matches, filePath, provider) {
|
|
|
137
141
|
// extraction remains byte-identical.
|
|
138
142
|
const callableFlowSites = [];
|
|
139
143
|
pass6CollectCallableFlows(partitioned.callableFlow, positionIndex, filePath, callableFlowSites);
|
|
144
|
+
// ── Pass 7: preserve call-result assignment identity ───────────────
|
|
145
|
+
const callResultAssignmentSites = [];
|
|
146
|
+
pass7CollectCallResultAssignments(partitioned.callResultAssignment, positionIndex, filePath, callResultAssignmentSites);
|
|
140
147
|
// Freeze Scope drafts into final shape and return.
|
|
141
148
|
const frozenScopes = scopeDrafts.map(draftToScope);
|
|
142
149
|
return Object.freeze({
|
|
@@ -149,6 +156,9 @@ export function extract(matches, filePath, provider) {
|
|
|
149
156
|
...(callableFlowSites.length > 0
|
|
150
157
|
? { callableFlowSites: Object.freeze(callableFlowSites.slice()) }
|
|
151
158
|
: {}),
|
|
159
|
+
...(callResultAssignmentSites.length > 0
|
|
160
|
+
? { callResultAssignmentSites: Object.freeze(callResultAssignmentSites.slice()) }
|
|
161
|
+
: {}),
|
|
152
162
|
});
|
|
153
163
|
}
|
|
154
164
|
/**
|
|
@@ -168,6 +178,7 @@ function partitionByTopic(matches) {
|
|
|
168
178
|
const typeBinding = [];
|
|
169
179
|
const reference = [];
|
|
170
180
|
const callableFlow = [];
|
|
181
|
+
const callResultAssignment = [];
|
|
171
182
|
for (const match of matches) {
|
|
172
183
|
for (const topic of topicsOf(match)) {
|
|
173
184
|
switch (topic) {
|
|
@@ -189,10 +200,21 @@ function partitionByTopic(matches) {
|
|
|
189
200
|
case 'callable-flow':
|
|
190
201
|
callableFlow.push(match);
|
|
191
202
|
break;
|
|
203
|
+
case 'call-result-assignment':
|
|
204
|
+
callResultAssignment.push(match);
|
|
205
|
+
break;
|
|
192
206
|
}
|
|
193
207
|
}
|
|
194
208
|
}
|
|
195
|
-
return {
|
|
209
|
+
return {
|
|
210
|
+
scope,
|
|
211
|
+
declaration,
|
|
212
|
+
import_,
|
|
213
|
+
typeBinding,
|
|
214
|
+
reference,
|
|
215
|
+
callableFlow,
|
|
216
|
+
callResultAssignment,
|
|
217
|
+
};
|
|
196
218
|
}
|
|
197
219
|
function topicsOf(match) {
|
|
198
220
|
const topics = new Set();
|
|
@@ -209,6 +231,8 @@ function topicsOf(match) {
|
|
|
209
231
|
topics.add('reference');
|
|
210
232
|
else if (name.startsWith('@callable-flow.'))
|
|
211
233
|
topics.add('callable-flow');
|
|
234
|
+
else if (name.startsWith('@call-result-assignment.'))
|
|
235
|
+
topics.add('call-result-assignment');
|
|
212
236
|
}
|
|
213
237
|
return topics;
|
|
214
238
|
}
|
|
@@ -396,19 +420,28 @@ function pass2AttachDeclarations(matches, drafts, positionIndex, localDefs, file
|
|
|
396
420
|
// fact is the failure mode this subsystem rejects everywhere else.
|
|
397
421
|
//
|
|
398
422
|
// Copying the field onto BOTH twins makes the outcome identical whichever
|
|
399
|
-
// one wins. Deliberately narrow — only
|
|
400
|
-
//
|
|
401
|
-
// change what every existing duplicate
|
|
402
|
-
// change with a different blast radius
|
|
423
|
+
// one wins. Deliberately narrow — only metadata whose asymmetric twins have
|
|
424
|
+
// executable regressions (`typeParameters` and `returnType`). Widening this
|
|
425
|
+
// to "merge all metadata" would change what every existing duplicate
|
|
426
|
+
// resolves to, which is a different change with a different blast radius
|
|
427
|
+
// and no evidence behind it yet.
|
|
403
428
|
const first = firstDefByNodeId.get(def.nodeId);
|
|
404
429
|
if (first === undefined) {
|
|
405
430
|
firstDefByNodeId.set(def.nodeId, def);
|
|
406
431
|
}
|
|
407
|
-
else
|
|
408
|
-
first.typeParameters
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
def.typeParameters
|
|
432
|
+
else {
|
|
433
|
+
if (first.typeParameters === undefined && def.typeParameters !== undefined) {
|
|
434
|
+
first.typeParameters = def.typeParameters;
|
|
435
|
+
}
|
|
436
|
+
else if (def.typeParameters === undefined && first.typeParameters !== undefined) {
|
|
437
|
+
def.typeParameters = first.typeParameters;
|
|
438
|
+
}
|
|
439
|
+
if (first.returnType === undefined && def.returnType !== undefined) {
|
|
440
|
+
first.returnType = def.returnType;
|
|
441
|
+
}
|
|
442
|
+
else if (def.returnType === undefined && first.returnType !== undefined) {
|
|
443
|
+
def.returnType = first.returnType;
|
|
444
|
+
}
|
|
412
445
|
}
|
|
413
446
|
// Find the innermost scope that contains the declaration's anchor range.
|
|
414
447
|
const innermostId = positionIndex.atPosition(filePath, anchor.range.startLine, anchor.range.startCol);
|
|
@@ -1343,6 +1376,19 @@ function pass6CollectCallableFlows(matches, positionIndex, filePath, out) {
|
|
|
1343
1376
|
}
|
|
1344
1377
|
}
|
|
1345
1378
|
}
|
|
1379
|
+
// ─── Pass 7: collect call-result assignment identity ──────────────────────
|
|
1380
|
+
function pass7CollectCallResultAssignments(matches, positionIndex, filePath, out) {
|
|
1381
|
+
for (const match of matches) {
|
|
1382
|
+
const call = match['@call-result-assignment.call'];
|
|
1383
|
+
const lhs = match['@call-result-assignment.lhs'];
|
|
1384
|
+
if (call === undefined || lhs === undefined || !nonEmpty(lhs.text))
|
|
1385
|
+
continue;
|
|
1386
|
+
const inScope = positionIndex.atPosition(filePath, call.range.startLine, call.range.startCol);
|
|
1387
|
+
if (inScope === undefined)
|
|
1388
|
+
continue;
|
|
1389
|
+
out.push({ callSite: call.range, inScope, lhs: lhs.text });
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1346
1392
|
function callableFlowKind(match) {
|
|
1347
1393
|
return CALLABLE_FLOW_KINDS.find((kind) => match[`@callable-flow.${kind}`] !== undefined);
|
|
1348
1394
|
}
|
|
@@ -612,6 +612,7 @@ export interface ScopeResolver {
|
|
|
612
612
|
*/
|
|
613
613
|
readonly populateWorkspaceOwners?: (parsedFiles: readonly ParsedFile[], ctx: {
|
|
614
614
|
readonly fileContents: ReadonlyMap<string, string>;
|
|
615
|
+
readonly resolutionConfig?: unknown;
|
|
615
616
|
}) => void;
|
|
616
617
|
/**
|
|
617
618
|
* Optional workspace-wide enrichment of extracted reference sites. Runs
|
|
@@ -862,6 +863,10 @@ export interface ScopeResolver {
|
|
|
862
863
|
* regression).
|
|
863
864
|
*/
|
|
864
865
|
readonly freeCallsRequireInstanceOwnership?: boolean;
|
|
866
|
+
/** Whether an unqualified call inside a type may dispatch to an inherited
|
|
867
|
+
* instance method. Languages such as Swift allow implicit-self lookup,
|
|
868
|
+
* while Python/JavaScript/PHP require an explicit receiver. */
|
|
869
|
+
readonly implicitThisWalksMro?: boolean;
|
|
865
870
|
/**
|
|
866
871
|
* When true, a constructor-form call `Type(...)` links to the Class def
|
|
867
872
|
* itself rather than its explicit Constructor def. Default
|
|
@@ -82,6 +82,7 @@ export declare function emitFreeCallFallback(graph: KnowledgeGraph, scopes: Scop
|
|
|
82
82
|
* contains the method's owner. See
|
|
83
83
|
* `ScopeResolver.freeCallsRequireInstanceOwnership`. */
|
|
84
84
|
readonly freeCallsRequireInstanceOwnership?: boolean;
|
|
85
|
+
readonly implicitThisWalksMro?: boolean;
|
|
85
86
|
readonly recordResolutionOutcome?: ResolutionOutcomeRecorder;
|
|
86
87
|
/** Call sites owned by a later precise pass (for example callable-value-flow). */
|
|
87
88
|
readonly skipSites?: ReadonlySet<string>;
|
|
@@ -164,11 +165,14 @@ export declare function pickUniqueGlobalClass(name: string, index: ReadonlyMap<s
|
|
|
164
165
|
* pick a method member by name with overload narrowing on arity +
|
|
165
166
|
* argument types. Returns undefined if there's no enclosing class,
|
|
166
167
|
* no matching method, OR narrowing leaves multiple compatible
|
|
167
|
-
* candidates —
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
168
|
+
* candidates — except when those survivors are a protocol/interface
|
|
169
|
+
* requirement plus exactly one extension witness, in which case the
|
|
170
|
+
* witness (the default body) is returned. An inherited class, struct,
|
|
171
|
+
* or enum member still wins over a protocol-extension default.
|
|
172
|
+
* Picking `candidates[0]` would emit a high-confidence CALLS edge
|
|
173
|
+
* whose target depends on registration order rather than a
|
|
174
|
+
* defensible resolution. Mirrors `pickUniqueGlobalCallable`'s
|
|
175
|
+
* uniqueness check in the same file (Codex PR #1497 review, finding 2).
|
|
172
176
|
*
|
|
173
177
|
* Exported for unit testing — language-agnostic logic, exercised
|
|
174
178
|
* via synthetic stubs in `pick-implicit-this-overload.test.ts`. The
|
|
@@ -183,4 +187,5 @@ export declare function pickImplicitThisOverload(site: {
|
|
|
183
187
|
readonly conversionRankFn?: ConversionRankFn;
|
|
184
188
|
readonly conversionOnlyArgTypePrefixes?: readonly string[];
|
|
185
189
|
readonly constraintCompatibility?: ScopeResolver['constraintCompatibility'];
|
|
190
|
+
readonly implicitThisWalksMro?: boolean;
|
|
186
191
|
}): SymbolDefinition | undefined;
|
|
@@ -171,6 +171,7 @@ export function emitFreeCallFallback(graph, scopes, parsedFiles, nodeLookup, _re
|
|
|
171
171
|
conversionRankFn: options.conversionRankFn,
|
|
172
172
|
conversionOnlyArgTypePrefixes: options.conversionOnlyArgTypePrefixes,
|
|
173
173
|
constraintCompatibility: options.constraintCompatibility,
|
|
174
|
+
implicitThisWalksMro: options.implicitThisWalksMro,
|
|
174
175
|
});
|
|
175
176
|
fnDefFromImplicitThis = fnDef !== undefined;
|
|
176
177
|
}
|
|
@@ -925,11 +926,14 @@ export function pickUniqueGlobalClass(name, index) {
|
|
|
925
926
|
* pick a method member by name with overload narrowing on arity +
|
|
926
927
|
* argument types. Returns undefined if there's no enclosing class,
|
|
927
928
|
* no matching method, OR narrowing leaves multiple compatible
|
|
928
|
-
* candidates —
|
|
929
|
-
*
|
|
930
|
-
*
|
|
931
|
-
*
|
|
932
|
-
*
|
|
929
|
+
* candidates — except when those survivors are a protocol/interface
|
|
930
|
+
* requirement plus exactly one extension witness, in which case the
|
|
931
|
+
* witness (the default body) is returned. An inherited class, struct,
|
|
932
|
+
* or enum member still wins over a protocol-extension default.
|
|
933
|
+
* Picking `candidates[0]` would emit a high-confidence CALLS edge
|
|
934
|
+
* whose target depends on registration order rather than a
|
|
935
|
+
* defensible resolution. Mirrors `pickUniqueGlobalCallable`'s
|
|
936
|
+
* uniqueness check in the same file (Codex PR #1497 review, finding 2).
|
|
933
937
|
*
|
|
934
938
|
* Exported for unit testing — language-agnostic logic, exercised
|
|
935
939
|
* via synthetic stubs in `pick-implicit-this-overload.test.ts`. The
|
|
@@ -954,24 +958,93 @@ export function pickImplicitThisOverload(site, scopes, workspaceIndex, model, ho
|
|
|
954
958
|
const classDefId = workspaceIndex.classScopeIdToDefId.get(classScopeId);
|
|
955
959
|
if (classDefId === undefined)
|
|
956
960
|
return undefined;
|
|
957
|
-
|
|
961
|
+
// Bare calls in an instance method use the same implicit receiver as
|
|
962
|
+
// `self.member()`. Prefer declarations on the enclosing type; when the
|
|
963
|
+
// language opts into MRO implicit-this, walk inherited owners
|
|
964
|
+
// nearest-first and arity-narrow per owner. Compatible-but-ambiguous
|
|
965
|
+
// on a nearer ancestor fail-closes — do not fall through to a farther
|
|
966
|
+
// override. Falling through to the global name lookup makes inherited
|
|
967
|
+
// defaults depend on file order.
|
|
968
|
+
const own = model.methods.lookupAllByOwner(classDefId, site.name);
|
|
969
|
+
const ownPicked = pickUniqueImplicitThisCandidate(own, site, hookCtx, workspaceIndex);
|
|
970
|
+
if (ownPicked !== undefined)
|
|
971
|
+
return ownPicked;
|
|
972
|
+
if (own.length > 0) {
|
|
973
|
+
const ownCompatible = narrowOverloadCandidates(own, site.arity, site.argumentTypes, {
|
|
974
|
+
argumentTypeClasses: site.argumentTypeClasses,
|
|
975
|
+
conversionRankFn: hookCtx?.conversionRankFn,
|
|
976
|
+
conversionOnlyArgTypePrefixes: hookCtx?.conversionOnlyArgTypePrefixes,
|
|
977
|
+
constraintCompatibility: hookCtx?.constraintCompatibility,
|
|
978
|
+
});
|
|
979
|
+
if (ownCompatible.length > 0)
|
|
980
|
+
return undefined;
|
|
981
|
+
}
|
|
982
|
+
if (hookCtx?.implicitThisWalksMro !== true)
|
|
983
|
+
return undefined;
|
|
984
|
+
for (const ownerId of scopes.methodDispatch?.mroFor(classDefId) ?? []) {
|
|
985
|
+
const inherited = model.methods.lookupAllByOwner(ownerId, site.name);
|
|
986
|
+
const inheritedPicked = pickUniqueImplicitThisCandidate(inherited, site, hookCtx, workspaceIndex);
|
|
987
|
+
if (inheritedPicked !== undefined)
|
|
988
|
+
return inheritedPicked;
|
|
989
|
+
if (inherited.length > 0) {
|
|
990
|
+
const inheritedCompatible = narrowOverloadCandidates(inherited, site.arity, site.argumentTypes, {
|
|
991
|
+
argumentTypeClasses: site.argumentTypeClasses,
|
|
992
|
+
conversionRankFn: hookCtx?.conversionRankFn,
|
|
993
|
+
conversionOnlyArgTypePrefixes: hookCtx?.conversionOnlyArgTypePrefixes,
|
|
994
|
+
constraintCompatibility: hookCtx?.constraintCompatibility,
|
|
995
|
+
});
|
|
996
|
+
if (inheritedCompatible.length > 0)
|
|
997
|
+
return undefined;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
return undefined;
|
|
1001
|
+
}
|
|
1002
|
+
function pickUniqueImplicitThisCandidate(overloads, site, hookCtx, workspaceIndex) {
|
|
958
1003
|
if (overloads.length === 0)
|
|
959
1004
|
return undefined;
|
|
960
|
-
if (overloads.length === 1)
|
|
961
|
-
return overloads[0];
|
|
962
|
-
// Narrow on arity + argument types. Require a UNIQUE survivor —
|
|
963
|
-
// ambiguous narrowing (multiple compatible candidates with no
|
|
964
|
-
// disambiguating signal) leaves the call unresolved rather than
|
|
965
|
-
// routing to an arbitrary first overload by registration order.
|
|
966
1005
|
const candidates = narrowOverloadCandidates(overloads, site.arity, site.argumentTypes, {
|
|
967
1006
|
argumentTypeClasses: site.argumentTypeClasses,
|
|
968
1007
|
conversionRankFn: hookCtx?.conversionRankFn,
|
|
969
1008
|
conversionOnlyArgTypePrefixes: hookCtx?.conversionOnlyArgTypePrefixes,
|
|
970
1009
|
constraintCompatibility: hookCtx?.constraintCompatibility,
|
|
971
1010
|
});
|
|
972
|
-
if (candidates.length
|
|
1011
|
+
if (candidates.length === 0)
|
|
973
1012
|
return undefined;
|
|
974
|
-
|
|
1013
|
+
if (candidates.length === 1)
|
|
1014
|
+
return candidates[0];
|
|
1015
|
+
const witnesses = preferExtensionWitnesses(candidates, workspaceIndex);
|
|
1016
|
+
return witnesses.length === 1 ? witnesses[0] : undefined;
|
|
1017
|
+
}
|
|
1018
|
+
function preferExtensionWitnesses(candidates, workspaceIndex) {
|
|
1019
|
+
const onOwnerType = [];
|
|
1020
|
+
const extensionWitnesses = [];
|
|
1021
|
+
for (const def of candidates) {
|
|
1022
|
+
const ownerId = def.ownerId;
|
|
1023
|
+
if (ownerId === undefined) {
|
|
1024
|
+
extensionWitnesses.push(def);
|
|
1025
|
+
continue;
|
|
1026
|
+
}
|
|
1027
|
+
const ownerScope = workspaceIndex.classScopeByDefId?.get(ownerId);
|
|
1028
|
+
const livesOnOwner = ownerScope?.ownedDefs.some((owned) => owned.nodeId === def.nodeId) === true;
|
|
1029
|
+
if (livesOnOwner)
|
|
1030
|
+
onOwnerType.push(def);
|
|
1031
|
+
else
|
|
1032
|
+
extensionWitnesses.push(def);
|
|
1033
|
+
}
|
|
1034
|
+
if (extensionWitnesses.length === 0 || onOwnerType.length === 0)
|
|
1035
|
+
return candidates;
|
|
1036
|
+
const concrete = onOwnerType.filter((def) => !isProtocolLikeOwner(def.ownerId, workspaceIndex));
|
|
1037
|
+
if (concrete.length > 0)
|
|
1038
|
+
return concrete;
|
|
1039
|
+
return extensionWitnesses;
|
|
1040
|
+
}
|
|
1041
|
+
function isProtocolLikeOwner(ownerId, workspaceIndex) {
|
|
1042
|
+
if (ownerId === undefined)
|
|
1043
|
+
return false;
|
|
1044
|
+
const ownerScope = workspaceIndex.classScopeByDefId?.get(ownerId);
|
|
1045
|
+
if (ownerScope === undefined)
|
|
1046
|
+
return false;
|
|
1047
|
+
return ownerScope.ownedDefs.some((owned) => owned.nodeId === ownerId && (owned.type === 'Protocol' || owned.type === 'Interface'));
|
|
975
1048
|
}
|
|
976
1049
|
/**
|
|
977
1050
|
* True when `name` is bound somewhere along the TRUE lexical scope
|
|
@@ -25,14 +25,25 @@
|
|
|
25
25
|
import type { ParsedFile } from '../../../../_shared/index.js';
|
|
26
26
|
import type { KnowledgeGraph } from '../../../graph/types.js';
|
|
27
27
|
import type { MutableSemanticModel } from '../../model/semantic-model.js';
|
|
28
|
+
import { finalizeScopeModel } from '../../finalize-orchestrator.js';
|
|
28
29
|
import { type ResolveStats } from '../../resolve-references.js';
|
|
29
30
|
import { buildGraphNodeLookup } from '../graph-bridge/node-lookup.js';
|
|
30
31
|
import { type FunctionNodeIndex } from '../../taint/summary-harvest-driver.js';
|
|
31
32
|
import type { FunctionSummary } from '../../taint/summary-model.js';
|
|
32
33
|
import type { CallSummary } from '../../taint/call-summary-model.js';
|
|
33
34
|
import { type PropertyNameIndex } from '../passes/unique-name-properties.js';
|
|
35
|
+
import { type CalleeIdAccumulator } from '../graph-bridge/callee-id-sink.js';
|
|
34
36
|
import type { ScopeResolver, UndecidedSatisfaction } from '../contract/scope-resolver.js';
|
|
37
|
+
import { buildWorkspaceResolutionIndex } from '../workspace-index.js';
|
|
35
38
|
import type { ResolutionOutcome, ResolutionOutcomeRecorder } from '../resolution-outcome.js';
|
|
39
|
+
/**
|
|
40
|
+
* Join extraction-time assignment identity to Phase-4's exact resolved callee.
|
|
41
|
+
* Ambiguous dispatch and missing return annotations deliberately produce no
|
|
42
|
+
* binding. Extraction emits these facts only for untyped declarations, so an
|
|
43
|
+
* existing entry here is necessarily inference/mirroring and may be corrected;
|
|
44
|
+
* explicit annotations never enter this join.
|
|
45
|
+
*/
|
|
46
|
+
export declare function applyPreciseCallResultBindings(parsedFiles: readonly ParsedFile[], indexes: ReturnType<typeof finalizeScopeModel>, workspaceIndex: ReturnType<typeof buildWorkspaceResolutionIndex>, calleeIds: CalleeIdAccumulator, nodeLookup: ReturnType<typeof buildGraphNodeLookup>): number;
|
|
36
47
|
export type ScopeResolutionSubPhase = 'extracting' | 'analyzing types' | 'resolving references' | 'linking symbols';
|
|
37
48
|
interface RunScopeResolutionInput {
|
|
38
49
|
readonly graph: KnowledgeGraph;
|
|
@@ -47,7 +47,7 @@ import { emitReferencesViaLookup } from '../graph-bridge/references-to-edges.js'
|
|
|
47
47
|
import { buildPropertyNameIndex, emitUniqueNamePropertyAccesses, } from '../passes/unique-name-properties.js';
|
|
48
48
|
import { emitReturnShapeMemberAccesses } from '../passes/return-shape-members.js';
|
|
49
49
|
import { emitImportedValueReferences } from '../passes/imported-value-refs.js';
|
|
50
|
-
import { createCalleeIdAccumulator, } from '../graph-bridge/callee-id-sink.js';
|
|
50
|
+
import { calleeIdPosKey, createCalleeIdAccumulator, } from '../graph-bridge/callee-id-sink.js';
|
|
51
51
|
import { emitImportEdges } from '../graph-bridge/imports-to-edges.js';
|
|
52
52
|
import { callableFlowSiteKey, collectDeferredIndirectCollection, emitCallableValueFlow, } from '../passes/callable-value-flow.js';
|
|
53
53
|
import { findEnclosingClassDef, resolveInheritanceBaseInScope } from '../scope/walkers.js';
|
|
@@ -55,6 +55,56 @@ import { heritageTypeArgumentsKey, } from '../utils/generic-instantiation.js';
|
|
|
55
55
|
import { buildWorkspaceResolutionIndex } from '../workspace-index.js';
|
|
56
56
|
import { logHeapProbe } from '../../utils/heap-probe.js';
|
|
57
57
|
import { parseTruthyEnv } from '../../utils/env.js';
|
|
58
|
+
/**
|
|
59
|
+
* Join extraction-time assignment identity to Phase-4's exact resolved callee.
|
|
60
|
+
* Ambiguous dispatch and missing return annotations deliberately produce no
|
|
61
|
+
* binding. Extraction emits these facts only for untyped declarations, so an
|
|
62
|
+
* existing entry here is necessarily inference/mirroring and may be corrected;
|
|
63
|
+
* explicit annotations never enter this join.
|
|
64
|
+
*/
|
|
65
|
+
export function applyPreciseCallResultBindings(parsedFiles, indexes, workspaceIndex, calleeIds, nodeLookup) {
|
|
66
|
+
let updated = 0;
|
|
67
|
+
const returnTypeByGraphId = new Map();
|
|
68
|
+
for (const parsed of parsedFiles) {
|
|
69
|
+
for (const def of parsed.localDefs) {
|
|
70
|
+
const returnType = workspaceIndex.declaredReturnTypeByCallableId.get(def.nodeId);
|
|
71
|
+
if (returnType === undefined)
|
|
72
|
+
continue;
|
|
73
|
+
const graphId = resolveDefGraphId(def.filePath, def, nodeLookup);
|
|
74
|
+
if (graphId !== undefined)
|
|
75
|
+
returnTypeByGraphId.set(graphId, returnType);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
for (const parsed of parsedFiles) {
|
|
79
|
+
const resolvedByPosition = calleeIds.get(parsed.filePath);
|
|
80
|
+
if (resolvedByPosition === undefined)
|
|
81
|
+
continue;
|
|
82
|
+
for (const assignment of parsed.callResultAssignmentSites ?? []) {
|
|
83
|
+
const targets = resolvedByPosition.get(calleeIdPosKey(assignment.callSite.startLine, assignment.callSite.startCol));
|
|
84
|
+
if (targets === undefined || targets.size !== 1)
|
|
85
|
+
continue;
|
|
86
|
+
const targetId = targets.values().next().value;
|
|
87
|
+
if (targetId === undefined)
|
|
88
|
+
continue;
|
|
89
|
+
const returnType = returnTypeByGraphId.get(targetId);
|
|
90
|
+
if (returnType === undefined)
|
|
91
|
+
continue;
|
|
92
|
+
const scope = indexes.scopeTree.getScope(assignment.inScope);
|
|
93
|
+
if (scope === undefined)
|
|
94
|
+
continue;
|
|
95
|
+
scope.typeBindings.set(assignment.lhs, {
|
|
96
|
+
rawName: returnType.rawName,
|
|
97
|
+
...(returnType.declaredSpelling !== undefined
|
|
98
|
+
? { declaredSpelling: returnType.declaredSpelling }
|
|
99
|
+
: {}),
|
|
100
|
+
declaredAtScope: assignment.inScope,
|
|
101
|
+
source: 'assignment-inferred',
|
|
102
|
+
});
|
|
103
|
+
updated++;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return updated;
|
|
107
|
+
}
|
|
58
108
|
import { isValueDefinitionLabel } from '../../utils/ast-helpers.js';
|
|
59
109
|
import { TransitionalScopeTree } from '../../../../storage/scope-index-store.js';
|
|
60
110
|
import { forceGc } from '../../../../storage/parsedfile-store.js';
|
|
@@ -235,7 +285,6 @@ export function runScopeResolution(input, provider) {
|
|
|
235
285
|
const undecidedSatisfaction = [];
|
|
236
286
|
const recordResolutionOutcome = (outcome) => {
|
|
237
287
|
resolutionOutcomes.push(outcome);
|
|
238
|
-
input.recordResolutionOutcome?.(outcome);
|
|
239
288
|
};
|
|
240
289
|
const PROF = process.env.PROF_SCOPE_RESOLUTION === '1';
|
|
241
290
|
const tStart = PROF ? process.hrtime.bigint() : 0n;
|
|
@@ -311,7 +360,10 @@ export function runScopeResolution(input, provider) {
|
|
|
311
360
|
logger.warn(`[scope-resolution prof] pre-extracted hits: ${preExtractedHits}/${files.length}`);
|
|
312
361
|
}
|
|
313
362
|
logHeapProbe('sr-extract-end', `lang=${provider.language} parsedFiles=${parsedFiles.length} preExtractedHits=${preExtractedHits} skipped=${filesSkipped}`);
|
|
314
|
-
provider.populateWorkspaceOwners?.(parsedFiles, {
|
|
363
|
+
provider.populateWorkspaceOwners?.(parsedFiles, {
|
|
364
|
+
fileContents: getFileContents(),
|
|
365
|
+
resolutionConfig: input.resolutionConfig,
|
|
366
|
+
});
|
|
315
367
|
provider.populateWorkspaceReferences?.(parsedFiles, {
|
|
316
368
|
fileContents: getFileContents(),
|
|
317
369
|
treeCache,
|
|
@@ -481,7 +533,9 @@ export function runScopeResolution(input, provider) {
|
|
|
481
533
|
// views that delegate to it (out-of-core scope index) — the index pins no Scope objects, so the
|
|
482
534
|
// disk seal can reclaim them. Byte-identical: the view returns the same Scope
|
|
483
535
|
// the resident tree holds (or a value-identical revived one in disk mode).
|
|
484
|
-
const workspaceIndex = buildWorkspaceResolutionIndex(parsedFiles, indexes.scopeTree
|
|
536
|
+
const workspaceIndex = buildWorkspaceResolutionIndex(parsedFiles, indexes.scopeTree, {
|
|
537
|
+
stripTypePreservingDecoration: provider.stripTypePreservingDecoration,
|
|
538
|
+
});
|
|
485
539
|
logHeapProbe('sr-post-workspaceIndex', `lang=${provider.language}`);
|
|
486
540
|
// Cross-file implicit-namespace visibility (C#). Must run before
|
|
487
541
|
// propagateImportedReturnTypes so the latter pass sees siblings'
|
|
@@ -637,6 +691,12 @@ export function runScopeResolution(input, provider) {
|
|
|
637
691
|
const deferredIndirectCollection = collectDeferredIndirectCollection(emitParsedFiles, indexes);
|
|
638
692
|
const deferredIndirectSites = deferredIndirectCollection.sites;
|
|
639
693
|
const callableArgumentSites = new Set();
|
|
694
|
+
const callResultAssignmentSites = new Set();
|
|
695
|
+
for (const parsed of emitParsedFiles) {
|
|
696
|
+
for (const site of parsed.callResultAssignmentSites ?? []) {
|
|
697
|
+
callResultAssignmentSites.add(callableFlowSiteKey(parsed.filePath, site.callSite));
|
|
698
|
+
}
|
|
699
|
+
}
|
|
640
700
|
if (input.pdg !== true && deferredIndirectSites.size > 0) {
|
|
641
701
|
for (const parsed of emitParsedFiles) {
|
|
642
702
|
for (const site of parsed.callableFlowSites ?? []) {
|
|
@@ -650,10 +710,13 @@ export function runScopeResolution(input, provider) {
|
|
|
650
710
|
// for PDG OR when indirect-call facts need direct targets for actual→formal
|
|
651
711
|
// propagation. Populated below at every CALLS emit path before dedup; the CFG
|
|
652
712
|
// join still consumes it only inside the `input.pdg` block.
|
|
653
|
-
const calleeIdAccumulator = input.pdg === true || deferredIndirectSites.size > 0
|
|
713
|
+
const calleeIdAccumulator = input.pdg === true || deferredIndirectSites.size > 0 || callResultAssignmentSites.size > 0
|
|
654
714
|
? createCalleeIdAccumulator(input.pdg === true
|
|
655
715
|
? undefined
|
|
656
|
-
: (filePath, line, col) =>
|
|
716
|
+
: (filePath, line, col) => {
|
|
717
|
+
const key = `${filePath}:${line}:${col}`;
|
|
718
|
+
return callableArgumentSites.has(key) || callResultAssignmentSites.has(key);
|
|
719
|
+
})
|
|
657
720
|
: undefined;
|
|
658
721
|
const receiverBound = callableFlowOnly
|
|
659
722
|
? {
|
|
@@ -673,7 +736,7 @@ export function runScopeResolution(input, provider) {
|
|
|
673
736
|
// (#2912). Empty under `callableFlowOnly`, which emits no dispatch.
|
|
674
737
|
heritageTypeArguments,
|
|
675
738
|
});
|
|
676
|
-
|
|
739
|
+
let receiverExtras = receiverBound.emitted;
|
|
677
740
|
if (receiverBound.dispatchFanoutSkipped > 0) {
|
|
678
741
|
// Never drop dispatch coverage silently (#2829) — same contract as the
|
|
679
742
|
// property-dispatch cap below. An interface member over the cap loses real
|
|
@@ -704,6 +767,7 @@ export function runScopeResolution(input, provider) {
|
|
|
704
767
|
isFileLocalDef: provider.isFileLocalDef,
|
|
705
768
|
isBuiltInName: provider.languageProvider.isBuiltInName,
|
|
706
769
|
freeCallsRequireInstanceOwnership: provider.freeCallsRequireInstanceOwnership === true,
|
|
770
|
+
implicitThisWalksMro: provider.implicitThisWalksMro === true,
|
|
707
771
|
isCallableVisibleFromCaller: provider.isCallableVisibleFromCaller,
|
|
708
772
|
resolveAdlCandidates: provider.resolveAdlCandidates,
|
|
709
773
|
resolveQualifiedFreeCall: provider.resolveQualifiedFreeCall,
|
|
@@ -714,6 +778,42 @@ export function runScopeResolution(input, provider) {
|
|
|
714
778
|
calleeIdSink: calleeIdAccumulator,
|
|
715
779
|
skipSites: deferredIndirectSites,
|
|
716
780
|
});
|
|
781
|
+
const replayedCallResultBindings = callableFlowOnly || calleeIdAccumulator === undefined
|
|
782
|
+
? 0
|
|
783
|
+
: applyPreciseCallResultBindings(emitParsedFiles, indexes, workspaceIndex, calleeIdAccumulator, postHeritageNodeLookup);
|
|
784
|
+
if (replayedCallResultBindings > 0) {
|
|
785
|
+
const handledBeforeReplay = new Set(handledSites);
|
|
786
|
+
const replayedReceiverBound = emitReceiverBoundCalls(graph, indexes, emitParsedFiles, postHeritageNodeLookup, handledSites, provider, workspaceIndex, readonlyModel, {
|
|
787
|
+
calleeIdSink: calleeIdAccumulator,
|
|
788
|
+
isBuiltInName: provider.languageProvider.isBuiltInName,
|
|
789
|
+
heritageTypeArguments,
|
|
790
|
+
});
|
|
791
|
+
receiverExtras += replayedReceiverBound.emitted;
|
|
792
|
+
if (replayedReceiverBound.dispatchFanoutSkipped > 0) {
|
|
793
|
+
logger.warn({
|
|
794
|
+
lang: provider.language,
|
|
795
|
+
dispatchFanoutSkipped: replayedReceiverBound.dispatchFanoutSkipped,
|
|
796
|
+
dispatchFanoutSkippedNames: replayedReceiverBound.dispatchFanoutSkippedNames,
|
|
797
|
+
fanoutCap: MAX_INTERFACE_DISPATCH_FANOUT,
|
|
798
|
+
replay: true,
|
|
799
|
+
}, 'interface-dispatch: members over the fan-out cap dropped implementors (their CALLS edges were not emitted)');
|
|
800
|
+
}
|
|
801
|
+
const resolvedOnReplay = new Set();
|
|
802
|
+
for (const key of handledSites) {
|
|
803
|
+
if (!handledBeforeReplay.has(key))
|
|
804
|
+
resolvedOnReplay.add(key);
|
|
805
|
+
}
|
|
806
|
+
if (resolvedOnReplay.size > 0) {
|
|
807
|
+
for (let i = resolutionOutcomes.length - 1; i >= 0; i--) {
|
|
808
|
+
const outcome = resolutionOutcomes[i];
|
|
809
|
+
if (outcome.kind === 'suppressed' &&
|
|
810
|
+
outcome.reason === 'receiver-unresolved' &&
|
|
811
|
+
resolvedOnReplay.has(callableFlowSiteKey(outcome.filePath, outcome.range))) {
|
|
812
|
+
resolutionOutcomes.splice(i, 1);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
717
817
|
const referenceSkipSites = new Set(handledSites);
|
|
718
818
|
for (const key of deferredIndirectSites)
|
|
719
819
|
referenceSkipSites.add(key);
|
|
@@ -1176,6 +1276,8 @@ export function runScopeResolution(input, provider) {
|
|
|
1176
1276
|
` (${parsedFiles.length} files)`);
|
|
1177
1277
|
}
|
|
1178
1278
|
logHeapProbe('sr-end', `lang=${provider.language} parsedFiles=${parsedFiles.length}`);
|
|
1279
|
+
for (const outcome of resolutionOutcomes)
|
|
1280
|
+
input.recordResolutionOutcome?.(outcome);
|
|
1179
1281
|
return {
|
|
1180
1282
|
filesProcessed: parsedFiles.length,
|
|
1181
1283
|
filesSkipped,
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* See `./workspace-index.ts` for what belongs in this index versus what belongs
|
|
13
13
|
* on `SemanticModel`, and for the builder itself.
|
|
14
14
|
*/
|
|
15
|
-
import type { Scope, ScopeId, SymbolDefinition } from '../../../_shared/index.js';
|
|
15
|
+
import type { Scope, ScopeId, SymbolDefinition, TypeRef } from '../../../_shared/index.js';
|
|
16
16
|
export interface WorkspaceResolutionIndex {
|
|
17
17
|
/** Class def `nodeId` → that class's `Scope`. */
|
|
18
18
|
readonly classScopeByDefId: ReadonlyMap<string, Scope>;
|
|
@@ -31,4 +31,9 @@ export interface WorkspaceResolutionIndex {
|
|
|
31
31
|
* killer). "First module-local callable in `moduleScopeByFile` order" is the
|
|
32
32
|
* exact semantics the old scan returned, so it is byte-identical. */
|
|
33
33
|
readonly exportedCallableByName: ReadonlyMap<string, SymbolDefinition>;
|
|
34
|
+
/** Exact callable def `nodeId` → its declared return type binding.
|
|
35
|
+
* Built from definitions owned by each callable's Function scope, so methods
|
|
36
|
+
* declared in extension/partial scopes remain addressable even when those
|
|
37
|
+
* scopes deliberately own no separate class-like definition. */
|
|
38
|
+
readonly declaredReturnTypeByCallableId: ReadonlyMap<string, TypeRef>;
|
|
34
39
|
}
|
|
@@ -52,4 +52,6 @@ export type { WorkspaceResolutionIndex } from './workspace-index-types.js';
|
|
|
52
52
|
* reclaim them. Without it (unit tests), the legacy direct `Map<K, Scope>` form
|
|
53
53
|
* is returned unchanged.
|
|
54
54
|
*/
|
|
55
|
-
export declare function buildWorkspaceResolutionIndex(parsedFiles: readonly ParsedFile[], scopeTree?: ScopeTree
|
|
55
|
+
export declare function buildWorkspaceResolutionIndex(parsedFiles: readonly ParsedFile[], scopeTree?: ScopeTree, options?: {
|
|
56
|
+
readonly stripTypePreservingDecoration?: (typeName: string) => string | undefined;
|
|
57
|
+
}): WorkspaceResolutionIndex;
|
|
@@ -97,11 +97,12 @@ class ScopeByKeyView {
|
|
|
97
97
|
* reclaim them. Without it (unit tests), the legacy direct `Map<K, Scope>` form
|
|
98
98
|
* is returned unchanged.
|
|
99
99
|
*/
|
|
100
|
-
export function buildWorkspaceResolutionIndex(parsedFiles, scopeTree) {
|
|
100
|
+
export function buildWorkspaceResolutionIndex(parsedFiles, scopeTree, options) {
|
|
101
101
|
const classScopeIdByDefId = new Map();
|
|
102
102
|
const classScopeIdToDefId = new Map();
|
|
103
103
|
const moduleScopeIdByFile = new Map();
|
|
104
104
|
const exportedCallableByName = new Map();
|
|
105
|
+
const declaredReturnTypeByCallableId = new Map();
|
|
105
106
|
// Back-compat (no scopeTree): keep the direct Scope-object maps.
|
|
106
107
|
const classScopeByDefIdDirect = scopeTree === undefined ? new Map() : undefined;
|
|
107
108
|
const moduleScopeByFileDirect = scopeTree === undefined ? new Map() : undefined;
|
|
@@ -128,6 +129,24 @@ export function buildWorkspaceResolutionIndex(parsedFiles, scopeTree) {
|
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
for (const scope of parsed.scopes) {
|
|
132
|
+
if (scope.kind === 'Function' && scope.parent !== null) {
|
|
133
|
+
for (const def of scope.ownedDefs) {
|
|
134
|
+
if (def.type !== 'Function' && def.type !== 'Method' && def.type !== 'Constructor') {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (def.returnType !== undefined) {
|
|
138
|
+
const stripped = options?.stripTypePreservingDecoration?.(def.returnType);
|
|
139
|
+
const rawName = stripped ?? def.returnType;
|
|
140
|
+
declaredReturnTypeByCallableId.set(def.nodeId, {
|
|
141
|
+
rawName,
|
|
142
|
+
...(rawName !== def.returnType ? { declaredSpelling: def.returnType } : {}),
|
|
143
|
+
declaredAtScope: scope.id,
|
|
144
|
+
source: 'return-annotation',
|
|
145
|
+
});
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
131
150
|
if (scope.kind !== 'Class')
|
|
132
151
|
continue;
|
|
133
152
|
const cd = scope.ownedDefs.find((d) => isClassLike(d.type));
|
|
@@ -144,5 +163,11 @@ export function buildWorkspaceResolutionIndex(parsedFiles, scopeTree) {
|
|
|
144
163
|
const moduleScopeByFile = scopeTree === undefined
|
|
145
164
|
? moduleScopeByFileDirect
|
|
146
165
|
: new ScopeByKeyView(moduleScopeIdByFile, scopeTree);
|
|
147
|
-
return {
|
|
166
|
+
return {
|
|
167
|
+
classScopeByDefId,
|
|
168
|
+
classScopeIdToDefId,
|
|
169
|
+
moduleScopeByFile,
|
|
170
|
+
exportedCallableByName,
|
|
171
|
+
declaredReturnTypeByCallableId,
|
|
172
|
+
};
|
|
148
173
|
}
|
|
@@ -764,7 +764,9 @@ import { copyV8CacheIfPresent, tryLoadV8Cache, writeV8CacheFile } from './v8-sid
|
|
|
764
764
|
// v101 (#3294 review): Rust bare-keyword glob imports retain crate/self/super
|
|
765
765
|
// instead of an empty target path; restricted pub(...) imports are no longer
|
|
766
766
|
// captured as unrestricted reexports. Re-extract both facts on warm indexes.
|
|
767
|
-
|
|
767
|
+
// v102: ParsedFile gained callResultAssignmentSites; old durable shards do
|
|
768
|
+
// not carry the exact assignment identity required by return-type replay.
|
|
769
|
+
const SCHEMA_BUMP = 102;
|
|
768
770
|
const GITNEXUS_PKG_VERSION = (() => {
|
|
769
771
|
try {
|
|
770
772
|
// package.json sits at gitnexus/package.json — two levels up from
|
|
@@ -301,21 +301,27 @@ export const loadParsedFilesForPaths = async (storagePath, wantPaths) => {
|
|
|
301
301
|
rejectedFiles++;
|
|
302
302
|
continue;
|
|
303
303
|
}
|
|
304
|
+
const assignments = sanitizeCallResultAssignmentSites(pf.callResultAssignmentSites);
|
|
305
|
+
if (assignments === undefined) {
|
|
306
|
+
rejectedFiles++;
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
304
309
|
const chains = sanitizeReceiverChains(pf.referenceSites);
|
|
305
310
|
if (chains === undefined) {
|
|
306
311
|
rejectedFiles++;
|
|
307
312
|
continue;
|
|
308
313
|
}
|
|
309
|
-
if (flow.dropped === 0 && chains.dropped === 0) {
|
|
314
|
+
if (flow.dropped === 0 && assignments.dropped === 0 && chains.dropped === 0) {
|
|
310
315
|
out.set(pf.filePath, pf);
|
|
311
316
|
}
|
|
312
317
|
else {
|
|
313
|
-
droppedSites += flow.dropped;
|
|
318
|
+
droppedSites += flow.dropped + assignments.dropped;
|
|
314
319
|
droppedChains += chains.dropped;
|
|
315
320
|
filesWithDroppedSites++;
|
|
316
321
|
out.set(pf.filePath, {
|
|
317
322
|
...pf,
|
|
318
323
|
...(flow.dropped === 0 ? {} : { callableFlowSites: flow.sites }),
|
|
324
|
+
...(assignments.dropped === 0 ? {} : { callResultAssignmentSites: assignments.sites }),
|
|
319
325
|
...(chains.dropped === 0 ? {} : { referenceSites: chains.sites }),
|
|
320
326
|
});
|
|
321
327
|
}
|
|
@@ -342,6 +348,17 @@ function sanitizeCallableFlowSites(value) {
|
|
|
342
348
|
const sites = bounded.filter(isValidCallableFlowSite);
|
|
343
349
|
return { sites, dropped: value.length - sites.length };
|
|
344
350
|
}
|
|
351
|
+
function sanitizeCallResultAssignmentSites(value) {
|
|
352
|
+
if (value === undefined)
|
|
353
|
+
return { sites: undefined, dropped: 0 };
|
|
354
|
+
if (!Array.isArray(value))
|
|
355
|
+
return undefined;
|
|
356
|
+
const bounded = value.length > MAX_CALLABLE_FLOW_SITES_PER_FILE
|
|
357
|
+
? value.slice(0, MAX_CALLABLE_FLOW_SITES_PER_FILE)
|
|
358
|
+
: value;
|
|
359
|
+
const sites = bounded.filter(isValidCallResultAssignmentSite);
|
|
360
|
+
return { sites, dropped: value.length - sites.length };
|
|
361
|
+
}
|
|
345
362
|
/**
|
|
346
363
|
* Untrusted-boundary handling for the compact `receiverChain` on a reference site.
|
|
347
364
|
*
|
|
@@ -434,6 +451,12 @@ function isValidCallableFlowSite(value) {
|
|
|
434
451
|
return false;
|
|
435
452
|
}
|
|
436
453
|
}
|
|
454
|
+
function isValidCallResultAssignmentSite(value) {
|
|
455
|
+
return (isRecord(value) &&
|
|
456
|
+
isValidRange(value.callSite) &&
|
|
457
|
+
isBoundedString(value.inScope) &&
|
|
458
|
+
isBoundedString(value.lhs));
|
|
459
|
+
}
|
|
437
460
|
function isValidOperand(value) {
|
|
438
461
|
if (!isRecord(value))
|
|
439
462
|
return false;
|
package/package.json
CHANGED