Skip to content

Commit 3d0f16e

Browse files
committed
Drop dangling local symbol occurrences
Amp-Thread-ID: https://ampcode.com/threads/T-01a029e2-5095-710a-9cce-0c6d8645c173
1 parent 0f33ae3 commit 3d0f16e

6 files changed

Lines changed: 70 additions & 8 deletions

File tree

snapshots/input/multi-project/packages/a/src/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,10 @@
33
export function a(): string {
44
return ''
55
}
6+
7+
export function localResult() {
8+
interface LocalResult {
9+
value: string
10+
}
11+
return { value: '' } as LocalResult
12+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { a } from '@example/a/src'
1+
import { a, localResult } from '@example/a/src'
22

33
export function b() {
4+
localResult().value
45
return a()
56
}

snapshots/output/multi-project/packages/a/src/index.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,24 @@ export function a(): string {
1414
return ''
1515
}
1616

17+
export function localResult() {
18+
// ^^^^^^^^^^^ definition @example/a 1.0.0 src/`index.ts`/localResult().
19+
// documentation ```ts
20+
// > function localResult(): LocalResult
21+
// > ```
22+
interface LocalResult {
23+
// ^^^^^^^^^^^ definition local 0
24+
// documentation ```ts
25+
// > interface LocalResult
26+
// > ```
27+
value: string
28+
// ^^^^^ definition local 1
29+
// documentation ```ts
30+
// > (property) value: string
31+
// > ```
32+
}
33+
return { value: '' } as LocalResult
34+
// ^^^^^ reference local 1
35+
// ^^^^^^^^^^^ reference local 0
36+
}
37+

snapshots/output/multi-project/packages/b/src/b.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
// language TypeScript
22
// < definition @example/b 1.0.0 src/`b.ts`/
33

4-
import { a } from '@example/a/src'
4+
import { a, localResult } from '@example/a/src'
55
// ^ reference @example/a 1.0.0 src/`index.ts`/a().
6-
// ^^^^^^^^^^^^^^^^ reference @example/a 1.0.0 src/`index.ts`/
6+
// ^^^^^^^^^^^ reference @example/a 1.0.0 src/`index.ts`/localResult().
7+
// ^^^^^^^^^^^^^^^^ reference @example/a 1.0.0 src/`index.ts`/
78

89
export function b() {
910
// ^ definition @example/b 1.0.0 src/`b.ts`/b().
11+
localResult().value
12+
//^^^^^^^^^^^ reference @example/a 1.0.0 src/`index.ts`/localResult().
1013
return a()
1114
// ^ reference @example/a 1.0.0 src/`index.ts`/a().
1215
}

src/FileIndexer.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,34 @@ export class FileIndexer {
6565

6666
this.emitSourceFileOccurrence()
6767
this.visit(this.sourceFile)
68+
const missingLocalDefinition = this.document.occurrences.find(
69+
occurrence =>
70+
occurrence.symbol.startsWith('local ') &&
71+
(occurrence.symbol_roles & scip.scip.SymbolRole.Definition) !== 0 &&
72+
!this.symbolInformation.has(occurrence.symbol)
73+
)
74+
if (missingLocalDefinition) {
75+
throw new Error(
76+
`local definition '${missingLocalDefinition.symbol}' has no SymbolInformation in '${this.document.relative_path}'`
77+
)
78+
}
79+
// A SCIP local symbol is owned by one document. TypeScript can report
80+
// synthetic or cross-file declaration candidates that the symbol algorithm
81+
// cannot represent as locals in this document, so discard those unusable
82+
// occurrences instead of emitting dangling local identities.
83+
this.document.occurrences = this.document.occurrences.filter(
84+
occurrence =>
85+
!occurrence.symbol.startsWith('local ') ||
86+
this.symbolInformation.has(occurrence.symbol)
87+
)
88+
// Relationships to locals have the same document-local ownership rule.
89+
for (const symbol of this.document.symbols) {
90+
symbol.relationships = symbol.relationships.filter(
91+
relationship =>
92+
!relationship.symbol.startsWith('local ') ||
93+
this.symbolInformation.has(relationship.symbol)
94+
)
95+
}
6896
}
6997
private emitSourceFileOccurrence(): void {
7098
const symbol = this.scipSymbol(this.sourceFile)

src/main.test.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,22 +145,24 @@ for (const snapshotDirectory of snapshotDirectories) {
145145
.filter(
146146
symbol =>
147147
symbol &&
148-
!symbol.startsWith('local ') &&
149-
!availableSymbols.has(symbol)
148+
(symbol.startsWith('local ')
149+
? !symbols.has(symbol)
150+
: !availableSymbols.has(symbol))
150151
)
151152
assert.equal(
152153
missingOccurrenceSymbols,
153154
[],
154-
`${document.relative_path} global occurrences should have SymbolInformation`
155+
`${document.relative_path} occurrences should have SymbolInformation`
155156
)
156157
const missingRelationshipSymbols = document.symbols
157158
.flatMap(symbol => symbol.relationships)
158159
.map(relationship => relationship.symbol)
159160
.filter(
160161
symbol =>
161162
symbol &&
162-
!symbol.startsWith('local ') &&
163-
!availableSymbols.has(symbol)
163+
(symbol.startsWith('local ')
164+
? !symbols.has(symbol)
165+
: !availableSymbols.has(symbol))
164166
)
165167
assert.equal(
166168
missingRelationshipSymbols,

0 commit comments

Comments
 (0)