diff --git a/.changeset/bright-tires-report.md b/.changeset/bright-tires-report.md new file mode 100644 index 000000000000..f6aa16470827 --- /dev/null +++ b/.changeset/bright-tires-report.md @@ -0,0 +1,14 @@ +--- +"@biomejs/biome": patch +--- + +Fixed [#8148](https://github.com/biomejs/biome/issues/8148). [`noInvalidUseBeforeDeclaration`](https://biomejs.dev/linter/rules/no-invalid-use-before-declaration/) no longer reports some valid use before declarations. + +The following code is no longer reported as invalid: + +```ts +class classA { + C = C; +} +const C = 0; +``` diff --git a/crates/biome_js_analyze/src/lint/correctness/no_invalid_use_before_declaration.rs b/crates/biome_js_analyze/src/lint/correctness/no_invalid_use_before_declaration.rs index 1da77130fe35..44cde6a459df 100644 --- a/crates/biome_js_analyze/src/lint/correctness/no_invalid_use_before_declaration.rs +++ b/crates/biome_js_analyze/src/lint/correctness/no_invalid_use_before_declaration.rs @@ -1,13 +1,16 @@ -use crate::{services::control_flow::AnyJsControlFlowRoot, services::semantic::SemanticServices}; +use crate::services::semantic::SemanticServices; use biome_analyze::{Rule, RuleDiagnostic, RuleSource, context::RuleContext, declare_lint_rule}; use biome_console::markup; use biome_diagnostics::Severity; use biome_js_syntax::{ - AnyJsExportNamedSpecifier, AnyJsIdentifierUsage, JsFileSource, JsVariableDeclarationClause, - TsDeclareStatement, + AnyJsExportNamedSpecifier, AnyJsFunction, AnyJsIdentifierUsage, JsClassDeclaration, + JsConstructorClassMember, JsFileSource, JsGetterClassMember, JsGetterObjectMember, + JsMethodClassMember, JsMethodObjectMember, JsModule, JsScript, JsSetterClassMember, + JsSetterObjectMember, JsStaticInitializationBlockClassMember, JsVariableDeclarationClause, + TsDeclareStatement, TsModuleDeclaration, TsPropertySignatureTypeMember, binding_ext::{AnyJsBindingDeclaration, AnyJsIdentifierBinding}, }; -use biome_rowan::{AstNode, SyntaxNodeOptionExt, TextRange}; +use biome_rowan::{AstNode, SyntaxNodeOptionExt, TextRange, declare_node_union}; use biome_rule_options::no_invalid_use_before_declaration::NoInvalidUseBeforeDeclarationOptions; declare_lint_rule! { @@ -126,11 +129,11 @@ impl Rule for NoInvalidUseBeforeDeclaration { } else { declaration.range().end() }; - let declaration_control_flow_root = declaration + let declaration_scope = declaration .syntax() .ancestors() .skip(1) - .find(|ancestor| AnyJsControlFlowRoot::can_cast(ancestor.kind())); + .find(|ancestor| AnyJsVariableScope::can_cast(ancestor.kind())); for reference in binding.all_references() { if reference.range_start() < declaration_end { let reference_syntax = reference.syntax(); @@ -154,11 +157,10 @@ impl Rule for NoInvalidUseBeforeDeclaration { // function f() { X; } // const X = 0; // ``` - && (declaration_control_flow_root.is_none() || - declaration_control_flow_root == reference_syntax + && declaration_scope == reference_syntax .ancestors() .skip(1) - .find(|ancestor| AnyJsControlFlowRoot::can_cast(ancestor.kind())) + .find(|ancestor| AnyJsVariableScope::can_cast(ancestor.kind()) ) // ignore when used as a type. // For example: @@ -295,3 +297,21 @@ impl TryFrom<&AnyJsBindingDeclaration> for DeclarationKind { } } } + +declare_node_union! { + AnyJsVariableScope = + JsScript + | JsModule + | AnyJsFunction + | JsClassDeclaration + | JsConstructorClassMember + | JsGetterClassMember + | JsGetterObjectMember + | JsMethodClassMember + | JsMethodObjectMember + | JsSetterClassMember + | JsSetterObjectMember + | JsStaticInitializationBlockClassMember + | TsModuleDeclaration + | TsPropertySignatureTypeMember +} diff --git a/crates/biome_js_analyze/tests/specs/correctness/noInvalidUseBeforeDeclaration/valid.js b/crates/biome_js_analyze/tests/specs/correctness/noInvalidUseBeforeDeclaration/valid.js index b872cde10256..a534a0447507 100644 --- a/crates/biome_js_analyze/tests/specs/correctness/noInvalidUseBeforeDeclaration/valid.js +++ b/crates/biome_js_analyze/tests/specs/correctness/noInvalidUseBeforeDeclaration/valid.js @@ -13,6 +13,14 @@ function h() { Y; }; const Y = 0; function useClassInFunction() { const instance = new Class(); } + class Class { static SINGLETON = new Class(); } + +class classA { + C = C; + prop = new classB(); +} +class classB {} +const C = 0; diff --git a/crates/biome_js_analyze/tests/specs/correctness/noInvalidUseBeforeDeclaration/valid.js.snap b/crates/biome_js_analyze/tests/specs/correctness/noInvalidUseBeforeDeclaration/valid.js.snap index dbe98a756c50..bb4b50c49b9e 100644 --- a/crates/biome_js_analyze/tests/specs/correctness/noInvalidUseBeforeDeclaration/valid.js.snap +++ b/crates/biome_js_analyze/tests/specs/correctness/noInvalidUseBeforeDeclaration/valid.js.snap @@ -19,8 +19,16 @@ function h() { Y; }; const Y = 0; function useClassInFunction() { const instance = new Class(); } + class Class { static SINGLETON = new Class(); } +class classA { + C = C; + prop = new classB(); +} +class classB {} +const C = 0; + ```