Skip to content

Commit 7f51e81

Browse files
author
Ype Kingma
committed
Merge branch 'master' into lifetimes_bound_nested_ref
Also add IntegerDivisionRemainderUsed # Conflicts: # clippy_lints/src/lib.rs
2 parents 40aed9c + e9a50f2 commit 7f51e81

File tree

99 files changed

+2196
-733
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+2196
-733
lines changed

.github/workflows/clippy.yml

+6-4
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,19 @@ env:
2626
NO_FMT_TEST: 1
2727
CARGO_INCREMENTAL: 0
2828

29+
concurrency:
30+
# For a given workflow, if we push to the same PR, cancel all previous builds on that PR.
31+
# If the push is not attached to a PR, we will cancel all builds on the same branch.
32+
group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}"
33+
cancel-in-progress: true
34+
2935
jobs:
3036
base:
3137
# NOTE: If you modify this job, make sure you copy the changes to clippy_bors.yml
3238
runs-on: ubuntu-latest
3339

3440
steps:
3541
# Setup
36-
- uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
37-
with:
38-
github_token: "${{ secrets.github_token }}"
39-
4042
- name: Checkout
4143
uses: actions/checkout@v4
4244

.github/workflows/clippy_bors.yml

+5-20
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ env:
1212
NO_FMT_TEST: 1
1313
CARGO_INCREMENTAL: 0
1414

15+
concurrency:
16+
# For a given workflow, if we push to the same branch, cancel all previous builds on that branch.
17+
group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}"
18+
cancel-in-progress: true
19+
1520
defaults:
1621
run:
1722
shell: bash
@@ -21,10 +26,6 @@ jobs:
2126
runs-on: ubuntu-latest
2227

2328
steps:
24-
- uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
25-
with:
26-
github_token: "${{ secrets.github_token }}"
27-
2829
- name: Checkout
2930
uses: actions/checkout@v4
3031
with:
@@ -67,10 +68,6 @@ jobs:
6768
# NOTE: If you modify this job, make sure you copy the changes to clippy.yml
6869
steps:
6970
# Setup
70-
- uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
71-
with:
72-
github_token: "${{ secrets.github_token }}"
73-
7471
- name: Checkout
7572
uses: actions/checkout@v4
7673

@@ -131,10 +128,6 @@ jobs:
131128

132129
steps:
133130
# Setup
134-
- uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
135-
with:
136-
github_token: "${{ secrets.github_token }}"
137-
138131
- name: Checkout
139132
uses: actions/checkout@v4
140133

@@ -155,10 +148,6 @@ jobs:
155148

156149
steps:
157150
# Setup
158-
- uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
159-
with:
160-
github_token: "${{ secrets.github_token }}"
161-
162151
- name: Checkout
163152
uses: actions/checkout@v4
164153

@@ -211,10 +200,6 @@ jobs:
211200

212201
steps:
213202
# Setup
214-
- uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
215-
with:
216-
github_token: "${{ secrets.github_token }}"
217-
218203
- name: Checkout
219204
uses: actions/checkout@v4
220205

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -5157,6 +5157,7 @@ Released 2018-09-13
51575157
[`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
51585158
[`duplicate_mod`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_mod
51595159
[`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
5160+
[`duplicated_attributes`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicated_attributes
51605161
[`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
51615162
[`eager_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#eager_transmute
51625163
[`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
@@ -5282,6 +5283,7 @@ Released 2018-09-13
52825283
[`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
52835284
[`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
52845285
[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
5286+
[`integer_division_remainder_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division_remainder_used
52855287
[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
52865288
[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
52875289
[`into_iter_without_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_without_iter

Cargo.toml

+5-5
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,26 @@ path = "src/driver.rs"
2424
clippy_config = { path = "clippy_config" }
2525
clippy_lints = { path = "clippy_lints" }
2626
rustc_tools_util = "0.3.0"
27-
tempfile = { version = "3.2", optional = true }
27+
tempfile = { version = "3.3", optional = true }
2828
termize = "0.1"
2929
color-print = "0.3.4"
3030
anstream = "0.6.0"
3131

3232
[dev-dependencies]
3333
ui_test = "0.22.2"
3434
tester = "0.9"
35-
regex = "1.5"
35+
regex = "1.5.5"
3636
toml = "0.7.3"
3737
walkdir = "2.3"
3838
# This is used by the `collect-metadata` alias.
39-
filetime = "0.2"
39+
filetime = "0.2.9"
4040
itertools = "0.12"
4141

4242
# UI test dependencies
4343
clippy_utils = { path = "clippy_utils" }
4444
if_chain = "1.0"
45-
quote = "1.0"
46-
serde = { version = "1.0.125", features = ["derive"] }
45+
quote = "1.0.25"
46+
serde = { version = "1.0.145", features = ["derive"] }
4747
syn = { version = "2.0", features = ["full"] }
4848
futures = "0.3"
4949
parking_lot = "0.12"

book/src/development/macro_expansions.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ if expr.span.from_expansion() {
5252

5353
### `Span.ctxt` method
5454

55-
The `span`'s context, given by the method [`ctxt`] and returning [SpanContext],
55+
The `span`'s context, given by the method [`ctxt`] and returning [SyntaxContext],
5656
represents if the span is from a macro expansion and, if it is, which
5757
macro call expanded this span.
5858

@@ -155,4 +155,4 @@ if in_external_macro(cx.sess(), foo_span) {
155155
[`from_expansion`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
156156
[`in_external_macro`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html
157157
[Span]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html
158-
[SpanContext]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/hygiene/struct.SyntaxContext.html
158+
[SyntaxContext]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/hygiene/struct.SyntaxContext.html

clippy_dev/src/update_lints.rs

+2
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,8 @@ fn gen_deprecated_lints_test(lints: &[DeprecatedLint]) -> String {
689689
fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String {
690690
let mut seen_lints = HashSet::new();
691691
let mut res: String = GENERATED_FILE_COMMENT.into();
692+
693+
res.push_str("#![allow(clippy::duplicated_attributes)]\n");
692694
for lint in lints {
693695
if seen_lints.insert(&lint.new_name) {
694696
writeln!(res, "#![allow({})]", lint.new_name).unwrap();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use super::DUPLICATED_ATTRIBUTES;
2+
use clippy_utils::diagnostics::span_lint_and_then;
3+
use rustc_ast::{Attribute, MetaItem};
4+
use rustc_data_structures::fx::FxHashMap;
5+
use rustc_lint::EarlyContext;
6+
use rustc_span::{sym, Span};
7+
use std::collections::hash_map::Entry;
8+
9+
fn emit_if_duplicated(
10+
cx: &EarlyContext<'_>,
11+
attr: &MetaItem,
12+
attr_paths: &mut FxHashMap<String, Span>,
13+
complete_path: String,
14+
) {
15+
match attr_paths.entry(complete_path) {
16+
Entry::Vacant(v) => {
17+
v.insert(attr.span);
18+
},
19+
Entry::Occupied(o) => {
20+
span_lint_and_then(cx, DUPLICATED_ATTRIBUTES, attr.span, "duplicated attribute", |diag| {
21+
diag.span_note(*o.get(), "first defined here");
22+
diag.span_help(attr.span, "remove this attribute");
23+
});
24+
},
25+
}
26+
}
27+
28+
fn check_duplicated_attr(
29+
cx: &EarlyContext<'_>,
30+
attr: &MetaItem,
31+
attr_paths: &mut FxHashMap<String, Span>,
32+
parent: &mut Vec<String>,
33+
) {
34+
let Some(ident) = attr.ident() else { return };
35+
let name = ident.name;
36+
if name == sym::doc || name == sym::cfg_attr {
37+
// FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg
38+
// conditions are the same.
39+
return;
40+
}
41+
if let Some(value) = attr.value_str() {
42+
emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}={value}", parent.join(":")));
43+
} else if let Some(sub_attrs) = attr.meta_item_list() {
44+
parent.push(name.as_str().to_string());
45+
for sub_attr in sub_attrs {
46+
if let Some(meta) = sub_attr.meta_item() {
47+
check_duplicated_attr(cx, meta, attr_paths, parent);
48+
}
49+
}
50+
parent.pop();
51+
} else {
52+
emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}", parent.join(":")));
53+
}
54+
}
55+
56+
pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) {
57+
let mut attr_paths = FxHashMap::default();
58+
59+
for attr in attrs {
60+
if let Some(meta) = attr.meta() {
61+
check_duplicated_attr(cx, &meta, &mut attr_paths, &mut Vec::new());
62+
}
63+
}
64+
}

clippy_lints/src/attrs/mod.rs

+34-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod allow_attributes_without_reason;
44
mod blanket_clippy_restriction_lints;
55
mod deprecated_cfg_attr;
66
mod deprecated_semver;
7+
mod duplicated_attributes;
78
mod empty_line_after;
89
mod inline_always;
910
mod maybe_misused_cfg;
@@ -16,7 +17,7 @@ mod useless_attribute;
1617
mod utils;
1718

1819
use clippy_config::msrvs::Msrv;
19-
use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem};
20+
use rustc_ast::{Attribute, Crate, MetaItemKind, NestedMetaItem};
2021
use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
2122
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
2223
use rustc_session::{declare_lint_pass, impl_lint_pass};
@@ -489,6 +490,32 @@ declare_clippy_lint! {
489490
"item has both inner and outer attributes"
490491
}
491492

493+
declare_clippy_lint! {
494+
/// ### What it does
495+
/// Checks for attributes that appear two or more times.
496+
///
497+
/// ### Why is this bad?
498+
/// Repeating an attribute on the same item (or globally on the same crate)
499+
/// is unnecessary and doesn't have an effect.
500+
///
501+
/// ### Example
502+
/// ```no_run
503+
/// #[allow(dead_code)]
504+
/// #[allow(dead_code)]
505+
/// fn foo() {}
506+
/// ```
507+
///
508+
/// Use instead:
509+
/// ```no_run
510+
/// #[allow(dead_code)]
511+
/// fn foo() {}
512+
/// ```
513+
#[clippy::version = "1.78.0"]
514+
pub DUPLICATED_ATTRIBUTES,
515+
suspicious,
516+
"duplicated attribute"
517+
}
518+
492519
declare_lint_pass!(Attributes => [
493520
ALLOW_ATTRIBUTES_WITHOUT_REASON,
494521
INLINE_ALWAYS,
@@ -568,12 +595,18 @@ impl_lint_pass!(EarlyAttributes => [
568595
DEPRECATED_CLIPPY_CFG_ATTR,
569596
UNNECESSARY_CLIPPY_CFG,
570597
MIXED_ATTRIBUTES_STYLE,
598+
DUPLICATED_ATTRIBUTES,
571599
]);
572600

573601
impl EarlyLintPass for EarlyAttributes {
602+
fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
603+
duplicated_attributes::check(cx, &krate.attrs);
604+
}
605+
574606
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
575607
empty_line_after::check(cx, item);
576608
mixed_attributes_style::check(cx, item);
609+
duplicated_attributes::check(cx, &item.attrs);
577610
}
578611

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

clippy_lints/src/casts/cast_lossless.rs

+26-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use clippy_config::msrvs::{self, Msrv};
22
use clippy_utils::diagnostics::span_lint_and_sugg;
33
use clippy_utils::in_constant;
4-
use clippy_utils::source::snippet_opt;
4+
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
55
use clippy_utils::ty::is_isize_or_usize;
66
use rustc_errors::Applicability;
7-
use rustc_hir::{Expr, ExprKind};
7+
use rustc_hir::{Expr, ExprKind, QPath, TyKind};
88
use rustc_lint::LateContext;
99
use rustc_middle::ty::{self, FloatTy, Ty};
1010

@@ -16,6 +16,7 @@ pub(super) fn check(
1616
cast_op: &Expr<'_>,
1717
cast_from: Ty<'_>,
1818
cast_to: Ty<'_>,
19+
cast_to_hir: &rustc_hir::Ty<'_>,
1920
msrv: &Msrv,
2021
) {
2122
if !should_lint(cx, expr, cast_from, cast_to, msrv) {
@@ -24,11 +25,11 @@ pub(super) fn check(
2425

2526
// The suggestion is to use a function call, so if the original expression
2627
// has parens on the outside, they are no longer needed.
27-
let mut applicability = Applicability::MachineApplicable;
28+
let mut app = Applicability::MachineApplicable;
2829
let opt = snippet_opt(cx, cast_op.span.source_callsite());
2930
let sugg = opt.as_ref().map_or_else(
3031
|| {
31-
applicability = Applicability::HasPlaceholders;
32+
app = Applicability::HasPlaceholders;
3233
".."
3334
},
3435
|snip| {
@@ -40,10 +41,27 @@ pub(super) fn check(
4041
},
4142
);
4243

44+
// Display the type alias instead of the aliased type. Fixes #11285
45+
//
46+
// FIXME: Once `lazy_type_alias` is stabilized(?) we should use `rustc_middle` types instead,
47+
// this will allow us to display the right type with `cast_from` as well.
48+
let cast_to_fmt = if let TyKind::Path(QPath::Resolved(None, path)) = cast_to_hir.kind
49+
// It's a bit annoying but the turbofish is optional for types. A type in an `as` cast
50+
// shouldn't have these if they're primitives, which are the only things we deal with.
51+
//
52+
// This could be removed for performance if this check is determined to have a pretty major
53+
// effect.
54+
&& path.segments.iter().all(|segment| segment.args.is_none())
55+
{
56+
snippet_with_applicability(cx, cast_to_hir.span, "..", &mut app)
57+
} else {
58+
cast_to.to_string().into()
59+
};
60+
4361
let message = if cast_from.is_bool() {
44-
format!("casting `{cast_from:}` to `{cast_to:}` is more cleanly stated with `{cast_to:}::from(_)`")
62+
format!("casting `{cast_from}` to `{cast_to_fmt}` is more cleanly stated with `{cast_to_fmt}::from(_)`")
4563
} else {
46-
format!("casting `{cast_from}` to `{cast_to}` may become silently lossy if you later change the type")
64+
format!("casting `{cast_from}` to `{cast_to_fmt}` may become silently lossy if you later change the type")
4765
};
4866

4967
span_lint_and_sugg(
@@ -52,8 +70,8 @@ pub(super) fn check(
5270
expr.span,
5371
&message,
5472
"try",
55-
format!("{cast_to}::from({sugg})"),
56-
applicability,
73+
format!("{cast_to_fmt}::from({sugg})"),
74+
app,
5775
);
5876
}
5977

clippy_lints/src/casts/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
791791
cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
792792
cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to);
793793
}
794-
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
794+
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir, &self.msrv);
795795
cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
796796
}
797797

0 commit comments

Comments
 (0)