Skip to content

Commit f19db28

Browse files
committed
Auto merge of #10434 - Jarcho:snip_context, r=dswij
Remove `snippet_with_macro_callsite` `snippet_with_context` is used instead to support nested macro calls. changelog: None
2 parents e426ba4 + 1a81a3e commit f19db28

22 files changed

+200
-193
lines changed

clippy_lints/src/default.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
2-
use clippy_utils::source::snippet_with_macro_callsite;
2+
use clippy_utils::source::snippet_with_context;
33
use clippy_utils::ty::{has_drop, is_copy};
44
use clippy_utils::{
55
any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths,
@@ -160,6 +160,8 @@ impl<'tcx> LateLintPass<'tcx> for Default {
160160
}
161161
};
162162

163+
let init_ctxt = local.span.ctxt();
164+
163165
// find all "later statement"'s where the fields of the binding set as
164166
// Default::default() get reassigned, unless the reassignment refers to the original binding
165167
let mut first_assign = None;
@@ -169,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
169171
// find out if and which field was set by this `consecutive_statement`
170172
if let Some((field_ident, assign_rhs)) = field_reassigned_by_stmt(consecutive_statement, binding_name) {
171173
// interrupt and cancel lint if assign_rhs references the original binding
172-
if contains_name(binding_name, assign_rhs, cx) {
174+
if contains_name(binding_name, assign_rhs, cx) || init_ctxt != consecutive_statement.span.ctxt() {
173175
cancel_lint = true;
174176
break;
175177
}
@@ -204,11 +206,12 @@ impl<'tcx> LateLintPass<'tcx> for Default {
204206
.iter()
205207
.all(|field| assigned_fields.iter().any(|(a, _)| a == &field.name));
206208

209+
let mut app = Applicability::Unspecified;
207210
let field_list = assigned_fields
208211
.into_iter()
209212
.map(|(field, rhs)| {
210213
// extract and store the assigned value for help message
211-
let value_snippet = snippet_with_macro_callsite(cx, rhs.span, "..");
214+
let value_snippet = snippet_with_context(cx, rhs.span, init_ctxt, "..", &mut app).0;
212215
format!("{field}: {value_snippet}")
213216
})
214217
.collect::<Vec<String>>()

clippy_lints/src/if_then_some_else_none.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
use clippy_utils::diagnostics::span_lint_and_help;
22
use clippy_utils::eager_or_lazy::switch_to_eager_eval;
33
use clippy_utils::msrvs::{self, Msrv};
4-
use clippy_utils::source::snippet_with_macro_callsite;
4+
use clippy_utils::source::snippet_with_context;
5+
use clippy_utils::sugg::Sugg;
56
use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks};
7+
use rustc_errors::Applicability;
68
use rustc_hir::LangItem::{OptionNone, OptionSome};
79
use rustc_hir::{Expr, ExprKind, Stmt, StmtKind};
810
use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -72,21 +74,20 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
7274
return;
7375
}
7476

77+
let ctxt = expr.span.ctxt();
78+
7579
if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr)
7680
&& let ExprKind::Block(then_block, _) = then.kind
7781
&& let Some(then_expr) = then_block.expr
7882
&& let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
83+
&& then_expr.span.ctxt() == ctxt
7984
&& is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome)
8085
&& is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone)
8186
&& !stmts_contains_early_return(then_block.stmts)
8287
{
83-
let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]");
84-
let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) {
85-
format!("({cond_snip})")
86-
} else {
87-
cond_snip.into_owned()
88-
};
89-
let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, "");
88+
let mut app = Applicability::Unspecified;
89+
let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app).maybe_par().to_string();
90+
let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0;
9091
let mut method_body = if then_block.stmts.is_empty() {
9192
arg_snip.into_owned()
9293
} else {

clippy_lints/src/loops/same_item_push.rs

+19-13
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
use super::SAME_ITEM_PUSH;
22
use clippy_utils::diagnostics::span_lint_and_help;
33
use clippy_utils::path_to_local;
4-
use clippy_utils::source::snippet_with_macro_callsite;
4+
use clippy_utils::source::snippet_with_context;
55
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
66
use if_chain::if_chain;
77
use rustc_data_structures::fx::FxHashSet;
8+
use rustc_errors::Applicability;
89
use rustc_hir::def::{DefKind, Res};
910
use rustc_hir::intravisit::{walk_expr, Visitor};
1011
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind};
1112
use rustc_lint::LateContext;
1213
use rustc_span::symbol::sym;
14+
use rustc_span::SyntaxContext;
1315
use std::iter::Iterator;
1416

1517
/// Detects for loop pushing the same item into a Vec
@@ -20,9 +22,10 @@ pub(super) fn check<'tcx>(
2022
body: &'tcx Expr<'_>,
2123
_: &'tcx Expr<'_>,
2224
) {
23-
fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) {
24-
let vec_str = snippet_with_macro_callsite(cx, vec.span, "");
25-
let item_str = snippet_with_macro_callsite(cx, pushed_item.span, "");
25+
fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>, ctxt: SyntaxContext) {
26+
let mut app = Applicability::Unspecified;
27+
let vec_str = snippet_with_context(cx, vec.span, ctxt, "", &mut app).0;
28+
let item_str = snippet_with_context(cx, pushed_item.span, ctxt, "", &mut app).0;
2629

2730
span_lint_and_help(
2831
cx,
@@ -43,7 +46,7 @@ pub(super) fn check<'tcx>(
4346
walk_expr(&mut same_item_push_visitor, body);
4447
if_chain! {
4548
if same_item_push_visitor.should_lint();
46-
if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push;
49+
if let Some((vec, pushed_item, ctxt)) = same_item_push_visitor.vec_push;
4750
let vec_ty = cx.typeck_results().expr_ty(vec);
4851
let ty = vec_ty.walk().nth(1).unwrap().expect_ty();
4952
if cx
@@ -69,11 +72,11 @@ pub(super) fn check<'tcx>(
6972
then {
7073
match init.kind {
7174
// immutable bindings that are initialized with literal
72-
ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item),
75+
ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt),
7376
// immutable bindings that are initialized with constant
7477
ExprKind::Path(ref path) => {
7578
if let Res::Def(DefKind::Const, ..) = cx.qpath_res(path, init.hir_id) {
76-
emit_lint(cx, vec, pushed_item);
79+
emit_lint(cx, vec, pushed_item, ctxt);
7780
}
7881
}
7982
_ => {},
@@ -82,11 +85,11 @@ pub(super) fn check<'tcx>(
8285
}
8386
},
8487
// constant
85-
Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item),
88+
Res::Def(DefKind::Const, ..) => emit_lint(cx, vec, pushed_item, ctxt),
8689
_ => {},
8790
}
8891
},
89-
ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item),
92+
ExprKind::Lit(..) => emit_lint(cx, vec, pushed_item, ctxt),
9093
_ => {},
9194
}
9295
}
@@ -98,7 +101,7 @@ struct SameItemPushVisitor<'a, 'tcx> {
98101
non_deterministic_expr: bool,
99102
multiple_pushes: bool,
100103
// this field holds the last vec push operation visited, which should be the only push seen
101-
vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>,
104+
vec_push: Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)>,
102105
cx: &'a LateContext<'tcx>,
103106
used_locals: FxHashSet<HirId>,
104107
}
@@ -118,7 +121,7 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> {
118121
if_chain! {
119122
if !self.non_deterministic_expr;
120123
if !self.multiple_pushes;
121-
if let Some((vec, _)) = self.vec_push;
124+
if let Some((vec, _, _)) = self.vec_push;
122125
if let Some(hir_id) = path_to_local(vec);
123126
then {
124127
!self.used_locals.contains(&hir_id)
@@ -173,7 +176,10 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
173176

174177
// Given some statement, determine if that statement is a push on a Vec. If it is, return
175178
// the Vec being pushed into and the item being pushed
176-
fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
179+
fn get_vec_push<'tcx>(
180+
cx: &LateContext<'tcx>,
181+
stmt: &'tcx Stmt<'_>,
182+
) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)> {
177183
if_chain! {
178184
// Extract method being called
179185
if let StmtKind::Semi(semi_stmt) = &stmt.kind;
@@ -184,7 +190,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&
184190
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
185191
if path.ident.name.as_str() == "push";
186192
then {
187-
return Some((self_expr, pushed_item))
193+
return Some((self_expr, pushed_item, semi_stmt.span.ctxt()))
188194
}
189195
}
190196
None

clippy_lints/src/matches/manual_unwrap_or.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee:
3232
let reindented_or_body =
3333
reindent_multiline(or_body_snippet.into(), true, Some(indent));
3434

35-
let suggestion = if scrutinee.span.from_expansion() {
36-
// we don't want parentheses around macro, e.g. `(some_macro!()).unwrap_or(0)`
37-
sugg::Sugg::hir_with_macro_callsite(cx, scrutinee, "..")
38-
}
39-
else {
40-
sugg::Sugg::hir(cx, scrutinee, "..").maybe_par()
41-
};
42-
35+
let mut app = Applicability::MachineApplicable;
36+
let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par();
4337
span_lint_and_sugg(
4438
cx,
4539
MANUAL_UNWRAP_OR, expr.span,
@@ -48,7 +42,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee:
4842
format!(
4943
"{suggestion}.unwrap_or({reindented_or_body})",
5044
),
51-
Applicability::MachineApplicable,
45+
app,
5246
);
5347
}
5448
}

clippy_lints/src/matches/match_bool.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ use rustc_middle::ty;
1010

1111
use super::MATCH_BOOL;
1212

13-
pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
13+
pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
1414
// Type of expression is `bool`.
15-
if *cx.typeck_results().expr_ty(ex).kind() == ty::Bool {
15+
if *cx.typeck_results().expr_ty(scrutinee).kind() == ty::Bool {
1616
span_lint_and_then(
1717
cx,
1818
MATCH_BOOL,
@@ -36,24 +36,26 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
3636
};
3737

3838
if let Some((true_expr, false_expr)) = exprs {
39+
let mut app = Applicability::HasPlaceholders;
40+
let ctxt = expr.span.ctxt();
3941
let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) {
4042
(false, false) => Some(format!(
4143
"if {} {} else {}",
42-
snippet(cx, ex.span, "b"),
43-
expr_block(cx, true_expr, None, "..", Some(expr.span)),
44-
expr_block(cx, false_expr, None, "..", Some(expr.span))
44+
snippet(cx, scrutinee.span, "b"),
45+
expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app),
46+
expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app)
4547
)),
4648
(false, true) => Some(format!(
4749
"if {} {}",
48-
snippet(cx, ex.span, "b"),
49-
expr_block(cx, true_expr, None, "..", Some(expr.span))
50+
snippet(cx, scrutinee.span, "b"),
51+
expr_block(cx, true_expr, ctxt, "..", Some(expr.span), &mut app)
5052
)),
5153
(true, false) => {
52-
let test = Sugg::hir(cx, ex, "..");
54+
let test = Sugg::hir(cx, scrutinee, "..");
5355
Some(format!(
5456
"if {} {}",
5557
!test,
56-
expr_block(cx, false_expr, None, "..", Some(expr.span))
58+
expr_block(cx, false_expr, ctxt, "..", Some(expr.span), &mut app)
5759
))
5860
},
5961
(true, true) => None,

clippy_lints/src/matches/match_ref_pats.rs

+22-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
2-
use clippy_utils::source::snippet;
2+
use clippy_utils::source::{snippet, walk_span_to_context};
33
use clippy_utils::sugg::Sugg;
44
use core::iter::once;
5+
use rustc_errors::Applicability;
56
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
67
use rustc_lint::LateContext;
78

89
use super::MATCH_REF_PATS;
910

10-
pub(crate) fn check<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
11+
pub(crate) fn check<'a, 'b, I>(cx: &LateContext<'_>, scrutinee: &Expr<'_>, pats: I, expr: &Expr<'_>)
1112
where
1213
'b: 'a,
1314
I: Clone + Iterator<Item = &'a Pat<'b>>,
@@ -17,13 +18,28 @@ where
1718
}
1819

1920
let (first_sugg, msg, title);
20-
let span = ex.span.source_callsite();
21-
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind {
22-
first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
21+
let ctxt = expr.span.ctxt();
22+
let mut app = Applicability::Unspecified;
23+
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = scrutinee.kind {
24+
if scrutinee.span.ctxt() != ctxt {
25+
return;
26+
}
27+
first_sugg = once((
28+
scrutinee.span,
29+
Sugg::hir_with_context(cx, inner, ctxt, "..", &mut app).to_string(),
30+
));
2331
msg = "try";
2432
title = "you don't need to add `&` to both the expression and the patterns";
2533
} else {
26-
first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
34+
let Some(span) = walk_span_to_context(scrutinee.span, ctxt) else {
35+
return;
36+
};
37+
first_sugg = once((
38+
span,
39+
Sugg::hir_with_context(cx, scrutinee, ctxt, "..", &mut app)
40+
.deref()
41+
.to_string(),
42+
));
2743
msg = "instead of prefixing all patterns with `&`, you can dereference the expression";
2844
title = "you don't need to add `&` to all patterns";
2945
}

0 commit comments

Comments
 (0)