diff --git a/.changeset/full-dancers-repeat.md b/.changeset/full-dancers-repeat.md new file mode 100644 index 000000000000..942c6412df25 --- /dev/null +++ b/.changeset/full-dancers-repeat.md @@ -0,0 +1,5 @@ +--- +"@biomejs/biome": patch +--- + +Fixed [#8475](https://github.com/biomejs/biome/issues/8475): fixed a regression in how `noExtraNonNullAssertion` flags extra non-null assertions diff --git a/crates/biome_js_analyze/src/lint/suspicious/no_extra_non_null_assertion.rs b/crates/biome_js_analyze/src/lint/suspicious/no_extra_non_null_assertion.rs index 88e5c2f8dd1e..b32005d80f81 100644 --- a/crates/biome_js_analyze/src/lint/suspicious/no_extra_non_null_assertion.rs +++ b/crates/biome_js_analyze/src/lint/suspicious/no_extra_non_null_assertion.rs @@ -84,18 +84,16 @@ impl Rule for NoExtraNonNullAssertion { AnyTsNonNullAssertion::TsNonNullAssertionExpression(_) => { // First check if this is nested within another non-null assertion (always invalid) - let mut is_nested_in_non_null_assertion = false; - for ancestor in node.syntax().ancestors().skip(1) { - if JsParenthesizedExpression::can_cast(ancestor.kind()) { - continue; - } - if TsNonNullAssertionExpression::can_cast(ancestor.kind()) { - is_nested_in_non_null_assertion = true; - break; - } - } - - if is_nested_in_non_null_assertion { + if let Some(parent) = node + .syntax() + .ancestors() + .skip(1) + .filter(|ancestor| !JsParenthesizedExpression::can_cast(ancestor.kind())) + // Consider only the first immediate ancestor that is not a parenthesized expression + .take(1) + .next() + && TsNonNullAssertionExpression::can_cast(parent.kind()) + { return Some(()); } diff --git a/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/invalid.ts b/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/invalid.ts index 0202d2bb89d6..e1eff705c43f 100644 --- a/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/invalid.ts +++ b/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/invalid.ts @@ -53,3 +53,7 @@ arr1[0]!! ^= arr1[1]; const arr2: number[] = [1, 2, 3]; arr2[0] ^= arr2[1]!!; + +// Test case for issue #8475 +const _d2 = (blob.b!)!.d!.length; +const _d2 = ((blob.b!))!.d!.length; diff --git a/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/invalid.ts.snap b/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/invalid.ts.snap index e1e6698d429c..73f29c60ad01 100644 --- a/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/invalid.ts.snap +++ b/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/invalid.ts.snap @@ -1,6 +1,5 @@ --- source: crates/biome_js_analyze/tests/spec_tests.rs -assertion_line: 151 expression: invalid.ts --- # Input @@ -61,6 +60,10 @@ arr1[0]!! ^= arr1[1]; const arr2: number[] = [1, 2, 3]; arr2[0] ^= arr2[1]!!; +// Test case for issue #8475 +const _d2 = (blob.b!)!.d!.length; +const _d2 = ((blob.b!))!.d!.length; + ``` # Diagnostics @@ -407,6 +410,7 @@ invalid.ts:55:12 lint/suspicious/noExtraNonNullAssertion FIXABLE ━━━━ > 55 │ arr2[0] ^= arr2[1]!!; │ ^^^^^^^^ 56 │ + 57 │ // Test case for issue #8475 i Safe fix: Remove extra non-null assertion. @@ -414,3 +418,39 @@ invalid.ts:55:12 lint/suspicious/noExtraNonNullAssertion FIXABLE ━━━━ │ - ``` + +``` +invalid.ts:58:14 lint/suspicious/noExtraNonNullAssertion FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Forbidden extra non-null assertion. + + 57 │ // Test case for issue #8475 + > 58 │ const _d2 = (blob.b!)!.d!.length; + │ ^^^^^^^ + 59 │ const _d2 = ((blob.b!))!.d!.length; + 60 │ + + i Safe fix: Remove extra non-null assertion. + + 58 │ const·_d2·=·(blob.b!)!.d!.length; + │ - + +``` + +``` +invalid.ts:59:15 lint/suspicious/noExtraNonNullAssertion FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + ! Forbidden extra non-null assertion. + + 57 │ // Test case for issue #8475 + 58 │ const _d2 = (blob.b!)!.d!.length; + > 59 │ const _d2 = ((blob.b!))!.d!.length; + │ ^^^^^^^ + 60 │ + + i Safe fix: Remove extra non-null assertion. + + 59 │ const·_d2·=·((blob.b!))!.d!.length; + │ - + +``` diff --git a/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/valid.ts b/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/valid.ts index 0dfc9988e558..5b0303f0f01b 100644 --- a/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/valid.ts +++ b/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/valid.ts @@ -23,3 +23,7 @@ function issue3419(value: string | null): string { // Test case for issue #7927: compound assignment with non-null assertions on both sides const arr: number[] = [1, 2, 3]; arr[0]! ^= arr[1]!; + +// Test case for issue #8475 +const _d2 = blob.b!.d!.length; +const _d2 = blob.b?.d!.length; diff --git a/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/valid.ts.snap b/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/valid.ts.snap index 86ba3e5f6108..a08b61a9e693 100644 --- a/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/valid.ts.snap +++ b/crates/biome_js_analyze/tests/specs/suspicious/noExtraNonNullAssertion/valid.ts.snap @@ -1,6 +1,5 @@ --- source: crates/biome_js_analyze/tests/spec_tests.rs -assertion_line: 151 expression: valid.ts --- # Input @@ -31,4 +30,8 @@ function issue3419(value: string | null): string { const arr: number[] = [1, 2, 3]; arr[0]! ^= arr[1]!; +// Test case for issue #8475 +const _d2 = blob.b!.d!.length; +const _d2 = blob.b?.d!.length; + ```