From 2f6b59eab9e9e77c133798097b0359e5be009c53 Mon Sep 17 00:00:00 2001 From: Andy Date: Wed, 18 Apr 2018 15:24:19 -0700 Subject: [PATCH] Misc. improvements to addImplementationReferences (#23507) * Misc. improvements to addImplementationReferences * Test typeHavingNode.type === typeNode * Fix bug: refNode.parent -> refNode --- src/services/findAllReferences.ts | 60 +++++++++++-------------------- 1 file changed, 20 insertions(+), 40 deletions(-) diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index b7baf7166b7..60f53c2f527 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -1102,57 +1102,37 @@ namespace ts.FindAllReferences.Core { } // If we got a type reference, try and see if the reference applies to any expressions that can implement an interface - const containingTypeReference = getContainingTypeReference(refNode); - if (containingTypeReference && state.markSeenContainingTypeReference(containingTypeReference)) { - const parent = containingTypeReference.parent; - if (hasType(parent) && parent.type === containingTypeReference && hasInitializer(parent) && isImplementationExpression(parent.initializer)) { - addReference(parent.initializer); + // Find the first node whose parent isn't a type node -- i.e., the highest type node. + const typeNode = findAncestor(refNode, a => !isQualifiedName(a.parent) && !isTypeNode(a.parent) && !isTypeElement(a.parent)); + const typeHavingNode = typeNode.parent; + if (hasType(typeHavingNode) && typeHavingNode.type === typeNode && state.markSeenContainingTypeReference(typeHavingNode)) { + if (hasInitializer(typeHavingNode)) { + addIfImplementation(typeHavingNode.initializer); } - else if (isFunctionLike(parent) && parent.type === containingTypeReference && (parent as FunctionLikeDeclaration).body) { - const body = (parent as FunctionLikeDeclaration).body; + else if (isFunctionLike(typeHavingNode) && (typeHavingNode as FunctionLikeDeclaration).body) { + const body = (typeHavingNode as FunctionLikeDeclaration).body; if (body.kind === SyntaxKind.Block) { forEachReturnStatement(body, returnStatement => { - if (returnStatement.expression && isImplementationExpression(returnStatement.expression)) { - addReference(returnStatement.expression); - } + if (returnStatement.expression) addIfImplementation(returnStatement.expression); }); } - else if (isImplementationExpression(body)) { - addReference(body); + else { + addIfImplementation(body); } } - else if (isAssertionExpression(parent) && isImplementationExpression(parent.expression)) { - addReference(parent.expression); + else if (isAssertionExpression(typeHavingNode)) { + addIfImplementation(typeHavingNode.expression); } } + + function addIfImplementation(e: Expression): void { + if (isImplementationExpression(e)) addReference(e); + } } - function getContainingTypeReference(node: Node): Node { - let topLevelTypeReference: Node; - - while (node) { - if (isTypeNode(node)) { - topLevelTypeReference = node; - } - node = node.parent; - } - - return topLevelTypeReference; - } - - function getContainingClassIfInHeritageClause(node: Node): ClassLikeDeclaration { - if (node && node.parent) { - if (node.kind === SyntaxKind.ExpressionWithTypeArguments - && node.parent.kind === SyntaxKind.HeritageClause - && isClassLike(node.parent.parent)) { - return node.parent.parent; - } - - else if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PropertyAccessExpression) { - return getContainingClassIfInHeritageClause(node.parent); - } - } - return undefined; + function getContainingClassIfInHeritageClause(node: Node): ClassLikeDeclaration | InterfaceDeclaration { + return isIdentifier(node) || isPropertyAccessExpression(node) ? getContainingClassIfInHeritageClause(node.parent) + : isExpressionWithTypeArguments(node) ? tryCast(node.parent.parent, isClassLike) : undefined; } /**