Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions clippy_lints/src/loops/for_kv_map.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
use super::FOR_KV_MAP;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::res::MaybeDef;
use clippy_utils::source::snippet;
use clippy_utils::source::{snippet_with_applicability, walk_span_to_context};
use clippy_utils::{pat_is_wild, sugg};
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::sym;
use rustc_span::{Span, sym};

/// Checks for the `FOR_KV_MAP` lint.
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
pat: &'tcx Pat<'_>,
arg: &'tcx Expr<'_>,
body: &'tcx Expr<'_>,
span: Span,
) {
let pat_span = pat.span;

if let PatKind::Tuple(pat, _) = pat.kind
Expand All @@ -34,21 +40,25 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx
_ => arg,
};

if matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap)) {
if matches!(ty.opt_diag_name(cx), Some(sym::HashMap | sym::BTreeMap))
&& let Some(arg_span) = walk_span_to_context(arg_span, span.ctxt())
{
span_lint_and_then(
cx,
FOR_KV_MAP,
arg_span,
format!("you seem to want to iterate on a map's {kind}s"),
|diag| {
let map = sugg::Sugg::hir(cx, arg, "map");
let mut applicability = Applicability::MachineApplicable;
let map = sugg::Sugg::hir_with_context(cx, arg, span.ctxt(), "map", &mut applicability);
let pat = snippet_with_applicability(cx, new_pat_span, kind, &mut applicability);
diag.multipart_suggestion(
"use the corresponding method",
vec![
(pat_span, snippet(cx, new_pat_span, kind).into_owned()),
(pat_span, pat.to_string()),
(arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_paren())),
],
Applicability::MachineApplicable,
applicability,
);
},
);
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/loops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,7 @@ impl Loops {
explicit_counter_loop::check(cx, pat, arg, body, expr, label);
}
self.check_for_loop_arg(cx, pat, arg);
for_kv_map::check(cx, pat, arg, body);
for_kv_map::check(cx, pat, arg, body, span);
mut_range_bound::check(cx, arg, body);
single_element_loop::check(cx, pat, arg, body, expr);
same_item_push::check(cx, pat, arg, body, expr, self.msrv);
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/matches/manual_ok_err.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok
} else {
Applicability::MachineApplicable
};
let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_paren();
let scrut = Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_paren();

let scrutinee_ty = cx.typeck_results().expr_ty(scrutinee);
let (_, _, mutability) = peel_and_count_ty_refs(scrutinee_ty);
Expand Down
5 changes: 3 additions & 2 deletions clippy_lints/src/matches/match_as_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
let cast = if input_ty == output_ty { "" } else { ".map(|x| x as _)" };

let mut applicability = Applicability::MachineApplicable;
let ctxt = expr.span.ctxt();
span_lint_and_then(
cx,
MATCH_AS_REF,
Expand All @@ -59,7 +60,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
"use `Option::as_ref()`",
format!(
"{}.as_ref(){cast}",
Sugg::hir_with_applicability(cx, ex, "_", &mut applicability).maybe_paren(),
Sugg::hir_with_context(cx, ex, ctxt, "_", &mut applicability).maybe_paren(),
),
applicability,
);
Expand All @@ -69,7 +70,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
format!("use `Option::{method}()` directly"),
format!(
"{}.{method}(){cast}",
Sugg::hir_with_applicability(cx, ex, "_", &mut applicability).maybe_paren(),
Sugg::hir_with_context(cx, ex, ctxt, "_", &mut applicability).maybe_paren(),
),
applicability,
);
Expand Down
5 changes: 3 additions & 2 deletions clippy_lints/src/matches/match_bool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
"`match` on a boolean expression",
move |diag| {
let mut app = Applicability::MachineApplicable;
let ctxt = expr.span.ctxt();
let test_sugg = if let PatKind::Expr(arm_bool) = arms[0].pat.kind {
let test = Sugg::hir_with_applicability(cx, scrutinee, "_", &mut app);
let test = Sugg::hir_with_context(cx, scrutinee, ctxt, "_", &mut app);
if let PatExprKind::Lit { lit, .. } = arm_bool.kind {
match &lit.node {
LitKind::Bool(true) => Some(test),
Expand All @@ -36,7 +37,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
.map(|test| {
if let Some(guard) = &arms[0]
.guard
.map(|g| Sugg::hir_with_applicability(cx, g, "_", &mut app))
.map(|g| Sugg::hir_with_context(cx, g, ctxt, "_", &mut app))
{
test.and(guard)
} else {
Expand Down
9 changes: 5 additions & 4 deletions clippy_lints/src/matches/redundant_pattern_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,13 +267,14 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
if let Ok(arms) = arms.try_into() // TODO: use `slice::as_array` once stabilized
&& let Some((good_method, maybe_guard)) = found_good_method(cx, arms)
{
let span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span.to(op.span));
let expr_span = is_expn_of(expr.span, sym::matches).unwrap_or(expr.span);

let result_expr = match &op.kind {
ExprKind::AddrOf(_, _, borrowed) => borrowed,
_ => op,
};
let mut app = Applicability::MachineApplicable;
let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_paren();
let receiver_sugg = Sugg::hir_with_context(cx, result_expr, expr_span.ctxt(), "_", &mut app).maybe_paren();
let mut sugg = format!("{receiver_sugg}.{good_method}");

if let Some(guard) = maybe_guard {
Expand All @@ -296,14 +297,14 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
return;
}

let guard = Sugg::hir(cx, guard, "..");
let guard = Sugg::hir_with_context(cx, guard, expr_span.ctxt(), "..", &mut app);
let _ = write!(sugg, " && {}", guard.maybe_paren());
}

span_lint_and_sugg(
cx,
REDUNDANT_PATTERN_MATCHING,
span,
expr_span,
format!("redundant pattern matching, consider using `{good_method}`"),
"try",
sugg,
Expand Down
7 changes: 4 additions & 3 deletions clippy_lints/src/methods/iter_kv_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::ITER_KV_MAP;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::MaybeDef;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::{pat_is_wild, sym};
use rustc_hir::{Body, Expr, ExprKind, PatKind};
use rustc_lint::LateContext;
Expand Down Expand Up @@ -58,16 +58,17 @@ pub(super) fn check<'tcx>(
applicability,
);
} else {
let (body_snippet, _) =
snippet_with_context(cx, body_expr.span, expr.span.ctxt(), "..", &mut applicability);
span_lint_and_sugg(
cx,
ITER_KV_MAP,
expr.span,
format!("iterating on a map's {replacement_kind}s"),
"try",
format!(
"{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {})",
"{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {body_snippet})",
annotation.prefix_str(),
snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)
),
applicability,
);
Expand Down
7 changes: 4 additions & 3 deletions clippy_lints/src/methods/unnecessary_fold.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath, MaybeTypeckRes};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::source::snippet_with_context;
use clippy_utils::{DefinedTy, ExprUseNode, expr_use_ctxt, peel_blocks, strip_pat_refs};
use rustc_ast::ast;
use rustc_data_structures::packed::Pu128;
Expand Down Expand Up @@ -124,11 +124,12 @@ fn check_fold_with_op(
let mut applicability = replacement.default_applicability();
let turbofish =
replacement.maybe_turbofish(cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs());
let (r_snippet, _) =
snippet_with_context(cx, right_expr.span, expr.span.ctxt(), "EXPR", &mut applicability);
let sugg = if replacement.has_args {
format!(
"{method}{turbofish}(|{second_arg_ident}| {r})",
"{method}{turbofish}(|{second_arg_ident}| {r_snippet})",
method = replacement.method_name,
r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability),
)
} else {
format!("{method}{turbofish}()", method = replacement.method_name)
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/mutex_atomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty_ascription: &T
&& new.ident.name == sym::new
{
let mut applicability = Applicability::MaybeIncorrect;
let arg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability);
let arg = Sugg::hir_with_context(cx, arg, expr.span.ctxt(), "_", &mut applicability);
let mut suggs = vec![(expr.span, format!("std::sync::atomic::{atomic_name}::new({arg})"))];
match ty_ascription {
TypeAscriptionKind::Required(ty_ascription) => {
Expand Down
7 changes: 4 additions & 3 deletions clippy_lints/src/question_mark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use clippy_config::types::MatchLintBehaviour;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{implements_trait, is_copy};
use clippy_utils::usage::local_used_after_expr;
Expand Down Expand Up @@ -147,7 +147,8 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
&& !span_contains_cfg(cx, els.span)
{
let mut applicability = Applicability::MaybeIncorrect;
let init_expr_str = Sugg::hir_with_applicability(cx, init_expr, "..", &mut applicability).maybe_paren();
let init_expr_str =
Sugg::hir_with_context(cx, init_expr, stmt.span.ctxt(), "..", &mut applicability).maybe_paren();
// Take care when binding is `ref`
let sugg = if let PatKind::Binding(
BindingMode(ByRef::Yes(_, ref_mutability), binding_mutability),
Expand Down Expand Up @@ -295,7 +296,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex
&& (is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block))
{
let mut applicability = Applicability::MachineApplicable;
let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability);
let receiver_str = snippet_with_context(cx, caller.span, expr.span.ctxt(), "..", &mut applicability).0;
let by_ref = !cx.type_is_copy_modulo_regions(caller_ty)
&& !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..));
let sugg = if let Some(else_inner) = r#else {
Expand Down
8 changes: 5 additions & 3 deletions clippy_lints/src/strings.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::res::{MaybeDef, MaybeQPath};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
use clippy_utils::{
SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, method_calls, peel_blocks, sym,
};
Expand Down Expand Up @@ -273,14 +273,15 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
let string_expression = &expressions[0].0;

let snippet_app = snippet_with_applicability(cx, string_expression.span, "..", &mut applicability);
let (right_snip, _) = snippet_with_context(cx, right.span, e.span.ctxt(), "..", &mut applicability);

span_lint_and_sugg(
cx,
STRING_FROM_UTF8_AS_BYTES,
e.span,
"calling a slice of `as_bytes()` with `from_utf8` should be not necessary",
"try",
format!("Some(&{snippet_app}[{}])", snippet(cx, right.span, "..")),
format!("Some(&{snippet_app}[{right_snip}])"),
applicability,
);
}
Expand Down Expand Up @@ -404,7 +405,8 @@ impl<'tcx> LateLintPass<'tcx> for StrToString {
"`to_string()` called on a `&str`",
|diag| {
let mut applicability = Applicability::MachineApplicable;
let snippet = snippet_with_applicability(cx, self_arg.span, "..", &mut applicability);
let (snippet, _) =
snippet_with_context(cx, self_arg.span, expr.span.ctxt(), "..", &mut applicability);
diag.span_suggestion(expr.span, "try", format!("{snippet}.to_owned()"), applicability);
},
);
Expand Down
17 changes: 17 additions & 0 deletions tests/ui/for_kv_map.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,20 @@ fn main() {
let _v = v;
}
}

fn wrongly_unmangled_macros() {
use std::collections::HashMap;

macro_rules! test_map {
($val:expr) => {
&*$val
};
}

let m: HashMap<u64, u64> = HashMap::new();
let wrapped = Rc::new(m);
for v in test_map!(wrapped).values() {
//~^ for_kv_map
let _v = v;
}
}
17 changes: 17 additions & 0 deletions tests/ui/for_kv_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,20 @@ fn main() {
let _v = v;
}
}

fn wrongly_unmangled_macros() {
use std::collections::HashMap;

macro_rules! test_map {
($val:expr) => {
&*$val
};
}

let m: HashMap<u64, u64> = HashMap::new();
let wrapped = Rc::new(m);
for (_, v) in test_map!(wrapped) {
//~^ for_kv_map
let _v = v;
}
}
14 changes: 13 additions & 1 deletion tests/ui/for_kv_map.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,17 @@ LL - 'label: for (k, _value) in rm {
LL + 'label: for k in rm.keys() {
|

error: aborting due to 6 previous errors
error: you seem to want to iterate on a map's values
--> tests/ui/for_kv_map.rs:84:19
|
LL | for (_, v) in test_map!(wrapped) {
| ^^^^^^^^^^^^^^^^^^
|
help: use the corresponding method
|
LL - for (_, v) in test_map!(wrapped) {
LL + for v in test_map!(wrapped).values() {
|

error: aborting due to 7 previous errors

6 changes: 6 additions & 0 deletions tests/ui/iter_kv_map.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,9 @@ fn issue14595() {
let _ = map.as_ref().values().copied().collect::<Vec<_>>();
//~^ iter_kv_map
}

fn issue16340() {
let hm: HashMap<&str, &str> = HashMap::new();
let _ = hm.keys().map(|key| vec![key]);
//~^ iter_kv_map
}
6 changes: 6 additions & 0 deletions tests/ui/iter_kv_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,9 @@ fn issue14595() {
let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::<Vec<_>>();
//~^ iter_kv_map
}

fn issue16340() {
let hm: HashMap<&str, &str> = HashMap::new();
let _ = hm.iter().map(|(key, _)| vec![key]);
//~^ iter_kv_map
}
8 changes: 7 additions & 1 deletion tests/ui/iter_kv_map.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -269,5 +269,11 @@ error: iterating on a map's values
LL | let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.as_ref().values()`

error: aborting due to 39 previous errors
error: iterating on a map's keys
--> tests/ui/iter_kv_map.rs:199:13
|
LL | let _ = hm.iter().map(|(key, _)| vec![key]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hm.keys().map(|key| vec![key])`

error: aborting due to 40 previous errors

10 changes: 10 additions & 0 deletions tests/ui/manual_ok_err.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,13 @@ mod issue15051 {
result_with_ref_mut(x).as_mut().ok()
}
}

fn wrongly_unmangled_macros() {
macro_rules! test_expr {
($val:expr) => {
Ok::<i32, ()>($val)
};
}

let _ = test_expr!(42).ok();
}
Loading