Skip to content

Commit 8ec6f1a

Browse files
Fix suggestion-cases-error of empty_line_after_outer_attr (#15078)
Fixes: #14980 changelog: Fix suggestion-cases-error of [`empty_line_after_outer_attr`]
2 parents 62fd159 + 95778b5 commit 8ec6f1a

File tree

5 files changed

+97
-8
lines changed

5 files changed

+97
-8
lines changed

clippy_lints/src/empty_line_after.rs

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_errors::{Applicability, Diag, SuggestionStyle};
1010
use rustc_lexer::TokenKind;
1111
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
1212
use 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

1515
declare_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

134135
impl 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

tests/ui/empty_line_after/outer_attribute.1.fixed

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,13 @@ second line
105105
")]
106106
pub struct Args;
107107

108+
mod issue_14980 {
109+
//~v empty_line_after_outer_attr
110+
#[repr(align(536870912))]
111+
enum Aligned {
112+
Zero = 0,
113+
One = 1,
114+
}
115+
}
116+
108117
fn main() {}

tests/ui/empty_line_after/outer_attribute.2.fixed

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,13 @@ second line
108108
")]
109109
pub struct Args;
110110

111+
mod issue_14980 {
112+
//~v empty_line_after_outer_attr
113+
#[repr(align(536870912))]
114+
enum Aligned {
115+
Zero = 0,
116+
One = 1,
117+
}
118+
}
119+
111120
fn main() {}

tests/ui/empty_line_after/outer_attribute.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,14 @@ second line
116116
")]
117117
pub struct Args;
118118

119+
mod issue_14980 {
120+
//~v empty_line_after_outer_attr
121+
#[repr(align(536870912))]
122+
123+
enum Aligned {
124+
Zero = 0,
125+
One = 1,
126+
}
127+
}
128+
119129
fn main() {}

tests/ui/empty_line_after/outer_attribute.stderr

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,5 +111,16 @@ LL | pub fn isolated_comment() {}
111111
|
112112
= help: if the empty lines are unintentional, remove them
113113

114-
error: aborting due to 9 previous errors
114+
error: empty line after outer attribute
115+
--> tests/ui/empty_line_after/outer_attribute.rs:121:5
116+
|
117+
LL | / #[repr(align(536870912))]
118+
LL | |
119+
| |_^
120+
LL | enum Aligned {
121+
| ------------ the attribute applies to this enum
122+
|
123+
= help: if the empty line is unintentional, remove it
124+
125+
error: aborting due to 10 previous errors
115126

0 commit comments

Comments
 (0)