diff --git a/snapshots/input/multi-project/packages/a/src/index.ts b/snapshots/input/multi-project/packages/a/src/index.ts index f007160d..8949bb62 100644 --- a/snapshots/input/multi-project/packages/a/src/index.ts +++ b/snapshots/input/multi-project/packages/a/src/index.ts @@ -3,3 +3,10 @@ export function a(): string { return '' } + +export function localResult() { + interface LocalResult { + value: string + } + return { value: '' } as LocalResult +} diff --git a/snapshots/input/multi-project/packages/b/src/b.ts b/snapshots/input/multi-project/packages/b/src/b.ts index f9834ab6..64c09925 100644 --- a/snapshots/input/multi-project/packages/b/src/b.ts +++ b/snapshots/input/multi-project/packages/b/src/b.ts @@ -1,5 +1,6 @@ -import { a } from '@example/a/src' +import { a, localResult } from '@example/a/src' export function b() { + localResult().value return a() } diff --git a/snapshots/output/multi-project/packages/a/src/index.ts b/snapshots/output/multi-project/packages/a/src/index.ts index f5ace936..073d79ff 100644 --- a/snapshots/output/multi-project/packages/a/src/index.ts +++ b/snapshots/output/multi-project/packages/a/src/index.ts @@ -14,3 +14,24 @@ export function a(): string { return '' } +export function localResult() { +// ^^^^^^^^^^^ definition @example/a 1.0.0 src/`index.ts`/localResult(). +// documentation ```ts +// > function localResult(): LocalResult +// > ``` + interface LocalResult { +// ^^^^^^^^^^^ definition local 0 +// documentation ```ts +// > interface LocalResult +// > ``` + value: string +// ^^^^^ definition local 1 +// documentation ```ts +// > (property) value: string +// > ``` + } + return { value: '' } as LocalResult +// ^^^^^ reference local 1 +// ^^^^^^^^^^^ reference local 0 +} + diff --git a/snapshots/output/multi-project/packages/b/src/b.ts b/snapshots/output/multi-project/packages/b/src/b.ts index e992caf3..dfece73b 100644 --- a/snapshots/output/multi-project/packages/b/src/b.ts +++ b/snapshots/output/multi-project/packages/b/src/b.ts @@ -1,12 +1,15 @@ // language TypeScript // < definition @example/b 1.0.0 src/`b.ts`/ -import { a } from '@example/a/src' +import { a, localResult } from '@example/a/src' // ^ reference @example/a 1.0.0 src/`index.ts`/a(). -// ^^^^^^^^^^^^^^^^ reference @example/a 1.0.0 src/`index.ts`/ +// ^^^^^^^^^^^ reference @example/a 1.0.0 src/`index.ts`/localResult(). +// ^^^^^^^^^^^^^^^^ reference @example/a 1.0.0 src/`index.ts`/ export function b() { // ^ definition @example/b 1.0.0 src/`b.ts`/b(). + localResult().value +//^^^^^^^^^^^ reference @example/a 1.0.0 src/`index.ts`/localResult(). return a() // ^ reference @example/a 1.0.0 src/`index.ts`/a(). } diff --git a/src/FileIndexer.ts b/src/FileIndexer.ts index d7b04caa..31f87342 100644 --- a/src/FileIndexer.ts +++ b/src/FileIndexer.ts @@ -65,6 +65,34 @@ export class FileIndexer { this.emitSourceFileOccurrence() this.visit(this.sourceFile) + const missingLocalDefinition = this.document.occurrences.find( + occurrence => + occurrence.symbol.startsWith('local ') && + (occurrence.symbol_roles & scip.scip.SymbolRole.Definition) !== 0 && + !this.symbolInformation.has(occurrence.symbol) + ) + if (missingLocalDefinition) { + throw new Error( + `local definition '${missingLocalDefinition.symbol}' has no SymbolInformation in '${this.document.relative_path}'` + ) + } + // A SCIP local symbol is owned by one document. TypeScript can report + // synthetic or cross-file declaration candidates that the symbol algorithm + // cannot represent as locals in this document, so discard those unusable + // occurrences instead of emitting dangling local identities. + this.document.occurrences = this.document.occurrences.filter( + occurrence => + !occurrence.symbol.startsWith('local ') || + this.symbolInformation.has(occurrence.symbol) + ) + // Relationships to locals have the same document-local ownership rule. + for (const symbol of this.document.symbols) { + symbol.relationships = symbol.relationships.filter( + relationship => + !relationship.symbol.startsWith('local ') || + this.symbolInformation.has(relationship.symbol) + ) + } } private emitSourceFileOccurrence(): void { const symbol = this.scipSymbol(this.sourceFile) diff --git a/src/main.test.ts b/src/main.test.ts index 51c9df2f..34d60e99 100644 --- a/src/main.test.ts +++ b/src/main.test.ts @@ -145,13 +145,14 @@ for (const snapshotDirectory of snapshotDirectories) { .filter( symbol => symbol && - !symbol.startsWith('local ') && - !availableSymbols.has(symbol) + (symbol.startsWith('local ') + ? !symbols.has(symbol) + : !availableSymbols.has(symbol)) ) assert.equal( missingOccurrenceSymbols, [], - `${document.relative_path} global occurrences should have SymbolInformation` + `${document.relative_path} occurrences should have SymbolInformation` ) const missingRelationshipSymbols = document.symbols .flatMap(symbol => symbol.relationships) @@ -159,8 +160,9 @@ for (const snapshotDirectory of snapshotDirectories) { .filter( symbol => symbol && - !symbol.startsWith('local ') && - !availableSymbols.has(symbol) + (symbol.startsWith('local ') + ? !symbols.has(symbol) + : !availableSymbols.has(symbol)) ) assert.equal( missingRelationshipSymbols,