Skip to content

Commit 0375be6

Browse files
committed
Fix suggestion-cases-error of empty_line_after_outer_attr
1 parent 506411d commit 0375be6

File tree

4 files changed

+82
-7
lines changed

4 files changed

+82
-7
lines changed

clippy_lints/src/empty_line_after.rs

Lines changed: 48 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,54 @@ struct Stop {
129129
kind: StopKind,
130130
first: usize,
131131
last: usize,
132+
ident: Option<Ident>,
132133
}
133134

134135
impl Stop {
135-
fn convert_to_inner(&self) -> (Span, String) {
136+
fn could_only_be_outer_attr(&self) -> bool {
137+
if let Some(ident) = self.ident {
138+
return matches!(
139+
ident.name,
140+
// Cannot be used at crate level
141+
sym::repr | sym::test | sym::derive | sym::automatically_derived | sym::macro_export |
142+
sym::on_unimplemented | sym::do_not_recommend | sym::path | sym::panic_handler | sym::global_allocator |
143+
// Only has an effect on items but not throgh compile errors
144+
sym::ignore | sym::should_panic | sym::proc_macro | sym::proc_macro_derive | sym::proc_macro_attribute |
145+
// Has no effect when applied to a module
146+
sym::must_use |
147+
// Should be applied to a foreign function or static
148+
sym::link_name | sym::link_ordinal | sym::link_section |
149+
// Should be applied to an `extern crate` item
150+
sym::no_link |
151+
// Should be applied to a free function, impl method or static
152+
sym::export_name | sym::no_mangle |
153+
// Should be applied to a `static` variable
154+
sym::used |
155+
// Should be applied to function or closure
156+
sym::inline |
157+
// Should be applied to a function definition
158+
sym::cold | sym::target_feature | sym::track_caller | sym::instruction_set |
159+
// Only has an effect on modules
160+
sym::no_implicit_prelude | sym::debugger_visualizer |
161+
// Should be applied to a struct or enum
162+
sym::non_exhaustive
163+
);
164+
}
165+
false
166+
}
167+
168+
fn convert_to_inner(&self) -> Option<(Span, String)> {
169+
if self.could_only_be_outer_attr() {
170+
return None;
171+
}
136172
let inner = match self.kind {
137173
// #![...]
138174
StopKind::Attr => InnerSpan::new(1, 1),
139175
// /// or /**
140176
// ^ ^
141177
StopKind::Doc(_) => InnerSpan::new(2, 3),
142178
};
143-
(self.span.from_inner(inner), "!".into())
179+
Some((self.span.from_inner(inner), "!".into()))
144180
}
145181

146182
fn comment_out(&self, cx: &EarlyContext<'_>, suggestions: &mut Vec<(Span, String)>) {
@@ -177,6 +213,7 @@ impl Stop {
177213
},
178214
first: file.lookup_line(file.relative_position(lo))?,
179215
last: file.lookup_line(file.relative_position(hi))?,
216+
ident: attr.ident(),
180217
})
181218
}
182219
}
@@ -356,6 +393,12 @@ impl EmptyLineAfter {
356393
if let Some(parent) = self.items.iter().rev().nth(1)
357394
&& (parent.kind == "module" || parent.kind == "crate")
358395
&& parent.mod_items == Some(id)
396+
&& let suggestions = gaps
397+
.iter()
398+
.flat_map(|gap| gap.prev_chunk)
399+
.filter_map(Stop::convert_to_inner)
400+
.collect::<Vec<(Span, String)>>()
401+
&& !suggestions.is_empty()
359402
{
360403
let desc = if parent.kind == "module" {
361404
"parent module"
@@ -367,10 +410,7 @@ impl EmptyLineAfter {
367410
StopKind::Attr => format!("if the attribute should apply to the {desc} use an inner attribute"),
368411
StopKind::Doc(_) => format!("if the comment should document the {desc} use an inner doc comment"),
369412
},
370-
gaps.iter()
371-
.flat_map(|gap| gap.prev_chunk)
372-
.map(Stop::convert_to_inner)
373-
.collect(),
413+
suggestions,
374414
Applicability::MaybeIncorrect,
375415
);
376416
}
@@ -425,6 +465,7 @@ impl EmptyLineAfter {
425465
first: line.line,
426466
// last doesn't need to be accurate here, we don't compare it with anything
427467
last: line.line,
468+
ident: None,
428469
});
429470
}
430471

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![warn(clippy::empty_line_after_outer_attr)]
2+
#![allow(dead_code)]
3+
4+
//~v empty_line_after_outer_attr
5+
#[repr(align(536870912))]
6+
enum Aligned {
7+
Zero = 0,
8+
One = 1,
9+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![warn(clippy::empty_line_after_outer_attr)]
2+
#![allow(dead_code)]
3+
4+
//~v empty_line_after_outer_attr
5+
#[repr(align(536870912))]
6+
7+
enum Aligned {
8+
Zero = 0,
9+
One = 1,
10+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: empty line after outer attribute
2+
--> tests/ui/empty_line_after/outer_attribute_only_be_outer.rs:5:1
3+
|
4+
LL | / #[repr(align(536870912))]
5+
LL | |
6+
| |_^
7+
LL | enum Aligned {
8+
| ------------ the attribute applies to this enum
9+
|
10+
= note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings`
11+
= help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]`
12+
= help: if the empty line is unintentional, remove it
13+
14+
error: aborting due to 1 previous error
15+

0 commit comments

Comments
 (0)