From 4ff180d8149a2b96aec15bd64064d5cc2a6aa55f Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 21 Apr 2017 07:53:09 -0700 Subject: [PATCH] Fix null error in importTracker: VariableDeclaration might not have a VariableStatement ancestor --- src/compiler/utilities.ts | 2 +- src/services/importTracker.ts | 17 ++++++++++++++--- tests/cases/fourslash/findAllRefsCatchClause.ts | 8 ++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 tests/cases/fourslash/findAllRefsCatchClause.ts diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f34c15ee346..646a7b22e3f 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1870,7 +1870,7 @@ namespace ts { } } - export function getAncestor(node: Node | undefined, kind: SyntaxKind): Node { + export function getAncestor(node: Node | undefined, kind: SyntaxKind): Node | undefined { while (node) { if (node.kind === kind) { return node; diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index 1d1f9d881e1..0108d830dd1 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -387,6 +387,7 @@ namespace ts.FindAllReferences { symbol: Symbol; exportInfo: ExportInfo; } + /** * Given a local reference, we might notice that it's an import/export and recursively search for references of that. * If at an import, look locally for the symbol it imports. @@ -398,7 +399,7 @@ namespace ts.FindAllReferences { return comingFromExport ? getExport() : getExport() || getImport(); function getExport(): ExportedSymbol | ImportedSymbol | undefined { - const { parent } = node; + const parent = node.parent!; if (symbol.flags & SymbolFlags.Export) { if (parent.kind === SyntaxKind.PropertyAccessExpression) { // When accessing an export of a JS module, there's no alias. The symbol will still be flagged as an export even though we're at the use. @@ -414,8 +415,8 @@ namespace ts.FindAllReferences { } } else { - const exportNode = parent.kind === SyntaxKind.VariableDeclaration ? getAncestor(parent, SyntaxKind.VariableStatement) : parent; - if (hasModifier(exportNode, ModifierFlags.Export)) { + const exportNode = getExportNode(parent); + if (exportNode && hasModifier(exportNode, ModifierFlags.Export)) { if (exportNode.kind === SyntaxKind.ImportEqualsDeclaration && (exportNode as ImportEqualsDeclaration).moduleReference === node) { // We're at `Y` in `export import X = Y`. This is not the exported symbol, the left-hand-side is. So treat this as an import statement. if (comingFromExport) { @@ -492,6 +493,16 @@ namespace ts.FindAllReferences { } } + // If a reference is a variable declaration, the exported node would be the variable statement. + function getExportNode(parent: Node): Node | undefined { + if (parent.kind === SyntaxKind.VariableDeclaration) { + const p = parent as ts.VariableDeclaration; + return p.parent.kind === ts.SyntaxKind.CatchClause ? undefined : p.parent.parent.kind === SyntaxKind.VariableStatement ? p.parent.parent : undefined; + } else { + return parent; + } + } + function isNodeImport(node: Node): { isNamedImport: boolean } | undefined { const { parent } = node; switch (parent.kind) { diff --git a/tests/cases/fourslash/findAllRefsCatchClause.ts b/tests/cases/fourslash/findAllRefsCatchClause.ts new file mode 100644 index 00000000000..0e7e3799850 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsCatchClause.ts @@ -0,0 +1,8 @@ +/// + +////try { } +////catch ([|{| "isWriteAccess": true, "isDefinition": true |}err|]) { +//// [|err|]; +////} + +verify.singleReferenceGroup("var err: any");