fix(linter): no-lone-blocks erroring on block statements containing comments (#8720)

This PR fixes #8697 by checking if semantic detects a comment in the
span of an otherwise empty block statement.

I also formatted some of the existing test cases to improve readability.
This commit is contained in:
Tyler Earls 2025-01-25 19:20:05 -06:00 committed by GitHub
parent 3e509e1c9b
commit 1de6f854cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 276 additions and 257 deletions

View file

@ -62,7 +62,12 @@ impl Rule for NoLoneBlocks {
};
if stmt.body.is_empty() {
if !matches!(parent_node.kind(), AstKind::TryStatement(_) | AstKind::CatchClause(_)) {
let is_comment_in_stmt =
ctx.semantic().comments_range(stmt.span.start..stmt.span.end).last().is_some();
if !is_comment_in_stmt
&& !matches!(parent_node.kind(), AstKind::TryStatement(_) | AstKind::CatchClause(_))
{
report(ctx, node, parent_node);
}
return;
@ -155,30 +160,30 @@ fn test() {
"{ class Bar {} }", // { "ecmaVersion": 6 },
"{ {let y = 1;} let x = 1; }", // { "ecmaVersion": 6 },
"
switch (foo) {
case bar: {
baz;
}
}
",
switch (foo) {
case bar: {
baz;
}
}
",
"
switch (foo) {
case bar: {
baz;
}
case qux: {
boop;
}
}
",
switch (foo) {
case bar: {
baz;
}
case qux: {
boop;
}
}
",
"
switch (foo) {
case bar:
{
baz;
}
}
",
switch (foo) {
case bar:
{
baz;
}
}
",
"function foo() { { const x = 4 } const x = 3 }", // { "ecmaVersion": 6 },
"class C { static {} }", // { "ecmaVersion": 2022 },
"class C { static { foo; } }", // { "ecmaVersion": 2022 },
@ -189,15 +194,29 @@ fn test() {
"class C { static { { function block(){} } something; } }", // { "ecmaVersion": 2022 },
"class C { static { something; { class block {} } } }", // { "ecmaVersion": 2022 },
"
{
using x = makeDisposable();
}", // { "parser": require(parser("typescript-parsers/no-lone-blocks/using")), "ecmaVersion": 2022 },
{
using x = makeDisposable();
}
", // { "parser": require(parser("typescript-parsers/no-lone-blocks/using")), "ecmaVersion": 2022 },
"
{
await using x = makeDisposable();
}", // { "parser": require(parser("typescript-parsers/no-lone-blocks/await-using")), "ecmaVersion": 2022 }
{
await using x = makeDisposable();
}
", // { "parser": require(parser("typescript-parsers/no-lone-blocks/await-using")), "ecmaVersion": 2022 }
// Issue: <https://github.com/oxc-project/oxc/issues/8515>
"try {} catch {}",
// Issue: https://github.com/oxc-project/oxc/issues/8697
"
if (foo) {
// do nothing
}
else if (bar) {
// do nothing again
}
else {
// do nothing
}
",
];
let fail = vec![
@ -215,154 +234,154 @@ fn test() {
"{var x = 1;}", // { "ecmaVersion": 6 },
"{
{var x = 1;}
let y = 2; } {let z = 1;}", // { "ecmaVersion": 6 },
let y = 2; } {let z = 1;}", // { "ecmaVersion": 6 },
"{
{let x = 1;}
var y = 2; } {let z = 1;}", // { "ecmaVersion": 6 },
var y = 2; } {let z = 1;}", // { "ecmaVersion": 6 },
"{
{var x = 1;}
var y = 2; }
{var z = 1;}", // { "ecmaVersion": 6 },
var y = 2; }
{var z = 1;}", // { "ecmaVersion": 6 },
"
switch (foo) {
case 1:
foo();
{
bar;
}
}
",
switch (foo) {
case 1:
foo();
{
bar;
}
}
",
"
switch (foo) {
case 1:
{
bar;
}
foo();
}
",
switch (foo) {
case 1:
{
bar;
}
foo();
}
",
"
function foo () {
{
const x = 4;
}
}
", // { "ecmaVersion": 6 },
function foo () {
{
const x = 4;
}
}
", // { "ecmaVersion": 6 },
"
function foo () {
{
var x = 4;
}
}
",
function foo () {
{
var x = 4;
}
}
",
"
class C {
static {
if (foo) {
{
let block;
}
}
}
}
", // { "ecmaVersion": 2022 },
class C {
static {
if (foo) {
{
let block;
}
}
}
}
", // { "ecmaVersion": 2022 },
"
class C {
static {
if (foo) {
{
block;
}
something;
}
}
}
", // { "ecmaVersion": 2022 },
class C {
static {
if (foo) {
{
block;
}
something;
}
}
}
", // { "ecmaVersion": 2022 },
"
class C {
static {
{
block;
}
}
}
", // { "ecmaVersion": 2022 },
class C {
static {
{
block;
}
}
}
", // { "ecmaVersion": 2022 },
"
class C {
static {
{
let block;
}
}
}
", // { "ecmaVersion": 2022 },
class C {
static {
{
let block;
}
}
}
", // { "ecmaVersion": 2022 },
"
class C {
static {
{
const block = 1;
}
}
}
", // { "ecmaVersion": 2022 },
class C {
static {
{
const block = 1;
}
}
}
", // { "ecmaVersion": 2022 },
"
class C {
static {
{
function block() {}
}
}
}
", // { "ecmaVersion": 2022 },
class C {
static {
{
function block() {}
}
}
}
", // { "ecmaVersion": 2022 },
"
class C {
static {
{
class block {}
}
}
}
", // { "ecmaVersion": 2022 },
class C {
static {
{
class block {}
}
}
}
", // { "ecmaVersion": 2022 },
"
class C {
static {
{
var block;
}
something;
}
}
", // { "ecmaVersion": 2022 },
class C {
static {
{
var block;
}
something;
}
}
", // { "ecmaVersion": 2022 },
"
class C {
static {
something;
{
var block;
}
}
}
", // { "ecmaVersion": 2022 },
class C {
static {
something;
{
var block;
}
}
}
", // { "ecmaVersion": 2022 },
"
class C {
static {
{
block;
}
something;
}
}
", // { "ecmaVersion": 2022 },
class C {
static {
{
block;
}
something;
}
}
", // { "ecmaVersion": 2022 },
"
class C {
static {
something;
{
block;
}
}
}
", // { "ecmaVersion": 2022 }
class C {
static {
something;
{
block;
}
}
}
", // { "ecmaVersion": 2022 }
];
Tester::new(NoLoneBlocks::NAME, NoLoneBlocks::PLUGIN, pass, fail).test_and_snapshot();

View file

@ -67,22 +67,22 @@ source: crates/oxc_linter/src/tester.rs
1 │ {
2 │ {var x = 1;}
· ────────────
3 │ let y = 2; } {let z = 1;}
3 │ let y = 2; } {let z = 1;}
╰────
⚠ eslint(no-lone-blocks): Block is unnecessary.
╭─[no_lone_blocks.tsx:1:1]
1 │ ╭─▶ {
2 │ │ {let x = 1;}
3 │ ╰─▶ var y = 2; } {let z = 1;}
3 │ ╰─▶ var y = 2; } {let z = 1;}
╰────
⚠ eslint(no-lone-blocks): Block is unnecessary.
╭─[no_lone_blocks.tsx:1:1]
1 │ ╭─▶ {
2 │ │ {var x = 1;}
3 │ ╰─▶ var y = 2; }
4 │ {var z = 1;}
3 │ ╰─▶ var y = 2; }
4 │ {var z = 1;}
╰────
⚠ eslint(no-lone-blocks): Nested block is redundant.
@ -90,147 +90,147 @@ source: crates/oxc_linter/src/tester.rs
1 │ {
2 │ {var x = 1;}
· ────────────
3 │ var y = 2; }
3 │ var y = 2; }
╰────
⚠ eslint(no-lone-blocks): Block is unnecessary.
╭─[no_lone_blocks.tsx:4:5]
3 │ var y = 2; }
4 │ {var z = 1;}
· ────────────
╭─[no_lone_blocks.tsx:4:4]
3 │ var y = 2; }
4 │ {var z = 1;}
· ────────────
╰────
⚠ eslint(no-lone-blocks): Block is unnecessary.
╭─[no_lone_blocks.tsx:5:24]
4 │ foo();
5 │ ╭─▶ {
6 │ │ bar;
7 │ ╰─▶ }
8 │ }
╭─[no_lone_blocks.tsx:5:17]
4 │ foo();
5 │ ╭─▶ {
6 │ │ bar;
7 │ ╰─▶ }
8 │ }
╰────
⚠ eslint(no-lone-blocks): Block is unnecessary.
╭─[no_lone_blocks.tsx:4:20]
3 │ case 1:
4 │ ╭─▶ {
5 │ │ bar;
6 │ ╰─▶ }
7 │ foo();
╭─[no_lone_blocks.tsx:4:21]
3 │ case 1:
4 │ ╭─▶ {
5 │ │ bar;
6 │ ╰─▶ }
7 │ foo();
╰────
⚠ eslint(no-lone-blocks): Block is unnecessary.
╭─[no_lone_blocks.tsx:3:20]
2 │ function foo () {
3 │ ╭─▶ {
4 │ │ const x = 4;
5 │ ╰─▶ }
6 │ }
╭─[no_lone_blocks.tsx:3:17]
2 │ function foo () {
3 │ ╭─▶ {
4 │ │ const x = 4;
5 │ ╰─▶ }
6 │ }
╰────
⚠ eslint(no-lone-blocks): Block is unnecessary.
╭─[no_lone_blocks.tsx:3:20]
2 │ function foo () {
3 │ ╭─▶ {
4 │ │ var x = 4;
5 │ ╰─▶ }
6 │ }
╭─[no_lone_blocks.tsx:3:17]
2 │ function foo () {
3 │ ╭─▶ {
4 │ │ var x = 4;
5 │ ╰─▶ }
6 │ }
╰────
⚠ eslint(no-lone-blocks): Nested block is redundant.
╭─[no_lone_blocks.tsx:5:24]
4 │ if (foo) {
5 │ ╭─▶ {
6 │ │ let block;
7 │ ╰─▶ }
8 │ }
╭─[no_lone_blocks.tsx:5:25]
4 │ if (foo) {
5 │ ╭─▶ {
6 │ │ let block;
7 │ ╰─▶ }
8 │ }
╰────
⚠ eslint(no-lone-blocks): Nested block is redundant.
╭─[no_lone_blocks.tsx:5:24]
4 │ if (foo) {
5 │ ╭─▶ {
6 │ │ block;
7 │ ╰─▶ }
8 │ something;
╭─[no_lone_blocks.tsx:5:25]
4 │ if (foo) {
5 │ ╭─▶ {
6 │ │ block;
7 │ ╰─▶ }
8 │ something;
╰────
⚠ eslint(no-lone-blocks): Nested block is redundant.
╭─[no_lone_blocks.tsx:4:22]
3 │ static {
4 │ ╭─▶ {
5 │ │ block;
6 │ ╰─▶ }
7 │ }
╭─[no_lone_blocks.tsx:4:21]
3 │ static {
4 │ ╭─▶ {
5 │ │ block;
6 │ ╰─▶ }
7 │ }
╰────
⚠ eslint(no-lone-blocks): Nested block is redundant.
╭─[no_lone_blocks.tsx:4:22]
3 │ static {
4 │ ╭─▶ {
5 │ │ let block;
6 │ ╰─▶ }
7 │ }
╭─[no_lone_blocks.tsx:4:21]
3 │ static {
4 │ ╭─▶ {
5 │ │ let block;
6 │ ╰─▶ }
7 │ }
╰────
⚠ eslint(no-lone-blocks): Nested block is redundant.
╭─[no_lone_blocks.tsx:4:22]
3 │ static {
4 │ ╭─▶ {
5 │ │ const block = 1;
6 │ ╰─▶ }
7 │ }
╭─[no_lone_blocks.tsx:4:21]
3 │ static {
4 │ ╭─▶ {
5 │ │ const block = 1;
6 │ ╰─▶ }
7 │ }
╰────
⚠ eslint(no-lone-blocks): Nested block is redundant.
╭─[no_lone_blocks.tsx:4:22]
3 │ static {
4 │ ╭─▶ {
5 │ │ function block() {}
6 │ ╰─▶ }
7 │ }
╭─[no_lone_blocks.tsx:4:21]
3 │ static {
4 │ ╭─▶ {
5 │ │ function block() {}
6 │ ╰─▶ }
7 │ }
╰────
⚠ eslint(no-lone-blocks): Nested block is redundant.
╭─[no_lone_blocks.tsx:4:22]
3 │ static {
4 │ ╭─▶ {
5 │ │ class block {}
6 │ ╰─▶ }
7 │ }
╭─[no_lone_blocks.tsx:4:21]
3 │ static {
4 │ ╭─▶ {
5 │ │ class block {}
6 │ ╰─▶ }
7 │ }
╰────
⚠ eslint(no-lone-blocks): Nested block is redundant.
╭─[no_lone_blocks.tsx:4:22]
3 │ static {
4 │ ╭─▶ {
5 │ │ var block;
6 │ ╰─▶ }
7 │ something;
╭─[no_lone_blocks.tsx:4:21]
3 │ static {
4 │ ╭─▶ {
5 │ │ var block;
6 │ ╰─▶ }
7 │ something;
╰────
⚠ eslint(no-lone-blocks): Nested block is redundant.
╭─[no_lone_blocks.tsx:5:22]
4 │ something;
5 │ ╭─▶ {
6 │ │ var block;
7 │ ╰─▶ }
8 │ }
╭─[no_lone_blocks.tsx:5:21]
4 │ something;
5 │ ╭─▶ {
6 │ │ var block;
7 │ ╰─▶ }
8 │ }
╰────
⚠ eslint(no-lone-blocks): Nested block is redundant.
╭─[no_lone_blocks.tsx:4:22]
3 │ static {
4 │ ╭─▶ {
5 │ │ block;
6 │ ╰─▶ }
7 │ something;
╭─[no_lone_blocks.tsx:4:21]
3 │ static {
4 │ ╭─▶ {
5 │ │ block;
6 │ ╰─▶ }
7 │ something;
╰────
⚠ eslint(no-lone-blocks): Nested block is redundant.
╭─[no_lone_blocks.tsx:5:22]
4 │ something;
5 │ ╭─▶ {
6 │ │ block;
7 │ ╰─▶ }
8 │ }
╭─[no_lone_blocks.tsx:5:21]
4 │ something;
5 │ ╭─▶ {
6 │ │ block;
7 │ ╰─▶ }
8 │ }
╰────