Skip to content

Commit 2069e1c

Browse files
committed
Prevent duplicate entries from type references
1 parent 1cdd1d3 commit 2069e1c

File tree

2 files changed

+15
-4
lines changed

2 files changed

+15
-4
lines changed

src/services/services.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6408,20 +6408,31 @@ namespace ts {
64086408
if (containingTypeReference) {
64096409
const parent = containingTypeReference.parent;
64106410
if (isVariableLike(parent) && parent.type === containingTypeReference && parent.initializer && isImplementationExpression(parent.initializer)) {
6411-
result.push(getReferenceEntryFromNode(parent.initializer));
6411+
maybeAdd(getReferenceEntryFromNode(parent.initializer));
64126412
}
64136413
else if (isFunctionLike(parent) && parent.type === containingTypeReference && parent.body && parent.body.kind === SyntaxKind.Block) {
64146414
forEachReturnStatement(<Block>parent.body, (returnStatement) => {
64156415
if (returnStatement.expression && isImplementationExpression(returnStatement.expression)) {
6416-
result.push(getReferenceEntryFromNode(returnStatement.expression));
6416+
maybeAdd(getReferenceEntryFromNode(returnStatement.expression));
64176417
}
64186418
});
64196419
}
64206420
else if (isTypeAssertionExpression(parent) && isImplementationExpression(parent.expression)) {
6421-
result.push(getReferenceEntryFromNode(parent.expression));
6421+
maybeAdd(getReferenceEntryFromNode(parent.expression));
64226422
}
64236423
}
64246424
}
6425+
6426+
// Type nodes can contain multiple references to the same type. For example:
6427+
// let x: Foo & (Foo & Bar) = ...
6428+
// Because we are returning the implementation locations and not the identifier locations,
6429+
// duplicate entries would be returned here as each of the type references is part of
6430+
// the same implementation. For that reason, check before we add a new entry
6431+
function maybeAdd(a: ReferenceEntry) {
6432+
if (!forEach(result, b => a.fileName === b.fileName && a.textSpan.start === b.textSpan.start && a.textSpan.length === b.textSpan.length)) {
6433+
result.push(a);
6434+
}
6435+
}
64256436
}
64266437

64276438
function getSymbolsForComponentTypes(type: UnionOrIntersectionType, result: Symbol[] = []): Symbol[] {

tests/cases/fourslash/goToImplementationInterface_07.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//// let x1: Foo = [|{ hello () { /**typeReference*/ } }|];
1414
//// let x2: () => Foo = [|(() => { hello () { /**functionType*/} })|];
1515
//// let x3: Foo | Bar = [|{ hello () { /**unionType*/} }|];
16-
//// let x4: Foo & Bar = [|{ hello () { /**intersectionType*/} }|];
16+
//// let x4: Foo & (Foo & Bar) = [|{ hello () { /**intersectionType*/} }|];
1717
//// let x5: [Foo] = [|[{ hello () { /**tupleType*/} }]|];
1818
//// let x6: (Foo) = [|{ hello () { /**parenthesizedType*/} }|];
1919
//// let x7: (new() => Foo) = [|class { hello () { /**constructorType*/} }|];

0 commit comments

Comments
 (0)