From f4e371c73127494d5231b793396def3a958fafe2 Mon Sep 17 00:00:00 2001 From: Ryan Cavanaugh Date: Thu, 27 Feb 2020 14:55:49 -0800 Subject: [PATCH] Harden findAllReferences.ts against `symbol.declarations = undefined` cases (#37088) Fixes #37086 --- src/services/findAllReferences.ts | 36 ++++++++++--------- ...hlightsForExportFromUnfoundModule.baseline | 5 +++ .../highlightsForExportFromUnfoundModule.ts | 17 +++++++++ 3 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 tests/baselines/reference/highlightsForExportFromUnfoundModule.baseline create mode 100644 tests/cases/fourslash/highlightsForExportFromUnfoundModule.ts diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 474cb590a00..4682bd29fe3 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -700,19 +700,21 @@ namespace ts.FindAllReferences { } }); - for (const decl of symbol.declarations) { - switch (decl.kind) { - case SyntaxKind.SourceFile: - // Don't include the source file itself. (This may not be ideal behavior, but awkward to include an entire file as a reference.) - break; - case SyntaxKind.ModuleDeclaration: - if (sourceFilesSet.has(decl.getSourceFile().fileName)) { - references.push(nodeEntry((decl as ModuleDeclaration).name)); - } - break; - default: - // This may be merged with something. - Debug.assert(!!(symbol.flags & SymbolFlags.Transient), "Expected a module symbol to be declared by a SourceFile or ModuleDeclaration."); + if (symbol.declarations) { + for (const decl of symbol.declarations) { + switch (decl.kind) { + case SyntaxKind.SourceFile: + // Don't include the source file itself. (This may not be ideal behavior, but awkward to include an entire file as a reference.) + break; + case SyntaxKind.ModuleDeclaration: + if (sourceFilesSet.has(decl.getSourceFile().fileName)) { + references.push(nodeEntry((decl as ModuleDeclaration).name)); + } + break; + default: + // This may be merged with something. + Debug.assert(!!(symbol.flags & SymbolFlags.Transient), "Expected a module symbol to be declared by a SourceFile or ModuleDeclaration."); + } } } @@ -1075,6 +1077,8 @@ namespace ts.FindAllReferences { // Go to the symbol we imported from and find references for it. function searchForImportedSymbol(symbol: Symbol, state: State): void { + if (!symbol.declarations) return; + for (const declaration of symbol.declarations) { const exportingFile = declaration.getSourceFile(); // Need to search in the file even if it's not in the search-file set, because it might export the symbol. @@ -1554,7 +1558,7 @@ namespace ts.FindAllReferences { */ function findOwnConstructorReferences(classSymbol: Symbol, sourceFile: SourceFile, addNode: (node: Node) => void): void { const constructorSymbol = getClassConstructorSymbol(classSymbol); - if (constructorSymbol) { + if (constructorSymbol && constructorSymbol.declarations) { for (const decl of constructorSymbol.declarations) { const ctrKeyword = findChildOfKind(decl, SyntaxKind.ConstructorKeyword, sourceFile)!; Debug.assert(decl.kind === SyntaxKind.Constructor && !!ctrKeyword); @@ -1586,7 +1590,7 @@ namespace ts.FindAllReferences { /** Find references to `super` in the constructor of an extending class. */ function findSuperConstructorAccesses(classDeclaration: ClassLikeDeclaration, addNode: (node: Node) => void): void { const constructor = getClassConstructorSymbol(classDeclaration.symbol); - if (!constructor) { + if (!(constructor && constructor.declarations)) { return; } @@ -1722,7 +1726,7 @@ namespace ts.FindAllReferences { // Set the key so that we don't infinitely recurse cachedResults.set(key, false); - const inherits = symbol.declarations.some(declaration => + const inherits = !!symbol.declarations && symbol.declarations.some(declaration => getAllSuperTypeNodes(declaration).some(typeReference => { const type = checker.getTypeAtLocation(typeReference); return !!type && !!type.symbol && explicitlyInheritsFrom(type.symbol, parent, cachedResults, checker); diff --git a/tests/baselines/reference/highlightsForExportFromUnfoundModule.baseline b/tests/baselines/reference/highlightsForExportFromUnfoundModule.baseline new file mode 100644 index 00000000000..6f5759046e7 --- /dev/null +++ b/tests/baselines/reference/highlightsForExportFromUnfoundModule.baseline @@ -0,0 +1,5 @@ +/*====== /tests/cases/fourslash/b.js ======*/ + +export { + [|RENAME|] +} from './a'; diff --git a/tests/cases/fourslash/highlightsForExportFromUnfoundModule.ts b/tests/cases/fourslash/highlightsForExportFromUnfoundModule.ts new file mode 100644 index 00000000000..146441505d5 --- /dev/null +++ b/tests/cases/fourslash/highlightsForExportFromUnfoundModule.ts @@ -0,0 +1,17 @@ +/// + +// @allowJs: true + +// @Filename: a.js +//// import foo from 'unfound'; +//// export { +//// foo, +//// }; + +// @Filename: b.js +//// export { +//// /**/foo +//// } from './a'; + +goTo.marker(); +verify.baselineRename("", { });