From 06e72461bd445d4ed662836638701e14fe2878a6 Mon Sep 17 00:00:00 2001 From: Victorien Elvinger Date: Mon, 30 Sep 2024 18:03:11 +0200 Subject: [PATCH] fix(noUnusedVariables): don't panic when renaming ref at the start --- CHANGELOG.md | 2 ++ .../noUnusedVariables/issue4114.js | 2 ++ .../noUnusedVariables/issue4114.js.snap | 31 +++++++++++++++++++ .../src/semantic_model/model.rs | 5 ++- .../src/semantic_model/reference.rs | 8 +++-- 5 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 crates/biome_js_analyze/tests/specs/correctness/noUnusedVariables/issue4114.js create mode 100644 crates/biome_js_analyze/tests/specs/correctness/noUnusedVariables/issue4114.js.snap diff --git a/CHANGELOG.md b/CHANGELOG.md index 10b3283d1cc7..de1864582c7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -105,6 +105,8 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b Contributed by @Conaclos +- [noUnusedVariables](https://biomejs.dev/linter/rules/no-unused-variables/) no longer panics when suggesting the renaming of a variable at the start of a file ([#4114](https://github.com/biomejs/biome/issues/4114)). Contributed by @Conaclos + - [noUselessEscapeInRegex](https://biomejs.dev/linter/rules/no-useless-escape-in-regex/) no longer panics on regexes that start with an empty character class. Contributed by @Conaclos - [noUselessStringConcat](https://biomejs.dev/linter/rules/no-useless-string-concat/) no longer panics when it encounters malformed code. Contributed by @Conaclos diff --git a/crates/biome_js_analyze/tests/specs/correctness/noUnusedVariables/issue4114.js b/crates/biome_js_analyze/tests/specs/correctness/noUnusedVariables/issue4114.js new file mode 100644 index 000000000000..963a7b32417a --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/correctness/noUnusedVariables/issue4114.js @@ -0,0 +1,2 @@ +c; +const c = 0; \ No newline at end of file diff --git a/crates/biome_js_analyze/tests/specs/correctness/noUnusedVariables/issue4114.js.snap b/crates/biome_js_analyze/tests/specs/correctness/noUnusedVariables/issue4114.js.snap new file mode 100644 index 000000000000..bc22f1dfa9a8 --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/correctness/noUnusedVariables/issue4114.js.snap @@ -0,0 +1,31 @@ +--- +source: crates/biome_js_analyze/tests/spec_tests.rs +expression: issue4114.js +--- +# Input +```jsx +c; +const c = 0; +``` + +# Diagnostics +``` +issue4114.js:2:7 lint/correctness/noUnusedVariables FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! This variable is unused. + + 1 │ c; + > 2 │ const c = 0; + │ ^ + + i Unused variables usually are result of incomplete refactoring, typos and other source of bugs. + + i Unsafe fix: If this is intentional, prepend c with an underscore. + + 1 │ - c; + 2 │ - const·c·=·0; + 1 │ + _c; + 2 │ + const·_c·=·0; + + +``` diff --git a/crates/biome_js_semantic/src/semantic_model/model.rs b/crates/biome_js_semantic/src/semantic_model/model.rs index 436aad7771f4..97e34d49bb11 100644 --- a/crates/biome_js_semantic/src/semantic_model/model.rs +++ b/crates/biome_js_semantic/src/semantic_model/model.rs @@ -124,13 +124,16 @@ impl SemanticModelData { /// Returns the [ScopeId] which the syntax is part of. pub(crate) fn scope(&self, range: TextRange) -> ScopeId { + // Seeking an interval in `self.scope_by_range` require a non-empty interval + debug_assert!(range.len() > 0.into(), "the range must not be empty."); let start = range.start().into(); let end = range.end().into(); let scopes = self .scope_by_range + // Find overlapping intervals .find(start, end) + // Only take intersecting intervals .filter(|x| !(start < x.start || end > x.stop)); - // We always want the most tight scope match scopes.map(|x| x.val).max() { Some(val) => val, diff --git a/crates/biome_js_semantic/src/semantic_model/reference.rs b/crates/biome_js_semantic/src/semantic_model/reference.rs index 105d89813584..8d53e8497bbb 100644 --- a/crates/biome_js_semantic/src/semantic_model/reference.rs +++ b/crates/biome_js_semantic/src/semantic_model/reference.rs @@ -58,9 +58,11 @@ impl Reference { /// Returns the scope of this reference pub fn scope(&self) -> Scope { - let id = self - .data - .scope(TextRange::new(self.range_start(), self.range_start())); + let start = self.range_start(); + let id = self.data.scope(TextRange::new( + start, + start.checked_add(1.into()).unwrap_or(start), + )); Scope { data: self.data.clone(), id,