From 4881b1be1d1220508c78235f86f5ae77bfb3f8ec Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Wed, 24 May 2017 14:53:34 -0700 Subject: [PATCH 1/4] importFixes: Support missing "React" at a JSXOpeningElement --- src/compiler/checker.ts | 14 +++++-- src/compiler/types.ts | 2 + src/compiler/utilities.ts | 8 ++++ src/harness/fourslash.ts | 5 ++- src/services/codefixes/importFixes.ts | 37 +++++++++++++------ .../importNameCodeFixUMDGlobalReact0.ts | 28 ++++++++++++++ .../importNameCodeFixUMDGlobalReact1.ts | 28 ++++++++++++++ .../importNameCodeFixUMDGlobalReact2.ts | 21 +++++++++++ 8 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 tests/cases/fourslash/importNameCodeFixUMDGlobalReact0.ts create mode 100644 tests/cases/fourslash/importNameCodeFixUMDGlobalReact1.ts create mode 100644 tests/cases/fourslash/importNameCodeFixUMDGlobalReact2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1cbd9e5b54a14..c79c2212de051 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -210,6 +210,10 @@ namespace ts { getSuggestionForNonexistentProperty, getSuggestionForNonexistentSymbol, getBaseConstraintOfType, + getJsxNamespaceSymbol: node => { + node = getParseTreeNode(node); + return getJsxNamespaceSymbol(node, /*diagnostics*/ false); + }, }; const tupleTypes: GenericType[] = []; @@ -14101,9 +14105,7 @@ namespace ts { checkJsxPreconditions(node); // The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import. // And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error. - const reactRefErr = compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined; - const reactNamespace = getJsxNamespace(); - const reactSym = resolveName(node.tagName, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace); + const reactSym = getJsxNamespaceSymbol(node.tagName, /*diagnostics*/ true); if (reactSym) { // Mark local symbol as referenced here because it might not have been marked // if jsx emit was not react as there wont be error being emitted @@ -14118,6 +14120,12 @@ namespace ts { checkJsxAttributesAssignableToTagNameAttributes(node); } + function getJsxNamespaceSymbol(location: ts.Node, diagnostics: boolean): Symbol { + const reactRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined; + const reactNamespace = getJsxNamespace(); + return resolveName(location, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace); + } + /** * Check if a property with the given name is known anywhere in the given type. In an object type, a property * is considered known if the object type is empty and the check is for assignability, if the object type has diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 73a2e46be902f..5a48b68a8be4d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2594,6 +2594,8 @@ namespace ts { * Does not include properties of primitive types. */ /* @internal */ getAllPossiblePropertiesOfType(type: Type): Symbol[]; + + /* @internal */ getJsxNamespaceSymbol(location: ts.Node): Symbol; } export enum NodeBuilderFlags { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 22210419af772..2c04ad0f89ee6 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2004,6 +2004,10 @@ namespace ts { return node.kind === SyntaxKind.NumericLiteral; } + export function isStringLiteral(node: Node): node is StringLiteral { + return node.kind === SyntaxKind.StringLiteral; + } + export function isStringOrNumericLiteral(node: Node): node is StringLiteral | NumericLiteral { const kind = node.kind; return kind === SyntaxKind.StringLiteral @@ -4043,6 +4047,10 @@ namespace ts { return node.kind === SyntaxKind.ExportAssignment; } + export function isModuleDeclaration(node: Node): node is ModuleDeclaration { + return node.kind === SyntaxKind.ModuleDeclaration; + } + export function isModuleOrEnumDeclaration(node: Node): node is ModuleDeclaration | EnumDeclaration { return node.kind === SyntaxKind.ModuleDeclaration || node.kind === SyntaxKind.EnumDeclaration; } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 8f19b83c7ada5..a66d86f0199dd 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2385,7 +2385,10 @@ namespace FourSlash { const codeFixes = this.getCodeFixActions(this.activeFile.fileName, errorCode); if (!codeFixes || codeFixes.length === 0) { - this.raiseError("No codefixes returned."); + if (expectedTextArray.length !== 0) { + this.raiseError("No codefixes returned."); + } + return; } const actualTextArray: string[] = []; diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 53ec99fac81a4..e1688cd810c0b 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -138,8 +138,22 @@ namespace ts.codefix { const currentTokenMeaning = getMeaningFromLocation(token); if (context.errorCode === Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code) { - const symbol = checker.getAliasedSymbol(checker.getSymbolAtLocation(token)); - return getCodeActionForImport(symbol, /*isDefault*/ false, /*isNamespaceImport*/ true); + const umdSymbol = checker.getSymbolAtLocation(token); + let symbol: ts.Symbol; + let symbolName: string; + if (umdSymbol.flags & ts.SymbolFlags.Alias) { + symbol = checker.getAliasedSymbol(umdSymbol); + symbolName = name; + } else if (isJsxOpeningLikeElement(token.parent) && token.parent.tagName === token) { + // The error wasn't for the symbolAtLocation, it was for the JSX tag itself, which needs access to e.g. `React`. + symbol = checker.getAliasedSymbol(checker.getJsxNamespaceSymbol(token)); + symbolName = symbol.name; + } + else { + Debug.fail("Either the symbol or the JSX namespace should be a UMD global if we got here"); + } + + return getCodeActionForImport(symbol, symbolName, /*isDefault*/ false, /*isNamespaceImport*/ true); } const candidateModules = checker.getAmbientModules(); @@ -159,7 +173,7 @@ namespace ts.codefix { if (localSymbol && localSymbol.name === name && checkSymbolHasMeaning(localSymbol, currentTokenMeaning)) { // check if this symbol is already used const symbolId = getUniqueSymbolId(localSymbol); - symbolIdActionMap.addActions(symbolId, getCodeActionForImport(moduleSymbol, /*isDefault*/ true)); + symbolIdActionMap.addActions(symbolId, getCodeActionForImport(moduleSymbol, name, /*isDefault*/ true)); } } @@ -167,7 +181,7 @@ namespace ts.codefix { const exportSymbolWithIdenticalName = checker.tryGetMemberInModuleExports(name, moduleSymbol); if (exportSymbolWithIdenticalName && checkSymbolHasMeaning(exportSymbolWithIdenticalName, currentTokenMeaning)) { const symbolId = getUniqueSymbolId(exportSymbolWithIdenticalName); - symbolIdActionMap.addActions(symbolId, getCodeActionForImport(moduleSymbol)); + symbolIdActionMap.addActions(symbolId, getCodeActionForImport(moduleSymbol, name)); } } @@ -218,7 +232,7 @@ namespace ts.codefix { return declarations ? some(symbol.declarations, decl => !!(getMeaningFromDeclaration(decl) & meaning)) : false; } - function getCodeActionForImport(moduleSymbol: Symbol, isDefault?: boolean, isNamespaceImport?: boolean): ImportCodeAction[] { + function getCodeActionForImport(moduleSymbol: Symbol, symbolName: string, isDefault?: boolean, isNamespaceImport?: boolean): ImportCodeAction[] { const existingDeclarations = getImportDeclarations(moduleSymbol); if (existingDeclarations.length > 0) { // With an existing import statement, there are more than one actions the user can do. @@ -375,10 +389,10 @@ namespace ts.codefix { const moduleSpecifierWithoutQuotes = stripQuotes(moduleSpecifier || getModuleSpecifierForNewImport()); const changeTracker = createChangeTracker(); const importClause = isDefault - ? createImportClause(createIdentifier(name), /*namedBindings*/ undefined) + ? createImportClause(createIdentifier(symbolName), /*namedBindings*/ undefined) : isNamespaceImport - ? createImportClause(/*name*/ undefined, createNamespaceImport(createIdentifier(name))) - : createImportClause(/*name*/ undefined, createNamedImports([createImportSpecifier(/*propertyName*/ undefined, createIdentifier(name))])); + ? createImportClause(/*name*/ undefined, createNamespaceImport(createIdentifier(symbolName))) + : createImportClause(/*name*/ undefined, createNamedImports([createImportSpecifier(/*propertyName*/ undefined, createIdentifier(symbolName))])); const importDecl = createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, importClause, createLiteral(moduleSpecifierWithoutQuotes)); if (!lastImportDeclaration) { changeTracker.insertNodeAt(sourceFile, sourceFile.getStart(), importDecl, { suffix: `${context.newLineCharacter}${context.newLineCharacter}` }); @@ -392,7 +406,7 @@ namespace ts.codefix { // are there are already a new line seperating code and import statements. return createCodeAction( Diagnostics.Import_0_from_1, - [name, `"${moduleSpecifierWithoutQuotes}"`], + [symbolName, `"${moduleSpecifierWithoutQuotes}"`], changeTracker.getChanges(), "NewImport", moduleSpecifierWithoutQuotes @@ -412,8 +426,9 @@ namespace ts.codefix { removeFileExtension(getRelativePath(moduleFileName, sourceDirectory)); function tryGetModuleNameFromAmbientModule(): string { - if (moduleSymbol.valueDeclaration.kind !== SyntaxKind.SourceFile) { - return moduleSymbol.name; + const decl = moduleSymbol.valueDeclaration; + if (isModuleDeclaration(decl) && isStringLiteral(decl.name)) { + return decl.name.text; } } diff --git a/tests/cases/fourslash/importNameCodeFixUMDGlobalReact0.ts b/tests/cases/fourslash/importNameCodeFixUMDGlobalReact0.ts new file mode 100644 index 0000000000000..260c34d10a604 --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFixUMDGlobalReact0.ts @@ -0,0 +1,28 @@ +/// + +// @jsx: react + +// @Filename: /node_modules/@types/react/index.d.ts +////export = React; +////export as namespace React; +////declare namespace React { +//// export class Component { render(): JSX.Element | null; } +////} +////declare global { +//// namespace JSX { +//// interface Element {} +//// } +////} + +// @Filename: /a.tsx +////[|import { Component } from "react"; +////export class MyMap extends Component { } +////;|] + +goTo.file("/a.tsx"); + +verify.importFixAtPosition([ +`import { Component } from "react"; +import * as React from "react"; +export class MyMap extends Component { } +;`]); diff --git a/tests/cases/fourslash/importNameCodeFixUMDGlobalReact1.ts b/tests/cases/fourslash/importNameCodeFixUMDGlobalReact1.ts new file mode 100644 index 0000000000000..ccd69c501997a --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFixUMDGlobalReact1.ts @@ -0,0 +1,28 @@ +/// + +// @jsx: react + +// @Filename: /node_modules/@types/react/index.d.ts +////export = React; +////export as namespace React; +////declare namespace React { +//// export class Component { render(): JSX.Element | null; } +////} +////declare global { +//// namespace JSX { +//// interface Element {} +//// } +////} + +// @Filename: /a.tsx +////[|import { Component } from "react"; +////export class MyMap extends Component { } +////;|] + +goTo.file("/a.tsx"); + +verify.importFixAtPosition([ +`import { Component } from "react"; +import * as React from "react"; +export class MyMap extends Component { } +;`]); diff --git a/tests/cases/fourslash/importNameCodeFixUMDGlobalReact2.ts b/tests/cases/fourslash/importNameCodeFixUMDGlobalReact2.ts new file mode 100644 index 0000000000000..a3c8253fbd1a7 --- /dev/null +++ b/tests/cases/fourslash/importNameCodeFixUMDGlobalReact2.ts @@ -0,0 +1,21 @@ +/// + +// https://github.com/Microsoft/TypeScript/issues/16065 + +// @jsx: react +// @jsxFactory: factory + +// @Filename: /factory.ts +////export function factory() { return {}; } +////declare global { +//// namespace JSX { +//// interface Element {} +//// } +////} + +// @Filename: /a.tsx +////[|
|] + +goTo.file("/a.tsx"); +verify.not +verify.importFixAtPosition([]); From dbb4d46e6bf8b16f78af76bc8d895fc161d8ae0c Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Thu, 25 May 2017 07:09:04 -0700 Subject: [PATCH 2/4] Fix nextLineRule linting --- scripts/tslint/nextLineRule.ts | 4 ++-- src/compiler/checker.ts | 3 ++- src/compiler/program.ts | 3 ++- src/services/codefixes/importFixes.ts | 3 ++- src/services/findAllReferences.ts | 3 ++- src/services/importTracker.ts | 3 ++- 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/scripts/tslint/nextLineRule.ts b/scripts/tslint/nextLineRule.ts index b149d09eb38a8..fa03746afc6b9 100644 --- a/scripts/tslint/nextLineRule.ts +++ b/scripts/tslint/nextLineRule.ts @@ -18,7 +18,7 @@ export class Rule extends Lint.Rules.AbstractRule { function walk(ctx: Lint.WalkContext, checkCatch: boolean, checkElse: boolean): void { const { sourceFile } = ctx; - function recur(node: ts.Node): void { + ts.forEachChild(sourceFile, function recur(node) { switch (node.kind) { case ts.SyntaxKind.IfStatement: checkIf(node as ts.IfStatement); @@ -28,7 +28,7 @@ function walk(ctx: Lint.WalkContext, checkCatch: boolean, checkElse: boole break; } ts.forEachChild(node, recur); - } + }); function checkIf(node: ts.IfStatement): void { const { thenStatement, elseStatement } = node; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c79c2212de051..280d610a46b7a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5844,7 +5844,8 @@ namespace ts { } } return arrayFrom(props.values()); - } else { + } + else { return getPropertiesOfType(type); } } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index dd293727b4ad6..c43ec82e2f22f 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1483,7 +1483,8 @@ namespace ts { } } return sourceFile; - } else { + } + else { const sourceFileNoExtension = options.allowNonTsExtensions && getSourceFile(fileName); if (sourceFileNoExtension) return sourceFileNoExtension; diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index e1688cd810c0b..c1e72c1655e92 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -144,7 +144,8 @@ namespace ts.codefix { if (umdSymbol.flags & ts.SymbolFlags.Alias) { symbol = checker.getAliasedSymbol(umdSymbol); symbolName = name; - } else if (isJsxOpeningLikeElement(token.parent) && token.parent.tagName === token) { + } + else if (isJsxOpeningLikeElement(token.parent) && token.parent.tagName === token) { // The error wasn't for the symbolAtLocation, it was for the JSX tag itself, which needs access to e.g. `React`. symbol = checker.getAliasedSymbol(checker.getJsxNamespaceSymbol(token)); symbolName = symbol.name; diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index efc6a6f6ed1cf..5425239307e27 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -185,7 +185,8 @@ namespace ts.FindAllReferences { if (entry.type === "node") { const { node } = entry; return { textSpan: getTextSpan(node), fileName: node.getSourceFile().fileName, ...implementationKindDisplayParts(node, checker) }; - } else { + } + else { const { textSpan, fileName } = entry; return { textSpan, fileName, kind: ScriptElementKind.unknown, displayParts: [] }; } diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index f20c80c14ef96..585af7ebd31aa 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -530,7 +530,8 @@ namespace ts.FindAllReferences { 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 { + } + else { return parent; } } From e31b4e7f435159a3a0a514a6dd42d42d119d85d1 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Thu, 25 May 2017 12:58:36 -0700 Subject: [PATCH 3/4] Rename to resolveJsxNamespaceAtLocation --- src/compiler/checker.ts | 8 ++++---- src/compiler/types.ts | 2 +- src/services/codefixes/importFixes.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 280d610a46b7a..4f9aeda8ca63a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -210,9 +210,9 @@ namespace ts { getSuggestionForNonexistentProperty, getSuggestionForNonexistentSymbol, getBaseConstraintOfType, - getJsxNamespaceSymbol: node => { + resolveJsxNamespaceAtLocation: node => { node = getParseTreeNode(node); - return getJsxNamespaceSymbol(node, /*diagnostics*/ false); + return resolveJsxNamespaceAtLocation(node, /*diagnostics*/ false); }, }; @@ -14106,7 +14106,7 @@ namespace ts { checkJsxPreconditions(node); // The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import. // And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error. - const reactSym = getJsxNamespaceSymbol(node.tagName, /*diagnostics*/ true); + const reactSym = resolveJsxNamespaceAtLocation(node.tagName, /*diagnostics*/ true); if (reactSym) { // Mark local symbol as referenced here because it might not have been marked // if jsx emit was not react as there wont be error being emitted @@ -14121,7 +14121,7 @@ namespace ts { checkJsxAttributesAssignableToTagNameAttributes(node); } - function getJsxNamespaceSymbol(location: ts.Node, diagnostics: boolean): Symbol { + function resolveJsxNamespaceAtLocation(location: ts.Node, diagnostics: boolean): Symbol { const reactRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined; const reactNamespace = getJsxNamespace(); return resolveName(location, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5a48b68a8be4d..d1a667c311e32 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2595,7 +2595,7 @@ namespace ts { */ /* @internal */ getAllPossiblePropertiesOfType(type: Type): Symbol[]; - /* @internal */ getJsxNamespaceSymbol(location: ts.Node): Symbol; + /* @internal */ resolveJsxNamespaceAtLocation(location: ts.Node): Symbol; } export enum NodeBuilderFlags { diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index c1e72c1655e92..087dc514cf0c9 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -147,7 +147,7 @@ namespace ts.codefix { } else if (isJsxOpeningLikeElement(token.parent) && token.parent.tagName === token) { // The error wasn't for the symbolAtLocation, it was for the JSX tag itself, which needs access to e.g. `React`. - symbol = checker.getAliasedSymbol(checker.getJsxNamespaceSymbol(token)); + symbol = checker.getAliasedSymbol(checker.resolveJsxNamespaceAtLocation(token)); symbolName = symbol.name; } else { From 69056393d3e5737bac72b3e8d8b1470f64e2d008 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Fri, 26 May 2017 07:36:19 -0700 Subject: [PATCH 4/4] Expose getJsxNamespace and resolveNameAtLocation separately --- src/compiler/checker.ts | 19 ++++++++----------- src/compiler/types.ts | 3 ++- src/services/codefixes/importFixes.ts | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4f9aeda8ca63a..b876c758f4b38 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -210,9 +210,10 @@ namespace ts { getSuggestionForNonexistentProperty, getSuggestionForNonexistentSymbol, getBaseConstraintOfType, - resolveJsxNamespaceAtLocation: node => { - node = getParseTreeNode(node); - return resolveJsxNamespaceAtLocation(node, /*diagnostics*/ false); + getJsxNamespace, + resolveNameAtLocation(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined { + location = getParseTreeNode(location); + return resolveName(location, name, meaning, /*nameNotFoundMessage*/ undefined, name); }, }; @@ -851,7 +852,7 @@ namespace ts { location: Node | undefined, name: string, meaning: SymbolFlags, - nameNotFoundMessage: DiagnosticMessage, + nameNotFoundMessage: DiagnosticMessage | undefined, nameArg: string | Identifier, suggestedNameNotFoundMessage?: DiagnosticMessage): Symbol { return resolveNameHelper(location, name, meaning, nameNotFoundMessage, nameArg, getSymbol, suggestedNameNotFoundMessage); @@ -14106,7 +14107,9 @@ namespace ts { checkJsxPreconditions(node); // The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import. // And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error. - const reactSym = resolveJsxNamespaceAtLocation(node.tagName, /*diagnostics*/ true); + const reactRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined; + const reactNamespace = getJsxNamespace(); + const reactSym = resolveName(node.tagName, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace); if (reactSym) { // Mark local symbol as referenced here because it might not have been marked // if jsx emit was not react as there wont be error being emitted @@ -14121,12 +14124,6 @@ namespace ts { checkJsxAttributesAssignableToTagNameAttributes(node); } - function resolveJsxNamespaceAtLocation(location: ts.Node, diagnostics: boolean): Symbol { - const reactRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined; - const reactNamespace = getJsxNamespace(); - return resolveName(location, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace); - } - /** * Check if a property with the given name is known anywhere in the given type. In an object type, a property * is considered known if the object type is empty and the check is for assignability, if the object type has diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d1a667c311e32..3a2e8f4914bf6 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2595,7 +2595,8 @@ namespace ts { */ /* @internal */ getAllPossiblePropertiesOfType(type: Type): Symbol[]; - /* @internal */ resolveJsxNamespaceAtLocation(location: ts.Node): Symbol; + /* @internal */ getJsxNamespace(): string; + /* @internal */ resolveNameAtLocation(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined; } export enum NodeBuilderFlags { diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 087dc514cf0c9..c2d26da4392d1 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -147,7 +147,7 @@ namespace ts.codefix { } else if (isJsxOpeningLikeElement(token.parent) && token.parent.tagName === token) { // The error wasn't for the symbolAtLocation, it was for the JSX tag itself, which needs access to e.g. `React`. - symbol = checker.getAliasedSymbol(checker.resolveJsxNamespaceAtLocation(token)); + symbol = checker.getAliasedSymbol(checker.resolveNameAtLocation(token, checker.getJsxNamespace(), SymbolFlags.Value)); symbolName = symbol.name; } else {