about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJonathan Dönszelmann <jonathan@donsz.nl>2025-02-06 21:44:00 +0100
committerJana Dönszelmann <jana@donsz.nl>2025-02-07 16:47:26 +0100
commit4044c1aa496e39e4fc1ec34d646d84ea639253ad (patch)
tree30d826ef33280b06afb4ae54e50aead4f44c471a
parent42453bd73a39ef96727774159d300f0a27aec73d (diff)
downloadrust-4044c1aa496e39e4fc1ec34d646d84ea639253ad.tar.gz
rust-4044c1aa496e39e4fc1ec34d646d84ea639253ad.zip
fix empty after lint on impl/trait items
Co-authored-by: Guillaume Gomez <guillaume1.gomez@gmail.com>
-rw-r--r--clippy_lints/src/empty_line_after.rs113
-rw-r--r--tests/ui/empty_line_after/doc_comments.1.fixed9
-rw-r--r--tests/ui/empty_line_after/doc_comments.2.fixed9
-rw-r--r--tests/ui/empty_line_after/doc_comments.rs10
-rw-r--r--tests/ui/empty_line_after/doc_comments.stderr13
5 files changed, 116 insertions, 38 deletions
diff --git a/clippy_lints/src/empty_line_after.rs b/clippy_lints/src/empty_line_after.rs
index 4f1c6186cfe..89ddd885b6e 100644
--- a/clippy_lints/src/empty_line_after.rs
+++ b/clippy_lints/src/empty_line_after.rs
@@ -3,13 +3,13 @@ use clippy_utils::source::{SpanRangeExt, snippet_indent};
 use clippy_utils::tokenize_with_text;
 use itertools::Itertools;
 use rustc_ast::token::CommentKind;
-use rustc_ast::{AttrKind, AttrStyle, Attribute, Crate, Item, ItemKind, ModKind, NodeId};
+use rustc_ast::{AssocItemKind, AttrKind, AttrStyle, Attribute, Crate, Item, ItemKind, ModKind, NodeId};
 use rustc_errors::{Applicability, Diag, SuggestionStyle};
 use rustc_lexer::TokenKind;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::kw;
-use rustc_span::{BytePos, ExpnKind, InnerSpan, Span, SpanData, Symbol};
+use rustc_span::{BytePos, ExpnKind, Ident, InnerSpan, Span, SpanData, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -92,7 +92,7 @@ struct ItemInfo {
     kind: &'static str,
     name: Symbol,
     span: Span,
-    mod_items: Vec<NodeId>,
+    mod_items: Option<NodeId>,
 }
 
 pub struct EmptyLineAfter {
@@ -347,7 +347,7 @@ impl EmptyLineAfter {
     fn suggest_inner(&self, diag: &mut Diag<'_, ()>, kind: StopKind, gaps: &[Gap<'_>], id: NodeId) {
         if let Some(parent) = self.items.iter().rev().nth(1)
             && (parent.kind == "module" || parent.kind == "crate")
-            && parent.mod_items.first() == Some(&id)
+            && parent.mod_items == Some(id)
         {
             let desc = if parent.kind == "module" {
                 "parent module"
@@ -367,48 +367,35 @@ impl EmptyLineAfter {
             );
         }
     }
-}
 
-impl EarlyLintPass for EmptyLineAfter {
-    fn check_crate(&mut self, _: &EarlyContext<'_>, krate: &Crate) {
+    fn check_item_kind(
+        &mut self,
+        cx: &EarlyContext<'_>,
+        kind: &ItemKind,
+        ident: &Ident,
+        span: Span,
+        attrs: &[Attribute],
+        id: NodeId,
+    ) {
         self.items.push(ItemInfo {
-            kind: "crate",
-            name: kw::Crate,
-            span: krate.spans.inner_span.with_hi(krate.spans.inner_span.lo()),
-            mod_items: krate
-                .items
-                .iter()
-                .filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
-                .map(|i| i.id)
-                .collect::<Vec<_>>(),
-        });
-    }
-
-    fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &Item) {
-        self.items.pop();
-    }
-
-    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        self.items.push(ItemInfo {
-            kind: item.kind.descr(),
-            name: item.ident.name,
-            span: if item.span.contains(item.ident.span) {
-                item.span.with_hi(item.ident.span.hi())
+            kind: kind.descr(),
+            name: ident.name,
+            span: if span.contains(ident.span) {
+                span.with_hi(ident.span.hi())
             } else {
-                item.span.with_hi(item.span.lo())
+                span.with_hi(span.lo())
             },
-            mod_items: match item.kind {
-                ItemKind::Mod(_, ModKind::Loaded(ref items, _, _, _)) => items
+            mod_items: match kind {
+                ItemKind::Mod(_, ModKind::Loaded(items, _, _, _)) => items
                     .iter()
                     .filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
                     .map(|i| i.id)
-                    .collect::<Vec<_>>(),
-                _ => Vec::new(),
+                    .next(),
+                _ => None,
             },
         });
 
-        let mut outer = item
-            .attrs
+        let mut outer = attrs
             .iter()
             .filter(|attr| attr.style == AttrStyle::Outer && !attr.span.from_expansion())
             .map(|attr| Stop::from_attr(cx, attr))
@@ -448,6 +435,58 @@ impl EarlyLintPass for EmptyLineAfter {
             }
         }
 
-        self.check_gaps(cx, &gaps, item.id);
+        self.check_gaps(cx, &gaps, id);
+    }
+}
+
+impl EarlyLintPass for EmptyLineAfter {
+    fn check_crate(&mut self, _: &EarlyContext<'_>, krate: &Crate) {
+        self.items.push(ItemInfo {
+            kind: "crate",
+            name: kw::Crate,
+            span: krate.spans.inner_span.with_hi(krate.spans.inner_span.lo()),
+            mod_items: krate
+                .items
+                .iter()
+                .filter(|i| !matches!(i.span.ctxt().outer_expn_data().kind, ExpnKind::AstPass(_)))
+                .map(|i| i.id)
+                .next(),
+        });
+    }
+
+    fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &Item) {
+        self.items.pop();
+    }
+    fn check_impl_item_post(&mut self, _: &EarlyContext<'_>, _: &Item<AssocItemKind>) {
+        self.items.pop();
+    }
+    fn check_trait_item_post(&mut self, _: &EarlyContext<'_>, _: &Item<AssocItemKind>) {
+        self.items.pop();
+    }
+
+    fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &Item<AssocItemKind>) {
+        self.check_item_kind(
+            cx,
+            &item.kind.clone().into(),
+            &item.ident,
+            item.span,
+            &item.attrs,
+            item.id,
+        );
+    }
+
+    fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &Item<AssocItemKind>) {
+        self.check_item_kind(
+            cx,
+            &item.kind.clone().into(),
+            &item.ident,
+            item.span,
+            &item.attrs,
+            item.id,
+        );
+    }
+
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        self.check_item_kind(cx, &item.kind, &item.ident, item.span, &item.attrs, item.id);
     }
 }
diff --git a/tests/ui/empty_line_after/doc_comments.1.fixed b/tests/ui/empty_line_after/doc_comments.1.fixed
index fd6a94b6a80..3772b465fdb 100644
--- a/tests/ui/empty_line_after/doc_comments.1.fixed
+++ b/tests/ui/empty_line_after/doc_comments.1.fixed
@@ -132,4 +132,13 @@ pub struct BlockComment;
 ))]
 fn empty_line_in_cfg_attr() {}
 
+trait Foo {
+    fn bar();
+}
+
+impl Foo for LineComment {
+    /// comment on assoc item
+    fn bar() {}
+}
+
 fn main() {}
diff --git a/tests/ui/empty_line_after/doc_comments.2.fixed b/tests/ui/empty_line_after/doc_comments.2.fixed
index 7a57dcd9233..3028d03b669 100644
--- a/tests/ui/empty_line_after/doc_comments.2.fixed
+++ b/tests/ui/empty_line_after/doc_comments.2.fixed
@@ -141,4 +141,13 @@ pub struct BlockComment;
 ))]
 fn empty_line_in_cfg_attr() {}
 
+trait Foo {
+    fn bar();
+}
+
+impl Foo for LineComment {
+    /// comment on assoc item
+    fn bar() {}
+}
+
 fn main() {}
diff --git a/tests/ui/empty_line_after/doc_comments.rs b/tests/ui/empty_line_after/doc_comments.rs
index 1da761a5c3d..ae4ebc271fa 100644
--- a/tests/ui/empty_line_after/doc_comments.rs
+++ b/tests/ui/empty_line_after/doc_comments.rs
@@ -144,4 +144,14 @@ pub struct BlockComment;
 ))]
 fn empty_line_in_cfg_attr() {}
 
+trait Foo {
+    fn bar();
+}
+
+impl Foo for LineComment {
+    /// comment on assoc item
+
+    fn bar() {}
+}
+
 fn main() {}
diff --git a/tests/ui/empty_line_after/doc_comments.stderr b/tests/ui/empty_line_after/doc_comments.stderr
index d71c888e196..10189665f01 100644
--- a/tests/ui/empty_line_after/doc_comments.stderr
+++ b/tests/ui/empty_line_after/doc_comments.stderr
@@ -171,5 +171,16 @@ help: if the doc comment should not document `new_code2` comment it out
 LL |     // /// Docs for `old_code2`
    |     ++
 
-error: aborting due to 10 previous errors
+error: empty line after doc comment
+  --> tests/ui/empty_line_after/doc_comments.rs:152:5
+   |
+LL | /     /// comment on assoc item
+LL | |
+   | |_^
+LL |       fn bar() {}
+   |       ------ the comment documents this function
+   |
+   = help: if the empty line is unintentional remove it
+
+error: aborting due to 11 previous errors