Skip to content

Commit a29f0c4

Browse files
authored
Merge branch 'master' into master
2 parents 348a7f8 + 9e9042a commit a29f0c4

Some content is hidden

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

45 files changed

+648
-239
lines changed

.github/workflows/clippy_bors.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ jobs:
162162
find $DIR ! -executable -o -type d ! -path $DIR | xargs rm -rf
163163
164164
- name: Upload Binaries
165-
uses: actions/upload-artifact@v3
165+
uses: actions/upload-artifact@v4
166166
with:
167167
name: binaries
168168
path: target/debug
@@ -202,7 +202,7 @@ jobs:
202202

203203
# Download
204204
- name: Download target dir
205-
uses: actions/download-artifact@v3
205+
uses: actions/download-artifact@v4
206206
with:
207207
name: binaries
208208
path: target/debug

CHANGELOG.md

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,61 @@ document.
66

77
## Unreleased / Beta / In Rust Nightly
88

9-
[c9139bd5...master](https://github.com/rust-lang/rust-clippy/compare/c9139bd5...master)
9+
[b794b8e0...master](https://github.com/rust-lang/rust-clippy/compare/b794b8e0...master)
10+
11+
## Rust 1.81
12+
13+
Current stable, released 2024-09-05
14+
15+
### New Lints
16+
17+
* Added [`cfg_not_test`] to `restriction`
18+
[#11293](https://github.com/rust-lang/rust-clippy/pull/11293)
19+
* Added [`byte_char_slices`] to `style`
20+
[#10155](https://github.com/rust-lang/rust-clippy/pull/10155)
21+
* Added [`set_contains_or_insert`] to `nursery`
22+
[#12873](https://github.com/rust-lang/rust-clippy/pull/12873)
23+
* Added [`manual_rotate`] to `style`
24+
[#12983](https://github.com/rust-lang/rust-clippy/pull/12983)
25+
* Added [`unnecessary_min_or_max`] to `complexity`
26+
[#12368](https://github.com/rust-lang/rust-clippy/pull/12368)
27+
* Added [`manual_inspect`] to `complexity`
28+
[#12287](https://github.com/rust-lang/rust-clippy/pull/12287)
29+
* Added [`field_scoped_visibility_modifiers`] to `restriction`
30+
[#12893](https://github.com/rust-lang/rust-clippy/pull/12893)
31+
* Added [`manual_pattern_char_comparison`] to `style`
32+
[#12849](https://github.com/rust-lang/rust-clippy/pull/12849)
33+
* Added [`needless_maybe_sized`] to `suspicious`
34+
[#10632](https://github.com/rust-lang/rust-clippy/pull/10632)
35+
* Added [`needless_character_iteration`] to `suspicious`
36+
[#12815](https://github.com/rust-lang/rust-clippy/pull/12815)
37+
38+
### Moves and Deprecations
39+
40+
* [`allow_attributes`], [`allow_attributes_without_reason`]: Now work on stable
41+
[rust#120924](https://github.com/rust-lang/rust/pull/120924)
42+
* Renamed `overflow_check_conditional` to [`panicking_overflow_checks`]
43+
[#12944](https://github.com/rust-lang/rust-clippy/pull/12944)
44+
* Moved [`panicking_overflow_checks`] to `correctness` (From `complexity` now deny-by-default)
45+
[#12944](https://github.com/rust-lang/rust-clippy/pull/12944)
46+
* Renamed `thread_local_initializer_can_be_made_const` to [`missing_const_for_thread_local`]
47+
[#12974](https://github.com/rust-lang/rust-clippy/pull/12974)
48+
* Deprecated [`maybe_misused_cfg`] and [`mismatched_target_os`] as they are now caught by cargo
49+
and rustc
50+
[#12875](https://github.com/rust-lang/rust-clippy/pull/12875)
51+
52+
### Enhancements
53+
54+
* [`significant_drop_in_scrutinee`]: Now also checks scrutinies of `while let` and `for let`
55+
expressions
56+
[#12870](https://github.com/rust-lang/rust-clippy/pull/12870)
57+
* [`std_instead_of_core`]: Now respects the `msrv` configuration
58+
[#13168](https://github.com/rust-lang/rust-clippy/pull/13168)
59+
60+
### ICE Fixes
61+
62+
* [`suboptimal_flops`]: No longer crashes on custom `.log()` functions
63+
[#12884](https://github.com/rust-lang/rust-clippy/pull/12884)
1064

1165
## Rust 1.80
1266

@@ -5560,6 +5614,7 @@ Released 2018-09-13
55605614
[`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits
55615615
[`manual_c_str_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals
55625616
[`manual_clamp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp
5617+
[`manual_div_ceil`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_div_ceil
55635618
[`manual_filter`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter
55645619
[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
55655620
[`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "clippy"
3-
version = "0.1.82"
3+
version = "0.1.83"
44
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
55
repository = "https://github.com/rust-lang/rust-clippy"
66
readme = "README.md"

clippy_config/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "clippy_config"
3-
version = "0.1.82"
3+
version = "0.1.83"
44
edition = "2021"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

clippy_config/src/conf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,7 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec<usize>) {
864864
cmp::max(1, terminal_width / (SEPARATOR_WIDTH + max_field_width))
865865
});
866866

867-
let rows = (fields.len() + (columns - 1)) / columns;
867+
let rows = fields.len().div_ceil(columns);
868868

869869
let column_widths = (0..columns)
870870
.map(|column| {

clippy_config/src/msrvs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ msrv_aliases! {
2121
1,80,0 { BOX_INTO_ITER}
2222
1,77,0 { C_STR_LITERALS }
2323
1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT }
24+
1,73,0 { MANUAL_DIV_CEIL }
2425
1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE }
2526
1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN }
2627
1,68,0 { PATH_MAIN_SEPARATOR_STR }

clippy_lints/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "clippy_lints"
3-
version = "0.1.82"
3+
version = "0.1.83"
44
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
55
repository = "https://github.com/rust-lang/rust-clippy"
66
readme = "README.md"

clippy_lints/src/byte_char_slices.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ declare_clippy_lint! {
2222
/// ```ignore
2323
/// b"Hello"
2424
/// ```
25-
#[clippy::version = "1.68.0"]
25+
#[clippy::version = "1.81.0"]
2626
pub BYTE_CHAR_SLICES,
2727
style,
2828
"hard to read byte char slice"

clippy_lints/src/cfg_not_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ declare_clippy_lint! {
2222
/// # fn important_check() {}
2323
/// important_check();
2424
/// ```
25-
#[clippy::version = "1.73.0"]
25+
#[clippy::version = "1.81.0"]
2626
pub CFG_NOT_TEST,
2727
restriction,
2828
"enforce against excluding code from test builds"

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
301301
crate::manual_async_fn::MANUAL_ASYNC_FN_INFO,
302302
crate::manual_bits::MANUAL_BITS_INFO,
303303
crate::manual_clamp::MANUAL_CLAMP_INFO,
304+
crate::manual_div_ceil::MANUAL_DIV_CEIL_INFO,
304305
crate::manual_float_methods::MANUAL_IS_FINITE_INFO,
305306
crate::manual_float_methods::MANUAL_IS_INFINITE_INFO,
306307
crate::manual_hash_one::MANUAL_HASH_ONE_INFO,

clippy_lints/src/field_scoped_visibility_modifiers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ declare_clippy_lint! {
4141
/// }
4242
/// }
4343
/// ```
44-
#[clippy::version = "1.78.0"]
44+
#[clippy::version = "1.81.0"]
4545
pub FIELD_SCOPED_VISIBILITY_MODIFIERS,
4646
restriction,
4747
"checks for usage of a scoped visibility modifier, like `pub(crate)`, on fields"

clippy_lints/src/implied_bounds_in_impls.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds
246246
&& let [.., path] = poly_trait.trait_ref.path.segments
247247
&& poly_trait.bound_generic_params.is_empty()
248248
&& let Some(trait_def_id) = path.res.opt_def_id()
249-
&& let predicates = cx.tcx.explicit_super_predicates_of(trait_def_id).predicates
249+
&& let predicates = cx.tcx.explicit_super_predicates_of(trait_def_id).skip_binder()
250250
// If the trait has no supertrait, there is no need to collect anything from that bound
251251
&& !predicates.is_empty()
252252
{

clippy_lints/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ mod manual_assert;
203203
mod manual_async_fn;
204204
mod manual_bits;
205205
mod manual_clamp;
206+
mod manual_div_ceil;
206207
mod manual_float_methods;
207208
mod manual_hash_one;
208209
mod manual_is_ascii_check;
@@ -635,8 +636,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
635636
let format_args = format_args_storage.clone();
636637
store.register_late_pass(move |_| Box::new(methods::Methods::new(conf, format_args.clone())));
637638
store.register_late_pass(move |_| Box::new(matches::Matches::new(conf)));
638-
store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(conf)));
639-
store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(conf)));
639+
store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustive::new(conf)));
640640
store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(conf)));
641641
store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(conf)));
642642
store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(conf)));
@@ -939,5 +939,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
939939
store.register_late_pass(|_| Box::new(zombie_processes::ZombieProcesses));
940940
store.register_late_pass(|_| Box::new(pointers_in_nomem_asm_block::PointersInNomemAsmBlock));
941941
store.register_late_pass(|_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo));
942+
store.register_late_pass(move |_| Box::new(manual_div_ceil::ManualDivCeil::new(conf)));
942943
// add lints here, do not remove this comment, it's used in `new_lint`
943944
}

clippy_lints/src/manual_div_ceil.rs

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
use clippy_config::msrvs::{self, Msrv};
2+
use clippy_utils::diagnostics::span_lint_and_sugg;
3+
use clippy_utils::source::snippet_with_applicability;
4+
use clippy_utils::sugg::Sugg;
5+
use clippy_utils::SpanlessEq;
6+
use rustc_ast::{BinOpKind, LitKind};
7+
use rustc_data_structures::packed::Pu128;
8+
use rustc_errors::Applicability;
9+
use rustc_hir::{Expr, ExprKind};
10+
use rustc_lint::{LateContext, LateLintPass};
11+
use rustc_middle::ty::{self};
12+
use rustc_session::impl_lint_pass;
13+
use rustc_span::symbol::Symbol;
14+
15+
use clippy_config::Conf;
16+
17+
declare_clippy_lint! {
18+
/// ### What it does
19+
/// Checks for an expression like `(x + (y - 1)) / y` which is a common manual reimplementation
20+
/// of `x.div_ceil(y)`.
21+
///
22+
/// ### Why is this bad?
23+
/// It's simpler, clearer and more readable.
24+
///
25+
/// ### Example
26+
/// ```no_run
27+
/// let x: i32 = 7;
28+
/// let y: i32 = 4;
29+
/// let div = (x + (y - 1)) / y;
30+
/// ```
31+
/// Use instead:
32+
/// ```no_run
33+
/// #![feature(int_roundings)]
34+
/// let x: i32 = 7;
35+
/// let y: i32 = 4;
36+
/// let div = x.div_ceil(y);
37+
/// ```
38+
#[clippy::version = "1.81.0"]
39+
pub MANUAL_DIV_CEIL,
40+
complexity,
41+
"manually reimplementing `div_ceil`"
42+
}
43+
44+
pub struct ManualDivCeil {
45+
msrv: Msrv,
46+
}
47+
48+
impl ManualDivCeil {
49+
#[must_use]
50+
pub fn new(conf: &'static Conf) -> Self {
51+
Self {
52+
msrv: conf.msrv.clone(),
53+
}
54+
}
55+
}
56+
57+
impl_lint_pass!(ManualDivCeil => [MANUAL_DIV_CEIL]);
58+
59+
impl<'tcx> LateLintPass<'tcx> for ManualDivCeil {
60+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
61+
if !self.msrv.meets(msrvs::MANUAL_DIV_CEIL) {
62+
return;
63+
}
64+
65+
let mut applicability = Applicability::MachineApplicable;
66+
67+
if let ExprKind::Binary(div_op, div_lhs, div_rhs) = expr.kind
68+
&& div_op.node == BinOpKind::Div
69+
&& check_int_ty_and_feature(cx, div_lhs)
70+
&& check_int_ty_and_feature(cx, div_rhs)
71+
&& let ExprKind::Binary(inner_op, inner_lhs, inner_rhs) = div_lhs.kind
72+
{
73+
// (x + (y - 1)) / y
74+
if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_rhs.kind
75+
&& inner_op.node == BinOpKind::Add
76+
&& sub_op.node == BinOpKind::Sub
77+
&& check_literal(sub_rhs)
78+
&& check_eq_expr(cx, sub_lhs, div_rhs)
79+
{
80+
build_suggestion(cx, expr, inner_lhs, div_rhs, &mut applicability);
81+
return;
82+
}
83+
84+
// ((y - 1) + x) / y
85+
if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_lhs.kind
86+
&& inner_op.node == BinOpKind::Add
87+
&& sub_op.node == BinOpKind::Sub
88+
&& check_literal(sub_rhs)
89+
&& check_eq_expr(cx, sub_lhs, div_rhs)
90+
{
91+
build_suggestion(cx, expr, inner_rhs, div_rhs, &mut applicability);
92+
return;
93+
}
94+
95+
// (x + y - 1) / y
96+
if let ExprKind::Binary(add_op, add_lhs, add_rhs) = inner_lhs.kind
97+
&& inner_op.node == BinOpKind::Sub
98+
&& add_op.node == BinOpKind::Add
99+
&& check_literal(inner_rhs)
100+
&& check_eq_expr(cx, add_rhs, div_rhs)
101+
{
102+
build_suggestion(cx, expr, add_lhs, div_rhs, &mut applicability);
103+
}
104+
}
105+
}
106+
107+
extract_msrv_attr!(LateContext);
108+
}
109+
110+
fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
111+
let expr_ty = cx.typeck_results().expr_ty(expr);
112+
match expr_ty.peel_refs().kind() {
113+
ty::Uint(_) => true,
114+
ty::Int(_) => cx
115+
.tcx
116+
.features()
117+
.declared_features
118+
.contains(&Symbol::intern("int_roundings")),
119+
120+
_ => false,
121+
}
122+
}
123+
124+
fn check_literal(expr: &Expr<'_>) -> bool {
125+
if let ExprKind::Lit(lit) = expr.kind
126+
&& let LitKind::Int(Pu128(1), _) = lit.node
127+
{
128+
return true;
129+
}
130+
false
131+
}
132+
133+
fn check_eq_expr(cx: &LateContext<'_>, lhs: &Expr<'_>, rhs: &Expr<'_>) -> bool {
134+
SpanlessEq::new(cx).eq_expr(lhs, rhs)
135+
}
136+
137+
fn build_suggestion(
138+
cx: &LateContext<'_>,
139+
expr: &Expr<'_>,
140+
lhs: &Expr<'_>,
141+
rhs: &Expr<'_>,
142+
applicability: &mut Applicability,
143+
) {
144+
let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_par();
145+
let divisor_snippet = snippet_with_applicability(cx, rhs.span.source_callsite(), "..", applicability);
146+
147+
let sugg = format!("{dividend_sugg}.div_ceil({divisor_snippet})");
148+
149+
span_lint_and_sugg(
150+
cx,
151+
MANUAL_DIV_CEIL,
152+
expr.span,
153+
"manually reimplementing `div_ceil`",
154+
"consider using `.div_ceil()`",
155+
sugg,
156+
*applicability,
157+
);
158+
}

0 commit comments

Comments
 (0)