From a88d588a07d66b2dc71d667075d70c5b7c271f54 Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Wed, 17 Jul 2024 09:52:57 +0000 Subject: [PATCH] feat(semantic): add `ReferenceFlags::TSTypeQuery` to indicate referenced by `TSTypeQuery` (#4317) `ReferenceFlags::TSTypeQuery` can be used to help us insist on whether the reference is referenced by the type or not. --- .../typescript/consistent_type_imports.rs | 20 ++-------------- crates/oxc_semantic/src/builder.rs | 24 ++++++++++++------- crates/oxc_semantic/src/reference.rs | 2 +- .../class/declaration/type-reference.snap | 2 +- .../type-arguments2.snap | 11 ++------- .../type-declaration/function/function2.snap | 2 +- .../type-declaration/index-access3.snap | 2 +- .../type-query-qualified.snap | 2 +- .../type-query-with-parameters.snap | 11 ++------- .../type-declaration/type-query.snap | 2 +- crates/oxc_syntax/src/reference.rs | 7 ++++++ tasks/coverage/transformer_typescript.snap | 4 +--- tasks/transform_conformance/babel.snap.md | 5 ++-- 13 files changed, 37 insertions(+), 57 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/consistent_type_imports.rs b/crates/oxc_linter/src/rules/typescript/consistent_type_imports.rs index c2eb127395a9b..9cf66fa38d045 100644 --- a/crates/oxc_linter/src/rules/typescript/consistent_type_imports.rs +++ b/crates/oxc_linter/src/rules/typescript/consistent_type_imports.rs @@ -10,7 +10,7 @@ use oxc_ast::{ }; use oxc_diagnostics::OxcDiagnostic; use oxc_macros::declare_oxc_lint; -use oxc_semantic::SymbolId; +use oxc_semantic::{Reference, SymbolId}; use oxc_span::{CompactStr, GetSpan, Span}; use crate::{ @@ -309,23 +309,7 @@ fn is_only_has_type_references(symbol_id: SymbolId, ctx: &LintContext) -> bool { if peekable_iter.peek().is_none() { return false; } - peekable_iter.all(|reference| { - if reference.is_type() { - return true; - } else if reference.is_read() { - for node in ctx.nodes().iter_parents(reference.node_id()).skip(1) { - return match node.kind() { - // CASE 1: - // `type T = typeof foo` will create a value reference because "foo" must be a value type - // however this value reference is safe to use with type-only imports - AstKind::TSTypeQuery(_) => true, - AstKind::TSTypeName(_) | AstKind::TSQualifiedName(_) => continue, - _ => false, - }; - } - } - false - }) + peekable_iter.all(Reference::is_type) } struct FixOptions<'a, 'b> { diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index 3c57834985c5f..a6defb7ba98d5 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -1715,15 +1715,17 @@ impl<'a> SemanticBuilder<'a> { AstKind::TSInterfaceHeritage(_) => { self.current_reference_flag = ReferenceFlag::Type; } + AstKind::TSTypeQuery(_) => { + // type A = typeof a; + // ^^^^^^^^ + self.current_reference_flag = ReferenceFlag::Read | ReferenceFlag::TSTypeQuery; + } AstKind::TSTypeName(_) => { match self.nodes.parent_kind(self.current_node_id) { Some( - // type A = typeof a; - // ^^^^^^^^ - AstKind::TSTypeQuery(_) // import A = a; // ^ - | AstKind::TSModuleReference(_) + AstKind::TSModuleReference(_), ) => { self.current_reference_flag = ReferenceFlag::Read; } @@ -1732,7 +1734,9 @@ impl<'a> SemanticBuilder<'a> { // ^^^ Keep the current reference flag } _ => { - self.current_reference_flag = ReferenceFlag::Type; + if !self.current_reference_flag.is_ts_type_query() { + self.current_reference_flag = ReferenceFlag::Type; + } } } } @@ -1847,7 +1851,9 @@ impl<'a> SemanticBuilder<'a> { self.current_reference_flag -= ReferenceFlag::Read; } } - AstKind::MemberExpression(_) => self.current_reference_flag = ReferenceFlag::empty(), + AstKind::MemberExpression(_) | AstKind::TSTypeQuery(_) => { + self.current_reference_flag = ReferenceFlag::empty(); + } AstKind::AssignmentTarget(_) => self.current_reference_flag -= ReferenceFlag::Write, _ => {} } @@ -1873,10 +1879,10 @@ impl<'a> SemanticBuilder<'a> { /// Resolve reference flags for the current ast node. fn resolve_reference_usages(&self) -> ReferenceFlag { - if self.current_reference_flag.is_write() || self.current_reference_flag.is_type() { - self.current_reference_flag - } else { + if self.current_reference_flag.is_empty() { ReferenceFlag::Read + } else { + self.current_reference_flag } } diff --git a/crates/oxc_semantic/src/reference.rs b/crates/oxc_semantic/src/reference.rs index ab5e601917607..ed62050d4d45c 100644 --- a/crates/oxc_semantic/src/reference.rs +++ b/crates/oxc_semantic/src/reference.rs @@ -80,6 +80,6 @@ impl Reference { } pub fn is_type(&self) -> bool { - self.flag.is_type() + self.flag.is_type() || self.flag.is_ts_type_query() } } diff --git a/crates/oxc_semantic/tests/fixtures/typescript-eslint/class/declaration/type-reference.snap b/crates/oxc_semantic/tests/fixtures/typescript-eslint/class/declaration/type-reference.snap index 34be306653cfe..59e4e6ddeba29 100644 --- a/crates/oxc_semantic/tests/fixtures/typescript-eslint/class/declaration/type-reference.snap +++ b/crates/oxc_semantic/tests/fixtures/typescript-eslint/class/declaration/type-reference.snap @@ -44,7 +44,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/class/declarati "node_id": 8 }, { - "flag": "ReferenceFlag(Read)", + "flag": "ReferenceFlag(Read | TSTypeQuery)", "id": 1, "name": "A", "node_id": 13 diff --git a/crates/oxc_semantic/tests/fixtures/typescript-eslint/instantiation-expressions/type-arguments2.snap b/crates/oxc_semantic/tests/fixtures/typescript-eslint/instantiation-expressions/type-arguments2.snap index b050a79c0e400..f87324181ba7c 100644 --- a/crates/oxc_semantic/tests/fixtures/typescript-eslint/instantiation-expressions/type-arguments2.snap +++ b/crates/oxc_semantic/tests/fixtures/typescript-eslint/instantiation-expressions/type-arguments2.snap @@ -52,14 +52,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/instantiation-e "id": 4, "name": "T", "node": "TSTypeParameter", - "references": [ - { - "flag": "ReferenceFlag(Type)", - "id": 0, - "name": "T", - "node_id": 31 - } - ] + "references": [] } ] } @@ -75,7 +68,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/instantiation-e "node": "Function(makeBox)", "references": [ { - "flag": "ReferenceFlag(Read)", + "flag": "ReferenceFlag(Read | TSTypeQuery)", "id": 0, "name": "makeBox", "node_id": 27 diff --git a/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/function/function2.snap b/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/function/function2.snap index 1830abb5a568a..17c47c483dc87 100644 --- a/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/function/function2.snap +++ b/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/function/function2.snap @@ -24,7 +24,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaratio "node": "VariableDeclarator", "references": [ { - "flag": "ReferenceFlag(Read)", + "flag": "ReferenceFlag(Read | TSTypeQuery)", "id": 0, "name": "arg", "node_id": 15 diff --git a/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/index-access3.snap b/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/index-access3.snap index b66e0db5c670c..b117cf70dee59 100644 --- a/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/index-access3.snap +++ b/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/index-access3.snap @@ -45,7 +45,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaratio "node": "VariableDeclarator", "references": [ { - "flag": "ReferenceFlag(Read)", + "flag": "ReferenceFlag(Read | TSTypeQuery)", "id": 0, "name": "k", "node_id": 21 diff --git a/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/type-query-qualified.snap b/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/type-query-qualified.snap index 63c6d8c69e262..a53a6103c15e9 100644 --- a/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/type-query-qualified.snap +++ b/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/type-query-qualified.snap @@ -31,7 +31,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaratio "node": "VariableDeclarator", "references": [ { - "flag": "ReferenceFlag(Read)", + "flag": "ReferenceFlag(Read | TSTypeQuery)", "id": 0, "name": "x", "node_id": 21 diff --git a/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/type-query-with-parameters.snap b/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/type-query-with-parameters.snap index 5d901eed89ccd..0c962ae33942a 100644 --- a/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/type-query-with-parameters.snap +++ b/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/type-query-with-parameters.snap @@ -52,14 +52,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaratio "id": 4, "name": "T", "node": "TSTypeParameter", - "references": [ - { - "flag": "ReferenceFlag(Type)", - "id": 0, - "name": "T", - "node_id": 33 - } - ] + "references": [] } ] } @@ -75,7 +68,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaratio "node": "Function(foo)", "references": [ { - "flag": "ReferenceFlag(Read)", + "flag": "ReferenceFlag(Read | TSTypeQuery)", "id": 0, "name": "foo", "node_id": 29 diff --git a/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/type-query.snap b/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/type-query.snap index e95a6cea4cd66..77c8393747425 100644 --- a/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/type-query.snap +++ b/crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaration/type-query.snap @@ -31,7 +31,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/type-declaratio "node": "VariableDeclarator", "references": [ { - "flag": "ReferenceFlag(Read)", + "flag": "ReferenceFlag(Read | TSTypeQuery)", "id": 0, "name": "x", "node_id": 9 diff --git a/crates/oxc_syntax/src/reference.rs b/crates/oxc_syntax/src/reference.rs index 95a893886c0de..ce036ad993771 100644 --- a/crates/oxc_syntax/src/reference.rs +++ b/crates/oxc_syntax/src/reference.rs @@ -45,6 +45,8 @@ bitflags! { const Write = 1 << 1; // Used in type definitions. const Type = 1 << 2; + // Used in `typeof xx` + const TSTypeQuery = 1 << 3; const Value = Self::Read.bits() | Self::Write.bits(); } } @@ -87,6 +89,11 @@ impl ReferenceFlag { self.contains(Self::Read | Self::Write) } + /// The identifier is used in a type referenced + pub fn is_ts_type_query(&self) -> bool { + self.contains(Self::TSTypeQuery) + } + /// The identifier is used in a type definition. pub const fn is_type(&self) -> bool { self.contains(Self::Type) diff --git a/tasks/coverage/transformer_typescript.snap b/tasks/coverage/transformer_typescript.snap index 61250e368a477..94311ce35a448 100644 --- a/tasks/coverage/transformer_typescript.snap +++ b/tasks/coverage/transformer_typescript.snap @@ -2,10 +2,8 @@ commit: d8086f14 transformer_typescript Summary: AST Parsed : 6456/6456 (100.00%) -Positive Passed: 6450/6456 (99.91%) +Positive Passed: 6452/6456 (99.94%) Mismatch: "compiler/constEnumNamespaceReferenceCausesNoImport2.ts" Mismatch: "compiler/elidedEmbeddedStatementsReplacedWithSemicolon.ts" -Mismatch: "conformance/dynamicImport/importCallExpressionReturnPromiseOfAny.ts" Mismatch: "conformance/externalModules/typeOnly/exportDeclaration.ts" -Mismatch: "conformance/externalModules/typeOnly/namespaceImportTypeQuery2.ts" Mismatch: "conformance/jsx/inline/inlineJsxAndJsxFragPragmaOverridesCompilerOptions.tsx" diff --git a/tasks/transform_conformance/babel.snap.md b/tasks/transform_conformance/babel.snap.md index f5ef55fde85c8..caab34c9dce50 100644 --- a/tasks/transform_conformance/babel.snap.md +++ b/tasks/transform_conformance/babel.snap.md @@ -1,6 +1,6 @@ commit: 12619ffe -Passed: 473/927 +Passed: 474/927 # All Passed: * babel-preset-react @@ -445,14 +445,13 @@ Passed: 473/927 * opts/optimizeConstEnums/input.ts * opts/rewriteImportExtensions/input.ts -# babel-plugin-transform-typescript (129/151) +# babel-plugin-transform-typescript (130/151) * class/accessor-allowDeclareFields-false/input.ts * class/accessor-allowDeclareFields-true/input.ts * enum/mix-references/input.ts * enum/ts5.0-const-foldable/input.ts * exports/declared-types/input.ts * exports/interface/input.ts -* imports/elide-typeof/input.ts * imports/only-remove-type-imports/input.ts * imports/type-only-export-specifier-2/input.ts * imports/type-only-import-specifier-4/input.ts