Skip to content

Commit 00ff8c9

Browse files
committed
Auto merge of #12354 - GuillaumeGomez:mixed_attributes_style, r=llogiq
Add new `mixed_attributes_style` lint Add a new lint to detect cases where both inner and outer attributes are used on a same item. r? `@llogiq` ---- changelog: Add new [`mixed_attributes_style`] lint
2 parents 04b74ee + f301386 commit 00ff8c9

File tree

7 files changed

+137
-9
lines changed

7 files changed

+137
-9
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5423,6 +5423,7 @@ Released 2018-09-13
54235423
[`missing_spin_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_spin_loop
54245424
[`missing_trait_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_trait_methods
54255425
[`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes
5426+
[`mixed_attributes_style`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_attributes_style
54265427
[`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals
54275428
[`mixed_read_write_in_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_read_write_in_expression
54285429
[`mod_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#mod_module_files

clippy_lints/src/attrs.rs

+55
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,33 @@ declare_clippy_lint! {
485485
"usage of `cfg_attr(clippy, allow(clippy::lint))` instead of `allow(clippy::lint)`"
486486
}
487487

488+
declare_clippy_lint! {
489+
/// ### What it does
490+
/// Checks that an item has only one kind of attributes.
491+
///
492+
/// ### Why is this bad?
493+
/// Having both kinds of attributes makes it more complicated to read code.
494+
///
495+
/// ### Example
496+
/// ```no_run
497+
/// #[cfg(linux)]
498+
/// pub fn foo() {
499+
/// #![cfg(windows)]
500+
/// }
501+
/// ```
502+
/// Use instead:
503+
/// ```no_run
504+
/// #[cfg(linux)]
505+
/// #[cfg(windows)]
506+
/// pub fn foo() {
507+
/// }
508+
/// ```
509+
#[clippy::version = "1.78.0"]
510+
pub MIXED_ATTRIBUTES_STYLE,
511+
suspicious,
512+
"item has both inner and outer attributes"
513+
}
514+
488515
declare_lint_pass!(Attributes => [
489516
ALLOW_ATTRIBUTES_WITHOUT_REASON,
490517
INLINE_ALWAYS,
@@ -849,11 +876,13 @@ impl_lint_pass!(EarlyAttributes => [
849876
MAYBE_MISUSED_CFG,
850877
DEPRECATED_CLIPPY_CFG_ATTR,
851878
UNNECESSARY_CLIPPY_CFG,
879+
MIXED_ATTRIBUTES_STYLE,
852880
]);
853881

854882
impl EarlyLintPass for EarlyAttributes {
855883
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
856884
check_empty_line_after_outer_attr(cx, item);
885+
check_mixed_attributes(cx, item);
857886
}
858887

859888
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
@@ -867,6 +896,32 @@ impl EarlyLintPass for EarlyAttributes {
867896
extract_msrv_attr!(EarlyContext);
868897
}
869898

899+
fn check_mixed_attributes(cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
900+
let mut has_outer = false;
901+
let mut has_inner = false;
902+
903+
for attr in &item.attrs {
904+
if attr.span.from_expansion() {
905+
continue;
906+
}
907+
match attr.style {
908+
AttrStyle::Inner => has_inner = true,
909+
AttrStyle::Outer => has_outer = true,
910+
}
911+
}
912+
if !has_outer || !has_inner {
913+
return;
914+
}
915+
let mut attrs_iter = item.attrs.iter().filter(|attr| !attr.span.from_expansion());
916+
let span = attrs_iter.next().unwrap().span;
917+
span_lint(
918+
cx,
919+
MIXED_ATTRIBUTES_STYLE,
920+
span.with_hi(attrs_iter.last().unwrap().span.hi()),
921+
"item has both inner and outer attributes",
922+
);
923+
}
924+
870925
/// Check for empty lines after outer attributes.
871926
///
872927
/// Attributes and documentation comments are both considered outer attributes

clippy_lints/src/declared_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
5858
crate::attrs::INLINE_ALWAYS_INFO,
5959
crate::attrs::MAYBE_MISUSED_CFG_INFO,
6060
crate::attrs::MISMATCHED_TARGET_OS_INFO,
61+
crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO,
6162
crate::attrs::NON_MINIMAL_CFG_INFO,
6263
crate::attrs::SHOULD_PANIC_WITHOUT_EXPECT_INFO,
6364
crate::attrs::UNNECESSARY_CLIPPY_CFG_INFO,

tests/ui/empty_docs.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#![allow(unused)]
22
#![warn(clippy::empty_docs)]
3+
#![allow(clippy::mixed_attributes_style)]
4+
35
mod outer {
46
//!
57

tests/ui/empty_docs.stderr

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: empty doc comment
2-
--> tests/ui/empty_docs.rs:4:5
2+
--> tests/ui/empty_docs.rs:6:5
33
|
44
LL | //!
55
| ^^^
@@ -9,31 +9,31 @@ LL | //!
99
= help: to override `-D warnings` add `#[allow(clippy::empty_docs)]`
1010

1111
error: empty doc comment
12-
--> tests/ui/empty_docs.rs:12:5
12+
--> tests/ui/empty_docs.rs:14:5
1313
|
1414
LL | ///
1515
| ^^^
1616
|
1717
= help: consider removing or filling it
1818

1919
error: empty doc comment
20-
--> tests/ui/empty_docs.rs:14:9
20+
--> tests/ui/empty_docs.rs:16:9
2121
|
2222
LL | ///
2323
| ^^^
2424
|
2525
= help: consider removing or filling it
2626

2727
error: empty doc comment
28-
--> tests/ui/empty_docs.rs:25:5
28+
--> tests/ui/empty_docs.rs:27:5
2929
|
3030
LL | #[doc = ""]
3131
| ^^^^^^^^^^^
3232
|
3333
= help: consider removing or filling it
3434

3535
error: empty doc comment
36-
--> tests/ui/empty_docs.rs:28:5
36+
--> tests/ui/empty_docs.rs:30:5
3737
|
3838
LL | / #[doc = ""]
3939
LL | | #[doc = ""]
@@ -42,31 +42,31 @@ LL | | #[doc = ""]
4242
= help: consider removing or filling it
4343

4444
error: empty doc comment
45-
--> tests/ui/empty_docs.rs:35:5
45+
--> tests/ui/empty_docs.rs:37:5
4646
|
4747
LL | ///
4848
| ^^^
4949
|
5050
= help: consider removing or filling it
5151

5252
error: empty doc comment
53-
--> tests/ui/empty_docs.rs:48:13
53+
--> tests/ui/empty_docs.rs:50:13
5454
|
5555
LL | /*! */
5656
| ^^^^^^
5757
|
5858
= help: consider removing or filling it
5959

6060
error: empty doc comment
61-
--> tests/ui/empty_docs.rs:56:13
61+
--> tests/ui/empty_docs.rs:58:13
6262
|
6363
LL | ///
6464
| ^^^
6565
|
6666
= help: consider removing or filling it
6767

6868
error: empty doc comment
69-
--> tests/ui/empty_docs.rs:64:9
69+
--> tests/ui/empty_docs.rs:66:9
7070
|
7171
LL | ///
7272
| ^^^

tests/ui/mixed_attributes_style.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#![warn(clippy::mixed_attributes_style)]
2+
3+
#[allow(unused)] //~ ERROR: item has both inner and outer attributes
4+
fn foo1() {
5+
#![allow(unused)]
6+
}
7+
8+
#[allow(unused)]
9+
#[allow(unused)]
10+
fn foo2() {}
11+
12+
fn foo3() {
13+
#![allow(unused)]
14+
#![allow(unused)]
15+
}
16+
17+
/// linux
18+
//~^ ERROR: item has both inner and outer attributes
19+
fn foo4() {
20+
//! windows
21+
}
22+
23+
/// linux
24+
/// windows
25+
fn foo5() {}
26+
27+
fn foo6() {
28+
//! linux
29+
//! windows
30+
}
31+
32+
#[allow(unused)] //~ ERROR: item has both inner and outer attributes
33+
mod bar {
34+
#![allow(unused)]
35+
}
36+
37+
fn main() {
38+
// test code goes here
39+
}
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error: item has both inner and outer attributes
2+
--> tests/ui/mixed_attributes_style.rs:3:1
3+
|
4+
LL | / #[allow(unused)]
5+
LL | | fn foo1() {
6+
LL | | #![allow(unused)]
7+
| |_____________________^
8+
|
9+
= note: `-D clippy::mixed-attributes-style` implied by `-D warnings`
10+
= help: to override `-D warnings` add `#[allow(clippy::mixed_attributes_style)]`
11+
12+
error: item has both inner and outer attributes
13+
--> tests/ui/mixed_attributes_style.rs:17:1
14+
|
15+
LL | / /// linux
16+
LL | |
17+
LL | | fn foo4() {
18+
LL | | //! windows
19+
| |_______________^
20+
21+
error: item has both inner and outer attributes
22+
--> tests/ui/mixed_attributes_style.rs:32:1
23+
|
24+
LL | / #[allow(unused)]
25+
LL | | mod bar {
26+
LL | | #![allow(unused)]
27+
| |_____________________^
28+
29+
error: aborting due to 3 previous errors
30+

0 commit comments

Comments
 (0)