Skip to content

Commit 8521427

Browse files
committed
move [mixed_attributes_style] to LateLintPass to enable global allow
1 parent c6f794a commit 8521427

File tree

5 files changed

+77
-30
lines changed

5 files changed

+77
-30
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,73 @@
11
use super::MIXED_ATTRIBUTES_STYLE;
22
use clippy_utils::diagnostics::span_lint;
3-
use rustc_ast::{AttrKind, AttrStyle};
4-
use rustc_lint::EarlyContext;
3+
use rustc_ast::{AttrKind, AttrStyle, Attribute};
4+
use rustc_data_structures::fx::FxHashSet;
5+
use rustc_lint::{LateContext, LintContext};
6+
use rustc_span::Span;
7+
use std::sync::Arc;
58

6-
pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
7-
let mut has_outer_normal = false;
8-
let mut has_inner_normal = false;
9-
let mut has_outer_doc = false;
10-
let mut has_inner_doc = false;
9+
#[derive(Hash, PartialEq, Eq)]
10+
enum SimpleAttrKind {
11+
Doc,
12+
Normal,
13+
}
1114

12-
for attr in &item.attrs {
13-
if attr.span.from_expansion() {
14-
continue;
15-
}
16-
match (&attr.style, &attr.kind) {
17-
(AttrStyle::Inner, AttrKind::Normal(_)) => has_inner_normal = true,
18-
(AttrStyle::Inner, AttrKind::DocComment(..)) => has_inner_doc = true,
19-
(AttrStyle::Outer, AttrKind::Normal(_)) => has_outer_normal = true,
20-
(AttrStyle::Outer, AttrKind::DocComment(..)) => has_outer_doc = true,
15+
impl From<&AttrKind> for SimpleAttrKind {
16+
fn from(value: &AttrKind) -> Self {
17+
match value {
18+
AttrKind::Normal(_) => Self::Normal,
19+
AttrKind::DocComment(..) => Self::Doc,
2120
}
2221
}
23-
// Separating doc and normal attributes because mixing inner/outer docs
24-
// with other outer/inner attributes doesn't really affecting readability.
25-
if (has_inner_doc && has_outer_doc) || (has_outer_normal && has_inner_normal) {
26-
let mut attrs_iter = item.attrs.iter().filter(|attr| !attr.span.from_expansion());
27-
let span = attrs_iter.next().unwrap().span;
28-
span_lint(
29-
cx,
30-
MIXED_ATTRIBUTES_STYLE,
31-
span.with_hi(attrs_iter.last().unwrap().span.hi()),
32-
"item has both inner and outer attributes",
33-
);
22+
}
23+
24+
pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) {
25+
let mut inner_attr_kind: FxHashSet<SimpleAttrKind> = FxHashSet::default();
26+
let mut outer_attr_kind: FxHashSet<SimpleAttrKind> = FxHashSet::default();
27+
28+
for attr in attrs {
29+
if attr.span.from_expansion() || !attr_in_same_src_as_item(cx, attr.span, item_span) {
30+
continue;
31+
}
32+
33+
let kind: SimpleAttrKind = (&attr.kind).into();
34+
match attr.style {
35+
AttrStyle::Inner => {
36+
if outer_attr_kind.contains(&kind) {
37+
lint_mixed_attrs(cx, attrs);
38+
return;
39+
}
40+
inner_attr_kind.insert(kind);
41+
},
42+
AttrStyle::Outer => {
43+
if inner_attr_kind.contains(&kind) {
44+
lint_mixed_attrs(cx, attrs);
45+
return;
46+
}
47+
outer_attr_kind.insert(kind);
48+
},
49+
};
3450
}
3551
}
52+
53+
fn lint_mixed_attrs(cx: &LateContext<'_>, attrs: &[Attribute]) {
54+
let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion());
55+
let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) {
56+
first.span.with_hi(last.span.hi())
57+
} else {
58+
return;
59+
};
60+
span_lint(
61+
cx,
62+
MIXED_ATTRIBUTES_STYLE,
63+
span,
64+
"item has both inner and outer attributes",
65+
);
66+
}
67+
68+
fn attr_in_same_src_as_item(cx: &LateContext<'_>, attr_span: Span, item_span: Span) -> bool {
69+
let source_map = cx.sess().source_map();
70+
let item_src = source_map.lookup_source_file(item_span.lo());
71+
let attr_src = source_map.lookup_source_file(attr_span.lo());
72+
Arc::ptr_eq(&attr_src, &item_src)
73+
}

clippy_lints/src/attrs/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ declare_lint_pass!(Attributes => [
523523
USELESS_ATTRIBUTE,
524524
BLANKET_CLIPPY_RESTRICTION_LINTS,
525525
SHOULD_PANIC_WITHOUT_EXPECT,
526+
MIXED_ATTRIBUTES_STYLE,
526527
]);
527528

528529
impl<'tcx> LateLintPass<'tcx> for Attributes {
@@ -566,6 +567,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
566567
ItemKind::ExternCrate(..) | ItemKind::Use(..) => useless_attribute::check(cx, item, attrs),
567568
_ => {},
568569
}
570+
mixed_attributes_style::check(cx, item.span, attrs);
569571
}
570572

571573
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
@@ -594,7 +596,6 @@ impl_lint_pass!(EarlyAttributes => [
594596
MAYBE_MISUSED_CFG,
595597
DEPRECATED_CLIPPY_CFG_ATTR,
596598
UNNECESSARY_CLIPPY_CFG,
597-
MIXED_ATTRIBUTES_STYLE,
598599
DUPLICATED_ATTRIBUTES,
599600
]);
600601

@@ -605,7 +606,6 @@ impl EarlyLintPass for EarlyAttributes {
605606

606607
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
607608
empty_line_after::check(cx, item);
608-
mixed_attributes_style::check(cx, item);
609609
duplicated_attributes::check(cx, &item.attrs);
610610
}
611611

Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
//! Module level doc
2+
3+
#![allow(dead_code)]
4+
15
#[allow(unused)]
6+
//~^ ERROR: item has both inner and outer attributes
27
mod foo {
38
#![allow(dead_code)]
49
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#[path = "auxiliary/submodule.rs"] // don't lint.
2+
/// This doc comment should not lint, it could be used to add context to the original module doc
3+
mod submodule;

tests/ui/mixed_attributes_style/global_allow.stderr renamed to tests/ui/mixed_attributes_style/mod_declaration.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
error: item has both inner and outer attributes
2-
--> tests/ui/mixed_attributes_style/auxiliary/submodule.rs:1:1
2+
--> tests/ui/mixed_attributes_style/auxiliary/submodule.rs:5:1
33
|
44
LL | / #[allow(unused)]
5+
LL | |
56
LL | | mod foo {
67
LL | | #![allow(dead_code)]
78
| |________________________^

0 commit comments

Comments
 (0)