@@ -10,7 +10,7 @@ use rustc_errors::{Applicability, Diag, SuggestionStyle};
1010use rustc_lexer:: TokenKind ;
1111use rustc_lint:: { EarlyContext , EarlyLintPass , LintContext } ;
1212use rustc_session:: impl_lint_pass;
13- use rustc_span:: { BytePos , ExpnKind , Ident , InnerSpan , Span , SpanData , Symbol , kw} ;
13+ use rustc_span:: { BytePos , ExpnKind , Ident , InnerSpan , Span , SpanData , Symbol , kw, sym } ;
1414
1515declare_clippy_lint ! {
1616 /// ### What it does
@@ -129,18 +129,63 @@ struct Stop {
129129 kind : StopKind ,
130130 first : usize ,
131131 last : usize ,
132+ name : Option < Symbol > ,
132133}
133134
134135impl Stop {
135- fn convert_to_inner ( & self ) -> ( Span , String ) {
136+ fn is_outer_attr_only ( & self ) -> bool {
137+ let Some ( name) = self . name else {
138+ return false ;
139+ } ;
140+ // Check if the attribute only has effect when as an outer attribute
141+ // The below attributes are collected from the builtin attributes of The Rust Reference
142+ // https://doc.rust-lang.org/reference/attributes.html#r-attributes.builtin
143+ // And the comments below are from compiler errors and warnings
144+ matches ! (
145+ name,
146+ // Cannot be used at crate level
147+ sym:: repr | sym:: test | sym:: derive | sym:: automatically_derived | sym:: path | sym:: global_allocator |
148+ // Only has an effect on macro definitions
149+ sym:: macro_export |
150+ // Only be applied to trait definitions
151+ sym:: on_unimplemented |
152+ // Only be placed on trait implementations
153+ sym:: do_not_recommend |
154+ // Only has an effect on items
155+ sym:: ignore | sym:: should_panic | sym:: proc_macro | sym:: proc_macro_derive | sym:: proc_macro_attribute |
156+ // Has no effect when applied to a module
157+ sym:: must_use |
158+ // Should be applied to a foreign function or static
159+ sym:: link_name | sym:: link_ordinal | sym:: link_section |
160+ // Should be applied to an `extern crate` item
161+ sym:: no_link |
162+ // Should be applied to a free function, impl method or static
163+ sym:: export_name | sym:: no_mangle |
164+ // Should be applied to a `static` variable
165+ sym:: used |
166+ // Should be applied to function or closure
167+ sym:: inline |
168+ // Should be applied to a function definition
169+ sym:: cold | sym:: target_feature | sym:: track_caller | sym:: instruction_set |
170+ // Should be applied to a struct or enum
171+ sym:: non_exhaustive |
172+ // Note: No any warning when it as an inner attribute, but it has no effect
173+ sym:: panic_handler
174+ )
175+ }
176+
177+ fn convert_to_inner ( & self ) -> Option < ( Span , String ) > {
178+ if self . is_outer_attr_only ( ) {
179+ return None ;
180+ }
136181 let inner = match self . kind {
137182 // #![...]
138183 StopKind :: Attr => InnerSpan :: new ( 1 , 1 ) ,
139184 // /// or /**
140185 // ^ ^
141186 StopKind :: Doc ( _) => InnerSpan :: new ( 2 , 3 ) ,
142187 } ;
143- ( self . span . from_inner ( inner) , "!" . into ( ) )
188+ Some ( ( self . span . from_inner ( inner) , "!" . into ( ) ) )
144189 }
145190
146191 fn comment_out ( & self , cx : & EarlyContext < ' _ > , suggestions : & mut Vec < ( Span , String ) > ) {
@@ -177,6 +222,7 @@ impl Stop {
177222 } ,
178223 first : file. lookup_line ( file. relative_position ( lo) ) ?,
179224 last : file. lookup_line ( file. relative_position ( hi) ) ?,
225+ name : attr. name ( ) ,
180226 } )
181227 }
182228}
@@ -356,6 +402,12 @@ impl EmptyLineAfter {
356402 if let Some ( parent) = self . items . iter ( ) . rev ( ) . nth ( 1 )
357403 && ( parent. kind == "module" || parent. kind == "crate" )
358404 && parent. mod_items == Some ( id)
405+ && let suggestions = gaps
406+ . iter ( )
407+ . flat_map ( |gap| gap. prev_chunk )
408+ . filter_map ( Stop :: convert_to_inner)
409+ . collect :: < Vec < _ > > ( )
410+ && !suggestions. is_empty ( )
359411 {
360412 let desc = if parent. kind == "module" {
361413 "parent module"
@@ -367,10 +419,7 @@ impl EmptyLineAfter {
367419 StopKind :: Attr => format ! ( "if the attribute should apply to the {desc} use an inner attribute" ) ,
368420 StopKind :: Doc ( _) => format ! ( "if the comment should document the {desc} use an inner doc comment" ) ,
369421 } ,
370- gaps. iter ( )
371- . flat_map ( |gap| gap. prev_chunk )
372- . map ( Stop :: convert_to_inner)
373- . collect ( ) ,
422+ suggestions,
374423 Applicability :: MaybeIncorrect ,
375424 ) ;
376425 }
@@ -425,6 +474,7 @@ impl EmptyLineAfter {
425474 first : line. line ,
426475 // last doesn't need to be accurate here, we don't compare it with anything
427476 last : line. line ,
477+ name : None ,
428478 } ) ;
429479 }
430480
0 commit comments