From 916f9b7344852baa8a3ac830954541b996e55d90 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 23 Mar 2023 12:08:52 -0700 Subject: [PATCH] Handle jsx runtime implicit synthetic import in find all references (#51319) --- src/services/findAllReferences.ts | 13 +++++ src/services/importTracker.ts | 10 ++-- ...esOnRuntimeImportWithPaths1.baseline.jsonc | 49 +++++++++++++++++++ ...esOnRuntimeImportWithPaths1.baseline.jsonc | 38 ++++++++++++++ ...dAllReferencesOnRuntimeImportWithPaths1.ts | 31 ++++++++++++ ...dAllReferencesOnRuntimeImportWithPaths1.ts | 25 ++++++++++ 6 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/jsxFindAllReferencesOnRuntimeImportWithPaths1.baseline.jsonc create mode 100644 tests/baselines/reference/tslibFindAllReferencesOnRuntimeImportWithPaths1.baseline.jsonc create mode 100644 tests/cases/fourslash/jsxFindAllReferencesOnRuntimeImportWithPaths1.ts create mode 100644 tests/cases/fourslash/tslibFindAllReferencesOnRuntimeImportWithPaths1.ts diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index e189ce87cae..519249b4103 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -29,6 +29,7 @@ import { escapeLeadingUnderscores, ExportSpecifier, Expression, + externalHelpersModuleNameText, FileIncludeReason, FileReference, filter, @@ -41,6 +42,7 @@ import { firstOrUndefined, flatMap, forEachChild, + forEachChildRecursively, forEachReturnStatement, ForInOrOfStatement, FunctionDeclaration, @@ -130,6 +132,8 @@ import { isJSDocMemberName, isJSDocTag, isJsxClosingElement, + isJsxElement, + isJsxFragment, isJsxOpeningElement, isJsxSelfClosingElement, isJumpStatementTarget, @@ -231,6 +235,7 @@ import { textPart, TextSpan, tokenToString, + TransformFlags, tryAddToSet, tryCast, tryGetClassExtendingExpressionWithTypeArguments, @@ -1125,6 +1130,14 @@ export namespace Core { // import("foo") with no qualifier will reference the `export =` of the module, which may be referenced anyway. return nodeEntry(reference.literal); } + else if (reference.kind === "implicit") { + // Return either: The first JSX node in the (if not a tslib import), the first statement of the file, or the whole file if neither of those exist + const range = reference.literal.text !== externalHelpersModuleNameText && forEachChildRecursively( + reference.referencingFile, + n => !(n.transformFlags & TransformFlags.ContainsJsx) ? "skip" : isJsxElement(n) || isJsxSelfClosingElement(n) || isJsxFragment(n) ? n : undefined + ) || reference.referencingFile.statements[0] || reference.referencingFile; + return nodeEntry(range); + } else { return { kind: EntryKind.Span, diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index c2a2bacc86c..c4e47695ebe 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -63,6 +63,7 @@ import { NamedImportsOrExports, NamespaceImport, Node, + nodeIsSynthesized, nodeSeenTracker, Program, some, @@ -450,7 +451,10 @@ export type ModuleReference = /** "import" also includes require() calls. */ | { kind: "import", literal: StringLiteralLike } /** or */ - | { kind: "reference", referencingFile: SourceFile, ref: FileReference }; + | { kind: "reference", referencingFile: SourceFile, ref: FileReference } + /** Containing file implicitly references the module (eg, via implicit jsx runtime import) */ + | { kind: "implicit", literal: StringLiteralLike, referencingFile: SourceFile }; + /** @internal */ export function findModuleReferences(program: Program, sourceFiles: readonly SourceFile[], searchModuleSymbol: Symbol): ModuleReference[] { const refs: ModuleReference[] = []; @@ -471,10 +475,10 @@ export function findModuleReferences(program: Program, sourceFiles: readonly Sou } } - forEachImport(referencingFile, (_importDecl, moduleSpecifier) => { + forEachImport(referencingFile, (importDecl, moduleSpecifier) => { const moduleSymbol = checker.getSymbolAtLocation(moduleSpecifier); if (moduleSymbol === searchModuleSymbol) { - refs.push({ kind: "import", literal: moduleSpecifier }); + refs.push(nodeIsSynthesized(importDecl) ? { kind: "implicit", literal: moduleSpecifier, referencingFile } : { kind: "import", literal: moduleSpecifier }); } }); } diff --git a/tests/baselines/reference/jsxFindAllReferencesOnRuntimeImportWithPaths1.baseline.jsonc b/tests/baselines/reference/jsxFindAllReferencesOnRuntimeImportWithPaths1.baseline.jsonc new file mode 100644 index 00000000000..e512e8d47cb --- /dev/null +++ b/tests/baselines/reference/jsxFindAllReferencesOnRuntimeImportWithPaths1.baseline.jsonc @@ -0,0 +1,49 @@ +// === findAllReferences === +// === /tests/cases/fourslash/project/src/dir/jsx-runtime.ts === +// [|export {}|] + +// === /tests/cases/fourslash/project/src/foo.ts === +// [|<|import * as x from /*FIND ALL REFS*/"[|@foo/dir/jsx-runtime|]";|]|> + +// === /tests/cases/fourslash/project/src/bar.tsx === +// <|export default [|
|];|> + +// === /tests/cases/fourslash/project/src/baz.tsx === +// <|export default [|<>|];|> + +// === /tests/cases/fourslash/project/src/bam.tsx === +// <|export default [|