From 405d8cf8ebd3f6c9c2a5f7e19c2a687235ec0a18 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 9 Oct 2017 10:45:50 -0700 Subject: [PATCH 1/4] In getSuggestionForNonexistentSymbol, guard name against undefined --- src/compiler/checker.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a8e18c432a6..738a484d254 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15064,7 +15064,10 @@ namespace ts { function getSuggestionForNonexistentSymbol(location: Node, name: __String, meaning: SymbolFlags): string { const result = resolveNameHelper(location, name, meaning, /*nameNotFoundMessage*/ undefined, name, /*isUse*/ false, (symbols, name, meaning) => { - // `name` from the callback === the outer `name` + // NOTE: `name` from the callback is supposed to === the outer `name`, but is undefined in some cases + if (name === undefined) { + return undefined; + } const symbol = getSymbol(symbols, name, meaning); // Sometimes the symbol is found when location is a return type of a function: `typeof x` and `x` is declared in the body of the function // So the table *contains* `x` but `x` isn't actually in scope. From a6a5b85b522b89d061aaf0baaaaf39103ba0c346 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 1 Nov 2017 10:33:24 -0700 Subject: [PATCH 2/4] Switch from undefined guard to asserts In both fixSpelling and getSuggestionForNonexistentSymbol --- src/compiler/checker.ts | 9 +++------ src/services/codefixes/fixSpelling.ts | 4 +++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 738a484d254..b28ecb082a1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15062,12 +15062,9 @@ namespace ts { return suggestion && symbolName(suggestion); } - function getSuggestionForNonexistentSymbol(location: Node, name: __String, meaning: SymbolFlags): string { - const result = resolveNameHelper(location, name, meaning, /*nameNotFoundMessage*/ undefined, name, /*isUse*/ false, (symbols, name, meaning) => { - // NOTE: `name` from the callback is supposed to === the outer `name`, but is undefined in some cases - if (name === undefined) { - return undefined; - } + function getSuggestionForNonexistentSymbol(location: Node, outerName: __String, meaning: SymbolFlags): string { + const result = resolveNameHelper(location, outerName, meaning, /*nameNotFoundMessage*/ undefined, outerName, /*isUse*/ false, (symbols, name, meaning) => { + Debug.assert(name !== undefined, "name should always be defined, and equal to " + outerName); const symbol = getSymbol(symbols, name, meaning); // Sometimes the symbol is found when location is a return type of a function: `typeof x` and `x` is declared in the body of the function // So the table *contains* `x` but `x` isn't actually in scope. diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts index ff3bd455291..e5c15ade5a2 100644 --- a/src/services/codefixes/fixSpelling.ts +++ b/src/services/codefixes/fixSpelling.ts @@ -22,7 +22,9 @@ namespace ts.codefix { } else { const meaning = getMeaningFromLocation(node); - suggestion = checker.getSuggestionForNonexistentSymbol(node, getTextOfNode(node), convertSemanticMeaningToSymbolFlags(meaning)); + const name = getTextOfNode(node); + Debug.assert(!!name, "name should be defined"); + suggestion = checker.getSuggestionForNonexistentSymbol(node, name, convertSemanticMeaningToSymbolFlags(meaning)); } if (suggestion) { return [{ From 146addc4d54b4146da359e69d643ea85f39abb55 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 1 Nov 2017 10:35:54 -0700 Subject: [PATCH 3/4] Use explicit undefined checkk --- src/services/codefixes/fixSpelling.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts index e5c15ade5a2..2546a92a32f 100644 --- a/src/services/codefixes/fixSpelling.ts +++ b/src/services/codefixes/fixSpelling.ts @@ -23,7 +23,7 @@ namespace ts.codefix { else { const meaning = getMeaningFromLocation(node); const name = getTextOfNode(node); - Debug.assert(!!name, "name should be defined"); + Debug.assert(name !== undefined, "name should be defined"); suggestion = checker.getSuggestionForNonexistentSymbol(node, name, convertSemanticMeaningToSymbolFlags(meaning)); } if (suggestion) { From c6f343e266f2ffd3c69711dbf3ea02fdde2d3485 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 7 Nov 2017 14:47:08 -0800 Subject: [PATCH 4/4] Improve asserts in getSuggestionForNonexistentSymbol --- src/compiler/checker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4c88bce12f2..2990f0cc3f8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15291,8 +15291,9 @@ namespace ts { } function getSuggestionForNonexistentSymbol(location: Node, outerName: __String, meaning: SymbolFlags): string { + Debug.assert(outerName !== undefined, "outername should always be defined"); const result = resolveNameHelper(location, outerName, meaning, /*nameNotFoundMessage*/ undefined, outerName, /*isUse*/ false, (symbols, name, meaning) => { - Debug.assert(name !== undefined, "name should always be defined, and equal to " + outerName); + Debug.assertEqual(outerName, name, "name should equal outerName"); const symbol = getSymbol(symbols, name, meaning); // Sometimes the symbol is found when location is a return type of a function: `typeof x` and `x` is declared in the body of the function // So the table *contains* `x` but `x` isn't actually in scope.