Start removing snippet_opt

This commit is contained in:
Jason Newcomb 2024-08-09 09:04:18 -04:00
parent a83146aea9
commit 8a4c34a5b7
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::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 rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
@ -134,28 +134,30 @@ fn check_inverted_bool_in_condition(
let suggestion = match (left.kind, right.kind) {
(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;
};
let Some(right) = snippet_opt(cx, right_sub.span) else {
let Some(right) = right_sub.span.get_source_text(cx) else {
return;
};
let Some(op) = bin_op_eq_str(op) else { return };
format!("{left} {op} {right}")
},
(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;
};
let Some(right) = snippet_opt(cx, right.span) else {
let Some(right) = right.span.get_source_text(cx) else {
return;
};
let Some(op) = inverted_bin_op_eq_str(op) else { return };
format!("{left} {op} {right}")
},
(_, ExprKind::Unary(UnOp::Not, right_sub)) => {
let Some(left) = snippet_opt(cx, left.span) else { return };
let Some(right) = snippet_opt(cx, right_sub.span) else {
let Some(left) = left.span.get_source_text(cx) else {
return;
};
let Some(right) = right_sub.span.get_source_text(cx) else {
return;
};
let Some(op) = inverted_bin_op_eq_str(op) else { return };
@ -313,8 +315,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
self.output.push_str(&str);
} else {
self.output.push('!');
let snip = snippet_opt(self.cx, terminal.span)?;
self.output.push_str(&snip);
self.output.push_str(&terminal.span.get_source_text(self.cx)?);
}
},
True | False | Not(_) => {
@ -345,8 +346,12 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
}
},
&Term(n) => {
let snip = snippet_opt(self.cx, self.terminals[n as usize].span.source_callsite())?;
self.output.push_str(&snip);
self.output.push_str(
&self.terminals[n as usize]
.span
.source_callsite()
.get_source_text(self.cx)?,
);
},
}
Some(())
@ -370,8 +375,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
_ => None,
}
.and_then(|op| {
let lhs_snippet = snippet_opt(cx, lhs.span)?;
let rhs_snippet = snippet_opt(cx, rhs.span)?;
let lhs_snippet = lhs.span.get_source_text(cx)?;
let rhs_snippet = rhs.span.get_source_text(cx)?;
if !(lhs_snippet.starts_with('(') && lhs_snippet.ends_with(')')) {
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();
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,
}

View File

@ -1,6 +1,6 @@
use crate::reference::DEREF_ADDROF;
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::{get_parent_expr, is_from_proc_macro, is_lint_allowed};
use rustc_errors::Applicability;
@ -73,6 +73,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
}
})
&& !is_from_proc_macro(cx, e)
&& let Some(deref_text) = deref_target.span.get_source_text(cx)
{
span_lint_and_then(
cx,
@ -83,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
diag.span_suggestion(
e.span,
"if you would like to reborrow, try removing `&*`",
snippet_opt(cx, deref_target.span).unwrap(),
deref_text.as_str(),
Applicability::MachineApplicable,
);
@ -98,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
diag.span_suggestion(
e.span,
"if you would like to deref, try using `&**`",
format!("&**{}", &snippet_opt(cx, deref_target.span).unwrap()),
format!("&**{deref_text}"),
Applicability::MaybeIncorrect,
);
},

View File

@ -1,6 +1,6 @@
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::source::{snippet_opt, snippet_with_context};
use clippy_utils::source::{snippet_with_context, SpanRangeExt};
use clippy_utils::sugg::Sugg;
use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait};
use rustc_errors::Applicability;
@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability),
([], [_]) => {
// 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;
};
let s_expand = snippet.replace("{{", "{").replace("}}", "}");

View File

@ -7,7 +7,7 @@ use clippy_utils::macros::{
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,
};
use clippy_utils::source::snippet_opt;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::{implements_trait, is_type_lang_item};
use itertools::Itertools;
use rustc_ast::{
@ -407,7 +407,7 @@ impl<'a, 'tcx> FormatArgsExpr<'a, 'tcx> {
count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter())
&& implements_trait(cx, target, display_trait_id, &[])
&& 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, &[]);
if n_needed_derefs == 0 && !needs_ref {

View File

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

View File

@ -1,5 +1,5 @@
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::token;
use rustc_errors::Applicability;
@ -130,8 +130,8 @@ impl IntPlusOne {
BinOpKind::Le => "<",
_ => return None,
};
if let Some(snippet) = snippet_opt(cx, node.span) {
if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) {
if let Some(snippet) = node.span.get_source_text(cx) {
if let Some(other_side_snippet) = other_side.span.get_source_text(cx) {
let rec = match side {
Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_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::source::snippet_opt;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro};
use rustc_errors::{Applicability, SuggestionStyle};
use rustc_hir::{HirId, Item, ItemKind, Mod};
@ -93,11 +93,14 @@ impl LateLintPass<'_> for ItemsAfterTestModule {
if let Some(prev) = mod_pos.checked_sub(1)
&& let prev = cx.tcx.hir().item(module.item_ids[prev])
&& 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(
"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,
SuggestionStyle::HideCodeAlways,
);

View File

@ -3,7 +3,7 @@ use std::{fmt, ops};
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_then;
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::intravisit::FnKind;
use rustc_hir::{Body, FnDecl};
@ -186,7 +186,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackFrames {
// TODO: Is there a cleaner, robust way to ask this question?
// 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.
if let Some(name) = snippet_opt(cx, local_span)
if let Some(name) = local_span.get_source_text(cx)
&& is_ident(&name)
{
// 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::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::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators};
use rustc_ast::ast::LitKind;
@ -216,7 +216,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
}
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;
};
if has_enclosing_paren(snippet) {

View File

@ -1,7 +1,7 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_then;
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::token;
use rustc_errors::Applicability;
@ -225,7 +225,7 @@ impl LiteralDigitGrouping {
}
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 Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind)
{
@ -439,7 +439,7 @@ impl DecimalLiteralRepresentation {
// Lint integral literals.
if let Ok(lit_kind) = LitKind::from_token_lit(lit)
&& 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)
&& num_lit.radix == Radix::Decimal
&& val >= u128::from(self.threshold)

View File

@ -1,6 +1,6 @@
use clippy_utils::consts::{ConstEvalCtxt, Constant};
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 rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Constness, Expr, ExprKind};
@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
// case somebody does that for some reason
&& (is_infinity(&const_1) && is_neg_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) {
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite,

View File

@ -1,7 +1,7 @@
use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf;
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::{is_trait_method, path_to_local_id};
use rustc_errors::Applicability;
@ -107,8 +107,8 @@ impl LateLintPass<'_> for ManualHashOne {
finish_expr.span,
"manual implementation of `BuildHasher::hash_one`",
|diag| {
if let Some(build_hasher) = snippet_opt(cx, build_hasher.span)
&& let Some(hashed_value) = snippet_opt(cx, hashed_value.span)
if let Some(build_hasher) = build_hasher.span.get_source_text(cx)
&& let Some(hashed_value) = hashed_value.span.get_source_text(cx)
{
diag.multipart_suggestion(
"try",

View File

@ -2,7 +2,7 @@ use clippy_config::msrvs::{self, Msrv};
use clippy_config::Conf;
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
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::attr;
use rustc_data_structures::fx::FxHashSet;
@ -124,7 +124,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
|diag| {
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 Some(snippet) = snippet_opt(cx, header_span)
&& let Some(snippet) = header_span.get_source_text(cx)
{
diag.span_suggestion(
header_span,
@ -194,7 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
"this seems like a manual implementation of the non-exhaustive pattern",
|diag| {
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(
header_span,
"add the attribute",

View File

@ -1,5 +1,5 @@
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_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@ -143,8 +143,8 @@ impl LateLintPass<'_> for ManualRangePatterns {
pat.span,
"this OR pattern can be rewritten using a range",
|diag| {
if let Some(min) = snippet_opt(cx, min.span)
&& let Some(max) = snippet_opt(cx, max.span)
if let Some(min) = min.span.get_source_text(cx)
&& let Some(max) = max.span.get_source_text(cx)
{
diag.span_suggestion(
pat.span,

View File

@ -1,7 +1,7 @@
use super::utils::clone_or_copy_needed;
use clippy_utils::diagnostics::span_lint_and_then;
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::visitors::for_each_expr_without_closures;
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 (clone_or_copy_needed, references_to_binding) = clone_or_copy_needed(cx, pat, body)
&& !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
// https://github.com/rust-lang/rust-clippy/issues/12098
@ -100,7 +100,7 @@ pub fn check_for_loop_iter(
&& 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")
&& 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
} else {
@ -122,7 +122,7 @@ pub fn check_for_loop_iter(
} else {
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() {
diag.multipart_suggestion(
"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::source::snippet_opt;
use clippy_utils::source::SpanRangeExt;
use itertools::Itertools;
use rustc_ast::ast::{Pat, PatKind};
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",
);
} 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")]
span_lint_and_then(
cx,
@ -65,7 +53,16 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
field.span,
"you matched a field with a wildcard pattern, consider using `..` instead",
|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_utils::def_path_def_ids;
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_hir::def::Res;
use rustc_hir::def_id::DefIdMap;
@ -73,7 +73,7 @@ impl LateLintPass<'_> for ImportRename {
&& let Some(name) = self.renames.get(&id)
// Remove semicolon since it is not present for nested imports
&& 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 ") {
None => Some(snip.as_str()),
Some((import, rename)) => {

View File

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher::If;
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_hir::{ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
@ -57,7 +57,7 @@ impl LateLintPass<'_> for NeedlessIf {
src.bytes()
.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)
{
span_lint_and_sugg(

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
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::visitors::{for_each_expr, for_each_expr_without_closures, is_local_used};
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 <pat>: <ty>;
// ~~~~~~~~~~~~~~~
@ -246,7 +246,7 @@ fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) ->
None => local.pat.span.hi(),
});
snippet_opt(cx, span)
span.get_source_text(cx)
}
fn check<'tcx>(
@ -275,7 +275,10 @@ fn check<'tcx>(
|diag| {
diag.multipart_suggestion(
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,
);
},

View File

@ -1,5 +1,5 @@
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::{
in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks,
@ -268,34 +268,31 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
&& reduced.iter().all(|e| e.span.ctxt() == ctxt)
{
if let ExprKind::Index(..) = &expr.kind {
if is_inside_always_const_context(cx.tcx, expr.hir_id) {
return;
if !is_inside_always_const_context(cx.tcx, expr.hir_id)
&& let [arr, func] = &*reduced
&& let Some(arr) = arr.span.get_source_text(cx)
&& let Some(func) = func.span.get_source_text(cx)
{
span_lint_hir_and_then(
cx,
UNNECESSARY_OPERATION,
expr.hir_id,
stmt.span,
"unnecessary operation",
|diag| {
diag.span_suggestion(
stmt.span,
"statement can be written as",
format!("assert!({arr}.len() > {func});"),
Applicability::MaybeIncorrect,
);
},
);
}
let snippet =
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(
cx,
UNNECESSARY_OPERATION,
expr.hir_id,
stmt.span,
"unnecessary operation",
|diag| {
diag.span_suggestion(
stmt.span,
"statement can be written as",
snippet,
Applicability::MaybeIncorrect,
);
},
);
} else {
let mut snippet = String::new();
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(';');
} else {

View File

@ -1,7 +1,7 @@
use clippy_config::types::MacroMatcher;
use clippy_config::Conf;
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_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability;
@ -34,7 +34,7 @@ declare_clippy_lint! {
}
/// The (callsite span, (open brace, close brace), source snippet)
type MacroInfo = (Span, (char, char), String);
type MacroInfo = (Span, (char, char), SourceText);
pub struct MacroBraces {
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
&& let name = mac_name.as_str()
&& 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
// https://github.com/rust-lang/rust-clippy/issues/7422
&& snip.starts_with(&format!("{name}!"))

View File

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

View File

@ -1,5 +1,5 @@
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 rustc_errors::Applicability;
use rustc_hir as hir;
@ -42,7 +42,9 @@ fn lint_misrefactored_assign_op(
expr.span,
"variable appears on both sides of an assignment operation",
|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 r = &sugg::Sugg::hir(cx, rhs, "..");
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::source::snippet_opt;
use clippy_utils::source::SpanRangeExt;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
@ -24,8 +24,8 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Exp
e.span,
"use of bitwise operator instead of lazy operator between booleans",
|diag| {
if let Some(lhs_snip) = snippet_opt(cx, lhs.span)
&& let Some(rhs_snip) = snippet_opt(cx, rhs.span)
if let Some(lhs_snip) = lhs.span.get_source_text(cx)
&& let Some(rhs_snip) = rhs.span.get_source_text(cx)
{
let sugg = format!("{lhs_snip} {op_str} {rhs_snip}");
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::source::snippet_opt;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::std_or_core;
use rustc_errors::Applicability;
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)
&& let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right)
&& let Some(left_snip) = snippet_opt(cx, left_var.span)
&& let Some(right_snip) = snippet_opt(cx, right_var.span)
&& let Some(left_snip) = left_var.span.get_source_text(cx)
&& let Some(right_snip) = right_var.span.get_source_text(cx)
{
let Some(top_crate) = std_or_core(cx) else { return };
span_lint_and_sugg(

View File

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

View File

@ -1,5 +1,5 @@
use clippy_utils::macros::FormatArgsStorage;
use clippy_utils::source::snippet_opt;
use clippy_utils::source::SpanRangeExt;
use itertools::Itertools;
use rustc_ast::{Crate, Expr, ExprKind, FormatArgs};
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")`
// ^^ ^^ ^^^^^^
let between_spans = once(args.span)
!once(args.span)
.chain(argument_span)
.tuple_windows()
.map(|(start, end)| start.between(end));
for between_span in between_spans {
let mut seen_comma = false;
let Some(snippet) = snippet_opt(cx, between_span) else {
return true;
};
for token in tokenize(&snippet) {
match token.kind {
TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {},
TokenKind::Comma if !seen_comma => seen_comma = true,
// 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
.map(|(start, end)| start.between(end))
.all(|sp| {
sp.check_source_text(cx, |src| {
// text should be either `, name` or `, name =`
let mut iter = tokenize(src).filter(|t| {
!matches!(
t.kind,
TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace
)
});
iter.next().is_some_and(|t| matches!(t.kind, TokenKind::Comma))
&& iter.all(|t| matches!(t.kind, TokenKind::Ident | TokenKind::Eq))
})
})
}

View File

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

View File

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