about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-08-13 21:06:51 -0700
committerGitHub <noreply@github.com>2022-08-13 21:06:51 -0700
commit86e1d1e28f0dab1bfe2dc3e8dbfc739778a8e135 (patch)
tree9316f6886d681f1ef44e82bcf16148338eec3691
parentd46451ce2c75dd0757916b87eb6522fb3739d6ef (diff)
parentd47df26784355eaa4006eee60f262c6035fea307 (diff)
downloadrust-86e1d1e28f0dab1bfe2dc3e8dbfc739778a8e135.tar.gz
rust-86e1d1e28f0dab1bfe2dc3e8dbfc739778a8e135.zip
Rollup merge of #100446 - TaKO8Ki:suggest-removing-semicolon-after-impl-trait-items, r=compiler-errors
Suggest removing a semicolon after impl/trait items

fixes #99822
-rw-r--r--compiler/rustc_parse/src/parser/item.rs38
-rw-r--r--src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed7
-rw-r--r--src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs7
-rw-r--r--src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr15
4 files changed, 63 insertions, 4 deletions
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index ac55aee9883..c6dd5e7fda3 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -675,14 +675,44 @@ impl<'a> Parser<'a> {
             }
             match parse_item(self) {
                 Ok(None) => {
+                    let is_unnecessary_semicolon = !items.is_empty()
+                        // When the close delim is `)` in a case like the following, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`,
+                        // but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`.
+                        // This is because the `token.kind` of the close delim is treated as the same as
+                        // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
+                        // Therefore, `token.kind` should not be compared here.
+                        //
+                        // issue-60075.rs
+                        // ```
+                        // trait T {
+                        //     fn qux() -> Option<usize> {
+                        //         let _ = if true {
+                        //         });
+                        //          ^ this close delim
+                        //         Some(4)
+                        //     }
+                        // ```
+                        && self
+                            .span_to_snippet(self.prev_token.span)
+                            .map_or(false, |snippet| snippet == "}")
+                        && self.token.kind == token::Semi;
+                    let semicolon_span = self.token.span;
                     // We have to bail or we'll potentially never make progress.
                     let non_item_span = self.token.span;
                     self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
-                    self.struct_span_err(non_item_span, "non-item in item list")
-                        .span_label(open_brace_span, "item list starts here")
+                    let mut err = self.struct_span_err(non_item_span, "non-item in item list");
+                    err.span_label(open_brace_span, "item list starts here")
                         .span_label(non_item_span, "non-item starts here")
-                        .span_label(self.prev_token.span, "item list ends here")
-                        .emit();
+                        .span_label(self.prev_token.span, "item list ends here");
+                    if is_unnecessary_semicolon {
+                        err.span_suggestion(
+                            semicolon_span,
+                            "consider removing this semicolon",
+                            "",
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    err.emit();
                     break;
                 }
                 Ok(Some(item)) => items.extend(item),
diff --git a/src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed b/src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed
new file mode 100644
index 00000000000..63704735490
--- /dev/null
+++ b/src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.fixed
@@ -0,0 +1,7 @@
+// run-rustfix
+
+trait Foo {
+    fn bar() {} //~ ERROR non-item in item list
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs b/src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs
new file mode 100644
index 00000000000..4650b05e20c
--- /dev/null
+++ b/src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.rs
@@ -0,0 +1,7 @@
+// run-rustfix
+
+trait Foo {
+    fn bar() {}; //~ ERROR non-item in item list
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr b/src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr
new file mode 100644
index 00000000000..396e0c130f1
--- /dev/null
+++ b/src/test/ui/parser/suggest-removing-semicolon-after-impl-trait-items.stderr
@@ -0,0 +1,15 @@
+error: non-item in item list
+  --> $DIR/suggest-removing-semicolon-after-impl-trait-items.rs:4:16
+   |
+LL | trait Foo {
+   |           - item list starts here
+LL |     fn bar() {};
+   |                ^
+   |                |
+   |                non-item starts here
+   |                help: consider removing this semicolon
+LL | }
+   | - item list ends here
+
+error: aborting due to previous error
+