Auto merge of #13244 - Jarcho:get_src_display, r=Alexendoo

Start removing `snippet_opt` in favor of `get_source_text`

Continuing the job of removing unnecessary allocations.

changelog: none
This commit is contained in:
bors 2024-08-21 17:08:49 +00:00
commit ecfc7d906f
29 changed files with 177 additions and 190 deletions

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::eq_expr_value; use clippy_utils::eq_expr_value;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -134,28 +134,30 @@ fn check_inverted_bool_in_condition(
let suggestion = match (left.kind, right.kind) { let suggestion = match (left.kind, right.kind) {
(ExprKind::Unary(UnOp::Not, left_sub), ExprKind::Unary(UnOp::Not, right_sub)) => { (ExprKind::Unary(UnOp::Not, left_sub), ExprKind::Unary(UnOp::Not, right_sub)) => {
let Some(left) = snippet_opt(cx, left_sub.span) else { let Some(left) = left_sub.span.get_source_text(cx) else {
return; return;
}; };
let Some(right) = snippet_opt(cx, right_sub.span) else { let Some(right) = right_sub.span.get_source_text(cx) else {
return; return;
}; };
let Some(op) = bin_op_eq_str(op) else { return }; let Some(op) = bin_op_eq_str(op) else { return };
format!("{left} {op} {right}") format!("{left} {op} {right}")
}, },
(ExprKind::Unary(UnOp::Not, left_sub), _) => { (ExprKind::Unary(UnOp::Not, left_sub), _) => {
let Some(left) = snippet_opt(cx, left_sub.span) else { let Some(left) = left_sub.span.get_source_text(cx) else {
return; return;
}; };
let Some(right) = snippet_opt(cx, right.span) else { let Some(right) = right.span.get_source_text(cx) else {
return; return;
}; };
let Some(op) = inverted_bin_op_eq_str(op) else { return }; let Some(op) = inverted_bin_op_eq_str(op) else { return };
format!("{left} {op} {right}") format!("{left} {op} {right}")
}, },
(_, ExprKind::Unary(UnOp::Not, right_sub)) => { (_, ExprKind::Unary(UnOp::Not, right_sub)) => {
let Some(left) = snippet_opt(cx, left.span) else { return }; let Some(left) = left.span.get_source_text(cx) else {
let Some(right) = snippet_opt(cx, right_sub.span) else { return;
};
let Some(right) = right_sub.span.get_source_text(cx) else {
return; return;
}; };
let Some(op) = inverted_bin_op_eq_str(op) else { return }; let Some(op) = inverted_bin_op_eq_str(op) else { return };
@ -313,8 +315,7 @@ fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
self.output.push_str(&str); self.output.push_str(&str);
} else { } else {
self.output.push('!'); self.output.push('!');
let snip = snippet_opt(self.cx, terminal.span)?; self.output.push_str(&terminal.span.get_source_text(self.cx)?);
self.output.push_str(&snip);
} }
}, },
True | False | Not(_) => { True | False | Not(_) => {
@ -345,8 +346,12 @@ fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
} }
}, },
&Term(n) => { &Term(n) => {
let snip = snippet_opt(self.cx, self.terminals[n as usize].span.source_callsite())?; self.output.push_str(
self.output.push_str(&snip); &self.terminals[n as usize]
.span
.source_callsite()
.get_source_text(self.cx)?,
);
}, },
} }
Some(()) Some(())
@ -370,8 +375,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
_ => None, _ => None,
} }
.and_then(|op| { .and_then(|op| {
let lhs_snippet = snippet_opt(cx, lhs.span)?; let lhs_snippet = lhs.span.get_source_text(cx)?;
let rhs_snippet = snippet_opt(cx, rhs.span)?; let rhs_snippet = rhs.span.get_source_text(cx)?;
if !(lhs_snippet.starts_with('(') && lhs_snippet.ends_with(')')) { if !(lhs_snippet.starts_with('(') && lhs_snippet.ends_with(')')) {
if let (ExprKind::Cast(..), BinOpKind::Ge) = (&lhs.kind, binop.node) { if let (ExprKind::Cast(..), BinOpKind::Ge) = (&lhs.kind, binop.node) {
@ -399,7 +404,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
let path: &str = path.ident.name.as_str(); let path: &str = path.ident.name.as_str();
a == path a == path
}) })
.and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", snippet_opt(cx, receiver.span)?))) .and_then(|(_, neg_method)| Some(format!("{}.{neg_method}()", receiver.span.get_source_text(cx)?)))
}, },
_ => None, _ => None,
} }

View File

@ -1,6 +1,6 @@
use crate::reference::DEREF_ADDROF; use crate::reference::DEREF_ADDROF;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::implements_trait; use clippy_utils::ty::implements_trait;
use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed}; use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed};
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -73,6 +73,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
} }
}) })
&& !is_from_proc_macro(cx, e) && !is_from_proc_macro(cx, e)
&& let Some(deref_text) = deref_target.span.get_source_text(cx)
{ {
span_lint_and_then( span_lint_and_then(
cx, cx,
@ -83,7 +84,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
diag.span_suggestion( diag.span_suggestion(
e.span, e.span,
"if you would like to reborrow, try removing `&*`", "if you would like to reborrow, try removing `&*`",
snippet_opt(cx, deref_target.span).unwrap(), deref_text.as_str(),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
@ -98,7 +99,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
diag.span_suggestion( diag.span_suggestion(
e.span, e.span,
"if you would like to deref, try using `&**`", "if you would like to deref, try using `&**`",
format!("&**{}", &snippet_opt(cx, deref_target.span).unwrap()), format!("&**{deref_text}"),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
}, },

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::{find_format_arg_expr, root_macro_call_first_node, FormatArgsStorage}; use clippy_utils::macros::{find_format_arg_expr, root_macro_call_first_node, FormatArgsStorage};
use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::source::{snippet_with_context, SpanRangeExt};
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait};
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -65,7 +65,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), ([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability),
([], [_]) => { ([], [_]) => {
// Simulate macro expansion, converting {{ and }} to { and }. // Simulate macro expansion, converting {{ and }} to { and }.
let Some(snippet) = snippet_opt(cx, format_args.span) else { let Some(snippet) = format_args.span.get_source_text(cx) else {
return; return;
}; };
let s_expand = snippet.replace("{{", "{").replace("}}", "}"); let s_expand = snippet.replace("{{", "{").replace("}}", "}");

View File

@ -7,7 +7,7 @@
find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro,
is_panic, matching_root_macro_call, root_macro_call_first_node, FormatArgsStorage, FormatParamUsage, MacroCall, is_panic, matching_root_macro_call, root_macro_call_first_node, FormatArgsStorage, FormatParamUsage, MacroCall,
}; };
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::{implements_trait, is_type_lang_item}; use clippy_utils::ty::{implements_trait, is_type_lang_item};
use itertools::Itertools; use itertools::Itertools;
use rustc_ast::{ use rustc_ast::{
@ -407,7 +407,7 @@ fn check_to_string_in_format_args(&self, name: Symbol, value: &Expr<'_>) {
count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter()) count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter())
&& implements_trait(cx, target, display_trait_id, &[]) && implements_trait(cx, target, display_trait_id, &[])
&& let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait() && let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait()
&& let Some(receiver_snippet) = snippet_opt(cx, receiver.span.source_callsite()) && let Some(receiver_snippet) = receiver.span.source_callsite().get_source_text(cx)
{ {
let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]); let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]);
if n_needed_derefs == 0 && !needs_ref { if n_needed_derefs == 0 && !needs_ref {

View File

@ -3,7 +3,7 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::span_is_local; use clippy_utils::macros::span_is_local;
use clippy_utils::path_def_id; use clippy_utils::path_def_id;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_path, Visitor}; use rustc_hir::intravisit::{walk_path, Visitor};
use rustc_hir::{ use rustc_hir::{
@ -178,8 +178,8 @@ fn convert_to_from(
return None; return None;
}; };
let from = snippet_opt(cx, self_ty.span)?; let from = self_ty.span.get_source_text(cx)?;
let into = snippet_opt(cx, target_ty.span)?; let into = target_ty.span.get_source_text(cx)?;
let return_type = matches!(sig.decl.output, FnRetTy::Return(_)) let return_type = matches!(sig.decl.output, FnRetTy::Return(_))
.then_some(String::from("Self")) .then_some(String::from("Self"))
@ -190,10 +190,10 @@ fn convert_to_from(
(into_trait_seg.ident.span, String::from("From")), (into_trait_seg.ident.span, String::from("From")),
// impl Into<T> for U -> impl Into<U> for U // impl Into<T> for U -> impl Into<U> for U
// ~ ~ // ~ ~
(target_ty.span, from.clone()), (target_ty.span, from.to_owned()),
// impl Into<T> for U -> impl Into<T> for T // impl Into<T> for U -> impl Into<T> for T
// ~ ~ // ~ ~
(self_ty.span, into), (self_ty.span, into.to_owned()),
// fn into(self) -> T -> fn from(self) -> T // fn into(self) -> T -> fn from(self) -> T
// ~~~~ ~~~~ // ~~~~ ~~~~
(impl_item.ident.span, String::from("from")), (impl_item.ident.span, String::from("from")),
@ -223,7 +223,7 @@ fn convert_to_from(
} }
for span in finder.upper { for span in finder.upper {
suggestions.push((span, from.clone())); suggestions.push((span, from.to_owned()));
} }
for span in finder.lower { for span in finder.lower {
suggestions.push((span, String::from("val"))); suggestions.push((span, String::from("val")));

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind}; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind};
use rustc_ast::token; use rustc_ast::token;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -130,8 +130,8 @@ fn generate_recommendation(
BinOpKind::Le => "<", BinOpKind::Le => "<",
_ => return None, _ => return None,
}; };
if let Some(snippet) = snippet_opt(cx, node.span) { if let Some(snippet) = node.span.get_source_text(cx) {
if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) { if let Some(other_side_snippet) = other_side.span.get_source_text(cx) {
let rec = match side { let rec = match side {
Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")), Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")),
Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")), Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")),

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro}; use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro};
use rustc_errors::{Applicability, SuggestionStyle}; use rustc_errors::{Applicability, SuggestionStyle};
use rustc_hir::{HirId, Item, ItemKind, Mod}; use rustc_hir::{HirId, Item, ItemKind, Mod};
@ -93,11 +93,14 @@ fn check_mod(&mut self, cx: &LateContext<'_>, module: &Mod<'_>, _: HirId) {
if let Some(prev) = mod_pos.checked_sub(1) if let Some(prev) = mod_pos.checked_sub(1)
&& let prev = cx.tcx.hir().item(module.item_ids[prev]) && let prev = cx.tcx.hir().item(module.item_ids[prev])
&& let items_span = last.span.with_lo(test_mod.span.hi()) && let items_span = last.span.with_lo(test_mod.span.hi())
&& let Some(items) = snippet_opt(cx, items_span) && let Some(items) = items_span.get_source_text(cx)
{ {
diag.multipart_suggestion_with_style( diag.multipart_suggestion_with_style(
"move the items to before the test module was defined", "move the items to before the test module was defined",
vec![(prev.span.shrink_to_hi(), items), (items_span, String::new())], vec![
(prev.span.shrink_to_hi(), items.to_owned()),
(items_span, String::new()),
],
Applicability::MachineApplicable, Applicability::MachineApplicable,
SuggestionStyle::HideCodeAlways, SuggestionStyle::HideCodeAlways,
); );

View File

@ -3,7 +3,7 @@
use clippy_config::Conf; use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::fn_has_unsatisfiable_preds; use clippy_utils::fn_has_unsatisfiable_preds;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::FnKind; use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, FnDecl}; use rustc_hir::{Body, FnDecl};
@ -186,7 +186,7 @@ fn check_fn(
// TODO: Is there a cleaner, robust way to ask this question? // TODO: Is there a cleaner, robust way to ask this question?
// The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data", // The obvious `LocalDecl::is_user_variable()` panics on "unwrapping cross-crate data",
// and that doesn't get us the true name in scope rather than the span text either. // and that doesn't get us the true name in scope rather than the span text either.
if let Some(name) = snippet_opt(cx, local_span) if let Some(name) = local_span.get_source_text(cx)
&& is_ident(&name) && is_ident(&name)
{ {
// If the local is an ordinary named variable, // If the local is an ordinary named variable,

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet_opt, snippet_with_context}; use clippy_utils::source::{snippet_with_context, SpanRangeExt};
use clippy_utils::sugg::{has_enclosing_paren, Sugg}; use clippy_utils::sugg::{has_enclosing_paren, Sugg};
use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators}; use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators};
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
@ -216,7 +216,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
} }
fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span { fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span {
let Some(snippet) = snippet_opt(cx, span) else { let Some(snippet) = span.get_source_text(cx) else {
return span; return span;
}; };
if has_enclosing_paren(snippet) { if has_enclosing_paren(snippet) {

View File

@ -1,7 +1,7 @@
use clippy_config::Conf; use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::numeric_literal::{NumericLiteral, Radix}; use clippy_utils::numeric_literal::{NumericLiteral, Radix};
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use rustc_ast::ast::{Expr, ExprKind, LitKind}; use rustc_ast::ast::{Expr, ExprKind, LitKind};
use rustc_ast::token; use rustc_ast::token;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -225,7 +225,7 @@ pub fn new(conf: &'static Conf) -> Self {
} }
fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) { fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
if let Some(src) = snippet_opt(cx, span) if let Some(src) = span.get_source_text(cx)
&& let Ok(lit_kind) = LitKind::from_token_lit(lit) && let Ok(lit_kind) = LitKind::from_token_lit(lit)
&& let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) && let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind)
{ {
@ -439,7 +439,7 @@ fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
// Lint integral literals. // Lint integral literals.
if let Ok(lit_kind) = LitKind::from_token_lit(lit) if let Ok(lit_kind) = LitKind::from_token_lit(lit)
&& let LitKind::Int(val, _) = lit_kind && let LitKind::Int(val, _) = lit_kind
&& let Some(src) = snippet_opt(cx, span) && let Some(src) = span.get_source_text(cx)
&& let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind)
&& num_lit.radix == Radix::Decimal && num_lit.radix == Radix::Decimal
&& val >= u128::from(self.threshold) && val >= u128::from(self.threshold)

View File

@ -1,6 +1,6 @@
use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use clippy_utils::{is_from_proc_macro, path_to_local}; use clippy_utils::{is_from_proc_macro, path_to_local};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Constness, Expr, ExprKind}; use rustc_hir::{BinOpKind, Constness, Expr, ExprKind};
@ -103,7 +103,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
// case somebody does that for some reason // case somebody does that for some reason
&& (is_infinity(&const_1) && is_neg_infinity(&const_2) && (is_infinity(&const_1) && is_neg_infinity(&const_2)
|| is_neg_infinity(&const_1) && is_infinity(&const_2)) || is_neg_infinity(&const_1) && is_infinity(&const_2))
&& let Some(local_snippet) = snippet_opt(cx, first.span) && let Some(local_snippet) = first.span.get_source_text(cx)
{ {
let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite, (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite,

View File

@ -1,7 +1,7 @@
use clippy_config::msrvs::{self, Msrv}; use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf; use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use clippy_utils::visitors::{is_local_used, local_used_once}; use clippy_utils::visitors::{is_local_used, local_used_once};
use clippy_utils::{is_trait_method, path_to_local_id}; use clippy_utils::{is_trait_method, path_to_local_id};
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -107,8 +107,8 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) {
finish_expr.span, finish_expr.span,
"manual implementation of `BuildHasher::hash_one`", "manual implementation of `BuildHasher::hash_one`",
|diag| { |diag| {
if let Some(build_hasher) = snippet_opt(cx, build_hasher.span) if let Some(build_hasher) = build_hasher.span.get_source_text(cx)
&& let Some(hashed_value) = snippet_opt(cx, hashed_value.span) && let Some(hashed_value) = hashed_value.span.get_source_text(cx)
{ {
diag.multipart_suggestion( diag.multipart_suggestion(
"try", "try",

View File

@ -2,7 +2,7 @@
use clippy_config::Conf; use clippy_config::Conf;
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::is_doc_hidden; use clippy_utils::is_doc_hidden;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use rustc_ast::ast::{self, VisibilityKind}; use rustc_ast::ast::{self, VisibilityKind};
use rustc_ast::attr; use rustc_ast::attr;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
@ -124,7 +124,7 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
|diag| { |diag| {
if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive)) if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive))
&& let header_span = cx.sess().source_map().span_until_char(item.span, delimiter) && let header_span = cx.sess().source_map().span_until_char(item.span, delimiter)
&& let Some(snippet) = snippet_opt(cx, header_span) && let Some(snippet) = header_span.get_source_text(cx)
{ {
diag.span_suggestion( diag.span_suggestion(
header_span, header_span,
@ -194,7 +194,7 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
"this seems like a manual implementation of the non-exhaustive pattern", "this seems like a manual implementation of the non-exhaustive pattern",
|diag| { |diag| {
let header_span = cx.sess().source_map().span_until_char(enum_span, '{'); let header_span = cx.sess().source_map().span_until_char(enum_span, '{');
if let Some(snippet) = snippet_opt(cx, header_span) { if let Some(snippet) = header_span.get_source_text(cx) {
diag.span_suggestion( diag.span_suggestion(
header_span, header_span,
"add the attribute", "add the attribute",

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use rustc_ast::LitKind; use rustc_ast::LitKind;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -143,8 +143,8 @@ fn check_pat(&mut self, cx: &LateContext<'_>, pat: &'_ rustc_hir::Pat<'_>) {
pat.span, pat.span,
"this OR pattern can be rewritten using a range", "this OR pattern can be rewritten using a range",
|diag| { |diag| {
if let Some(min) = snippet_opt(cx, min.span) if let Some(min) = min.span.get_source_text(cx)
&& let Some(max) = snippet_opt(cx, max.span) && let Some(max) = max.span.get_source_text(cx)
{ {
diag.span_suggestion( diag.span_suggestion(
pat.span, pat.span,

View File

@ -1,7 +1,7 @@
use super::utils::clone_or_copy_needed; use super::utils::clone_or_copy_needed;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::ForLoop; use clippy_utils::higher::ForLoop;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::{get_iterator_item_ty, implements_trait}; use clippy_utils::ty::{get_iterator_item_ty, implements_trait};
use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr, path_to_local}; use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr, path_to_local};
@ -40,7 +40,7 @@ pub fn check_for_loop_iter(
&& let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent) && let Some(ForLoop { pat, body, .. }) = ForLoop::hir(grandparent)
&& let (clone_or_copy_needed, references_to_binding) = clone_or_copy_needed(cx, pat, body) && let (clone_or_copy_needed, references_to_binding) = clone_or_copy_needed(cx, pat, body)
&& !clone_or_copy_needed && !clone_or_copy_needed
&& let Some(receiver_snippet) = snippet_opt(cx, receiver.span) && let Some(receiver_snippet) = receiver.span.get_source_text(cx)
{ {
// Issue 12098 // Issue 12098
// https://github.com/rust-lang/rust-clippy/issues/12098 // https://github.com/rust-lang/rust-clippy/issues/12098
@ -100,7 +100,7 @@ fn is_caller_or_fields_change(cx: &LateContext<'_>, body: &Expr<'_>, caller: &Ex
&& implements_trait(cx, collection_ty, into_iterator_trait_id, &[]) && implements_trait(cx, collection_ty, into_iterator_trait_id, &[])
&& let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item") && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item")
&& iter_item_ty == into_iter_item_ty && iter_item_ty == into_iter_item_ty
&& let Some(collection_snippet) = snippet_opt(cx, collection.span) && let Some(collection_snippet) = collection.span.get_source_text(cx)
{ {
collection_snippet collection_snippet
} else { } else {
@ -122,7 +122,7 @@ fn is_caller_or_fields_change(cx: &LateContext<'_>, body: &Expr<'_>, caller: &Ex
} else { } else {
Applicability::MachineApplicable Applicability::MachineApplicable
}; };
diag.span_suggestion(expr.span, "use", snippet, applicability); diag.span_suggestion(expr.span, "use", snippet.to_owned(), applicability);
if !references_to_binding.is_empty() { if !references_to_binding.is_empty() {
diag.multipart_suggestion( diag.multipart_suggestion(
"remove any references to the binding", "remove any references to the binding",

View File

@ -1,5 +1,6 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use itertools::Itertools;
use rustc_ast::ast::{Pat, PatKind}; use rustc_ast::ast::{Pat, PatKind};
use rustc_lint::EarlyContext; use rustc_lint::EarlyContext;
@ -45,19 +46,6 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
"you matched a field with a wildcard pattern, consider using `..` instead", "you matched a field with a wildcard pattern, consider using `..` instead",
); );
} else { } else {
let mut normal = vec![];
for field in pfields {
match field.pat.kind {
PatKind::Wild => {},
_ => {
if let Some(n) = snippet_opt(cx, field.span) {
normal.push(n);
}
},
}
}
#[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
span_lint_and_then( span_lint_and_then(
cx, cx,
@ -65,7 +53,16 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
field.span, field.span,
"you matched a field with a wildcard pattern, consider using `..` instead", "you matched a field with a wildcard pattern, consider using `..` instead",
|diag| { |diag| {
diag.help(format!("try with `{type_name} {{ {}, .. }}`", normal[..].join(", "))); diag.help(format!(
"try with `{type_name} {{ {}, .. }}`",
pfields
.iter()
.filter_map(|f| match f.pat.kind {
PatKind::Wild => None,
_ => f.span.get_source_text(cx),
})
.format(", "),
));
}, },
); );
} }

View File

@ -1,7 +1,7 @@
use clippy_config::Conf; use clippy_config::Conf;
use clippy_utils::def_path_def_ids; use clippy_utils::def_path_def_ids;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_hir::def_id::DefIdMap; use rustc_hir::def_id::DefIdMap;
@ -73,7 +73,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
&& let Some(name) = self.renames.get(&id) && let Some(name) = self.renames.get(&id)
// Remove semicolon since it is not present for nested imports // Remove semicolon since it is not present for nested imports
&& let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';') && let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';')
&& let Some(snip) = snippet_opt(cx, span_without_semi) && let Some(snip) = span_without_semi.get_source_text(cx)
&& let Some(import) = match snip.split_once(" as ") { && let Some(import) = match snip.split_once(" as ") {
None => Some(snip.as_str()), None => Some(snip.as_str()),
Some((import, rename)) => { Some((import, rename)) => {

View File

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher::If; use clippy_utils::higher::If;
use clippy_utils::is_from_proc_macro; use clippy_utils::is_from_proc_macro;
use clippy_utils::source::{snippet_opt, SpanRangeExt}; use clippy_utils::source::SpanRangeExt;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_hir::{ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
@ -57,7 +57,7 @@ fn check_stmt<'tcx>(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'tcx>) {
src.bytes() src.bytes()
.all(|ch| matches!(ch, b'{' | b'}') || ch.is_ascii_whitespace()) .all(|ch| matches!(ch, b'{' | b'}') || ch.is_ascii_whitespace())
}) })
&& let Some(cond_snippet) = snippet_opt(cx, cond.span) && let Some(cond_snippet) = cond.span.get_source_text(cx)
&& !is_from_proc_macro(cx, expr) && !is_from_proc_macro(cx, expr)
{ {
span_lint_and_sugg( span_lint_and_sugg(

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::path_to_local; use clippy_utils::path_to_local;
use clippy_utils::source::snippet_opt; use clippy_utils::source::{SourceText, SpanRangeExt};
use clippy_utils::ty::needs_ordered_drop; use clippy_utils::ty::needs_ordered_drop;
use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used}; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used};
use core::ops::ControlFlow; use core::ops::ControlFlow;
@ -236,7 +236,7 @@ fn first_usage<'tcx>(
}) })
} }
fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option<String> { fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> Option<SourceText> {
let span = local.span.with_hi(match local.ty { let span = local.span.with_hi(match local.ty {
// let <pat>: <ty>; // let <pat>: <ty>;
// ~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~
@ -246,7 +246,7 @@ fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) ->
None => local.pat.span.hi(), None => local.pat.span.hi(),
}); });
snippet_opt(cx, span) span.get_source_text(cx)
} }
fn check<'tcx>( fn check<'tcx>(
@ -275,7 +275,10 @@ fn check<'tcx>(
|diag| { |diag| {
diag.multipart_suggestion( diag.multipart_suggestion(
format!("move the declaration `{binding_name}` here"), format!("move the declaration `{binding_name}` here"),
vec![(local_stmt.span, String::new()), (assign.lhs_span, let_snippet)], vec![
(local_stmt.span, String::new()),
(assign.lhs_span, let_snippet.to_owned()),
],
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
}, },

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::has_drop; use clippy_utils::ty::has_drop;
use clippy_utils::{ use clippy_utils::{
in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks, in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks,
@ -268,15 +268,11 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
&& reduced.iter().all(|e| e.span.ctxt() == ctxt) && reduced.iter().all(|e| e.span.ctxt() == ctxt)
{ {
if let ExprKind::Index(..) = &expr.kind { if let ExprKind::Index(..) = &expr.kind {
if is_inside_always_const_context(cx.tcx, expr.hir_id) { if !is_inside_always_const_context(cx.tcx, expr.hir_id)
return; && let [arr, func] = &*reduced
} && let Some(arr) = arr.span.get_source_text(cx)
let snippet = && let Some(func) = func.span.get_source_text(cx)
if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) { {
format!("assert!({arr}.len() > {func});")
} else {
return;
};
span_lint_hir_and_then( span_lint_hir_and_then(
cx, cx,
UNNECESSARY_OPERATION, UNNECESSARY_OPERATION,
@ -287,15 +283,16 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
diag.span_suggestion( diag.span_suggestion(
stmt.span, stmt.span,
"statement can be written as", "statement can be written as",
snippet, format!("assert!({arr}.len() > {func});"),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
}, },
); );
}
} else { } else {
let mut snippet = String::new(); let mut snippet = String::new();
for e in reduced { for e in reduced {
if let Some(snip) = snippet_opt(cx, e.span) { if let Some(snip) = e.span.get_source_text(cx) {
snippet.push_str(&snip); snippet.push_str(&snip);
snippet.push(';'); snippet.push(';');
} else { } else {

View File

@ -1,7 +1,7 @@
use clippy_config::types::MacroMatcher; use clippy_config::types::MacroMatcher;
use clippy_config::Conf; use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt; use clippy_utils::source::{SourceText, SpanRangeExt};
use rustc_ast::ast; use rustc_ast::ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability; use rustc_errors::Applicability;
@ -34,7 +34,7 @@
} }
/// The (callsite span, (open brace, close brace), source snippet) /// The (callsite span, (open brace, close brace), source snippet)
type MacroInfo = (Span, (char, char), String); type MacroInfo = (Span, (char, char), SourceText);
pub struct MacroBraces { pub struct MacroBraces {
macro_braces: FxHashMap<String, (char, char)>, macro_braces: FxHashMap<String, (char, char)>,
@ -94,7 +94,7 @@ fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBrace
if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind
&& let name = mac_name.as_str() && let name = mac_name.as_str()
&& let Some(&braces) = mac_braces.macro_braces.get(name) && let Some(&braces) = mac_braces.macro_braces.get(name)
&& let Some(snip) = snippet_opt(cx, span_call_site) && let Some(snip) = span_call_site.get_source_text(cx)
// we must check only invocation sites // we must check only invocation sites
// https://github.com/rust-lang/rust-clippy/issues/7422 // https://github.com/rust-lang/rust-clippy/issues/7422
&& snip.starts_with(&format!("{name}!")) && snip.starts_with(&format!("{name}!"))

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::implements_trait; use clippy_utils::ty::implements_trait;
use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method}; use clippy_utils::{binop_traits, eq_expr_value, trait_ref_of_method};
@ -46,8 +46,8 @@ pub(super) fn check<'tcx>(
expr.span, expr.span,
"manual implementation of an assign operation", "manual implementation of an assign operation",
|diag| { |diag| {
if let (Some(snip_a), Some(snip_r)) = if let Some(snip_a) = assignee.span.get_source_text(cx)
(snippet_opt(cx, assignee.span), snippet_opt(cx, rhs.span)) && let Some(snip_r) = rhs.span.get_source_text(cx)
{ {
diag.span_suggestion( diag.span_suggestion(
expr.span, expr.span,

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use clippy_utils::{eq_expr_value, sugg}; use clippy_utils::{eq_expr_value, sugg};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
@ -42,7 +42,9 @@ fn lint_misrefactored_assign_op(
expr.span, expr.span,
"variable appears on both sides of an assignment operation", "variable appears on both sides of an assignment operation",
|diag| { |diag| {
if let (Some(snip_a), Some(snip_r)) = (snippet_opt(cx, assignee.span), snippet_opt(cx, rhs_other.span)) { if let Some(snip_a) = assignee.span.get_source_text(cx)
&& let Some(snip_r) = rhs_other.span.get_source_text(cx)
{
let a = &sugg::Sugg::hir(cx, assignee, ".."); let a = &sugg::Sugg::hir(cx, assignee, "..");
let r = &sugg::Sugg::hir(cx, rhs, ".."); let r = &sugg::Sugg::hir(cx, rhs, "..");
let long = format!("{snip_a} = {}", sugg::make_binop(op, a, r)); let long = format!("{snip_a} = {}", sugg::make_binop(op, a, r));

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
@ -24,8 +24,8 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Exp
e.span, e.span,
"use of bitwise operator instead of lazy operator between booleans", "use of bitwise operator instead of lazy operator between booleans",
|diag| { |diag| {
if let Some(lhs_snip) = snippet_opt(cx, lhs.span) if let Some(lhs_snip) = lhs.span.get_source_text(cx)
&& let Some(rhs_snip) = snippet_opt(cx, rhs.span) && let Some(rhs_snip) = rhs.span.get_source_text(cx)
{ {
let sugg = format!("{lhs_snip} {op_str} {rhs_snip}"); let sugg = format!("{lhs_snip} {op_str} {rhs_snip}");
diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable); diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);

View File

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use clippy_utils::std_or_core; use clippy_utils::std_or_core;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_hir::{BinOpKind, Expr, ExprKind};
@ -22,8 +22,8 @@ pub(super) fn check<'tcx>(
if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left) if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left)
&& let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right) && let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right)
&& let Some(left_snip) = snippet_opt(cx, left_var.span) && let Some(left_snip) = left_var.span.get_source_text(cx)
&& let Some(right_snip) = snippet_opt(cx, right_var.span) && let Some(right_snip) = right_var.span.get_source_text(cx)
{ {
let Some(top_crate) = std_or_core(cx) else { return }; let Some(top_crate) = std_or_core(cx) else { return };
span_lint_and_sugg( span_lint_and_sugg(

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_from_proc_macro; use clippy_utils::is_from_proc_macro;
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::source::{indent_of, reindent_multiline, SourceText, SpanRangeExt};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
@ -79,7 +79,7 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
&& block.expr.is_none() && block.expr.is_none()
&& let Some(last_stmt) = block.stmts.iter().last() && let Some(last_stmt) = block.stmts.iter().last()
&& let StmtKind::Semi(last_expr) = last_stmt.kind && let StmtKind::Semi(last_expr) = last_stmt.kind
&& let Some(snip) = snippet_opt(cx, last_expr.span) && let Some(snip) = last_expr.span.get_source_text(cx)
{ {
Some((last_stmt.span, snip)) Some((last_stmt.span, snip))
} else { } else {
@ -90,24 +90,24 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
db.span_suggestion( db.span_suggestion(
span, span,
"remove the semicolon from the last statement in the block", "remove the semicolon from the last statement in the block",
sugg, sugg.as_str(),
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
or = "or "; or = "or ";
applicability = Applicability::MaybeIncorrect; applicability = Applicability::MaybeIncorrect;
}); });
let arg_snippets: Vec<String> = args_to_recover let arg_snippets: Vec<_> = args_to_recover
.iter() .iter()
.filter_map(|arg| snippet_opt(cx, arg.span)) .filter_map(|arg| arg.span.get_source_text(cx))
.collect(); .collect();
let arg_snippets_without_empty_blocks: Vec<String> = args_to_recover let arg_snippets_without_empty_blocks: Vec<_> = args_to_recover
.iter() .iter()
.filter(|arg| !is_empty_block(arg)) .filter(|arg| !is_empty_block(arg))
.filter_map(|arg| snippet_opt(cx, arg.span)) .filter_map(|arg| arg.span.get_source_text(cx))
.collect(); .collect();
if let Some(call_snippet) = snippet_opt(cx, expr.span) { if let Some(call_snippet) = expr.span.get_source_text(cx) {
let sugg = fmt_stmts_and_call( let sugg = fmt_stmts_and_call(
cx, cx,
expr, expr,
@ -161,8 +161,8 @@ fn fmt_stmts_and_call(
cx: &LateContext<'_>, cx: &LateContext<'_>,
call_expr: &Expr<'_>, call_expr: &Expr<'_>,
call_snippet: &str, call_snippet: &str,
args_snippets: &[impl AsRef<str>], args_snippets: &[SourceText],
non_empty_block_args_snippets: &[impl AsRef<str>], non_empty_block_args_snippets: &[SourceText],
) -> String { ) -> String {
let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0); let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0);
let call_snippet_with_replacements = args_snippets let call_snippet_with_replacements = args_snippets

View File

@ -1,5 +1,5 @@
use clippy_utils::macros::FormatArgsStorage; use clippy_utils::macros::FormatArgsStorage;
use clippy_utils::source::snippet_opt; use clippy_utils::source::SpanRangeExt;
use itertools::Itertools; use itertools::Itertools;
use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_ast::{Crate, Expr, ExprKind, FormatArgs};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
@ -75,38 +75,21 @@ fn has_span_from_proc_macro(cx: &EarlyContext<'_>, args: &FormatArgs) -> bool {
// `format!("{} {} {c}", "one", "two", c = "three")` // `format!("{} {} {c}", "one", "two", c = "three")`
// ^^ ^^ ^^^^^^ // ^^ ^^ ^^^^^^
let between_spans = once(args.span) !once(args.span)
.chain(argument_span) .chain(argument_span)
.tuple_windows() .tuple_windows()
.map(|(start, end)| start.between(end)); .map(|(start, end)| start.between(end))
.all(|sp| {
for between_span in between_spans { sp.check_source_text(cx, |src| {
let mut seen_comma = false; // text should be either `, name` or `, name =`
let mut iter = tokenize(src).filter(|t| {
let Some(snippet) = snippet_opt(cx, between_span) else { !matches!(
return true; t.kind,
}; TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace
for token in tokenize(&snippet) { )
match token.kind { });
TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {}, iter.next().is_some_and(|t| matches!(t.kind, TokenKind::Comma))
TokenKind::Comma if !seen_comma => seen_comma = true, && iter.all(|t| matches!(t.kind, TokenKind::Ident | TokenKind::Eq))
// named arguments, `start_val, name = end_val` })
// ^^^^^^^^^ between_span })
TokenKind::Ident | TokenKind::Eq if seen_comma => {},
// An unexpected token usually indicates that we crossed a macro boundary
//
// `println!(some_proc_macro!("input {}"), a)`
// ^^^ between_span
// `println!("{}", val!(x))`
// ^^^^^^^ between_span
_ => return true,
}
}
if !seen_comma {
return true;
}
}
false
} }

View File

@ -7,7 +7,7 @@
use rustc_span::{sym, Span}; use rustc_span::{sym, Span};
use std::str::FromStr; use std::str::FromStr;
use crate::source::snippet_opt; use crate::source::SpanRangeExt;
use crate::tokenize_with_text; use crate::tokenize_with_text;
/// Deprecation status of attributes known by Clippy. /// Deprecation status of attributes known by Clippy.
@ -179,11 +179,8 @@ pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool {
/// Checks if the given span contains a `#[cfg(..)]` attribute /// Checks if the given span contains a `#[cfg(..)]` attribute
pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool {
let Some(snip) = snippet_opt(cx, s) else { s.check_source_text(cx, |src| {
// Assume true. This would require either an invalid span, or one which crosses file boundaries. let mut iter = tokenize_with_text(src);
return true;
};
let mut iter = tokenize_with_text(&snip);
// Search for the token sequence [`#`, `[`, `cfg`] // Search for the token sequence [`#`, `[`, `cfg`]
while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) {
@ -200,4 +197,5 @@ pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool {
} }
} }
false false
})
} }

View File

@ -1,6 +1,6 @@
use crate::consts::ConstEvalCtxt; use crate::consts::ConstEvalCtxt;
use crate::macros::macro_backtrace; use crate::macros::macro_backtrace;
use crate::source::{snippet_opt, walk_span_to_context, SpanRange, SpanRangeExt}; use crate::source::{walk_span_to_context, SpanRange, SpanRangeExt};
use crate::tokenize_with_text; use crate::tokenize_with_text;
use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_ast::ast::InlineAsmTemplatePiece;
use rustc_data_structures::fx::FxHasher; use rustc_data_structures::fx::FxHasher;
@ -588,10 +588,9 @@ fn reduce_exprkind<'hir>(cx: &LateContext<'_>, kind: &'hir ExprKind<'hir>) -> &'
// block with an empty span. // block with an empty span.
([], None) if block.span.is_empty() => &ExprKind::Tup(&[]), ([], None) if block.span.is_empty() => &ExprKind::Tup(&[]),
// `{}` => `()` // `{}` => `()`
([], None) => match snippet_opt(cx, block.span) { ([], None)
// Don't reduce if there are any tokens contained in the braces if block.span.check_source_text(cx, |src| {
Some(snip) tokenize(src)
if tokenize(&snip)
.map(|t| t.kind) .map(|t| t.kind)
.filter(|t| { .filter(|t| {
!matches!( !matches!(
@ -599,11 +598,10 @@ fn reduce_exprkind<'hir>(cx: &LateContext<'_>, kind: &'hir ExprKind<'hir>) -> &'
TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace
) )
}) })
.ne([TokenKind::OpenBrace, TokenKind::CloseBrace].iter().copied()) => .eq([TokenKind::OpenBrace, TokenKind::CloseBrace].iter().copied())
}) =>
{ {
kind &ExprKind::Tup(&[])
},
_ => &ExprKind::Tup(&[]),
}, },
([], Some(expr)) => match expr.kind { ([], Some(expr)) => match expr.kind {
// `{ return .. }` => `return ..` // `{ return .. }` => `return ..`