diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cd918ea4dce..027e8f095a0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1496,7 +1496,7 @@ namespace ts { } function checkAndReportErrorForMissingPrefix(errorLocation: Node, name: __String, nameArg: __String | Identifier): boolean { - if ((errorLocation.kind === SyntaxKind.Identifier && (isTypeReferenceIdentifier(errorLocation)) || isInTypeQuery(errorLocation))) { + if (!isIdentifier(errorLocation) || errorLocation.escapedText !== name || isTypeReferenceIdentifier(errorLocation) || isInTypeQuery(errorLocation)) { return false; } diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index f7f5aa0a22f..7dbbc39843f 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -86,7 +86,7 @@ namespace ts.codefix { else { const leftExpressionType = checker.getTypeAtLocation(parent.expression); const { symbol } = leftExpressionType; - if (!(leftExpressionType.flags & TypeFlags.Object && symbol.flags & SymbolFlags.Class)) { + if (!(symbol && leftExpressionType.flags & TypeFlags.Object && symbol.flags & SymbolFlags.Class)) { return undefined; } const classDeclaration = cast(first(symbol.declarations), isClassLike); diff --git a/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts index 1595bbf3c13..8d47e74d8a4 100644 --- a/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts +++ b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts @@ -34,7 +34,7 @@ namespace ts.codefix { function getNodes(sourceFile: SourceFile, pos: number): { readonly constructor: ConstructorDeclaration, readonly superCall: ExpressionStatement } { const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); - Debug.assert(token.kind === SyntaxKind.ThisKeyword); + if (token.kind !== SyntaxKind.ThisKeyword) return undefined; const constructor = getContainingFunction(token) as ConstructorDeclaration; const superCall = findSuperCall(constructor.body); // figure out if the `this` access is actually inside the supercall diff --git a/src/services/codefixes/fixForgottenThisPropertyAccess.ts b/src/services/codefixes/fixForgottenThisPropertyAccess.ts index a3eb30159f5..e71c06399c2 100644 --- a/src/services/codefixes/fixForgottenThisPropertyAccess.ts +++ b/src/services/codefixes/fixForgottenThisPropertyAccess.ts @@ -7,6 +7,9 @@ namespace ts.codefix { getCodeActions(context) { const { sourceFile } = context; const token = getNode(sourceFile, context.span.start); + if (!token) { + return undefined; + } const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, token)); return [{ description: getLocaleSpecificMessage(Diagnostics.Add_this_to_unresolved_variable), changes, fixId }]; }, @@ -16,13 +19,17 @@ namespace ts.codefix { }), }); - function getNode(sourceFile: SourceFile, pos: number): Identifier { - return cast(getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false), isIdentifier); + function getNode(sourceFile: SourceFile, pos: number): Identifier | undefined { + const node = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + return isIdentifier(node) ? node : undefined; } - function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Identifier): void { + function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Identifier | undefined): void { + if (!token) { + return; + } // TODO (https://github.com/Microsoft/TypeScript/issues/21246): use shared helper suppressLeadingAndTrailingTrivia(token); changes.replaceNode(sourceFile, token, createPropertyAccess(createThis(), token), textChanges.useNonAdjustedPositions); } -} \ No newline at end of file +} diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index 2abd82fa7a7..902764a1729 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -86,8 +86,8 @@ namespace ts.codefix { if (containingFunction === undefined) { return undefined; } - switch (errorCode) { + switch (errorCode) { // Parameter declarations case Diagnostics.Parameter_0_implicitly_has_an_1_type.code: if (isSetAccessor(containingFunction)) { @@ -96,7 +96,7 @@ namespace ts.codefix { // falls through case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code: return !seenFunctions || addToSeen(seenFunctions, getNodeId(containingFunction)) - ? getCodeActionForParameters(token.parent, containingFunction, sourceFile, program, cancellationToken) + ? getCodeActionForParameters(cast(token.parent, isParameter), containingFunction, sourceFile, program, cancellationToken) : undefined; // Get Accessor declarations diff --git a/src/services/refactors/useDefaultImport.ts b/src/services/refactors/useDefaultImport.ts index 6ee43cc7503..080092e16ab 100644 --- a/src/services/refactors/useDefaultImport.ts +++ b/src/services/refactors/useDefaultImport.ts @@ -7,7 +7,7 @@ namespace ts.refactor.installTypesForPackage { function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined { const { file, startPosition, program } = context; - if (!program.getCompilerOptions().allowSyntheticDefaultImports) { + if (!getAllowSyntheticDefaultImports(program.getCompilerOptions())) { return undefined; } @@ -17,8 +17,8 @@ namespace ts.refactor.installTypesForPackage { } const module = getResolvedModule(file, importInfo.moduleSpecifier.text); - const resolvedFile = program.getSourceFile(module.resolvedFileName); - if (!(resolvedFile.externalModuleIndicator && isExportAssignment(resolvedFile.externalModuleIndicator) && resolvedFile.externalModuleIndicator.isExportEquals)) { + const resolvedFile = module && program.getSourceFile(module.resolvedFileName); + if (!(resolvedFile && resolvedFile.externalModuleIndicator && isExportAssignment(resolvedFile.externalModuleIndicator) && resolvedFile.externalModuleIndicator.isExportEquals)) { return undefined; } @@ -69,7 +69,7 @@ namespace ts.refactor.installTypesForPackage { case SyntaxKind.ImportDeclaration: const d = node as ImportDeclaration; const { importClause } = d; - return !importClause.name && importClause.namedBindings.kind === SyntaxKind.NamespaceImport && isStringLiteral(d.moduleSpecifier) + return importClause && !importClause.name && importClause.namedBindings.kind === SyntaxKind.NamespaceImport && isStringLiteral(d.moduleSpecifier) ? { importStatement: d, name: importClause.namedBindings.name, moduleSpecifier: d.moduleSpecifier } : undefined; // For known child node kinds of convertible imports, try again with parent node. diff --git a/tests/baselines/reference/jsxFactoryMissingErrorInsideAClass.errors.txt b/tests/baselines/reference/jsxFactoryMissingErrorInsideAClass.errors.txt new file mode 100644 index 00000000000..4bcf84b79da --- /dev/null +++ b/tests/baselines/reference/jsxFactoryMissingErrorInsideAClass.errors.txt @@ -0,0 +1,12 @@ +tests/cases/compiler/test.tsx(3,17): error TS2304: Cannot find name 'factory'. + + +==== tests/cases/compiler/test.tsx (1 errors) ==== + export class C { + factory() { + return
; + ~~~ +!!! error TS2304: Cannot find name 'factory'. + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/jsxFactoryMissingErrorInsideAClass.js b/tests/baselines/reference/jsxFactoryMissingErrorInsideAClass.js new file mode 100644 index 00000000000..67daa7d3329 --- /dev/null +++ b/tests/baselines/reference/jsxFactoryMissingErrorInsideAClass.js @@ -0,0 +1,17 @@ +//// [test.tsx] +export class C { + factory() { + return
; + } +} + + +//// [test.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +class C { + factory() { + return factory.createElement("div", null); + } +} +exports.C = C; diff --git a/tests/baselines/reference/jsxFactoryMissingErrorInsideAClass.symbols b/tests/baselines/reference/jsxFactoryMissingErrorInsideAClass.symbols new file mode 100644 index 00000000000..5e3ada2a717 --- /dev/null +++ b/tests/baselines/reference/jsxFactoryMissingErrorInsideAClass.symbols @@ -0,0 +1,11 @@ +=== tests/cases/compiler/test.tsx === +export class C { +>C : Symbol(C, Decl(test.tsx, 0, 0)) + + factory() { +>factory : Symbol(C.factory, Decl(test.tsx, 0, 16)) + + return
; + } +} + diff --git a/tests/baselines/reference/jsxFactoryMissingErrorInsideAClass.types b/tests/baselines/reference/jsxFactoryMissingErrorInsideAClass.types new file mode 100644 index 00000000000..f1203cdff3c --- /dev/null +++ b/tests/baselines/reference/jsxFactoryMissingErrorInsideAClass.types @@ -0,0 +1,14 @@ +=== tests/cases/compiler/test.tsx === +export class C { +>C : C + + factory() { +>factory : () => any + + return
; +>
: any +>div : any +>div : any + } +} + diff --git a/tests/cases/compiler/jsxFactoryMissingErrorInsideAClass.ts b/tests/cases/compiler/jsxFactoryMissingErrorInsideAClass.ts new file mode 100644 index 00000000000..73b25974f5e --- /dev/null +++ b/tests/cases/compiler/jsxFactoryMissingErrorInsideAClass.ts @@ -0,0 +1,11 @@ +//@jsx: react +//@target: es6 +//@module: commonjs +//@reactNamespace: factory + +//@filename: test.tsx +export class C { + factory() { + return
; + } +} diff --git a/tests/cases/fourslash/codeFixAddMissingMember8.ts b/tests/cases/fourslash/codeFixAddMissingMember8.ts new file mode 100644 index 00000000000..6a3b67ca9f7 --- /dev/null +++ b/tests/cases/fourslash/codeFixAddMissingMember8.ts @@ -0,0 +1,7 @@ +/// + +// @Filename: a.ts +////declare var x: [1, 2]; +////x.b; + +verify.not.codeFixAvailable(); diff --git a/tests/cases/fourslash/codeFixForgottenThisPropertyAccess04.ts b/tests/cases/fourslash/codeFixForgottenThisPropertyAccess04.ts new file mode 100644 index 00000000000..884bad4d21a --- /dev/null +++ b/tests/cases/fourslash/codeFixForgottenThisPropertyAccess04.ts @@ -0,0 +1,14 @@ +/// + +// @jsx: react +// @jsxFactory: factory + +// @Filename: /a.tsx +////export class C { +//// foo() { +//// return ; +//// } +////} + + +verify.not.codeFixAvailable(); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index c05df7a68e6..987af1d6a3a 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -181,7 +181,7 @@ declare namespace FourSlashInterface { errorCode?: number, index?: number, }); - codeFixAvailable(options: Array<{ description: string, actions?: Array<{ type: string, data: {} }>, commands?: {}[] }>): void; + codeFixAvailable(options?: Array<{ description: string, actions?: Array<{ type: string, data: {} }>, commands?: {}[] }>): void; applicableRefactorAvailableAtMarker(markerName: string): void; codeFixDiagnosticsAvailableAtMarkers(markerNames: string[], diagnosticCode?: number): void; applicableRefactorAvailableForRange(): void; diff --git a/tests/cases/fourslash/refactorUseDefaultImport.ts b/tests/cases/fourslash/refactorUseDefaultImport.ts index 8834b70f85e..3846c1d5c1e 100644 --- a/tests/cases/fourslash/refactorUseDefaultImport.ts +++ b/tests/cases/fourslash/refactorUseDefaultImport.ts @@ -12,6 +12,12 @@ // @Filename: /c.ts /////*c0*/import a = require("./a");/*c1*/ +// @Filename: /d.ts +/////*d0*/import "./a";/*d1*/ + +// @Filename: /e.ts +/////*e0*/import * as n from "./non-existant";/*e1*/ + goTo.select("b0", "b1"); edit.applyRefactor({ refactorName: "Convert to default import", @@ -27,3 +33,9 @@ edit.applyRefactor({ actionDescription: "Convert to default import", newContent: 'import a from "./a";', }); + +goTo.select("d0", "d1"); +verify.not.applicableRefactorAvailableAtMarker("d0"); + +goTo.select("e0", "e1"); +verify.not.applicableRefactorAvailableAtMarker("e0"); \ No newline at end of file