Skip to content

Commit b7e3de2

Browse files
committed
Auto merge of #124369 - flip1995:clippy-backport, r=Mark-Simulacrum
[beta] Clippy backport r? `@Mark-Simulacrum` Backports: - rust-lang/rust-clippy#12486 - rust-lang/rust-clippy#12572 - rust-lang/rust-clippy#12508 - rust-lang/rust-clippy#12617 The first one is a bit bigger as usual for a backport. But it fixes a major issue with this lint that we overlooked. So I think this is worth it. After that was merged into nightly, there were no new issues opened about this lint, so IMO this is safe to backport to `beta` and put into stable.
2 parents 205af5d + 199c298 commit b7e3de2

15 files changed

+367
-114
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,85 @@
11
use super::MIXED_ATTRIBUTES_STYLE;
22
use clippy_utils::diagnostics::span_lint;
3-
use rustc_ast::AttrStyle;
4-
use rustc_lint::EarlyContext;
3+
use rustc_ast::{AttrKind, AttrStyle, Attribute};
4+
use rustc_data_structures::fx::FxHashSet;
5+
use rustc_data_structures::sync::Lrc;
6+
use rustc_lint::{LateContext, LintContext};
7+
use rustc_span::source_map::SourceMap;
8+
use rustc_span::{SourceFile, Span, Symbol};
59

6-
pub(super) fn check(cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
7-
let mut has_outer = false;
8-
let mut has_inner = false;
10+
#[derive(Hash, PartialEq, Eq)]
11+
enum SimpleAttrKind {
12+
Doc,
13+
/// A normal attribute, with its name symbols.
14+
Normal(Vec<Symbol>),
15+
}
16+
17+
impl From<&AttrKind> for SimpleAttrKind {
18+
fn from(value: &AttrKind) -> Self {
19+
match value {
20+
AttrKind::Normal(attr) => {
21+
let path_symbols = attr
22+
.item
23+
.path
24+
.segments
25+
.iter()
26+
.map(|seg| seg.ident.name)
27+
.collect::<Vec<_>>();
28+
Self::Normal(path_symbols)
29+
},
30+
AttrKind::DocComment(..) => Self::Doc,
31+
}
32+
}
33+
}
34+
35+
pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) {
36+
let mut inner_attr_kind: FxHashSet<SimpleAttrKind> = FxHashSet::default();
37+
let mut outer_attr_kind: FxHashSet<SimpleAttrKind> = FxHashSet::default();
38+
39+
let source_map = cx.sess().source_map();
40+
let item_src = source_map.lookup_source_file(item_span.lo());
941

10-
for attr in &item.attrs {
11-
if attr.span.from_expansion() {
42+
for attr in attrs {
43+
if attr.span.from_expansion() || !attr_in_same_src_as_item(source_map, &item_src, attr.span) {
1244
continue;
1345
}
46+
47+
let kind: SimpleAttrKind = (&attr.kind).into();
1448
match attr.style {
15-
AttrStyle::Inner => has_inner = true,
16-
AttrStyle::Outer => has_outer = true,
17-
}
49+
AttrStyle::Inner => {
50+
if outer_attr_kind.contains(&kind) {
51+
lint_mixed_attrs(cx, attrs);
52+
return;
53+
}
54+
inner_attr_kind.insert(kind);
55+
},
56+
AttrStyle::Outer => {
57+
if inner_attr_kind.contains(&kind) {
58+
lint_mixed_attrs(cx, attrs);
59+
return;
60+
}
61+
outer_attr_kind.insert(kind);
62+
},
63+
};
1864
}
19-
if !has_outer || !has_inner {
65+
}
66+
67+
fn lint_mixed_attrs(cx: &LateContext<'_>, attrs: &[Attribute]) {
68+
let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion());
69+
let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) {
70+
first.span.with_hi(last.span.hi())
71+
} else {
2072
return;
21-
}
22-
let mut attrs_iter = item.attrs.iter().filter(|attr| !attr.span.from_expansion());
23-
let span = attrs_iter.next().unwrap().span;
73+
};
2474
span_lint(
2575
cx,
2676
MIXED_ATTRIBUTES_STYLE,
27-
span.with_hi(attrs_iter.last().unwrap().span.hi()),
77+
span,
2878
"item has both inner and outer attributes",
2979
);
3080
}
81+
82+
fn attr_in_same_src_as_item(source_map: &SourceMap, item_src: &Lrc<SourceFile>, attr_span: Span) -> bool {
83+
let attr_src = source_map.lookup_source_file(attr_span.lo());
84+
Lrc::ptr_eq(item_src, &attr_src)
85+
}

src/tools/clippy/clippy_lints/src/attrs/mod.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -464,10 +464,20 @@ declare_clippy_lint! {
464464

465465
declare_clippy_lint! {
466466
/// ### What it does
467-
/// Checks that an item has only one kind of attributes.
467+
/// Checks for items that have the same kind of attributes with mixed styles (inner/outer).
468468
///
469469
/// ### Why is this bad?
470-
/// Having both kinds of attributes makes it more complicated to read code.
470+
/// Having both style of said attributes makes it more complicated to read code.
471+
///
472+
/// ### Known problems
473+
/// This lint currently has false-negatives when mixing same attributes
474+
/// but they have different path symbols, for example:
475+
/// ```ignore
476+
/// #[custom_attribute]
477+
/// pub fn foo() {
478+
/// #![my_crate::custom_attribute]
479+
/// }
480+
/// ```
471481
///
472482
/// ### Example
473483
/// ```no_run
@@ -485,7 +495,7 @@ declare_clippy_lint! {
485495
/// ```
486496
#[clippy::version = "1.78.0"]
487497
pub MIXED_ATTRIBUTES_STYLE,
488-
suspicious,
498+
style,
489499
"item has both inner and outer attributes"
490500
}
491501

@@ -496,6 +506,7 @@ declare_lint_pass!(Attributes => [
496506
USELESS_ATTRIBUTE,
497507
BLANKET_CLIPPY_RESTRICTION_LINTS,
498508
SHOULD_PANIC_WITHOUT_EXPECT,
509+
MIXED_ATTRIBUTES_STYLE,
499510
]);
500511

501512
impl<'tcx> LateLintPass<'tcx> for Attributes {
@@ -539,6 +550,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
539550
ItemKind::ExternCrate(..) | ItemKind::Use(..) => useless_attribute::check(cx, item, attrs),
540551
_ => {},
541552
}
553+
mixed_attributes_style::check(cx, item.span, attrs);
542554
}
543555

544556
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
@@ -567,13 +579,11 @@ impl_lint_pass!(EarlyAttributes => [
567579
MAYBE_MISUSED_CFG,
568580
DEPRECATED_CLIPPY_CFG_ATTR,
569581
UNNECESSARY_CLIPPY_CFG,
570-
MIXED_ATTRIBUTES_STYLE,
571582
]);
572583

573584
impl EarlyLintPass for EarlyAttributes {
574585
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
575586
empty_line_after::check(cx, item);
576-
mixed_attributes_style::check(cx, item);
577587
}
578588

579589
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {

src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ enum Sign {
118118
Uncertain,
119119
}
120120

121-
fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into<Option<Ty<'cx>>>) -> Sign {
121+
fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: impl Into<Option<Ty<'cx>>>) -> Sign {
122122
// Try evaluate this expr first to see if it's positive
123123
if let Some(val) = get_const_signed_int_eval(cx, expr, ty) {
124124
return if val >= 0 { Sign::ZeroOrPositive } else { Sign::Negative };
@@ -134,11 +134,12 @@ fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into<Option<T
134134
// Peel unwrap(), expect(), etc.
135135
while let Some(&found_name) = METHODS_UNWRAP.iter().find(|&name| &method_name == name)
136136
&& let Some(arglist) = method_chain_args(expr, &[found_name])
137-
&& let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind
137+
&& let ExprKind::MethodCall(inner_path, recv, ..) = &arglist[0].0.kind
138138
{
139139
// The original type has changed, but we can't use `ty` here anyway, because it has been
140140
// moved.
141141
method_name = inner_path.ident.name.as_str();
142+
expr = recv;
142143
}
143144

144145
if METHODS_POW.iter().any(|&name| method_name == name)

src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
6262
// we omit following `cast`:
6363
let omit_cast = if let ExprKind::Call(func, []) = cast_expr.kind
6464
&& let ExprKind::Path(ref qpath @ QPath::Resolved(None, path)) = func.kind
65+
&& let Some(method_defid) = path.res.opt_def_id()
6566
{
66-
let method_defid = path.res.def_id();
6767
if cx.tcx.is_diagnostic_item(sym::ptr_null, method_defid) {
6868
OmitFollowedCastReason::Null(qpath)
6969
} else if cx.tcx.is_diagnostic_item(sym::ptr_null_mut, method_defid) {

src/tools/clippy/tests/ui/cast.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@
99
clippy::cast_sign_loss,
1010
clippy::cast_possible_wrap
1111
)]
12-
#![allow(clippy::cast_abs_to_unsigned, clippy::no_effect, clippy::unnecessary_operation)]
12+
#![allow(
13+
clippy::cast_abs_to_unsigned,
14+
clippy::no_effect,
15+
clippy::unnecessary_operation,
16+
clippy::unnecessary_literal_unwrap
17+
)]
1318

1419
fn main() {
1520
// Test clippy::cast_precision_loss
@@ -457,3 +462,8 @@ fn issue11642() {
457462
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
458463
}
459464
}
465+
466+
fn issue12506() -> usize {
467+
let bar: Result<Option<i64>, u32> = Ok(Some(10));
468+
bar.unwrap().unwrap() as usize
469+
}

0 commit comments

Comments
 (0)