Skip to content

Commit c81afb5

Browse files
authored
Merge branch 'rust-lang:master' into patch-1
2 parents a73bc9d + 32374a1 commit c81afb5

34 files changed

+1088
-263
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5917,6 +5917,7 @@ Released 2018-09-13
59175917
[`unnecessary_lazy_evaluations`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations
59185918
[`unnecessary_literal_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_unwrap
59195919
[`unnecessary_map_on_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_on_constructor
5920+
[`unnecessary_min_or_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_min_or_max
59205921
[`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
59215922
[`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
59225923
[`unnecessary_owned_empty_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_owned_empty_strings

clippy_lints/src/cognitive_complexity.rs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! calculate cognitive complexity and warn about overly complex functions
22
33
use clippy_utils::diagnostics::span_lint_and_help;
4-
use clippy_utils::source::snippet_opt;
4+
use clippy_utils::source::{IntoSpan, SpanRangeExt};
55
use clippy_utils::ty::is_type_diagnostic_item;
66
use clippy_utils::visitors::for_each_expr_without_closures;
77
use clippy_utils::{get_async_fn_body, is_async_fn, LimitStack};
@@ -12,7 +12,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl};
1212
use rustc_lint::{LateContext, LateLintPass, LintContext};
1313
use rustc_session::impl_lint_pass;
1414
use rustc_span::def_id::LocalDefId;
15-
use rustc_span::{sym, BytePos, Span};
15+
use rustc_span::{sym, Span};
1616

1717
declare_clippy_lint! {
1818
/// ### What it does
@@ -50,7 +50,6 @@ impl CognitiveComplexity {
5050
impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]);
5151

5252
impl CognitiveComplexity {
53-
#[expect(clippy::cast_possible_truncation)]
5453
fn check<'tcx>(
5554
&mut self,
5655
cx: &LateContext<'tcx>,
@@ -100,17 +99,12 @@ impl CognitiveComplexity {
10099
FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span,
101100
FnKind::Closure => {
102101
let header_span = body_span.with_hi(decl.output.span().lo());
103-
let pos = snippet_opt(cx, header_span).and_then(|snip| {
104-
let low_offset = snip.find('|')?;
105-
let high_offset = 1 + snip.get(low_offset + 1..)?.find('|')?;
106-
let low = header_span.lo() + BytePos(low_offset as u32);
107-
let high = low + BytePos(high_offset as u32 + 1);
108-
109-
Some((low, high))
110-
});
111-
112-
if let Some((low, high)) = pos {
113-
Span::new(low, high, header_span.ctxt(), header_span.parent())
102+
#[expect(clippy::range_plus_one)]
103+
if let Some(range) = header_span.map_range(cx, |src, range| {
104+
let mut idxs = src.get(range.clone())?.match_indices('|');
105+
Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1)
106+
}) {
107+
range.with_ctxt(header_span.ctxt())
114108
} else {
115109
return;
116110
}

clippy_lints/src/copies.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then};
2-
use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, snippet_opt};
2+
use clippy_utils::source::{first_line_of_span, indent_of, reindent_multiline, snippet, IntoSpan, SpanRangeExt};
33
use clippy_utils::ty::{needs_ordered_drop, InteriorMut};
44
use clippy_utils::visitors::for_each_expr_without_closures;
55
use clippy_utils::{
@@ -14,7 +14,7 @@ use rustc_lint::{LateContext, LateLintPass};
1414
use rustc_session::impl_lint_pass;
1515
use rustc_span::hygiene::walk_chain;
1616
use rustc_span::source_map::SourceMap;
17-
use rustc_span::{BytePos, Span, Symbol};
17+
use rustc_span::{Span, Symbol};
1818
use std::borrow::Cow;
1919

2020
declare_clippy_lint! {
@@ -266,12 +266,12 @@ fn lint_branches_sharing_code<'tcx>(
266266

267267
let span = span.with_hi(last_block.span.hi());
268268
// Improve formatting if the inner block has indention (i.e. normal Rust formatting)
269-
let test_span = Span::new(span.lo() - BytePos(4), span.lo(), span.ctxt(), span.parent());
270-
let span = if snippet_opt(cx, test_span).map_or(false, |snip| snip == " ") {
271-
span.with_lo(test_span.lo())
272-
} else {
273-
span
274-
};
269+
let span = span
270+
.map_range(cx, |src, range| {
271+
(range.start > 4 && src.get(range.start - 4..range.start)? == " ")
272+
.then_some(range.start - 4..range.end)
273+
})
274+
.map_or(span, |range| range.with_ctxt(span.ctxt()));
275275
(span, suggestion.to_string())
276276
});
277277

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
471471
crate::methods::UNNECESSARY_JOIN_INFO,
472472
crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO,
473473
crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,
474+
crate::methods::UNNECESSARY_MIN_OR_MAX_INFO,
474475
crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO,
475476
crate::methods::UNNECESSARY_SORT_BY_INFO,
476477
crate::methods::UNNECESSARY_TO_OWNED_INFO,

clippy_lints/src/implicit_hasher.rs

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_span::symbol::sym;
1414
use rustc_span::Span;
1515

1616
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
17-
use clippy_utils::source::{snippet, snippet_opt};
17+
use clippy_utils::source::{snippet, IntoSpan, SpanRangeExt};
1818
use clippy_utils::ty::is_type_diagnostic_item;
1919

2020
declare_clippy_lint! {
@@ -59,10 +59,8 @@ declare_clippy_lint! {
5959
declare_lint_pass!(ImplicitHasher => [IMPLICIT_HASHER]);
6060

6161
impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
62-
#[expect(clippy::cast_possible_truncation, clippy::too_many_lines)]
62+
#[expect(clippy::too_many_lines)]
6363
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
64-
use rustc_span::BytePos;
65-
6664
fn suggestion(
6765
cx: &LateContext<'_>,
6866
diag: &mut Diag<'_, ()>,
@@ -123,10 +121,11 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
123121
}
124122

125123
let generics_suggestion_span = impl_.generics.span.substitute_dummy({
126-
let pos = snippet_opt(cx, item.span.until(target.span()))
127-
.and_then(|snip| Some(item.span.lo() + BytePos(snip.find("impl")? as u32 + 4)));
128-
if let Some(pos) = pos {
129-
Span::new(pos, pos, item.span.ctxt(), item.span.parent())
124+
let range = (item.span.lo()..target.span().lo()).map_range(cx, |src, range| {
125+
Some(src.get(range.clone())?.find("impl")? + 4..range.end)
126+
});
127+
if let Some(range) = range {
128+
range.with_ctxt(item.span.ctxt())
130129
} else {
131130
return;
132131
}
@@ -163,21 +162,16 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
163162
continue;
164163
}
165164
let generics_suggestion_span = generics.span.substitute_dummy({
166-
let pos = snippet_opt(
167-
cx,
168-
Span::new(
169-
item.span.lo(),
170-
body.params[0].pat.span.lo(),
171-
item.span.ctxt(),
172-
item.span.parent(),
173-
),
174-
)
175-
.and_then(|snip| {
176-
let i = snip.find("fn")?;
177-
Some(item.span.lo() + BytePos((i + snip[i..].find('(')?) as u32))
178-
})
179-
.expect("failed to create span for type parameters");
180-
Span::new(pos, pos, item.span.ctxt(), item.span.parent())
165+
let range = (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |src, range| {
166+
let (pre, post) = src.get(range.clone())?.split_once("fn")?;
167+
let pos = post.find('(')? + pre.len() + 2;
168+
Some(pos..pos)
169+
});
170+
if let Some(range) = range {
171+
range.with_ctxt(item.span.ctxt())
172+
} else {
173+
return;
174+
}
181175
});
182176

183177
let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target);

clippy_lints/src/manual_unwrap_or_default.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,15 @@ declare_lint_pass!(ManualUnwrapOrDefault => [MANUAL_UNWRAP_OR_DEFAULT]);
5353

5454
fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<HirId> {
5555
if let PatKind::TupleStruct(QPath::Resolved(_, path), &[pat], _) = pat.kind
56+
&& let PatKind::Binding(_, pat_id, _, _) = pat.kind
5657
&& let Some(def_id) = path.res.opt_def_id()
5758
// Since it comes from a pattern binding, we need to get the parent to actually match
5859
// against it.
5960
&& let Some(def_id) = cx.tcx.opt_parent(def_id)
6061
&& (cx.tcx.lang_items().get(LangItem::OptionSome) == Some(def_id)
6162
|| cx.tcx.lang_items().get(LangItem::ResultOk) == Some(def_id))
6263
{
63-
let mut bindings = Vec::new();
64-
pat.each_binding(|_, id, _, _| bindings.push(id));
65-
if let &[id] = bindings.as_slice() {
66-
Some(id)
67-
} else {
68-
None
69-
}
64+
Some(pat_id)
7065
} else {
7166
None
7267
}

clippy_lints/src/matches/single_match.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::source::{expr_block, get_source_text, snippet};
2+
use clippy_utils::source::{expr_block, snippet, SpanRangeExt};
33
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs};
44
use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs};
55
use core::cmp::max;
@@ -17,7 +17,7 @@ use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE};
1717
/// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty
1818
/// match arms.
1919
fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
20-
if let Some(ff) = get_source_text(cx, span)
20+
if let Some(ff) = span.get_source_text(cx)
2121
&& let Some(text) = ff.as_str()
2222
{
2323
text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*")

clippy_lints/src/methods/manual_inspect.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use clippy_config::msrvs::{self, Msrv};
22
use clippy_utils::diagnostics::span_lint_and_then;
3-
use clippy_utils::source::{get_source_text, with_leading_whitespace, SpanRange};
3+
use clippy_utils::source::{IntoSpan, SpanRangeExt};
44
use clippy_utils::ty::get_field_by_name;
55
use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures};
66
use clippy_utils::{expr_use_ctxt, is_diag_item_method, is_diag_trait_item, path_to_local_id, ExprUseNode};
@@ -9,7 +9,7 @@ use rustc_errors::Applicability;
99
use rustc_hir::{BindingMode, BorrowKind, ByRef, ClosureKind, Expr, ExprKind, Mutability, Node, PatKind};
1010
use rustc_lint::LateContext;
1111
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
12-
use rustc_span::{sym, BytePos, Span, Symbol, DUMMY_SP};
12+
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
1313

1414
use super::MANUAL_INSPECT;
1515

@@ -98,17 +98,19 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
9898
let mut addr_of_edits = Vec::with_capacity(delayed.len());
9999
for x in delayed {
100100
match x {
101-
UseKind::Return(s) => edits.push((with_leading_whitespace(cx, s).set_span_pos(s), String::new())),
101+
UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())),
102102
UseKind::Borrowed(s) => {
103-
if let Some(src) = get_source_text(cx, s)
104-
&& let Some(src) = src.as_str()
105-
&& let trim_src = src.trim_start_matches([' ', '\t', '\n', '\r', '('])
106-
&& trim_src.starts_with('&')
107-
{
108-
let range = s.into_range();
109-
#[expect(clippy::cast_possible_truncation)]
110-
let start = BytePos(range.start.0 + (src.len() - trim_src.len()) as u32);
111-
addr_of_edits.push(((start..BytePos(start.0 + 1)).set_span_pos(s), String::new()));
103+
#[expect(clippy::range_plus_one)]
104+
let range = s.map_range(cx, |src, range| {
105+
let src = src.get(range.clone())?;
106+
let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']);
107+
trimmed.starts_with('&').then(|| {
108+
let pos = range.start + src.len() - trimmed.len();
109+
pos..pos + 1
110+
})
111+
});
112+
if let Some(range) = range {
113+
addr_of_edits.push((range.with_ctxt(s.ctxt()), String::new()));
112114
} else {
113115
requires_copy = true;
114116
requires_deref = true;
@@ -174,7 +176,10 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
174176
}),
175177
));
176178
edits.push((
177-
with_leading_whitespace(cx, final_expr.span).set_span_pos(final_expr.span),
179+
final_expr
180+
.span
181+
.with_leading_whitespace(cx)
182+
.with_ctxt(final_expr.span.ctxt()),
178183
String::new(),
179184
));
180185
let app = if edits.iter().any(|(s, _)| s.from_expansion()) {

clippy_lints/src/methods/mod.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ mod unnecessary_iter_cloned;
117117
mod unnecessary_join;
118118
mod unnecessary_lazy_eval;
119119
mod unnecessary_literal_unwrap;
120+
mod unnecessary_min_or_max;
120121
mod unnecessary_result_map_or_else;
121122
mod unnecessary_sort_by;
122123
mod unnecessary_to_owned;
@@ -3945,6 +3946,31 @@ declare_clippy_lint! {
39453946
"cloning an `Option` via `as_ref().cloned()`"
39463947
}
39473948

3949+
declare_clippy_lint! {
3950+
/// ### What it does
3951+
/// Checks for unnecessary calls to `min()` or `max()` in the following cases
3952+
/// - Either both side is constant
3953+
/// - One side is clearly larger than the other, like i32::MIN and an i32 variable
3954+
///
3955+
/// ### Why is this bad?
3956+
///
3957+
/// In the aformentioned cases it is not necessary to call `min()` or `max()`
3958+
/// to compare values, it may even cause confusion.
3959+
///
3960+
/// ### Example
3961+
/// ```no_run
3962+
/// let _ = 0.min(7_u32);
3963+
/// ```
3964+
/// Use instead:
3965+
/// ```no_run
3966+
/// let _ = 0;
3967+
/// ```
3968+
#[clippy::version = "1.78.0"]
3969+
pub UNNECESSARY_MIN_OR_MAX,
3970+
complexity,
3971+
"using 'min()/max()' when there is no need for it"
3972+
}
3973+
39483974
declare_clippy_lint! {
39493975
/// ### What it does
39503976
/// Checks for usage of `.map_or_else()` "map closure" for `Result` type.
@@ -4267,6 +4293,7 @@ impl_lint_pass!(Methods => [
42674293
UNNECESSARY_GET_THEN_CHECK,
42684294
NEEDLESS_CHARACTER_ITERATION,
42694295
MANUAL_INSPECT,
4296+
UNNECESSARY_MIN_OR_MAX,
42704297
]);
42714298

42724299
/// Extracts a method call name, args, and `Span` of the method name.
@@ -4566,6 +4593,9 @@ impl Methods {
45664593
Some(("bytes", recv2, [], _, _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
45674594
_ => {},
45684595
},
4596+
("min" | "max", [arg]) => {
4597+
unnecessary_min_or_max::check(cx, expr, name, recv, arg);
4598+
},
45694599
("drain", ..) => {
45704600
if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id)
45714601
&& matches!(kind, StmtKind::Semi(_))

0 commit comments

Comments
 (0)