From 598d7aad295020761483caedd613a994221d3881 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 1 May 2025 22:59:40 -0400 Subject: [PATCH 1/5] Change `HasSession` to `HasSourceMap` --- clippy_lints/src/bool_to_int_with_if.rs | 3 +- clippy_lints/src/double_parens.rs | 4 +- clippy_lints/src/if_not_else.rs | 22 +-- clippy_lints/src/loops/manual_flatten.rs | 4 +- clippy_lints/src/loops/manual_slice_fill.rs | 4 +- clippy_lints/src/manual_abs_diff.rs | 6 +- clippy_lints/src/redundant_pub_crate.rs | 3 +- .../missing_transmute_annotations.rs | 6 +- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/lib.rs | 8 +- clippy_utils/src/source.rs | 179 ++++++++++-------- 11 files changed, 125 insertions(+), 116 deletions(-) diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs index 129e77478406..866b0055d0ab 100644 --- a/clippy_lints/src/bool_to_int_with_if.rs +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::HasSession; use clippy_utils::sugg::Sugg; use clippy_utils::{higher, is_else_clause, is_in_const_context, span_contains_comment}; use rustc_ast::LitKind; @@ -59,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf { && !is_in_const_context(cx) { let ty = cx.typeck_results().expr_ty(then); - let mut applicability = if span_contains_comment(cx.sess().source_map(), expr.span) { + let mut applicability = if span_contains_comment(cx, expr.span) { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 8defbeeaa5f2..80534021ebc4 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{HasSession, SpanRangeExt, snippet_with_applicability, snippet_with_context}; +use clippy_utils::source::{SpanRangeExt, snippet_with_applicability, snippet_with_context}; use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::declare_lint_pass; declare_clippy_lint! { diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs index 54e9538fcb99..d191794c2340 100644 --- a/clippy_lints/src/if_not_else.rs +++ b/clippy_lints/src/if_not_else.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::is_zero_integer_const; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::is_else_clause; -use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet}; +use clippy_utils::source::{indent_of, reindent_multiline, snippet}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -95,30 +95,30 @@ impl LateLintPass<'_> for IfNotElse { } } -fn make_sugg<'a>( - sess: &impl HasSession, - cond_kind: &'a ExprKind<'a>, +fn make_sugg( + cx: &LateContext<'_>, + cond_kind: &ExprKind<'_>, cond_inner: Span, els_span: Span, - default: &'a str, + default: &str, indent_relative_to: Option, ) -> String { - let cond_inner_snip = snippet(sess, cond_inner, default); - let els_snip = snippet(sess, els_span, default); - let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); + let cond_inner_snip = snippet(cx, cond_inner, default); + let els_snip = snippet(cx, els_span, default); + let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); let suggestion = match cond_kind { ExprKind::Unary(UnOp::Not, cond_rest) => { format!( "if {} {} else {}", - snippet(sess, cond_rest.span, default), + snippet(cx, cond_rest.span, default), els_snip, cond_inner_snip ) }, ExprKind::Binary(_, lhs, rhs) => { - let lhs_snip = snippet(sess, lhs.span, default); - let rhs_snip = snippet(sess, rhs.span, default); + let lhs_snip = snippet(cx, lhs.span, default); + let rhs_snip = snippet(cx, rhs.span, default); format!("if {lhs_snip} == {rhs_snip} {els_snip} else {cond_inner_snip}") }, diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs index 96de118b5233..64b71db034b5 100644 --- a/clippy_lints/src/loops/manual_flatten.rs +++ b/clippy_lints/src/loops/manual_flatten.rs @@ -3,7 +3,7 @@ use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_applicability}; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability}; use clippy_utils::visitors::is_local_used; use clippy_utils::{higher, is_refutable, peel_blocks_with_stmt, span_contains_comment}; use rustc_errors::Applicability; @@ -50,7 +50,7 @@ pub(super) fn check<'tcx>( format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used"); // Prepare the help message - let mut applicability = if span_contains_comment(cx.sess().source_map(), body.span) { + let mut applicability = if span_contains_comment(cx.tcx.sess.source_map(), body.span) { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable diff --git a/clippy_lints/src/loops/manual_slice_fill.rs b/clippy_lints/src/loops/manual_slice_fill.rs index a2ff60a3d8ac..f91e3e6d597f 100644 --- a/clippy_lints/src/loops/manual_slice_fill.rs +++ b/clippy_lints/src/loops/manual_slice_fill.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{HasSession, snippet_with_applicability}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{implements_trait, is_slice_like}; use clippy_utils::visitors::is_local_used; use clippy_utils::{higher, peel_blocks_with_stmt, span_contains_comment}; @@ -94,7 +94,7 @@ fn sugg<'tcx>( slice_span: rustc_span::Span, assignval_span: rustc_span::Span, ) { - let mut app = if span_contains_comment(cx.sess().source_map(), body.span) { + let mut app = if span_contains_comment(cx, body.span) { Applicability::MaybeIncorrect // Comments may be informational. } else { Applicability::MachineApplicable diff --git a/clippy_lints/src/manual_abs_diff.rs b/clippy_lints/src/manual_abs_diff.rs index 22de5e8268bd..c536d74ca2ca 100644 --- a/clippy_lints/src/manual_abs_diff.rs +++ b/clippy_lints/src/manual_abs_diff.rs @@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::If; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::HasSession as _; use clippy_utils::sugg::Sugg; use clippy_utils::ty::peel_and_count_ty_refs; use clippy_utils::{eq_expr_value, peel_blocks, span_contains_comment}; @@ -77,10 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAbsDiff { (a, b) = (b, a); } let applicability = { - let source_map = cx.sess().source_map(); - if span_contains_comment(source_map, if_expr.then.span) - || span_contains_comment(source_map, r#else.span) - { + if span_contains_comment(cx, if_expr.then.span) || span_contains_comment(cx, r#else.span) { Applicability::MaybeIncorrect } else { Applicability::MachineApplicable diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs index 0c1c664f1117..047e5780f3d7 100644 --- a/clippy_lints/src/redundant_pub_crate.rs +++ b/clippy_lints/src/redundant_pub_crate.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::HasSession; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Item, ItemKind, UseKind}; @@ -49,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { && !cx.effective_visibilities.is_exported(item.owner_id.def_id) && self.is_exported.last() == Some(&false) && !is_ignorable_export(item) - && !item.span.in_external_macro(cx.sess().source_map()) + && !item.span.in_external_macro(cx.tcx.sess.source_map()) { let span = item .kind diff --git a/clippy_lints/src/transmute/missing_transmute_annotations.rs b/clippy_lints/src/transmute/missing_transmute_annotations.rs index 543f3c45e146..f712b15c5768 100644 --- a/clippy_lints/src/transmute/missing_transmute_annotations.rs +++ b/clippy_lints/src/transmute/missing_transmute_annotations.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{HasSession, SpanRangeExt as _}; +use clippy_utils::source::SpanRangeExt as _; use rustc_errors::Applicability; use rustc_hir::{Expr, GenericArg, HirId, LetStmt, Node, Path, TyKind}; use rustc_lint::LateContext; @@ -111,8 +111,8 @@ fn ty_cannot_be_named(ty: Ty<'_>) -> bool { ) } -fn maybe_name_by_expr<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> { - span.with_source_text(sess, |name| { +fn maybe_name_by_expr<'a>(cx: &LateContext<'_>, span: Span, default: &'a str) -> Cow<'a, str> { + span.with_source_text(cx, |name| { (name.len() + 9 < default.len()).then_some(format!("`{name}`'s type").into()) }) .flatten() diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 7e3fa4f9909b..44a5a9380741 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -900,7 +900,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) && let expr_lo = expr_span.lo() && expr_lo >= span.lo - && let Some(src) = (span.lo..expr_lo).get_source_range(&self.tcx) + && let Some(src) = (span.lo..expr_lo).get_source_range(self.tcx) && let Some(src) = src.as_str() { use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index ed164fcf371b..93f831971a16 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -133,6 +133,7 @@ use crate::consts::{ConstEvalCtxt, Constant}; use crate::higher::Range; use crate::msrvs::Msrv; use crate::res::{MaybeDef, MaybeQPath, MaybeResPath}; +use crate::source::HasSourceMap; use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type}; use crate::visitors::for_each_expr_without_closures; @@ -2745,8 +2746,8 @@ pub fn tokenize_with_text(s: &str) -> impl Iterator bool { - let Ok(snippet) = sm.span_to_snippet(span) else { +pub fn span_contains_comment<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> bool { + let Ok(snippet) = sm.source_map().span_to_snippet(span) else { return false; }; return tokenize(&snippet, FrontmatterAllowed::No).any(|token| { @@ -2761,7 +2762,7 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { /// token, including comments unless `skip_comments` is set. /// This is useful to determine if there are any actual code tokens in the span that are omitted in /// the late pass, such as platform-specific code. -pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, skip_comments: bool) -> bool { +pub fn span_contains_non_whitespace<'sm>(cx: impl HasSourceMap<'sm>, span: Span, skip_comments: bool) -> bool { matches!(span.get_source_text(cx), Some(snippet) if tokenize_with_text(&snippet).any(|(token, _, _)| match token { TokenKind::Whitespace => false, @@ -2770,6 +2771,7 @@ pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, sk } )) } + /// Returns all the comments a given span contains /// /// Comments are returned wrapped with their relevant delimiters diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index e29d45551d1b..28122544a4e2 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -20,27 +20,38 @@ use std::borrow::Cow; use std::fmt; use std::ops::{Deref, Index, Range}; -pub trait HasSession { - fn sess(&self) -> &Session; +pub trait HasSourceMap<'sm>: Copy { + #[must_use] + fn source_map(self) -> &'sm SourceMap; } -impl HasSession for Session { - fn sess(&self) -> &Session { +impl<'sm> HasSourceMap<'sm> for &'sm SourceMap { + #[inline] + fn source_map(self) -> &'sm SourceMap { self } } -impl HasSession for TyCtxt<'_> { - fn sess(&self) -> &Session { - self.sess +impl<'sm> HasSourceMap<'sm> for &'sm Session { + #[inline] + fn source_map(self) -> &'sm SourceMap { + self.source_map() } } -impl HasSession for EarlyContext<'_> { - fn sess(&self) -> &Session { - ::rustc_lint::LintContext::sess(self) +impl<'sm> HasSourceMap<'sm> for TyCtxt<'sm> { + #[inline] + fn source_map(self) -> &'sm SourceMap { + self.sess.source_map() } } -impl HasSession for LateContext<'_> { - fn sess(&self) -> &Session { - self.tcx.sess() +impl<'sm> HasSourceMap<'sm> for &'sm EarlyContext<'_> { + #[inline] + fn source_map(self) -> &'sm SourceMap { + ::rustc_lint::LintContext::sess(self).source_map() + } +} +impl<'sm> HasSourceMap<'sm> for &LateContext<'sm> { + #[inline] + fn source_map(self) -> &'sm SourceMap { + self.tcx.sess.source_map() } } @@ -98,36 +109,36 @@ impl IntoSpan for Range { pub trait SpanRangeExt: SpanRange { /// Attempts to get a handle to the source text. Returns `None` if either the span is malformed, /// or the source text is not accessible. - fn get_source_text(self, cx: &impl HasSession) -> Option { - get_source_range(cx.sess().source_map(), self.into_range()).and_then(SourceText::new) + fn get_source_text<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { + get_source_range(sm.source_map(), self.into_range()).and_then(SourceText::new) } /// Gets the source file, and range in the file, of the given span. Returns `None` if the span /// extends through multiple files, or is malformed. - fn get_source_range(self, cx: &impl HasSession) -> Option { - get_source_range(cx.sess().source_map(), self.into_range()) + fn get_source_range<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { + get_source_range(sm.source_map(), self.into_range()) } /// Calls the given function with the source text referenced and returns the value. Returns /// `None` if the source text cannot be retrieved. - fn with_source_text(self, cx: &impl HasSession, f: impl for<'a> FnOnce(&'a str) -> T) -> Option { - with_source_text(cx.sess().source_map(), self.into_range(), f) + fn with_source_text<'sm, T>(self, sm: impl HasSourceMap<'sm>, f: impl for<'a> FnOnce(&'a str) -> T) -> Option { + with_source_text(sm.source_map(), self.into_range(), f) } /// Checks if the referenced source text satisfies the given predicate. Returns `false` if the /// source text cannot be retrieved. - fn check_source_text(self, cx: &impl HasSession, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { - self.with_source_text(cx, pred).unwrap_or(false) + fn check_source_text<'sm>(self, sm: impl HasSourceMap<'sm>, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { + self.with_source_text(sm, pred).unwrap_or(false) } /// Calls the given function with the both the text of the source file and the referenced range, /// and returns the value. Returns `None` if the source text cannot be retrieved. - fn with_source_text_and_range( + fn with_source_text_and_range<'sm, T>( self, - cx: &impl HasSession, + sm: impl HasSourceMap<'sm>, f: impl for<'a> FnOnce(&'a str, Range) -> T, ) -> Option { - with_source_text_and_range(cx.sess().source_map(), self.into_range(), f) + with_source_text_and_range(sm.source_map(), self.into_range(), f) } /// Calls the given function with the both the text of the source file and the referenced range, @@ -135,12 +146,12 @@ pub trait SpanRangeExt: SpanRange { /// retrieved, or no result is returned. /// /// The new range must reside within the same source file. - fn map_range( + fn map_range<'sm>( self, - cx: &impl HasSession, + sm: impl HasSourceMap<'sm>, f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range) -> Option>, ) -> Option> { - map_range(cx.sess().source_map(), self.into_range(), f) + map_range(sm.source_map(), self.into_range(), f) } /// Extends the range to include all preceding whitespace characters. @@ -156,13 +167,13 @@ pub trait SpanRangeExt: SpanRange { /// /// When the range points to `foo`, suggesting to remove the range after it's been extended will /// cause the `)` to be placed inside the line comment as `( // Some comment)`. - fn with_leading_whitespace(self, cx: &impl HasSession) -> Range { - with_leading_whitespace(cx.sess().source_map(), self.into_range()) + fn with_leading_whitespace<'sm>(self, sm: impl HasSourceMap<'sm>) -> Range { + with_leading_whitespace(sm.source_map(), self.into_range()) } /// Trims the leading whitespace from the range. - fn trim_start(self, cx: &impl HasSession) -> Range { - trim_start(cx.sess().source_map(), self.into_range()) + fn trim_start<'sm>(self, sm: impl HasSourceMap<'sm>) -> Range { + trim_start(sm.source_map(), self.into_range()) } } impl SpanRangeExt for T {} @@ -353,15 +364,15 @@ impl SourceFileRange { } /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block` with no label. -pub fn expr_block( - sess: &impl HasSession, +pub fn expr_block<'sm>( + sm: impl HasSourceMap<'sm>, expr: &Expr<'_>, outer: SyntaxContext, default: &str, indent_relative_to: Option, app: &mut Applicability, ) -> String { - let (code, from_macro) = snippet_block_with_context(sess, expr.span, outer, default, indent_relative_to, app); + let (code, from_macro) = snippet_block_with_context(sm, expr.span, outer, default, indent_relative_to, app); if !from_macro && let ExprKind::Block(block, None) = expr.kind && block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) @@ -386,13 +397,13 @@ pub fn expr_block( /// let x = (); /// // ^^^^^^^^^^ /// ``` -pub fn first_line_of_span(sess: &impl HasSession, span: Span) -> Span { - first_char_in_first_line(sess, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos)) +pub fn first_line_of_span<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span { + first_char_in_first_line(sm, span).map_or(span, |first_char_pos| span.with_lo(first_char_pos)) } -fn first_char_in_first_line(sess: &impl HasSession, span: Span) -> Option { - let line_span = line_span(sess, span); - snippet_opt(sess, line_span).and_then(|snip| { +fn first_char_in_first_line<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option { + let line_span = line_span(sm, span); + snippet_opt(sm, line_span).and_then(|snip| { snip.find(|c: char| !c.is_whitespace()) .map(|pos| line_span.lo() + BytePos::from_usize(pos)) }) @@ -407,9 +418,9 @@ fn first_char_in_first_line(sess: &impl HasSession, span: Span) -> Option Span { +fn line_span<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span { let span = original_sp(span, DUMMY_SP); - let SourceFileAndLine { sf, line } = sess.sess().source_map().lookup_line(span.lo()).unwrap(); + let SourceFileAndLine { sf, line } = sm.source_map().lookup_line(span.lo()).unwrap(); let line_start = sf.lines()[line]; let line_start = sf.absolute_position(line_start); span.with_lo(line_start) @@ -423,13 +434,13 @@ fn line_span(sess: &impl HasSession, span: Span) -> Span { /// let x = (); /// // ^^ -- will return 4 /// ``` -pub fn indent_of(sess: &impl HasSession, span: Span) -> Option { - snippet_opt(sess, line_span(sess, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) +pub fn indent_of<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option { + snippet_opt(sm, line_span(sm, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) } /// Gets a snippet of the indentation of the line of a span -pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option { - snippet_opt(sess, line_span(sess, span)).map(|mut s| { +pub fn snippet_indent<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option { + snippet_opt(sm, line_span(sm, span)).map(|mut s| { let len = s.len() - s.trim_start().len(); s.truncate(len); s @@ -441,8 +452,8 @@ pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option { // sources that the user has no control over. // For some reason these attributes don't have any expansion info on them, so // we have to check it this way until there is a better way. -pub fn is_present_in_source(sess: &impl HasSession, span: Span) -> bool { - if let Some(snippet) = snippet_opt(sess, span) +pub fn is_present_in_source<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> bool { + if let Some(snippet) = snippet_opt(sm, span) && snippet.is_empty() { return false; @@ -532,8 +543,8 @@ fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option, /// snippet(cx, span1, "..") // -> "value" /// snippet(cx, span2, "..") // -> "Vec::new()" /// ``` -pub fn snippet<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow<'a, str> { - snippet_opt(sess, span).map_or_else(|| Cow::Borrowed(default), From::from) +pub fn snippet<'a, 'sm>(sm: impl HasSourceMap<'sm>, span: Span, default: &'a str) -> Cow<'a, str> { + snippet_opt(sm, span).map_or_else(|| Cow::Borrowed(default), From::from) } /// Same as [`snippet`], but it adapts the applicability level by following rules: @@ -542,17 +553,17 @@ pub fn snippet<'a>(sess: &impl HasSession, span: Span, default: &'a str) -> Cow< /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`. /// - If the default value is used and the applicability level is `MachineApplicable`, change it to /// `HasPlaceholders` -pub fn snippet_with_applicability<'a>( - sess: &impl HasSession, +pub fn snippet_with_applicability<'a, 'sm>( + sm: impl HasSourceMap<'sm>, span: Span, default: &'a str, applicability: &mut Applicability, ) -> Cow<'a, str> { - snippet_with_applicability_sess(sess.sess(), span, default, applicability) + snippet_with_applicability_sm(sm.source_map(), span, default, applicability) } -fn snippet_with_applicability_sess<'a>( - sess: &Session, +fn snippet_with_applicability_sm<'a>( + sm: &SourceMap, span: Span, default: &'a str, applicability: &mut Applicability, @@ -560,7 +571,7 @@ fn snippet_with_applicability_sess<'a>( if *applicability != Applicability::Unspecified && span.from_expansion() { *applicability = Applicability::MaybeIncorrect; } - snippet_opt(sess, span).map_or_else( + snippet_opt(sm, span).map_or_else( || { if *applicability == Applicability::MachineApplicable { *applicability = Applicability::HasPlaceholders; @@ -572,8 +583,8 @@ fn snippet_with_applicability_sess<'a>( } /// Converts a span to a code snippet. Returns `None` if not available. -pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option { - sess.sess().source_map().span_to_snippet(span).ok() +pub fn snippet_opt<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Option { + sm.source_map().span_to_snippet(span).ok() } /// Converts a span (from a block) to a code snippet if available, otherwise use default. @@ -610,36 +621,41 @@ pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option { /// } // aligned with `if` /// ``` /// Note that the first line of the snippet always has 0 indentation. -pub fn snippet_block(sess: &impl HasSession, span: Span, default: &str, indent_relative_to: Option) -> String { - let snip = snippet(sess, span, default); - let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); +pub fn snippet_block<'sm>( + sm: impl HasSourceMap<'sm>, + span: Span, + default: &str, + indent_relative_to: Option, +) -> String { + let snip = snippet(sm, span, default); + let indent = indent_relative_to.and_then(|s| indent_of(sm, s)); reindent_multiline(&snip, true, indent) } /// Same as `snippet_block`, but adapts the applicability level by the rules of /// `snippet_with_applicability`. -pub fn snippet_block_with_applicability( - sess: &impl HasSession, +pub fn snippet_block_with_applicability<'sm>( + sm: impl HasSourceMap<'sm>, span: Span, default: &str, indent_relative_to: Option, applicability: &mut Applicability, ) -> String { - let snip = snippet_with_applicability(sess, span, default, applicability); - let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); + let snip = snippet_with_applicability(sm, span, default, applicability); + let indent = indent_relative_to.and_then(|s| indent_of(sm, s)); reindent_multiline(&snip, true, indent) } -pub fn snippet_block_with_context( - sess: &impl HasSession, +pub fn snippet_block_with_context<'sm>( + sm: impl HasSourceMap<'sm>, span: Span, outer: SyntaxContext, default: &str, indent_relative_to: Option, app: &mut Applicability, ) -> (String, bool) { - let (snip, from_macro) = snippet_with_context(sess, span, outer, default, app); - let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); + let (snip, from_macro) = snippet_with_context(sm, span, outer, default, app); + let indent = indent_relative_to.and_then(|s| indent_of(sm, s)); (reindent_multiline(&snip, true, indent), from_macro) } @@ -653,18 +669,18 @@ pub fn snippet_block_with_context( /// correctly get a snippet of `vec![]`. /// /// This will also return whether or not the snippet is a macro call. -pub fn snippet_with_context<'a>( - sess: &impl HasSession, +pub fn snippet_with_context<'a, 'sm>( + sm: impl HasSourceMap<'sm>, span: Span, outer: SyntaxContext, default: &'a str, applicability: &mut Applicability, ) -> (Cow<'a, str>, bool) { - snippet_with_context_sess(sess.sess(), span, outer, default, applicability) + snippet_with_context_sm(sm.source_map(), span, outer, default, applicability) } -fn snippet_with_context_sess<'a>( - sess: &Session, +fn snippet_with_context_sm<'a>( + sm: &SourceMap, span: Span, outer: SyntaxContext, default: &'a str, @@ -672,10 +688,7 @@ fn snippet_with_context_sess<'a>( ) -> (Cow<'a, str>, bool) { // If it is just range desugaring, use the desugaring span since it may include parenthesis. if span.desugaring_kind() == Some(DesugaringKind::RangeExpr) && span.parent_callsite().unwrap().ctxt() == outer { - return ( - snippet_with_applicability_sess(sess, span, default, applicability), - false, - ); + return (snippet_with_applicability_sm(sm, span, default, applicability), false); } let (span, is_macro_call) = walk_span_to_context(span, outer).map_or_else( @@ -691,7 +704,7 @@ fn snippet_with_context_sess<'a>( ); ( - snippet_with_applicability_sess(sess, span, default, applicability), + snippet_with_applicability_sm(sm, span, default, applicability), is_macro_call, ) } @@ -754,15 +767,15 @@ pub fn trim_span(sm: &SourceMap, span: Span) -> Span { /// writeln!(o, "") -> writeln!(o, "") /// ^^ ^^^^ /// ``` -pub fn expand_past_previous_comma(sess: &impl HasSession, span: Span) -> Span { - let extended = sess.sess().source_map().span_extend_to_prev_char(span, ',', true); +pub fn expand_past_previous_comma<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> Span { + let extended = sm.source_map().span_extend_to_prev_char(span, ',', true); extended.with_lo(extended.lo() - BytePos(1)) } /// Converts `expr` to a `char` literal if it's a `str` literal containing a single /// character (or a single byte with `ascii_only`) -pub fn str_literal_to_char_literal( - sess: &impl HasSession, +pub fn str_literal_to_char_literal<'sm>( + sm: impl HasSourceMap<'sm>, expr: &Expr<'_>, applicability: &mut Applicability, ascii_only: bool, @@ -777,7 +790,7 @@ pub fn str_literal_to_char_literal( } && len == 1 { - let snip = snippet_with_applicability(sess, expr.span, string, applicability); + let snip = snippet_with_applicability(sm, expr.span, string, applicability); let ch = if let StrStyle::Raw(nhash) = style { let nhash = nhash as usize; // for raw string: r##"a"## From 2fe1120d45d4199fdc7419b1383e750078a2d6a2 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 1 May 2025 23:53:16 -0400 Subject: [PATCH 2/5] Rename `SpanRangeExt` to `SpanExt` --- clippy_lints/src/attrs/non_minimal_cfg.rs | 2 +- clippy_lints/src/attrs/unnecessary_clippy_cfg.rs | 2 +- clippy_lints/src/attrs/useless_attribute.rs | 2 +- clippy_lints/src/booleans.rs | 2 +- clippy_lints/src/borrow_deref_ref.rs | 2 +- clippy_lints/src/casts/as_ptr_cast_mut.rs | 2 +- clippy_lints/src/casts/cast_lossless.rs | 2 +- clippy_lints/src/casts/manual_dangling_ptr.rs | 2 +- clippy_lints/src/casts/unnecessary_cast.rs | 2 +- clippy_lints/src/casts/zero_ptr.rs | 2 +- clippy_lints/src/cognitive_complexity.rs | 2 +- clippy_lints/src/collapsible_if.rs | 2 +- clippy_lints/src/default_constructed_unit_structs.rs | 2 +- clippy_lints/src/double_parens.rs | 2 +- clippy_lints/src/empty_line_after.rs | 2 +- clippy_lints/src/format.rs | 2 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/four_forward_slashes.rs | 2 +- clippy_lints/src/from_over_into.rs | 2 +- clippy_lints/src/functions/too_many_lines.rs | 2 +- clippy_lints/src/ifs/branches_sharing_code.rs | 2 +- clippy_lints/src/implicit_hasher.rs | 2 +- clippy_lints/src/ineffective_open_options.rs | 2 +- clippy_lints/src/int_plus_one.rs | 2 +- clippy_lints/src/items_after_test_module.rs | 2 +- clippy_lints/src/large_stack_frames.rs | 2 +- clippy_lints/src/legacy_numeric_constants.rs | 2 +- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/let_with_type_underscore.rs | 2 +- clippy_lints/src/literal_representation.rs | 2 +- clippy_lints/src/loops/unused_enumerate_index.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 2 +- clippy_lints/src/manual_float_methods.rs | 2 +- clippy_lints/src/manual_hash_one.rs | 2 +- clippy_lints/src/manual_range_patterns.rs | 2 +- clippy_lints/src/matches/manual_unwrap_or.rs | 2 +- clippy_lints/src/matches/match_same_arms.rs | 2 +- clippy_lints/src/matches/match_wild_enum.rs | 2 +- clippy_lints/src/matches/single_match.rs | 2 +- .../src/methods/case_sensitive_file_extension_comparisons.rs | 2 +- clippy_lints/src/methods/filter_map_bool_then.rs | 2 +- clippy_lints/src/methods/manual_inspect.rs | 2 +- clippy_lints/src/methods/manual_ok_or.rs | 2 +- clippy_lints/src/methods/manual_try_fold.rs | 2 +- clippy_lints/src/methods/map_all_any_identity.rs | 2 +- clippy_lints/src/methods/needless_character_iteration.rs | 2 +- clippy_lints/src/methods/needless_option_as_deref.rs | 2 +- clippy_lints/src/methods/range_zip_with_len.rs | 2 +- clippy_lints/src/methods/string_lit_chars_any.rs | 2 +- clippy_lints/src/methods/unnecessary_first_then_check.rs | 2 +- clippy_lints/src/methods/unnecessary_get_then_check.rs | 2 +- clippy_lints/src/methods/unnecessary_iter_cloned.rs | 2 +- clippy_lints/src/methods/unnecessary_to_owned.rs | 2 +- clippy_lints/src/misc_early/unneeded_field_pattern.rs | 2 +- clippy_lints/src/missing_enforced_import_rename.rs | 2 +- clippy_lints/src/multiple_bound_locations.rs | 2 +- clippy_lints/src/mutex_atomic.rs | 2 +- clippy_lints/src/needless_else.rs | 2 +- clippy_lints/src/needless_ifs.rs | 2 +- clippy_lints/src/needless_late_init.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/no_effect.rs | 2 +- clippy_lints/src/non_octal_unix_permissions.rs | 2 +- clippy_lints/src/nonstandard_macro_braces.rs | 2 +- clippy_lints/src/octal_escapes.rs | 2 +- clippy_lints/src/operators/assign_op_pattern.rs | 2 +- clippy_lints/src/operators/misrefactored_assign_op.rs | 2 +- clippy_lints/src/operators/needless_bitwise_bool.rs | 2 +- clippy_lints/src/pathbuf_init_then_push.rs | 2 +- clippy_lints/src/ptr/ptr_arg.rs | 2 +- clippy_lints/src/ranges.rs | 2 +- clippy_lints/src/raw_strings.rs | 2 +- clippy_lints/src/redundant_clone.rs | 2 +- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/returns/let_and_return.rs | 2 +- clippy_lints/src/semicolon_block.rs | 2 +- clippy_lints/src/single_range_in_vec_init.rs | 2 +- clippy_lints/src/trait_bounds.rs | 2 +- clippy_lints/src/transmute/missing_transmute_annotations.rs | 2 +- clippy_lints/src/unit_types/unit_arg.rs | 2 +- clippy_lints/src/unnecessary_mut_passed.rs | 2 +- clippy_lints/src/unused_unit.rs | 2 +- clippy_lints/src/useless_vec.rs | 2 +- clippy_lints/src/utils/format_args_collector.rs | 2 +- clippy_lints/src/visibility.rs | 2 +- clippy_lints/src/write/literal.rs | 2 +- clippy_lints/src/write/with_newline.rs | 2 +- clippy_utils/src/attrs.rs | 2 +- clippy_utils/src/consts.rs | 2 +- clippy_utils/src/hir_utils.rs | 2 +- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/source.rs | 4 ++-- 92 files changed, 93 insertions(+), 93 deletions(-) diff --git a/clippy_lints/src/attrs/non_minimal_cfg.rs b/clippy_lints/src/attrs/non_minimal_cfg.rs index 7eff5eccfa13..a76bdcfdfb3e 100644 --- a/clippy_lints/src/attrs/non_minimal_cfg.rs +++ b/clippy_lints/src/attrs/non_minimal_cfg.rs @@ -1,6 +1,6 @@ use super::{Attribute, NON_MINIMAL_CFG}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::{MetaItemInner, MetaItemKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; diff --git a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs index 6ee3290fa761..a647f976908a 100644 --- a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs +++ b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs @@ -1,6 +1,6 @@ use super::{Attribute, UNNECESSARY_CLIPPY_CFG}; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use itertools::Itertools; use rustc_ast::AttrStyle; use rustc_errors::Applicability; diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index 1cebc18edc90..fc780472e03c 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -1,7 +1,7 @@ use super::USELESS_ATTRIBUTE; use super::utils::{is_lint_level, is_word, namespace_and_lint}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, first_line_of_span}; +use clippy_utils::source::{SpanExt, first_line_of_span}; use clippy_utils::sym; use rustc_ast::{Attribute, Item, ItemKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 902ba70577b9..8896829653ad 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::higher::has_let_expr; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::{eq_expr_value, sym}; diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 70c9c45a60c8..350324099d0d 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -1,6 +1,6 @@ use crate::reference::DEREF_ADDROF; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::implements_trait; use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_from_proc_macro, is_lint_allowed, is_mutable}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/as_ptr_cast_mut.rs b/clippy_lints/src/casts/as_ptr_cast_mut.rs index 15ecba20a0bc..74388808a130 100644 --- a/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index c924fba6b5c8..bcfb59028201 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_in_const_context; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_isize_or_usize; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/manual_dangling_ptr.rs b/clippy_lints/src/casts/manual_dangling_ptr.rs index be1f406770ce..796c7e73ed51 100644 --- a/clippy_lints/src/casts/manual_dangling_ptr.rs +++ b/clippy_lints/src/casts/manual_dangling_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{expr_or_init, std_or_core, sym}; use rustc_ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 7bfe9201d812..22a50acb77d1 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::numeric_literal::NumericLiteral; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::{SpanRangeExt, snippet_opt}; +use clippy_utils::source::{SpanExt, snippet_opt}; use clippy_utils::visitors::{Visitable, for_each_expr_without_closures}; use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias}; use rustc_ast::{LitFloatType, LitIntType, LitKind}; diff --git a/clippy_lints/src/casts/zero_ptr.rs b/clippy_lints/src/casts/zero_ptr.rs index f4738e7b0d51..d33d08230d1a 100644 --- a/clippy_lints/src/casts/zero_ptr.rs +++ b/clippy_lints/src/casts/zero_ptr.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{is_in_const_context, is_integer_literal, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability, Ty, TyKind}; diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 595625c08bef..287b3fd1ce96 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::source::{IntoSpan, SpanExt}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{LimitStack, get_async_fn_body, sym}; use core::ops::ControlFlow; diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index b13e307a3f9c..354c39ab7b70 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::Msrv; -use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability}; +use clippy_utils::source::{IntoSpan as _, SpanExt, snippet, snippet_block_with_applicability}; use clippy_utils::{can_use_if_let_chains, span_contains_non_whitespace, sym, tokenize_with_text}; use rustc_ast::{BinOpKind, MetaItemInner}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index 641f8ae03b72..195c8c2d5989 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_ty_alias; -use clippy_utils::source::SpanRangeExt as _; +use clippy_utils::source::SpanExt as _; use hir::ExprKind; use hir::def::Res; use rustc_errors::Applicability; diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index 80534021ebc4..f442575749ac 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanRangeExt, snippet_with_applicability, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_applicability, snippet_with_context}; use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/clippy_lints/src/empty_line_after.rs b/clippy_lints/src/empty_line_after.rs index 76e67b1154be..c83570b336fb 100644 --- a/clippy_lints/src/empty_line_after.rs +++ b/clippy_lints/src/empty_line_after.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, snippet_indent}; +use clippy_utils::source::{SpanExt, snippet_indent}; use clippy_utils::tokenize_with_text; use itertools::Itertools; use rustc_ast::token::CommentKind; diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 098bf4ba42f9..b001d6983766 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, root_macro_call_first_node}; -use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_context}; use clippy_utils::sugg::Sugg; use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 011cbf8c5d41..b9e6b7c10b65 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -10,7 +10,7 @@ use clippy_utils::macros::{ }; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{SpanExt, snippet}; use clippy_utils::ty::implements_trait; use clippy_utils::{is_from_proc_macro, is_in_test, trait_ref_of_method}; use itertools::Itertools; diff --git a/clippy_lints/src/four_forward_slashes.rs b/clippy_lints/src/four_forward_slashes.rs index 5a0cee40a155..c099f56a2e5d 100644 --- a/clippy_lints/src/four_forward_slashes.rs +++ b/clippy_lints/src/four_forward_slashes.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt as _; +use clippy_utils::source::SpanExt as _; use itertools::Itertools; use rustc_errors::Applicability; use rustc_hir::Item; diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index ed55f90848f8..7998b7e707c8 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -5,7 +5,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::span_is_local; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_path}; use rustc_hir::{ diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs index 33eede8e65ac..da3ad2287c31 100644 --- a/clippy_lints/src/functions/too_many_lines.rs +++ b/clippy_lints/src/functions/too_many_lines.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; diff --git a/clippy_lints/src/ifs/branches_sharing_code.rs b/clippy_lints/src/ifs/branches_sharing_code.rs index b3f597cc8736..755a2a61d894 100644 --- a/clippy_lints/src/ifs/branches_sharing_code.rs +++ b/clippy_lints/src/ifs/branches_sharing_code.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet}; +use clippy_utils::source::{IntoSpan, SpanExt, first_line_of_span, indent_of, reindent_multiline, snippet}; use clippy_utils::ty::needs_ordered_drop; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index d2bc0b6d9935..cefefaccb189 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -13,7 +13,7 @@ use rustc_session::declare_lint_pass; use rustc_span::Span; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet}; +use clippy_utils::source::{IntoSpan, SpanExt, snippet}; use clippy_utils::sym; declare_clippy_lint! { diff --git a/clippy_lints/src/ineffective_open_options.rs b/clippy_lints/src/ineffective_open_options.rs index bc57d9e85478..aae847031bf6 100644 --- a/clippy_lints/src/ineffective_open_options.rs +++ b/clippy_lints/src/ineffective_open_options.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::res::MaybeDef; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{peel_blocks, peel_hir_expr_while, sym}; use rustc_ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 67ce57de254d..24d9ccb27788 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index dd63de288b87..3ab4be144251 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; 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}; diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index 5ed948c02bbc..922f81a92785 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -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::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index 8a5d97294d2b..4fd6bd384615 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use hir::def_id::DefId; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 877bd34a732b..138cac327d3f 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::Msrv; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_context}; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::ty::implements_trait; use clippy_utils::{fulfill_or_allowed, get_parent_as_impl, parent_item_name, peel_ref_operators, sym}; diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index 24a4c321bdab..2390c1ad95f8 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::source::{IntoSpan, SpanExt}; use rustc_ast::{Local, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 7cbfa2d097ae..b7ed91f241f7 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -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::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::ast::{Expr, ExprKind, LitKind}; use rustc_ast::token; use rustc_errors::Applicability; diff --git a/clippy_lints/src/loops/unused_enumerate_index.rs b/clippy_lints/src/loops/unused_enumerate_index.rs index 82ded453616d..930644ca17d1 100644 --- a/clippy_lints/src/loops/unused_enumerate_index.rs +++ b/clippy_lints/src/loops/unused_enumerate_index.rs @@ -1,7 +1,7 @@ use super::UNUSED_ENUMERATE_INDEX; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::{SpanRangeExt, walk_span_to_context}; +use clippy_utils::source::{SpanExt, walk_span_to_context}; use clippy_utils::{expr_or_init, pat_is_wild}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Pat, PatKind, TyKind}; diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index bee3b19b597c..dff324d132a0 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, position_before_rarrow, snippet_block}; +use clippy_utils::source::{SpanExt, position_before_rarrow, snippet_block}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index a81c4dc6a793..8fd9497c1d4e 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index ccb8d4272bfa..12fed3cf6b60 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sym; use clippy_utils::visitors::{is_local_used, local_used_once}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index bf4f2bff3195..13afac9b3edc 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index abbc43d8e9b0..17dbbb0266ee 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::ConstEvalCtxt; use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath}; -use clippy_utils::source::{SpanRangeExt as _, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanExt as _, indent_of, reindent_multiline}; use rustc_ast::{BindingMode, ByRef}; use rustc_errors::Applicability; use rustc_hir::def::Res; diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index c20217563d62..07eef8c7e7e9 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{SpanlessEq, fulfill_or_allowed, hash_expr, is_lint_allowed, search_same}; use core::cmp::Ordering; use core::{iter, slice}; diff --git a/clippy_lints/src/matches/match_wild_enum.rs b/clippy_lints/src/matches/match_wild_enum.rs index fa44a56af182..6aaf44cfe335 100644 --- a/clippy_lints/src/matches/match_wild_enum.rs +++ b/clippy_lints/src/matches/match_wild_enum.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns}; use rustc_errors::Applicability; use rustc_hir::def::{CtorKind, DefKind, Res}; diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 8642c7e349b1..a03c7a00f5f8 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{ - SpanRangeExt, expr_block, snippet, snippet_block_with_context, snippet_with_applicability, snippet_with_context, + SpanExt, expr_block, snippet, snippet_block_with_context, snippet_with_applicability, snippet_with_context, }; use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs}; use clippy_utils::{is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs}; diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index b4b10e972f6d..53dbba024520 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanExt, indent_of, reindent_multiline}; use clippy_utils::sym; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index b803d1a3309d..6d1028f8b326 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -1,7 +1,7 @@ use super::FILTER_MAP_BOOL_THEN; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_context}; use clippy_utils::ty::is_copy; use clippy_utils::{CaptureKind, can_move_expr_to_closure, contains_return, is_from_proc_macro, peel_blocks}; use rustc_ast::Mutability; diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index 1a5b180b0c86..9ef18875b1e7 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::source::{IntoSpan, SpanExt}; use clippy_utils::ty::get_field_by_name; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; use clippy_utils::{ExprUseNode, expr_use_ctxt, sym}; diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index a8e30e44488c..66e4b85528b9 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath}; -use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanExt, indent_of, reindent_multiline}; use rustc_errors::Applicability; use rustc_hir::LangItem::{ResultErr, ResultOk}; use rustc_hir::{Expr, ExprKind, PatKind}; diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index f2e127bedde5..8bb5ff8dedab 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; diff --git a/clippy_lints/src/methods/map_all_any_identity.rs b/clippy_lints/src/methods/map_all_any_identity.rs index ad950f75f813..91118c6fb1c4 100644 --- a/clippy_lints/src/methods/map_all_any_identity.rs +++ b/clippy_lints/src/methods/map_all_any_identity.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_expr_identity_function; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs index 948ed8a25746..ba62382da6b0 100644 --- a/clippy_lints/src/methods/needless_character_iteration.rs +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -8,7 +8,7 @@ use rustc_span::Span; use super::NEEDLESS_CHARACTER_ITERATION; use super::utils::get_last_chain_binding_hir_id; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{peel_blocks, sym}; fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> { diff --git a/clippy_lints/src/methods/needless_option_as_deref.rs b/clippy_lints/src/methods/needless_option_as_deref.rs index 06e6a3c70b87..0e510a88015e 100644 --- a/clippy_lints/src/methods/needless_option_as_deref.rs +++ b/clippy_lints/src/methods/needless_option_as_deref.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sym; use clippy_utils::usage::local_used_after_expr; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs index 7ece83ba7ca3..6b60792554c1 100644 --- a/clippy_lints/src/methods/range_zip_with_len.rs +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::{SpanRangeExt as _, snippet_with_applicability}; +use clippy_utils::source::{SpanExt as _, snippet_with_applicability}; use clippy_utils::{SpanlessEq, get_parent_expr, higher, is_integer_const, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node, Pat, PatKind, QPath}; diff --git a/clippy_lints/src/methods/string_lit_chars_any.rs b/clippy_lints/src/methods/string_lit_chars_any.rs index 48e89c2998ef..27c324f86328 100644 --- a/clippy_lints/src/methods/string_lit_chars_any.rs +++ b/clippy_lints/src/methods/string_lit_chars_any.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use itertools::Itertools; use rustc_ast::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/methods/unnecessary_first_then_check.rs b/clippy_lints/src/methods/unnecessary_first_then_check.rs index d322909bef35..9c5768dfb6f5 100644 --- a/clippy_lints/src/methods/unnecessary_first_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_first_then_check.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/methods/unnecessary_get_then_check.rs b/clippy_lints/src/methods/unnecessary_get_then_check.rs index 10ea0c0c3e23..83bdc6226d8c 100644 --- a/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 4142f9f75773..54caebc8cadc 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -2,7 +2,7 @@ use super::utils::clone_or_copy_needed; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::ForLoop; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; 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}; diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index a6a39cb6ab30..0525bf6f69e3 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -3,7 +3,7 @@ use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{SpanExt, snippet}; use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_and_count_ty_refs}; use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{fn_def_id, get_parent_expr, is_expr_temporary_value, return_ty, sym}; diff --git a/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/clippy_lints/src/misc_early/unneeded_field_pattern.rs index 33ab94e00a5c..b2ee3f0c24f1 100644 --- a/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use itertools::Itertools; use rustc_ast::ast::{Pat, PatKind}; use rustc_lint::EarlyContext; diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index eeea6dfd5f4b..c1c6ff13c6c5 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths::{PathNS, lookup_path_str}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefIdMap; diff --git a/clippy_lints/src/multiple_bound_locations.rs b/clippy_lints/src/multiple_bound_locations.rs index 741f38f97560..6b6f56e70ea9 100644 --- a/clippy_lints/src/multiple_bound_locations.rs +++ b/clippy_lints/src/multiple_bound_locations.rs @@ -6,7 +6,7 @@ use rustc_session::declare_lint_pass; use rustc_span::Span; use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; declare_clippy_lint! { /// ### What it does diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index 2fef8404f824..ef2b3eadc8e3 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::source::{IntoSpan, SpanExt}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::ty_from_hir_ty; use rustc_errors::{Applicability, Diag}; diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index f8bb72a16db2..b0ba6ea1d993 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{IntoSpan, SpanRangeExt}; +use clippy_utils::source::{IntoSpan, SpanExt}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; diff --git a/clippy_lints/src/needless_ifs.rs b/clippy_lints/src/needless_ifs.rs index 8ec7e47ccc5b..01b78fb05903 100644 --- a/clippy_lints/src/needless_ifs.rs +++ b/clippy_lints/src/needless_ifs.rs @@ -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::{SpanRangeExt, walk_span_to_context}; +use clippy_utils::source::{SpanExt, walk_span_to_context}; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 464a91959a8e..418ab8338b60 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::{SourceText, SpanRangeExt, snippet}; +use clippy_utils::source::{SourceText, SpanExt, snippet}; 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; diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index fb5f21acf2af..48e5e02d687b 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{SpanExt, snippet}; use clippy_utils::ty::{implements_trait, implements_trait_with_env_from_iter, is_copy}; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; use clippy_utils::{is_self, peel_hir_ty_options, strip_pat_refs, sym}; diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index fdb8e1b475c1..600705e851f9 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::{expr_type_is_certain, has_drop}; use clippy_utils::{in_automatically_derived, is_inside_always_const_context, is_lint_allowed, peel_blocks}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index cb934466bd89..72ebe13562be 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; +use clippy_utils::source::{SpanExt, snippet_with_applicability}; use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 3a8a4dd0c713..570a9dba63b3 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_config::types::MacroMatcher; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SourceText, SpanRangeExt}; +use clippy_utils::source::{SourceText, SpanExt}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 6e7ee727965d..2ac9e010c69c 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::token::LitKind; use rustc_ast::{Expr, ExprKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index 2d303e40bd1c..d2b08bee8c94 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::Msrv; use clippy_utils::qualify_min_const_fn::is_stable_const_fn; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::implements_trait; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{binop_traits, eq_expr_value, is_in_const_context, trait_ref_of_method}; diff --git a/clippy_lints/src/operators/misrefactored_assign_op.rs b/clippy_lints/src/operators/misrefactored_assign_op.rs index 8daedd1c9014..06f7cfec05ce 100644 --- a/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{eq_expr_value, sugg}; use rustc_errors::Applicability; use rustc_hir as hir; diff --git a/clippy_lints/src/operators/needless_bitwise_bool.rs b/clippy_lints/src/operators/needless_bitwise_bool.rs index 9d8e833ef6d7..8f41ade58313 100644 --- a/clippy_lints/src/operators/needless_bitwise_bool.rs +++ b/clippy_lints/src/operators/needless_bitwise_bool.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/pathbuf_init_then_push.rs b/clippy_lints/src/pathbuf_init_then_push.rs index a5e57d97301e..d26aa2577816 100644 --- a/clippy_lints/src/pathbuf_init_then_push.rs +++ b/clippy_lints/src/pathbuf_init_then_push.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use clippy_utils::source::{SpanRangeExt, snippet}; +use clippy_utils::source::{SpanExt, snippet}; use clippy_utils::sym; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/ptr/ptr_arg.rs b/clippy_lints/src/ptr/ptr_arg.rs index 4bfff64b1bd4..50a6bdee1c29 100644 --- a/clippy_lints/src/ptr/ptr_arg.rs +++ b/clippy_lints/src/ptr/ptr_arg.rs @@ -1,7 +1,7 @@ use super::PTR_ARG; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::{VEC_METHODS_SHADOWING_SLICE_METHODS, get_expr_use_or_unification_node, is_lint_allowed, sym}; use hir::LifetimeKind; use rustc_abi::ExternAbi; diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index ca0d41fca524..82e88b1453b4 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -3,7 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; +use clippy_utils::source::{SpanExt, snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::{expr_use_ctxt, fn_def_id, get_parent_expr, higher, is_in_const_context, is_integer_const}; diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index 943e662479e9..b29810a5c013 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, snippet_opt}; +use clippy_utils::source::{SpanExt, snippet_opt}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_ast::token::LitKind; use rustc_errors::Applicability; diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 13c1b10bf2e8..6898332f282b 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::fn_has_unsatisfiable_preds; use clippy_utils::mir::{LocalUsage, PossibleBorrowerMap, visit_local_usage}; use clippy_utils::res::MaybeDef; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::{has_drop, is_copy, peel_and_count_ty_refs}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index d1fc228f4b35..80d910442902 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -5,7 +5,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::paths; use clippy_utils::paths::PathLookup; use clippy_utils::res::MaybeQPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::ast::{LitKind, StrStyle}; use rustc_hir::def_id::DefIdMap; use rustc_hir::{BorrowKind, Expr, ExprKind, OwnerId}; diff --git a/clippy_lints/src/returns/let_and_return.rs b/clippy_lints/src/returns/let_and_return.rs index 0a00981e15be..01b0279462e8 100644 --- a/clippy_lints/src/returns/let_and_return.rs +++ b/clippy_lints/src/returns/let_and_return.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::visitors::for_each_expr; use clippy_utils::{binary_expr_needs_parentheses, fn_def_id, span_contains_non_whitespace}; diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index 371d62a06849..d7d77097a490 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index 92d1b112198f..0e72213757df 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::source::{SpanRangeExt, snippet_with_context}; +use clippy_utils::source::{SpanExt, snippet_with_context}; use clippy_utils::ty::implements_trait; use clippy_utils::{is_no_std_crate, sym}; use rustc_ast::{LitIntType, LitKind, UintTy}; diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 352b8526b021..31f66792dc06 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability}; +use clippy_utils::source::{SpanExt, snippet, snippet_with_applicability}; use clippy_utils::{SpanlessEq, SpanlessHash, is_from_proc_macro}; use core::hash::{Hash, Hasher}; use itertools::Itertools; diff --git a/clippy_lints/src/transmute/missing_transmute_annotations.rs b/clippy_lints/src/transmute/missing_transmute_annotations.rs index f712b15c5768..8566d4cfeaab 100644 --- a/clippy_lints/src/transmute/missing_transmute_annotations.rs +++ b/clippy_lints/src/transmute/missing_transmute_annotations.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt as _; +use clippy_utils::source::SpanExt as _; use rustc_errors::Applicability; use rustc_hir::{Expr, GenericArg, HirId, LetStmt, Node, Path, TyKind}; use rustc_lint::LateContext; diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index ae6d8a1c1aa3..c9d1ffe778ae 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -1,7 +1,7 @@ use std::iter; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanExt, indent_of, reindent_multiline}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::expr_type_is_certain; use clippy_utils::{is_expr_default, is_from_proc_macro}; diff --git a/clippy_lints/src/unnecessary_mut_passed.rs b/clippy_lints/src/unnecessary_mut_passed.rs index eb2d7639e91f..7c921fed3e9e 100644 --- a/clippy_lints/src/unnecessary_mut_passed.rs +++ b/clippy_lints/src/unnecessary_mut_passed.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index d503bd3379b0..bb2ad9f92157 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanRangeExt, position_before_rarrow}; +use clippy_utils::source::{SpanExt, position_before_rarrow}; use clippy_utils::{is_never_expr, is_unit_expr}; use rustc_ast::{Block, StmtKind}; use rustc_errors::Applicability; diff --git a/clippy_lints/src/useless_vec.rs b/clippy_lints/src/useless_vec.rs index 28c339ce2b7d..352fd05ee159 100644 --- a/clippy_lints/src/useless_vec.rs +++ b/clippy_lints/src/useless_vec.rs @@ -7,7 +7,7 @@ use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::ty::is_copy; use clippy_utils::visitors::for_each_local_use_after_expr; use clippy_utils::{VEC_METHODS_SHADOWING_SLICE_METHODS, get_parent_expr, higher, is_in_test, span_contains_comment}; diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index 6629a67f78bd..8f5014d1e3ad 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -1,5 +1,5 @@ use clippy_utils::macros::FormatArgsStorage; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use itertools::Itertools; use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_data_structures::fx::FxHashMap; diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index d17b3df99216..1a3d616121cb 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use rustc_ast::ast::{Item, VisibilityKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; diff --git a/clippy_lints/src/write/literal.rs b/clippy_lints/src/write/literal.rs index 699ac7ea7a5c..9711410ef885 100644 --- a/clippy_lints/src/write/literal.rs +++ b/clippy_lints/src/write/literal.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::format_arg_removal_span; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::SpanExt; use clippy_utils::sym; use rustc_ast::token::LitKind; use rustc_ast::{ diff --git a/clippy_lints/src/write/with_newline.rs b/clippy_lints/src/write/with_newline.rs index e4b51da3cadc..53109f4014c8 100644 --- a/clippy_lints/src/write/with_newline.rs +++ b/clippy_lints/src/write/with_newline.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::MacroCall; -use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma}; +use clippy_utils::source::{SpanExt, expand_past_previous_comma}; use clippy_utils::sym; use rustc_ast::{FormatArgs, FormatArgsPiece}; use rustc_errors::Applicability; diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 671b266ba008..e7e654373e5e 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -1,6 +1,6 @@ //! Utility functions for attributes, including Clippy's built-in ones -use crate::source::SpanRangeExt; +use crate::source::SpanExt; use crate::{sym, tokenize_with_text}; use rustc_ast::attr; use rustc_ast::attr::AttributeExt; diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index 44a5a9380741..cc5c3138cee5 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -5,7 +5,7 @@ #![expect(clippy::float_cmp)] use crate::res::MaybeDef; -use crate::source::{SpanRangeExt, walk_span_to_context}; +use crate::source::{SpanExt, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, sym, unsext}; use rustc_abi::Size; diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index b286701fbed1..e0cabb6e2dc3 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,6 +1,6 @@ use crate::consts::ConstEvalCtxt; use crate::macros::macro_backtrace; -use crate::source::{SpanRange, SpanRangeExt, walk_span_to_context}; +use crate::source::{SpanExt, SpanRange, walk_span_to_context}; use crate::tokenize_with_text; use rustc_ast::ast; use rustc_ast::ast::InlineAsmTemplatePiece; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 93f831971a16..5bdf060a05d9 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -125,7 +125,7 @@ use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; use rustc_span::{InnerSpan, Span}; -use source::{SpanRangeExt, walk_span_to_context}; +use source::{SpanExt, walk_span_to_context}; use visitors::{Visitable, for_each_unconsumed_temporary}; use crate::ast_utils::unordered_over; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 28122544a4e2..cdae3e07bc1d 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -106,7 +106,7 @@ impl IntoSpan for Range { } } -pub trait SpanRangeExt: SpanRange { +pub trait SpanExt: SpanRange { /// Attempts to get a handle to the source text. Returns `None` if either the span is malformed, /// or the source text is not accessible. fn get_source_text<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { @@ -176,7 +176,7 @@ pub trait SpanRangeExt: SpanRange { trim_start(sm.source_map(), self.into_range()) } } -impl SpanRangeExt for T {} +impl SpanExt for T {} /// Handle to a range of text in a source file. pub struct SourceText(SourceFileRange); From a6167b6cd33a8755728cb50e64bb450407ddac37 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 18 Nov 2025 23:49:16 -0500 Subject: [PATCH 3/5] Rename `get_source_text` and `check_source_text` to `get_text` and `check_text`. --- clippy_lints/src/attrs/non_minimal_cfg.rs | 2 +- .../src/attrs/unnecessary_clippy_cfg.rs | 4 +-- clippy_lints/src/attrs/useless_attribute.rs | 2 +- clippy_lints/src/booleans.rs | 29 +++++++------------ clippy_lints/src/borrow_deref_ref.rs | 2 +- clippy_lints/src/casts/as_ptr_cast_mut.rs | 2 +- clippy_lints/src/casts/cast_lossless.rs | 2 +- clippy_lints/src/casts/manual_dangling_ptr.rs | 2 +- clippy_lints/src/casts/unnecessary_cast.rs | 6 ++-- clippy_lints/src/casts/zero_ptr.rs | 2 +- .../src/default_constructed_unit_structs.rs | 2 +- clippy_lints/src/empty_line_after.rs | 2 +- clippy_lints/src/format.rs | 2 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/four_forward_slashes.rs | 2 +- clippy_lints/src/from_over_into.rs | 4 +-- clippy_lints/src/functions/too_many_lines.rs | 2 +- clippy_lints/src/int_plus_one.rs | 4 +-- clippy_lints/src/items_after_test_module.rs | 2 +- clippy_lints/src/large_stack_frames.rs | 2 +- clippy_lints/src/legacy_numeric_constants.rs | 2 +- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/literal_representation.rs | 4 +-- clippy_lints/src/manual_async_fn.rs | 6 ++-- clippy_lints/src/manual_float_methods.rs | 2 +- clippy_lints/src/manual_hash_one.rs | 4 +-- clippy_lints/src/manual_range_patterns.rs | 4 +-- clippy_lints/src/matches/manual_unwrap_or.rs | 2 +- clippy_lints/src/matches/match_same_arms.rs | 2 +- clippy_lints/src/matches/match_wild_enum.rs | 2 +- clippy_lints/src/matches/single_match.rs | 2 +- ...se_sensitive_file_extension_comparisons.rs | 2 +- .../src/methods/filter_map_bool_then.rs | 2 +- clippy_lints/src/methods/manual_ok_or.rs | 4 +-- clippy_lints/src/methods/manual_try_fold.rs | 6 ++-- .../src/methods/map_all_any_identity.rs | 2 +- .../methods/needless_character_iteration.rs | 4 +-- .../src/methods/needless_option_as_deref.rs | 2 +- .../src/methods/range_zip_with_len.rs | 4 +-- .../src/methods/string_lit_chars_any.rs | 2 +- .../methods/unnecessary_first_then_check.rs | 4 +-- .../src/methods/unnecessary_get_then_check.rs | 8 ++--- .../src/methods/unnecessary_iter_cloned.rs | 4 +-- .../src/methods/unnecessary_to_owned.rs | 12 ++++---- .../src/misc_early/unneeded_field_pattern.rs | 2 +- .../src/missing_enforced_import_rename.rs | 2 +- clippy_lints/src/needless_else.rs | 2 +- clippy_lints/src/needless_ifs.rs | 4 +-- clippy_lints/src/needless_late_init.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 4 +-- clippy_lints/src/no_effect.rs | 6 ++-- .../src/non_octal_unix_permissions.rs | 4 +-- clippy_lints/src/nonstandard_macro_braces.rs | 2 +- clippy_lints/src/octal_escapes.rs | 2 +- .../src/operators/assign_op_pattern.rs | 4 +-- .../src/operators/misrefactored_assign_op.rs | 4 +-- .../src/operators/needless_bitwise_bool.rs | 4 +-- clippy_lints/src/pathbuf_init_then_push.rs | 6 ++-- clippy_lints/src/ptr/ptr_arg.rs | 6 ++-- clippy_lints/src/ranges.rs | 2 +- clippy_lints/src/raw_strings.rs | 4 +-- clippy_lints/src/redundant_clone.rs | 2 +- clippy_lints/src/regex.rs | 2 +- clippy_lints/src/returns/let_and_return.rs | 2 +- clippy_lints/src/semicolon_block.rs | 2 +- clippy_lints/src/single_range_in_vec_init.rs | 2 +- clippy_lints/src/trait_bounds.rs | 7 ++--- clippy_lints/src/unit_types/unit_arg.rs | 4 +-- clippy_lints/src/useless_vec.rs | 4 +-- .../src/utils/format_args_collector.rs | 2 +- clippy_lints/src/visibility.rs | 2 +- clippy_lints/src/write/literal.rs | 4 +-- clippy_lints/src/write/with_newline.rs | 2 +- clippy_utils/src/attrs.rs | 2 +- clippy_utils/src/hir_utils.rs | 2 +- clippy_utils/src/lib.rs | 2 +- clippy_utils/src/source.rs | 4 +-- 77 files changed, 129 insertions(+), 141 deletions(-) diff --git a/clippy_lints/src/attrs/non_minimal_cfg.rs b/clippy_lints/src/attrs/non_minimal_cfg.rs index a76bdcfdfb3e..91e2689a1473 100644 --- a/clippy_lints/src/attrs/non_minimal_cfg.rs +++ b/clippy_lints/src/attrs/non_minimal_cfg.rs @@ -29,7 +29,7 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[MetaItemInner]) { meta.span, "unneeded sub `cfg` when there is only one condition", |diag| { - if let Some(snippet) = list[0].span().get_source_text(cx) { + if let Some(snippet) = list[0].span().get_text(cx) { diag.span_suggestion( meta.span, "try", diff --git a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs index a647f976908a..e8829a796921 100644 --- a/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs +++ b/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs @@ -32,7 +32,7 @@ pub(super) fn check( return; } if nb_items == clippy_lints.len() { - if let Some(snippet) = behind_cfg_attr.span.get_source_text(cx) { + if let Some(snippet) = behind_cfg_attr.span.get_text(cx) { span_lint_and_sugg( cx, UNNECESSARY_CLIPPY_CFG, @@ -48,7 +48,7 @@ pub(super) fn check( ); } } else { - let snippet = clippy_lints.iter().filter_map(|sp| sp.get_source_text(cx)).join(","); + let snippet = clippy_lints.iter().filter_map(|sp| sp.get_text(cx)).join(","); span_lint_and_note( cx, UNNECESSARY_CLIPPY_CFG, diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs index fc780472e03c..0597ac93ff43 100644 --- a/clippy_lints/src/attrs/useless_attribute.rs +++ b/clippy_lints/src/attrs/useless_attribute.rs @@ -73,7 +73,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { } let line_span = first_line_of_span(cx, attr.span); - if let Some(src) = line_span.get_source_text(cx) + if let Some(src) = line_span.get_text(cx) && src.contains("#[") { #[expect(clippy::collapsible_span_lint_calls)] diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 8896829653ad..a8c634070fb4 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -153,30 +153,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) = left_sub.span.get_source_text(cx) else { + let Some(left) = left_sub.span.get_text(cx) else { return; }; - let Some(right) = right_sub.span.get_source_text(cx) else { + let Some(right) = right_sub.span.get_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) = left_sub.span.get_source_text(cx) else { + let Some(left) = left_sub.span.get_text(cx) else { return; }; - let Some(right) = right.span.get_source_text(cx) else { + let Some(right) = right.span.get_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) = left.span.get_source_text(cx) else { + let Some(left) = left.span.get_text(cx) else { return; }; - let Some(right) = right_sub.span.get_source_text(cx) else { + let Some(right) = right_sub.span.get_text(cx) else { return; }; let Some(op) = inverted_bin_op_eq_str(op) else { return }; @@ -387,12 +387,8 @@ impl SuggestContext<'_, '_, '_> { } }, &Term(n) => { - self.output.push_str( - &self.terminals[n as usize] - .span - .source_callsite() - .get_source_text(self.cx)?, - ); + self.output + .push_str(&self.terminals[n as usize].span.source_callsite().get_text(self.cx)?); }, } Some(()) @@ -447,10 +443,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio .map(|arg| simplify_not(cx, curr_msrv, arg)) .collect::>>()? .join(", "); - Some(format!( - "{}.{neg_method}({negated_args})", - receiver.span.get_source_text(cx)? - )) + Some(format!("{}.{neg_method}({negated_args})", receiver.span.get_text(cx)?)) }) }, ExprKind::Closure(closure) => { @@ -458,13 +451,13 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio let params = body .params .iter() - .map(|param| param.span.get_source_text(cx).map(|t| t.to_string())) + .map(|param| param.span.get_text(cx).map(|t| t.to_string())) .collect::>>()? .join(", "); let negated = simplify_not(cx, curr_msrv, body.value)?; Some(format!("|{params}| {negated}")) }, - ExprKind::Unary(UnOp::Not, expr) => expr.span.get_source_text(cx).map(|t| t.to_string()), + ExprKind::Unary(UnOp::Not, expr) => expr.span.get_text(cx).map(|t| t.to_string()), _ => None, } } diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 350324099d0d..536d1c3230e6 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -79,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { // If the new borrow might be itself borrowed mutably and the original reference is not a temporary // value, do not propose to use it directly. && (is_expr_temporary_value(cx, deref_target) || !potentially_bound_to_mutable_ref(cx, e)) - && let Some(deref_text) = deref_target.span.get_source_text(cx) + && let Some(deref_text) = deref_target.span.get_text(cx) { span_lint_and_then( cx, diff --git a/clippy_lints/src/casts/as_ptr_cast_mut.rs b/clippy_lints/src/casts/as_ptr_cast_mut.rs index 74388808a130..728f9626b9a8 100644 --- a/clippy_lints/src/casts/as_ptr_cast_mut.rs +++ b/clippy_lints/src/casts/as_ptr_cast_mut.rs @@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).instantiate_identity() && let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next() && let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind() - && let Some(recv) = receiver.span.get_source_text(cx) + && let Some(recv) = receiver.span.get_text(cx) { // `as_mut_ptr` might not exist let applicability = Applicability::MaybeIncorrect; diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index bcfb59028201..d2bf6db75132 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -40,7 +40,7 @@ pub(super) fn check( diag.help("an `as` cast can become silently lossy if the types change in the future"); let mut applicability = Applicability::MachineApplicable; let from_sugg = Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "", &mut applicability); - let Some(ty) = hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt()).get_source_text(cx) else { + let Some(ty) = hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt()).get_text(cx) else { return; }; match cast_to_hir.kind { diff --git a/clippy_lints/src/casts/manual_dangling_ptr.rs b/clippy_lints/src/casts/manual_dangling_ptr.rs index 796c7e73ed51..39199c0b3cb1 100644 --- a/clippy_lints/src/casts/manual_dangling_ptr.rs +++ b/clippy_lints/src/casts/manual_dangling_ptr.rs @@ -23,7 +23,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: let sugg = if let TyKind::Infer(()) = ptr_ty.ty.kind { format!("{std_or_core}::{sugg_fn}()") - } else if let Some(mut_ty_snip) = ptr_ty.ty.span.get_source_text(cx) { + } else if let Some(mut_ty_snip) = ptr_ty.ty.span.get_text(cx) { format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()") } else { return; diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index 22a50acb77d1..6cf62d3cad7c 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -106,7 +106,7 @@ pub(super) fn check<'tcx>( let literal_str = &cast_str; if let LitKind::Int(n, _) = lit.node - && let Some(src) = cast_expr.span.get_source_text(cx) + && let Some(src) = cast_expr.span.get_text(cx) && cast_to.is_floating_point() && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) && let from_nbits = 128 - n.get().leading_zeros() @@ -133,7 +133,7 @@ pub(super) fn check<'tcx>( | LitKind::Float(_, LitFloatType::Suffixed(_)) if cast_from.kind() == cast_to.kind() => { - if let Some(src) = cast_expr.span.get_source_text(cx) + if let Some(src) = cast_expr.span.get_text(cx) && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) { lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to); @@ -281,7 +281,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx let res = cx.qpath_res(&qpath, expr.hir_id); // Function call if let Res::Def(DefKind::Fn, def_id) = res { - let Some(snippet) = cx.tcx.def_span(def_id).get_source_text(cx) else { + let Some(snippet) = cx.tcx.def_span(def_id).get_text(cx) else { return ControlFlow::Continue(()); }; // This is the worst part of this entire function. This is the only way I know of to diff --git a/clippy_lints/src/casts/zero_ptr.rs b/clippy_lints/src/casts/zero_ptr.rs index d33d08230d1a..90290caf10bf 100644 --- a/clippy_lints/src/casts/zero_ptr.rs +++ b/clippy_lints/src/casts/zero_ptr.rs @@ -21,7 +21,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: &Ty<'_> let sugg = if let TyKind::Infer(()) = mut_ty.ty.kind { format!("{std_or_core}::{sugg_fn}()") - } else if let Some(mut_ty_snip) = mut_ty.ty.span.get_source_text(cx) { + } else if let Some(mut_ty_snip) = mut_ty.ty.span.get_text(cx) { format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()") } else { return; diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs index 195c8c2d5989..1a93ce58b890 100644 --- a/clippy_lints/src/default_constructed_unit_structs.rs +++ b/clippy_lints/src/default_constructed_unit_structs.rs @@ -75,7 +75,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs { && !base.is_suggestable_infer_ty() { let mut removals = vec![(expr.span.with_lo(qpath.qself_span().hi()), String::new())]; - if expr.span.check_source_text(cx, |s| s.starts_with('<')) { + if expr.span.check_text(cx, |s| s.starts_with('<')) { // Remove `<`, '>` has already been removed by the existing removal expression. removals.push((expr.span.with_hi(qpath.qself_span().lo()), String::new())); } diff --git a/clippy_lints/src/empty_line_after.rs b/clippy_lints/src/empty_line_after.rs index c83570b336fb..95e97e7c781c 100644 --- a/clippy_lints/src/empty_line_after.rs +++ b/clippy_lints/src/empty_line_after.rs @@ -254,7 +254,7 @@ impl<'a> Gap<'a> { let prev_stop = prev_chunk.last()?; let next_stop = next_chunk.first()?; let gap_span = prev_stop.span.between(next_stop.span); - let gap_snippet = gap_span.get_source_text(cx)?; + let gap_snippet = gap_span.get_text(cx)?; let mut has_comment = false; let mut empty_lines = Vec::new(); diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index b001d6983766..061ab7adf8b5 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -64,7 +64,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) = format_args.span.get_source_text(cx) else { + let Some(snippet) = format_args.span.get_text(cx) else { return; }; let s_expand = snippet.replace("{{", "{").replace("}}", "}"); diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index b9e6b7c10b65..dfc12d07bf89 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -509,7 +509,7 @@ impl<'tcx> FormatArgsExpr<'_, '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) = receiver.span.source_callsite().get_source_text(cx) + && let Some(receiver_snippet) = receiver.span.source_callsite().get_text(cx) { let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]); if n_needed_derefs == 0 && !needs_ref { diff --git a/clippy_lints/src/four_forward_slashes.rs b/clippy_lints/src/four_forward_slashes.rs index c099f56a2e5d..8554dbcf834d 100644 --- a/clippy_lints/src/four_forward_slashes.rs +++ b/clippy_lints/src/four_forward_slashes.rs @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for FourForwardSlashes { // If the comment contains a bare CR (not followed by a LF), do not propose an auto-fix // as bare CR are not allowed in doc comments. - if span.check_source_text(cx, contains_bare_cr) { + if span.check_text(cx, contains_bare_cr) { diag.help(msg) .note("bare CR characters are not allowed in doc comments"); return; diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs index 7998b7e707c8..8f3eebf4d2e0 100644 --- a/clippy_lints/src/from_over_into.rs +++ b/clippy_lints/src/from_over_into.rs @@ -185,8 +185,8 @@ fn convert_to_from( return None; }; - let from = self_ty.span.get_source_text(cx)?; - let into = target_ty.span.get_source_text(cx)?; + let from = self_ty.span.get_text(cx)?; + let into = target_ty.span.get_text(cx)?; let mut suggestions = vec![ // impl Into for U -> impl From for U diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs index da3ad2287c31..a5fed9f03a62 100644 --- a/clippy_lints/src/functions/too_many_lines.rs +++ b/clippy_lints/src/functions/too_many_lines.rs @@ -23,7 +23,7 @@ pub(super) fn check_fn( } let mut line_count: u64 = 0; - let too_many = body.value.span.check_source_text(cx, |src| { + let too_many = body.value.span.check_text(cx, |src| { let mut in_comment = false; let mut code_in_line; diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 24d9ccb27788..58f4f936bae0 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -130,8 +130,8 @@ impl IntPlusOne { BinOpKind::Le => "<", _ => return None, }; - if let Some(snippet) = node.span.get_source_text(cx) - && let Some(other_side_snippet) = other_side.span.get_source_text(cx) + if let Some(snippet) = node.span.get_text(cx) + && let Some(other_side_snippet) = other_side.span.get_text(cx) { let rec = match side { Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")), diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs index 3ab4be144251..f83bcb3cf407 100644 --- a/clippy_lints/src/items_after_test_module.rs +++ b/clippy_lints/src/items_after_test_module.rs @@ -99,7 +99,7 @@ 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) = items_span.get_source_text(cx) + && let Some(items) = items_span.get_text(cx) { diag.multipart_suggestion_with_style( "move the items to before the test module was defined", diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs index 922f81a92785..cdd21e6fa3ec 100644 --- a/clippy_lints/src/large_stack_frames.rs +++ b/clippy_lints/src/large_stack_frames.rs @@ -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) = local_span.get_source_text(cx) + if let Some(name) = local_span.get_text(cx) && is_ident(&name) { // If the local is an ordinary named variable, diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs index 4fd6bd384615..781e3209d014 100644 --- a/clippy_lints/src/legacy_numeric_constants.rs +++ b/clippy_lints/src/legacy_numeric_constants.rs @@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { && let QPath::TypeRelative(ty, last_segment) = qpath && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() && is_integer_method(cx, def_id) - && let Some(mod_name) = ty.span.get_source_text(cx) + && let Some(mod_name) = ty.span.get_text(cx) && ty.span.eq_ctxt(last_segment.ident.span) { let name = last_segment.ident.name.as_str()[..=2].to_ascii_uppercase(); diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 138cac327d3f..ff0996a62929 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -343,7 +343,7 @@ impl LenZero { } fn span_without_enclosing_paren(cx: &LateContext<'_>, span: Span) -> Span { - let Some(snippet) = span.get_source_text(cx) else { + let Some(snippet) = span.get_text(cx) else { return span; }; if has_enclosing_paren(snippet) { diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index b7ed91f241f7..a8d55e736faa 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -224,7 +224,7 @@ impl LiteralDigitGrouping { } fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) { - if let Some(src) = span.get_source_text(cx) + if let Some(src) = span.get_text(cx) && let Ok(lit_kind) = LitKind::from_token_lit(lit) && let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) { @@ -436,7 +436,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) = span.get_source_text(cx) + && let Some(src) = span.get_text(cx) && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind) && num_lit.radix == Radix::Decimal && val >= u128::from(self.threshold) diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index dff324d132a0..161834914b30 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -76,8 +76,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { "this function can be simplified using the `async fn` syntax", |diag| { if let Some(vis_span) = vis_span_opt - && let Some(vis_snip) = vis_span.get_source_text(cx) - && let Some(header_snip) = header_span.get_source_text(cx) + && let Some(vis_snip) = vis_span.get_text(cx) + && let Some(header_snip) = header_span.get_text(cx) && let Some(ret_pos) = position_before_rarrow(&header_snip) && let Some((_, ret_snip)) = suggested_ret(cx, output) { @@ -185,6 +185,6 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, Some((sugg, String::new())) } else { let sugg = "return the output of the future directly"; - output.span.get_source_text(cx).map(|src| (sugg, format!(" -> {src}"))) + output.span.get_text(cx).map(|src| (sugg, format!(" -> {src}"))) } } diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs index 8fd9497c1d4e..a73206fea3aa 100644 --- a/clippy_lints/src/manual_float_methods.rs +++ b/clippy_lints/src/manual_float_methods.rs @@ -155,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { // case somebody does that for some reason && (const_1.is_pos_infinity() && const_2.is_neg_infinity() || const_1.is_neg_infinity() && const_2.is_pos_infinity()) - && let Some(local_snippet) = first.span.get_source_text(cx) + && let Some(local_snippet) = first.span.get_text(cx) { let variant = match (kind.node, lhs_kind.node, rhs_kind.node) { (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Eq) => Variant::ManualIsInfinite, diff --git a/clippy_lints/src/manual_hash_one.rs b/clippy_lints/src/manual_hash_one.rs index 12fed3cf6b60..32550e76730b 100644 --- a/clippy_lints/src/manual_hash_one.rs +++ b/clippy_lints/src/manual_hash_one.rs @@ -105,8 +105,8 @@ impl LateLintPass<'_> for ManualHashOne { finish_expr.span, "manual implementation of `BuildHasher::hash_one`", |diag| { - if let Some(build_hasher) = build_hasher.span.get_source_text(cx) - && let Some(hashed_value) = hashed_value.span.get_source_text(cx) + if let Some(build_hasher) = build_hasher.span.get_text(cx) + && let Some(hashed_value) = hashed_value.span.get_text(cx) { diag.multipart_suggestion( "try", diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs index 13afac9b3edc..c1e24aff586e 100644 --- a/clippy_lints/src/manual_range_patterns.rs +++ b/clippy_lints/src/manual_range_patterns.rs @@ -142,8 +142,8 @@ impl LateLintPass<'_> for ManualRangePatterns { pat.span, "this OR pattern can be rewritten using a range", |diag| { - if let Some(min) = min.span.get_source_text(cx) - && let Some(max) = max.span.get_source_text(cx) + if let Some(min) = min.span.get_text(cx) + && let Some(max) = max.span.get_text(cx) { diag.span_suggestion( pat.span, diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs index 17dbbb0266ee..e43620cde1db 100644 --- a/clippy_lints/src/matches/manual_unwrap_or.rs +++ b/clippy_lints/src/matches/manual_unwrap_or.rs @@ -160,7 +160,7 @@ fn handle( ); } else if let Some(ty_name) = find_type_name(cx, cx.typeck_results().expr_ty(condition)) && cx.typeck_results().expr_adjustments(body_some).is_empty() - && let Some(or_body_snippet) = peel_blocks(body_none).span.get_source_text(cx) + && let Some(or_body_snippet) = peel_blocks(body_none).span.get_text(cx) && let Some(indent) = indent_of(cx, expr.span) && ConstEvalCtxt::new(cx).eval_local(body_none, expr.span.ctxt()).is_some() { diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs index 07eef8c7e7e9..76357ee667dd 100644 --- a/clippy_lints/src/matches/match_same_arms.rs +++ b/clippy_lints/src/matches/match_same_arms.rs @@ -149,7 +149,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { if let Some(((_, dest), src)) = split && let Some(pat_snippets) = group .iter() - .map(|(_, arm)| arm.pat.span.get_source_text(cx)) + .map(|(_, arm)| arm.pat.span.get_text(cx)) .collect::>>() { let suggs = src diff --git a/clippy_lints/src/matches/match_wild_enum.rs b/clippy_lints/src/matches/match_wild_enum.rs index 6aaf44cfe335..aabc9d53b9c9 100644 --- a/clippy_lints/src/matches/match_wild_enum.rs +++ b/clippy_lints/src/matches/match_wild_enum.rs @@ -119,7 +119,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { wildcard_ident.map_or(String::new(), |ident| { ident .span - .get_source_text(cx) + .get_text(cx) .map_or_else(|| format!("{} @ ", ident.name), |s| format!("{s} @ ")) }), if let CommonPrefixSearcher::Path(path_prefix) = path_prefix { diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index a03c7a00f5f8..5be7f4e8d2f1 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -22,7 +22,7 @@ use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE}; /// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty /// match arms. fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool { - span.check_source_text(cx, |text| text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*")) + span.check_text(cx, |text| text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*")) } pub(crate) fn check<'tcx>( diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index 53dbba024520..e336639c6eed 100644 --- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -52,7 +52,7 @@ pub(super) fn check<'tcx>( "case-sensitive file extension comparison", |diag| { diag.help("consider using a case-insensitive comparison instead"); - if let Some(recv_source) = recv.span.get_source_text(cx) { + if let Some(recv_source) = recv.span.get_text(cx) { let recv_source = if cx.typeck_results().expr_ty(recv).is_ref() { recv_source.to_owned() } else { diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs index 6d1028f8b326..9d0e94dbcb58 100644 --- a/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/clippy_lints/src/methods/filter_map_bool_then.rs @@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & .iter() .filter(|adj| matches!(adj.kind, Adjust::Deref(_))) .count() - && let Some(param_snippet) = param.span.get_source_text(cx) + && let Some(param_snippet) = param.span.get_text(cx) { let mut applicability = Applicability::MachineApplicable; let (filter, _) = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut applicability); diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs index 66e4b85528b9..3f888042a336 100644 --- a/clippy_lints/src/methods/manual_ok_or.rs +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -26,8 +26,8 @@ pub(super) fn check<'tcx>( && let ExprKind::Call(err_path, [err_arg]) = or_expr.kind && err_path.res(cx).ctor_parent(cx).is_lang_item(cx, ResultErr) && is_ok_wrapping(cx, map_expr) - && let Some(recv_snippet) = recv.span.get_source_text(cx) - && let Some(err_arg_snippet) = err_arg.span.get_source_text(cx) + && let Some(recv_snippet) = recv.span.get_text(cx) + && let Some(err_arg_snippet) = err_arg.span.get_text(cx) && let Some(indent) = indent_of(cx, expr.span) { let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.as_str(), true, Some(indent + 4)); diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs index 8bb5ff8dedab..8442b58a40d4 100644 --- a/clippy_lints/src/methods/manual_try_fold.rs +++ b/clippy_lints/src/methods/manual_try_fold.rs @@ -31,14 +31,12 @@ pub(super) fn check<'tcx>( && let ExprKind::Closure(closure) = acc.kind && msrv.meets(cx, msrvs::ITERATOR_TRY_FOLD) && !is_from_proc_macro(cx, expr) - && let Some(args_snip) = closure - .fn_arg_span - .and_then(|fn_arg_span| fn_arg_span.get_source_text(cx)) + && let Some(args_snip) = closure.fn_arg_span.and_then(|fn_arg_span| fn_arg_span.get_text(cx)) { let init_snip = rest .is_empty() .then_some(first.span) - .and_then(|span| span.get_source_text(cx)) + .and_then(|span| span.get_text(cx)) .map_or_else(|| "...".to_owned(), |src| src.to_owned()); span_lint_and_sugg( diff --git a/clippy_lints/src/methods/map_all_any_identity.rs b/clippy_lints/src/methods/map_all_any_identity.rs index 91118c6fb1c4..14a9752d3bde 100644 --- a/clippy_lints/src/methods/map_all_any_identity.rs +++ b/clippy_lints/src/methods/map_all_any_identity.rs @@ -24,7 +24,7 @@ pub(super) fn check( && cx.ty_based_def(recv).opt_parent(cx).is_diag_item(cx, sym::Iterator) && is_expr_identity_function(cx, any_arg) && let map_any_call_span = map_call_span.with_hi(any_call_span.hi()) - && let Some(map_arg) = map_arg.span.get_source_text(cx) + && let Some(map_arg) = map_arg.span.get_text(cx) { span_lint_and_then( cx, diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs index ba62382da6b0..20468784aae7 100644 --- a/clippy_lints/src/methods/needless_character_iteration.rs +++ b/clippy_lints/src/methods/needless_character_iteration.rs @@ -36,7 +36,7 @@ fn handle_expr( && receiver.res_local_id() == Some(first_param) && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() && *char_arg_ty.kind() == ty::Char - && let Some(snippet) = before_chars.get_source_text(cx) + && let Some(snippet) = before_chars.get_text(cx) { span_lint_and_sugg( cx, @@ -78,7 +78,7 @@ fn handle_expr( if revert != is_all && fn_path.ty_rel_def(cx).is_diag_item(cx, sym::char_is_ascii) && peels_expr_ref(arg).res_local_id() == Some(first_param) - && let Some(snippet) = before_chars.get_source_text(cx) + && let Some(snippet) = before_chars.get_text(cx) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/needless_option_as_deref.rs b/clippy_lints/src/methods/needless_option_as_deref.rs index 0e510a88015e..7626cdb5a5fe 100644 --- a/clippy_lints/src/methods/needless_option_as_deref.rs +++ b/clippy_lints/src/methods/needless_option_as_deref.rs @@ -32,7 +32,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, name expr.span, "derefed type is same as origin", "try", - recv.span.get_source_text(cx).unwrap().to_owned(), + recv.span.get_text(cx).unwrap().to_owned(), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs index 6b60792554c1..65d87dad7396 100644 --- a/clippy_lints/src/methods/range_zip_with_len.rs +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -49,8 +49,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' ), )]; if let Some((left, right)) = invert_bindings - && let Some(snip_left) = left.get_source_text(cx) - && let Some(snip_right) = right.get_source_text(cx) + && let Some(snip_left) = left.get_text(cx) + && let Some(snip_right) = right.get_text(cx) { suggestions.extend([(left, snip_right.to_string()), (right, snip_left.to_string())]); } else { diff --git a/clippy_lints/src/methods/string_lit_chars_any.rs b/clippy_lints/src/methods/string_lit_chars_any.rs index 27c324f86328..53c695e37847 100644 --- a/clippy_lints/src/methods/string_lit_chars_any.rs +++ b/clippy_lints/src/methods/string_lit_chars_any.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( } && msrv.meets(cx, msrvs::MATCHES_MACRO) && !is_from_proc_macro(cx, expr) - && let Some(scrutinee_snip) = scrutinee.span.get_source_text(cx) + && let Some(scrutinee_snip) = scrutinee.span.get_text(cx) { // Normalize the char using `map` so `join` doesn't use `Display`, if we don't then // something like `r"\"` will become `'\'`, which is of course invalid diff --git a/clippy_lints/src/methods/unnecessary_first_then_check.rs b/clippy_lints/src/methods/unnecessary_first_then_check.rs index 9c5768dfb6f5..43dac249f744 100644 --- a/clippy_lints/src/methods/unnecessary_first_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_first_then_check.rs @@ -29,8 +29,8 @@ pub(super) fn check( }; let both_calls_span = first_call_span.with_hi(call_span.hi()); - if let Some(both_calls_snippet) = both_calls_span.get_source_text(cx) - && let Some(first_caller_snippet) = first_caller.span.get_source_text(cx) + if let Some(both_calls_snippet) = both_calls_span.get_text(cx) + && let Some(first_caller_snippet) = first_caller.span.get_text(cx) { let (sugg_span, suggestion) = if is_some { ( diff --git a/clippy_lints/src/methods/unnecessary_get_then_check.rs b/clippy_lints/src/methods/unnecessary_get_then_check.rs index 83bdc6226d8c..0cd9feb4c642 100644 --- a/clippy_lints/src/methods/unnecessary_get_then_check.rs +++ b/clippy_lints/src/methods/unnecessary_get_then_check.rs @@ -38,11 +38,11 @@ pub(super) fn check( return; }; let both_calls_span = get_call_span.with_hi(call_span.hi()); - if let Some(snippet) = both_calls_span.get_source_text(cx) - && let Some(arg_snippet) = arg.span.get_source_text(cx) + if let Some(snippet) = both_calls_span.get_text(cx) + && let Some(arg_snippet) = arg.span.get_text(cx) { let generics_snippet = if let Some(generics) = path.args - && let Some(generics_snippet) = generics.span_ext.get_source_text(cx) + && let Some(generics_snippet) = generics.span_ext.get_text(cx) { format!("::{generics_snippet}") } else { @@ -63,7 +63,7 @@ pub(super) fn check( suggestion, Applicability::MaybeIncorrect, ); - } else if let Some(caller_snippet) = get_caller.span.get_source_text(cx) { + } else if let Some(caller_snippet) = get_caller.span.get_text(cx) { let full_span = get_caller.span.with_hi(call_span.hi()); span_lint_and_then( diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 54caebc8cadc..79229154fe49 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -42,7 +42,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) = receiver.span.get_source_text(cx) + && let Some(receiver_snippet) = receiver.span.get_text(cx) { // Issue 12098 // https://github.com/rust-lang/rust-clippy/issues/12098 @@ -102,7 +102,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, sym::Item) && iter_item_ty == into_iter_item_ty - && let Some(collection_snippet) = collection.span.get_source_text(cx) + && let Some(collection_snippet) = collection.span.get_text(cx) { collection_snippet } else { diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 0525bf6f69e3..00b6a6078171 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -131,7 +131,7 @@ fn check_addr_of_expr( && (*referent_ty != receiver_ty || (matches!(referent_ty.kind(), ty::Array(..)) && is_copy(cx, *referent_ty)) || is_cow_into_owned(cx, method_name, method_parent_id)) - && let Some(receiver_snippet) = receiver.span.get_source_text(cx) + && let Some(receiver_snippet) = receiver.span.get_text(cx) { if receiver_ty == target_ty && n_target_refs >= n_receiver_refs { span_lint_and_sugg( @@ -215,7 +215,7 @@ fn check_into_iter_call_arg( && let parent_ty = cx.typeck_results().expr_ty(parent) && implements_trait(cx, parent_ty, iterator_trait_id, &[]) && let Some(item_ty) = get_iterator_item_ty(cx, parent_ty) - && let Some(receiver_snippet) = receiver.span.get_source_text(cx) + && let Some(receiver_snippet) = receiver.span.get_text(cx) // If the receiver is a `Cow`, we can't remove the `into_owned` generally, see https://github.com/rust-lang/rust-clippy/issues/13624. && !cx.typeck_results().expr_ty(receiver).is_diag_item(cx, sym::Cow) // Calling `iter()` on a temporary object can lead to false positives. #14242 @@ -311,8 +311,8 @@ fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { if let Some(parent) = get_parent_expr(cx, expr) && let Some((sym::split, argument_expr)) = get_fn_name_and_arg(cx, parent) - && let Some(receiver_snippet) = receiver.span.get_source_text(cx) - && let Some(arg_snippet) = argument_expr.span.get_source_text(cx) + && let Some(receiver_snippet) = receiver.span.get_text(cx) + && let Some(arg_snippet) = argument_expr.span.get_text(cx) { // We may end-up here because of an expression like `x.to_string().split(…)` where the type of `x` // implements `AsRef` but does not implement `Deref`. In this case, we have to @@ -409,7 +409,7 @@ fn check_other_call_arg<'tcx>( None } && can_change_type(cx, maybe_arg, receiver_ty) - && let Some(receiver_snippet) = receiver.span.get_source_text(cx) + && let Some(receiver_snippet) = receiver.span.get_text(cx) { span_lint_and_sugg( cx, @@ -710,7 +710,7 @@ fn check_if_applicable_to_argument<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'tcx && let arg_ty = arg_ty.peel_refs() // For now we limit this lint to `String` and `Vec`. && (is_str_and_string(cx, arg_ty, original_arg_ty) || is_slice_and_vec(cx, arg_ty, original_arg_ty)) - && let Some(snippet) = caller.span.get_source_text(cx) + && let Some(snippet) = caller.span.get_text(cx) { span_lint_and_sugg( cx, diff --git a/clippy_lints/src/misc_early/unneeded_field_pattern.rs b/clippy_lints/src/misc_early/unneeded_field_pattern.rs index b2ee3f0c24f1..5bc437cf24f4 100644 --- a/clippy_lints/src/misc_early/unneeded_field_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_field_pattern.rs @@ -59,7 +59,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { .iter() .filter_map(|f| match f.pat.kind { PatKind::Wild => None, - _ => f.span.get_source_text(cx), + _ => f.span.get_text(cx), }) .format(", "), )); diff --git a/clippy_lints/src/missing_enforced_import_rename.rs b/clippy_lints/src/missing_enforced_import_rename.rs index c1c6ff13c6c5..14c6b28c253f 100644 --- a/clippy_lints/src/missing_enforced_import_rename.rs +++ b/clippy_lints/src/missing_enforced_import_rename.rs @@ -78,7 +78,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) = span_without_semi.get_source_text(cx) + && let Some(snip) = span_without_semi.get_text(cx) && let Some(import) = match snip.split_once(" as ") { None => Some(snip.as_str()), Some((import, rename)) => { diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index b0ba6ea1d993..9b2ece9bb9ad 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -42,7 +42,7 @@ impl EarlyLintPass for NeedlessElse { && !else_clause.span.from_expansion() && block.stmts.is_empty() && let range = (then_block.span.hi()..expr.span.hi()).trim_start(cx) - && range.clone().check_source_text(cx, |src| { + && range.clone().check_text(cx, |src| { // Ignore else blocks that contain comments or #[cfg]s !src.contains(['/', '#']) }) diff --git a/clippy_lints/src/needless_ifs.rs b/clippy_lints/src/needless_ifs.rs index 01b78fb05903..f887bafb9509 100644 --- a/clippy_lints/src/needless_ifs.rs +++ b/clippy_lints/src/needless_ifs.rs @@ -47,7 +47,7 @@ impl LateLintPass<'_> for NeedlessIfs { && block.stmts.is_empty() && block.expr.is_none() && !expr.span.in_external_macro(cx.sess().source_map()) - && then.span.check_source_text(cx, |src| { + && then.span.check_text(cx, |src| { // Ignore // - empty macro expansions // - empty reptitions in macro expansions @@ -57,7 +57,7 @@ impl LateLintPass<'_> for NeedlessIfs { .all(|ch| matches!(ch, b'{' | b'}') || ch.is_ascii_whitespace()) }) && let Some(cond_span) = walk_span_to_context(cond.span, expr.span.ctxt()) - && let Some(cond_snippet) = cond_span.get_source_text(cx) + && let Some(cond_snippet) = cond_span.get_text(cx) && !is_from_proc_macro(cx, expr) { span_lint_and_sugg( diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index 418ab8338b60..1d0ed5eed5d7 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -248,7 +248,7 @@ fn local_snippet_without_semicolon(cx: &LateContext<'_>, local: &LetStmt<'_>) -> None => local.pat.span.hi(), }); - span.get_source_text(cx) + span.get_text(cx) } fn check<'tcx>( diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 48e5e02d687b..13c9ab3ccbca 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -248,7 +248,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { for (span, suggestion) in clone_spans { diag.span_suggestion( span, - span.get_source_text(cx).map_or_else( + span.get_text(cx).map_or_else( || "change the call to".to_owned(), |src| format!("change `{src}` to"), ), @@ -275,7 +275,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { for (span, suggestion) in clone_spans { diag.span_suggestion( span, - span.get_source_text(cx).map_or_else( + span.get_text(cx).map_or_else( || "change the call to".to_owned(), |src| format!("change `{src}` to"), ), diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs index 600705e851f9..88caf1db05a8 100644 --- a/clippy_lints/src/no_effect.rs +++ b/clippy_lints/src/no_effect.rs @@ -280,8 +280,8 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { if let ExprKind::Index(..) = &expr.kind { 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) + && let Some(arr) = arr.span.get_text(cx) + && let Some(func) = func.span.get_text(cx) { span_lint_hir_and_then( cx, @@ -302,7 +302,7 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { } else { let mut snippet = String::new(); for e in reduced { - if let Some(snip) = e.span.get_source_text(cx) { + if let Some(snip) = e.span.get_text(cx) { snippet.push_str(&snip); snippet.push_str("; "); } else { diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 72ebe13562be..cf19cd9fc81d 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { && param.span.eq_ctxt(expr.span) && param .span - .check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) + .check_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) { show_error(cx, param); } @@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { && param.span.eq_ctxt(expr.span) && param .span - .check_source_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) + .check_text(cx, |src| !matches!(src.as_bytes(), [b'0', b'o' | b'b', ..])) { show_error(cx, param); } diff --git a/clippy_lints/src/nonstandard_macro_braces.rs b/clippy_lints/src/nonstandard_macro_braces.rs index 570a9dba63b3..2699d414d06e 100644 --- a/clippy_lints/src/nonstandard_macro_braces.rs +++ b/clippy_lints/src/nonstandard_macro_braces.rs @@ -126,7 +126,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) = callsite_span.get_source_text(cx) + && let Some(snip) = callsite_span.get_text(cx) // we must check only invocation sites // https://github.com/rust-lang/rust-clippy/issues/7422 && let Some(macro_args_str) = snip.strip_prefix(name).and_then(|snip| snip.strip_prefix('!')) diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 2ac9e010c69c..5735c23a62ac 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -86,7 +86,7 @@ impl EarlyLintPass for OctalEscapes { // Last check to make sure the source text matches what we read from the string. // Macros are involved somehow if this doesn't match. - if span.check_source_text(cx, |src| match *src.as_bytes() { + if span.check_text(cx, |src| match *src.as_bytes() { [b'\\', b'0', lo] => lo == c_lo, [b'\\', b'0', hi, lo] => hi == c_hi && lo == c_lo, _ => false, diff --git a/clippy_lints/src/operators/assign_op_pattern.rs b/clippy_lints/src/operators/assign_op_pattern.rs index d2b08bee8c94..e68cd9dc0674 100644 --- a/clippy_lints/src/operators/assign_op_pattern.rs +++ b/clippy_lints/src/operators/assign_op_pattern.rs @@ -74,8 +74,8 @@ pub(super) fn check<'tcx>( expr.span, "manual implementation of an assign operation", |diag| { - if let Some(snip_a) = assignee.span.get_source_text(cx) - && let Some(snip_r) = rhs.span.get_source_text(cx) + if let Some(snip_a) = assignee.span.get_text(cx) + && let Some(snip_r) = rhs.span.get_text(cx) { diag.span_suggestion( expr.span, diff --git a/clippy_lints/src/operators/misrefactored_assign_op.rs b/clippy_lints/src/operators/misrefactored_assign_op.rs index 06f7cfec05ce..c12c333cbf0a 100644 --- a/clippy_lints/src/operators/misrefactored_assign_op.rs +++ b/clippy_lints/src/operators/misrefactored_assign_op.rs @@ -42,8 +42,8 @@ fn lint_misrefactored_assign_op( expr.span, "variable appears on both sides of an assignment operation", |diag| { - if let Some(snip_a) = assignee.span.get_source_text(cx) - && let Some(snip_r) = rhs_other.span.get_source_text(cx) + if let Some(snip_a) = assignee.span.get_text(cx) + && let Some(snip_r) = rhs_other.span.get_text(cx) { let a = &sugg::Sugg::hir(cx, assignee, ".."); let r = &sugg::Sugg::hir(cx, rhs, ".."); diff --git a/clippy_lints/src/operators/needless_bitwise_bool.rs b/clippy_lints/src/operators/needless_bitwise_bool.rs index 8f41ade58313..35c113addd8d 100644 --- a/clippy_lints/src/operators/needless_bitwise_bool.rs +++ b/clippy_lints/src/operators/needless_bitwise_bool.rs @@ -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) = lhs.span.get_source_text(cx) - && let Some(rhs_snip) = rhs.span.get_source_text(cx) + if let Some(lhs_snip) = lhs.span.get_text(cx) + && let Some(rhs_snip) = rhs.span.get_text(cx) { let sugg = format!("{lhs_snip} {op_str} {rhs_snip}"); diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable); diff --git a/clippy_lints/src/pathbuf_init_then_push.rs b/clippy_lints/src/pathbuf_init_then_push.rs index d26aa2577816..473718c5419f 100644 --- a/clippy_lints/src/pathbuf_init_then_push.rs +++ b/clippy_lints/src/pathbuf_init_then_push.rs @@ -73,7 +73,7 @@ impl PathbufPushSearcher<'_> { && let Some(arg) = self.arg && let ExprKind::Lit(x) = arg.kind && let LitKind::Str(_, StrStyle::Cooked) = x.node - && let Some(s) = arg.span.get_source_text(cx) + && let Some(s) = arg.span.get_text(cx) { Some(format!(" = PathBuf::from({s});")) } else { @@ -83,8 +83,8 @@ impl PathbufPushSearcher<'_> { fn gen_pathbuf_join(&self, cx: &LateContext<'_>) -> Option { let arg = self.arg?; - let arg_str = arg.span.get_source_text(cx)?; - let init_val = self.init_val.span.get_source_text(cx)?; + let arg_str = arg.span.get_text(cx)?; + let init_val = self.init_val.span.get_text(cx)?; Some(format!(" = {init_val}.join({arg_str});")) } diff --git a/clippy_lints/src/ptr/ptr_arg.rs b/clippy_lints/src/ptr/ptr_arg.rs index 50a6bdee1c29..506f0e1527ec 100644 --- a/clippy_lints/src/ptr/ptr_arg.rs +++ b/clippy_lints/src/ptr/ptr_arg.rs @@ -50,7 +50,7 @@ pub(super) fn check_body<'tcx>( .chain(result.replacements.iter().map(|r| { ( r.expr_span, - format!("{}{}", r.self_span.get_source_text(cx).unwrap(), r.replacement), + format!("{}{}", r.self_span.get_text(cx).unwrap(), r.replacement), ) })) .collect(), @@ -147,7 +147,7 @@ impl fmt::Display for DerefTyDisplay<'_, '_> { DerefTy::Path => f.write_str("Path"), DerefTy::Slice(hir_ty, ty) => { f.write_char('[')?; - match hir_ty.and_then(|s| s.get_source_text(self.0)) { + match hir_ty.and_then(|s| s.get_text(self.0)) { Some(s) => f.write_str(&s)?, None => ty.fmt(f)?, } @@ -270,7 +270,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( diag.span_suggestion( hir_ty.span, "change this to", - match ty.span().get_source_text(cx) { + match ty.span().get_text(cx) { Some(s) => format!("&{}{s}", mutability.prefix_str()), None => format!("&{}{}", mutability.prefix_str(), args.type_at(1)), }, diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 82e88b1453b4..7ccdac4c3344 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -288,7 +288,7 @@ fn check_possible_range_contains( if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind && op == lhs_op.node && let new_span = Span::new(new_lhs.span.lo(), right.span.hi(), expr.span.ctxt(), expr.span.parent()) - && new_span.check_source_text(cx, |src| { + && new_span.check_text(cx, |src| { // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong src.matches('(').count() == src.matches(')').count() }) diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs index b29810a5c013..9cb5854aa2a2 100644 --- a/clippy_lints/src/raw_strings.rs +++ b/clippy_lints/src/raw_strings.rs @@ -72,7 +72,7 @@ impl EarlyLintPass for RawStrings { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::FormatArgs(format_args) = &expr.kind && !format_args.span.in_external_macro(cx.sess().source_map()) - && format_args.span.check_source_text(cx, |src| src.starts_with('r')) + && format_args.span.check_text(cx, |src| src.starts_with('r')) && let Some(str) = snippet_opt(cx.sess(), format_args.span) && let count_hash = str.bytes().skip(1).take_while(|b| *b == b'#').count() && let Some(str) = str.get(count_hash + 2..str.len() - count_hash - 1) @@ -95,7 +95,7 @@ impl EarlyLintPass for RawStrings { _ => return, } && !expr.span.in_external_macro(cx.sess().source_map()) - && expr.span.check_source_text(cx, |src| src.starts_with(prefix)) + && expr.span.check_text(cx, |src| src.starts_with(prefix)) { self.check_raw_string(cx, lit.symbol.as_str(), expr.span, prefix, max, lit.kind.descr()); } diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 6898332f282b..e3f18c33c56b 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -214,7 +214,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { .unwrap_crate_local() .lint_root; - if let Some(snip) = span.get_source_text(cx) + if let Some(snip) = span.get_text(cx) && let Some(dot) = snip.rfind('.') { let sugg_span = span.with_lo(span.lo() + BytePos(u32::try_from(dot).unwrap())); diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 80d910442902..ef8dac42e91d 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -190,7 +190,7 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: ®ex_syntax::Error, unescape }; if let Some((primary, auxiliary, kind)) = parts - && let Some(literal_snippet) = base.get_source_text(cx) + && let Some(literal_snippet) = base.get_text(cx) && let Some(inner) = literal_snippet.get(offset as usize..) // Only convert to native rustc spans if the parsed regex matches the // source snippet exactly, to ensure the span offsets are correct diff --git a/clippy_lints/src/returns/let_and_return.rs b/clippy_lints/src/returns/let_and_return.rs index 01b0279462e8..aeb6d45b0820 100644 --- a/clippy_lints/src/returns/let_and_return.rs +++ b/clippy_lints/src/returns/let_and_return.rs @@ -38,7 +38,7 @@ pub(super) fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>) |err| { err.span_label(local.span, "unnecessary `let` binding"); - if let Some(src) = initexpr.span.get_source_text(cx) { + if let Some(src) = initexpr.span.get_text(cx) { let sugg = if binary_expr_needs_parentheses(initexpr) { if has_enclosing_paren(&src) { src.to_owned() diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs index d7d77097a490..786ecc0b3ab5 100644 --- a/clippy_lints/src/semicolon_block.rs +++ b/clippy_lints/src/semicolon_block.rs @@ -92,7 +92,7 @@ impl SemicolonBlock { // ({ 0 }); // if we remove this `;`, this will parse as a `({ 0 })(5);` function call // (5); // } - if remove_span.check_source_text(cx, |src| src.contains(')')) { + if remove_span.check_text(cx, |src| src.contains(')')) { return; } diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs index 0e72213757df..ecd1abe3c599 100644 --- a/clippy_lints/src/single_range_in_vec_init.rs +++ b/clippy_lints/src/single_range_in_vec_init.rs @@ -93,7 +93,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit { if inner_expr.span.is_desugaring(DesugaringKind::RangeExpr) && let ty = cx.typeck_results().expr_ty(start.expr) - && let Some(snippet) = span.get_source_text(cx) + && let Some(snippet) = span.get_text(cx) // `is_from_proc_macro` will skip any `vec![]`. Let's not! && snippet.starts_with(suggested_type.starts_with()) && snippet.ends_with(suggested_type.ends_with()) diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 31f66792dc06..59612131382e 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -205,10 +205,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { bounds_span = bounds_span.to(bound.span); } - let fixed_trait_snippet = unique_traits - .iter() - .filter_map(|b| b.span.get_source_text(cx)) - .join(" + "); + let fixed_trait_snippet = unique_traits.iter().filter_map(|b| b.span.get_text(cx)).join(" + "); span_lint_and_sugg( cx, @@ -442,7 +439,7 @@ fn rollup_traits<'cx, 'tcx>( let traits = comparable_bounds .iter() - .filter_map(|&(_, span)| span.get_source_text(cx)) + .filter_map(|&(_, span)| span.get_text(cx)) .join(" + "); span_lint_and_sugg( diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index c9d1ffe778ae..66891d50da1f 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -85,7 +85,7 @@ fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_ && block.expr.is_none() && let Some(last_stmt) = block.stmts.iter().last() && let StmtKind::Semi(last_expr) = last_stmt.kind - && let Some(snip) = last_expr.span.get_source_text(cx) + && let Some(snip) = last_expr.span.get_text(cx) { Some((last_stmt.span, snip)) } else { @@ -117,7 +117,7 @@ fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_ .filter_map(|arg| get_expr_snippet_with_type_certainty(cx, arg)) .collect(); - if let Some(call_snippet) = expr.span.get_source_text(cx) { + if let Some(call_snippet) = expr.span.get_text(cx) { if arg_snippets_without_redundant_exprs.is_empty() && let suggestions = args_to_recover .iter() diff --git a/clippy_lints/src/useless_vec.rs b/clippy_lints/src/useless_vec.rs index 352fd05ee159..828b1a203e18 100644 --- a/clippy_lints/src/useless_vec.rs +++ b/clippy_lints/src/useless_vec.rs @@ -285,10 +285,10 @@ impl SuggestedType { assert!(args_span.is_none_or(|s| !s.from_expansion())); assert!(len_span.is_none_or(|s| !s.from_expansion())); - let maybe_args = args_span.map(|sp| sp.get_source_text(cx).expect("spans are always crate-local")); + let maybe_args = args_span.map(|sp| sp.get_text(cx).expect("spans are always crate-local")); let maybe_args = maybe_args.as_deref().unwrap_or_default(); let maybe_len = len_span - .map(|sp| sp.get_source_text(cx).expect("spans are always crate-local")) + .map(|sp| sp.get_text(cx).expect("spans are always crate-local")) .map(|st| format!("; {st}")) .unwrap_or_default(); diff --git a/clippy_lints/src/utils/format_args_collector.rs b/clippy_lints/src/utils/format_args_collector.rs index 8f5014d1e3ad..ee1729750f2e 100644 --- a/clippy_lints/src/utils/format_args_collector.rs +++ b/clippy_lints/src/utils/format_args_collector.rs @@ -80,7 +80,7 @@ fn has_span_from_proc_macro(cx: &EarlyContext<'_>, args: &FormatArgs) -> bool { .tuple_windows() .map(|(start, end)| start.between(end)) .all(|sp| { - sp.check_source_text(cx, |src| { + sp.check_text(cx, |src| { // text should be either `, name` or `, name =` let mut iter = tokenize(src, FrontmatterAllowed::No).filter(|t| { !matches!( diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs index 1a3d616121cb..f825381cf29a 100644 --- a/clippy_lints/src/visibility.rs +++ b/clippy_lints/src/visibility.rs @@ -145,5 +145,5 @@ impl EarlyLintPass for Visibility { } fn is_from_proc_macro(cx: &EarlyContext<'_>, span: Span) -> bool { - !span.check_source_text(cx, |src| src.starts_with("pub")) + !span.check_text(cx, |src| src.starts_with("pub")) } diff --git a/clippy_lints/src/write/literal.rs b/clippy_lints/src/write/literal.rs index 9711410ef885..df31fad8615e 100644 --- a/clippy_lints/src/write/literal.rs +++ b/clippy_lints/src/write/literal.rs @@ -48,7 +48,7 @@ pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) && let Some(arg) = format_args.arguments.by_index(index) && let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind && !arg.expr.span.from_expansion() - && let Some(value_string) = arg.expr.span.get_source_text(cx) + && let Some(value_string) = arg.expr.span.get_text(cx) { let (replacement, replace_raw) = match lit.kind { LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) { @@ -71,7 +71,7 @@ pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) _ => continue, }; - let Some(format_string_snippet) = format_args.span.get_source_text(cx) else { + let Some(format_string_snippet) = format_args.span.get_text(cx) else { continue; }; let format_string_is_raw = format_string_snippet.starts_with('r'); diff --git a/clippy_lints/src/write/with_newline.rs b/clippy_lints/src/write/with_newline.rs index 53109f4014c8..15cc29818aec 100644 --- a/clippy_lints/src/write/with_newline.rs +++ b/clippy_lints/src/write/with_newline.rs @@ -48,7 +48,7 @@ pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: format!("using `{name}!()` with a format string that ends in a single newline"), |diag| { let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!'); - let Some(format_snippet) = format_string_span.get_source_text(cx) else { + let Some(format_snippet) = format_string_span.get_text(cx) else { return; }; diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index e7e654373e5e..0b4df91b71b2 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -109,7 +109,7 @@ pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: AdtDef<'_>) -> bool { /// Checks whether the given span contains a `#[cfg(..)]` attribute pub fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { - s.check_source_text(cx, |src| { + s.check_text(cx, |src| { let mut iter = tokenize_with_text(src); // Search for the token sequence [`#`, `[`, `cfg`] diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index e0cabb6e2dc3..015d1982534a 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -687,7 +687,7 @@ fn reduce_exprkind<'hir>(cx: &LateContext<'_>, kind: &'hir ExprKind<'hir>) -> &' ([], None) if block.span.is_empty() => &ExprKind::Tup(&[]), // `{}` => `()` ([], None) - if block.span.check_source_text(cx, |src| { + if block.span.check_text(cx, |src| { tokenize(src, FrontmatterAllowed::No) .map(|t| t.kind) .filter(|t| { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 5bdf060a05d9..6b92a180752d 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2763,7 +2763,7 @@ pub fn span_contains_comment<'sm>(sm: impl HasSourceMap<'sm>, span: Span) -> boo /// This is useful to determine if there are any actual code tokens in the span that are omitted in /// the late pass, such as platform-specific code. pub fn span_contains_non_whitespace<'sm>(cx: impl HasSourceMap<'sm>, span: Span, skip_comments: bool) -> bool { - matches!(span.get_source_text(cx), Some(snippet) if tokenize_with_text(&snippet).any(|(token, _, _)| + matches!(span.get_text(cx), Some(snippet) if tokenize_with_text(&snippet).any(|(token, _, _)| match token { TokenKind::Whitespace => false, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => !skip_comments, diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index cdae3e07bc1d..dab2a19af41b 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -109,7 +109,7 @@ impl IntoSpan for Range { pub trait SpanExt: SpanRange { /// Attempts to get a handle to the source text. Returns `None` if either the span is malformed, /// or the source text is not accessible. - fn get_source_text<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { + fn get_text<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { get_source_range(sm.source_map(), self.into_range()).and_then(SourceText::new) } @@ -127,7 +127,7 @@ pub trait SpanExt: SpanRange { /// Checks if the referenced source text satisfies the given predicate. Returns `false` if the /// source text cannot be retrieved. - fn check_source_text<'sm>(self, sm: impl HasSourceMap<'sm>, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { + fn check_text<'sm>(self, sm: impl HasSourceMap<'sm>, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { self.with_source_text(sm, pred).unwrap_or(false) } From 51934e246e75ddcf66adf36267d2dfa860ee7f4a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 15 Nov 2025 10:06:22 -0500 Subject: [PATCH 4/5] Rework `clippy_utils::source`. Rename `get_source_text` and `check_source_text` to `get_text` and `check_text`. --- clippy_lints/src/cognitive_complexity.rs | 12 +- clippy_lints/src/collapsible_if.rs | 30 +- clippy_lints/src/double_parens.rs | 17 +- clippy_lints/src/ifs/branches_sharing_code.rs | 19 +- clippy_lints/src/implicit_hasher.rs | 44 +- clippy_lints/src/ineffective_open_options.rs | 13 +- clippy_lints/src/let_with_type_underscore.rs | 12 +- clippy_lints/src/lib.rs | 28 +- .../src/loops/unused_enumerate_index.rs | 9 +- clippy_lints/src/methods/manual_inspect.rs | 37 +- clippy_lints/src/multiple_bound_locations.rs | 6 +- clippy_lints/src/mutex_atomic.rs | 21 +- clippy_lints/src/needless_else.rs | 19 +- clippy_lints/src/ranges.rs | 27 +- .../missing_transmute_annotations.rs | 29 +- clippy_lints/src/unnecessary_mut_passed.rs | 42 +- clippy_lints/src/unused_unit.rs | 45 +- clippy_utils/src/consts.rs | 10 +- clippy_utils/src/hir_utils.rs | 72 +- clippy_utils/src/lib.rs | 19 +- clippy_utils/src/source.rs | 1446 ++++++++++++++--- 21 files changed, 1507 insertions(+), 450 deletions(-) diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 287b3fd1ce96..30c07695f8ac 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{IntoSpan, SpanExt}; +use clippy_utils::source::{FileRangeExt, SpanExt, StrExt}; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{LimitStack, get_async_fn_body, sym}; use core::ops::ControlFlow; @@ -109,12 +109,12 @@ impl CognitiveComplexity { let fn_span = match kind { FnKind::ItemFn(ident, _, _) | FnKind::Method(ident, _) => ident.span, FnKind::Closure => { - let header_span = body_span.with_hi(decl.output.span().lo()); - if let Some(range) = header_span.map_range(cx, |_, src, range| { - let mut idxs = src.get(range.clone())?.match_indices('|'); - Some(range.start + idxs.next()?.0..range.start + idxs.next()?.0 + 1) + if let Some(sp) = body_span.map_range(cx, |scx, range| { + range + .shrink_end_to(scx, decl.output.span().lo_ctxt())? + .map_range_text(scx, |src| src.find_bounded_inclusive('|')) }) { - range.with_ctxt(header_span.ctxt()) + sp } else { return; } diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs index 354c39ab7b70..ac4841043a20 100644 --- a/clippy_lints/src/collapsible_if.rs +++ b/clippy_lints/src/collapsible_if.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::Msrv; -use clippy_utils::source::{IntoSpan as _, SpanExt, snippet, snippet_block_with_applicability}; +use clippy_utils::source::{FileRangeExt, SpanExt, StrExt, snippet, snippet_block_with_applicability}; use clippy_utils::{can_use_if_let_chains, span_contains_non_whitespace, sym, tokenize_with_text}; use rustc_ast::{BinOpKind, MetaItemInner}; use rustc_errors::Applicability; @@ -113,15 +113,15 @@ impl CollapsibleIf { span_extract_keyword(cx.tcx.sess.source_map(), up_to_else, "else") && let Some(else_if_keyword_span) = span_extract_keyword(cx.tcx.sess.source_map(), else_before_if, "if") + && let Some(else_keyword_span) = + else_keyword_span.map_range(cx, |scx, range| range.with_leading_whitespace(scx)) + && let Some([else_open_bracket, else_closing_bracket]) = + else_block.span.map_range(cx, |scx, range| { + range + .map_range_text(scx, |src| src.get_prefix_suffix('{', '}'))? + .try_map(|r| r.with_leading_whitespace(scx)) + }) { - let else_keyword_span = else_keyword_span.with_leading_whitespace(cx).into_span(); - let else_open_bracket = else_block.span.split_at(1).0.with_leading_whitespace(cx).into_span(); - let else_closing_bracket = { - let end = else_block.span.shrink_to_hi(); - end.with_lo(end.lo() - BytePos(1)) - .with_leading_whitespace(cx) - .into_span() - }; let sugg = vec![ // Remove the outer else block `else` (else_keyword_span, String::new()), @@ -170,6 +170,11 @@ impl CollapsibleIf { && self.eligible_condition(cx, check_inner) && expr.span.eq_ctxt(inner.span) && self.check_significant_tokens_and_expect_attrs(cx, then, inner, sym::collapsible_if) + && let Some([then_open_bracket, then_closing_bracket]) = then.span.map_range(cx, |scx, range| { + range + .map_range_text(scx, |src| src.get_prefix_suffix('{', '}'))? + .try_map(|r| r.with_leading_whitespace(scx)) + }) { span_lint_hir_and_then( cx, @@ -178,13 +183,6 @@ impl CollapsibleIf { expr.span, "this `if` statement can be collapsed", |diag| { - let then_open_bracket = then.span.split_at(1).0.with_leading_whitespace(cx).into_span(); - let then_closing_bracket = { - let end = then.span.shrink_to_hi(); - end.with_lo(end.lo() - BytePos(1)) - .with_leading_whitespace(cx) - .into_span() - }; let (paren_start, inner_if_span, paren_end) = peel_parens(cx.tcx.sess.source_map(), inner.span); let inner_if = inner_if_span.split_at(2).0; let mut sugg = vec![ diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index f442575749ac..5589fba49280 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanExt, snippet_with_applicability, snippet_with_context}; +use clippy_utils::source::{FileRangeExt, SpanExt, snippet_with_applicability, snippet_with_context}; use rustc_ast::ast::{Expr, ExprKind, MethodCall}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; @@ -104,16 +104,11 @@ impl EarlyLintPass for DoubleParens { /// Check that the span does indeed look like `( (..) )` fn check_source(cx: &EarlyContext<'_>, inner: &Expr) -> bool { - if let Some(sfr) = inner.span.get_source_range(cx) - // this is the same as `SourceFileRange::as_str`, but doesn't apply the range right away, because - // we're interested in the source code outside it - && let Some(src) = sfr.sf.src.as_ref().map(|src| src.as_str()) - && let Some((start, outer_after_inner)) = src.split_at_checked(sfr.range.end) - && let Some((outer_before_inner, inner)) = start.split_at_checked(sfr.range.start) - && outer_before_inner.trim_end().ends_with('(') - && inner.starts_with('(') - && inner.ends_with(')') - && outer_after_inner.trim_start().starts_with(')') + if let Some((scx, range)) = inner.span.mk_edit_cx(cx) + && let Some(range) = range.with_trailing_whitespace(&scx) + && let Some(range) = range.with_leading_whitespace(&scx) + && let Some(range) = range.with_trailing_match(&scx, ')') + && range.with_leading_match(&scx, '(').is_some() { true } else { diff --git a/clippy_lints/src/ifs/branches_sharing_code.rs b/clippy_lints/src/ifs/branches_sharing_code.rs index 755a2a61d894..88f1a7477005 100644 --- a/clippy_lints/src/ifs/branches_sharing_code.rs +++ b/clippy_lints/src/ifs/branches_sharing_code.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::{IntoSpan, SpanExt, first_line_of_span, indent_of, reindent_multiline, snippet}; +use clippy_utils::source::{FileRangeExt, SpanExt, first_line_of_span, indent_of, reindent_multiline, snippet}; use clippy_utils::ty::needs_ordered_drop; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{ @@ -44,21 +44,18 @@ pub(super) fn check<'tcx>( let suggestion = reindent_multiline(&suggestion, true, cond_indent); (replace_span, suggestion) }); - let end_suggestion = res.end_span(last_block, sm).map(|span| { + let end_suggestion = res.end_span(last_block, sm).and_then(|span| { let moved_snipped = reindent_multiline(&snippet(cx, span, "_"), true, None); let indent = indent_of(cx, expr.span.shrink_to_hi()); let suggestion = "}\n".to_string() + &moved_snipped; let suggestion = reindent_multiline(&suggestion, true, indent); - let span = span.with_hi(last_block.span.hi()); - // Improve formatting if the inner block has indentation (i.e. normal Rust formatting) - let span = span - .map_range(cx, |_, src, range| { - (range.start > 4 && src.get(range.start - 4..range.start)? == " ") - .then_some(range.start - 4..range.end) - }) - .map_or(span, |range| range.with_ctxt(span.ctxt())); - (span, suggestion.clone()) + span.map_range(cx, |scx, range| { + let range = range.extend_end_to(scx, last_block.span.hi_ctxt())?; + // Improve formatting if the inner block has indentation (i.e. normal Rust formatting) + Some(range.clone().with_leading_match(scx, " ").unwrap_or(range)) + }) + .map(|sp| (sp, suggestion)) }); let (span, msg, end_span) = match (&start_suggestion, &end_suggestion) { diff --git a/clippy_lints/src/implicit_hasher.rs b/clippy_lints/src/implicit_hasher.rs index cefefaccb189..b994e5618965 100644 --- a/clippy_lints/src/implicit_hasher.rs +++ b/clippy_lints/src/implicit_hasher.rs @@ -13,7 +13,7 @@ use rustc_session::declare_lint_pass; use rustc_span::Span; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::{IntoSpan, SpanExt, snippet}; +use clippy_utils::source::{FileRangeExt, SpanExt, snippet}; use clippy_utils::sym; declare_clippy_lint! { @@ -118,16 +118,19 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { return; } - let generics_suggestion_span = impl_.generics.span.substitute_dummy({ - let range = (item.span.lo()..target.span().lo()).map_range(cx, |_, src, range| { - Some(src.get(range.clone())?.find("impl")? + 4..range.end) - }); - if let Some(range) = range { - range.with_ctxt(item.span.ctxt()) + let generics_suggestion_span = if impl_.generics.span.is_dummy() { + if let Some(sp) = item.span.map_range(cx, |scx, range| { + range + .shrink_end_to(scx, target.span().lo_ctxt())? + .map_range_text(scx, |src| src.split_once("impl").map(|(_, x)| x)) + }) { + sp } else { return; } - }); + } else { + impl_.generics.span + }; let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target); for item in impl_.items.iter().map(|&item| cx.tcx.hir_impl_item(item)) { @@ -164,19 +167,24 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher { if generics.span.from_expansion() { continue; } - let generics_suggestion_span = generics.span.substitute_dummy({ - let range = - (item.span.lo()..body.params[0].pat.span.lo()).map_range(cx, |_, src, range| { - let (pre, post) = src.get(range.clone())?.split_once("fn")?; - let pos = post.find('(')? + pre.len() + 2; - Some(pos..pos) - }); - if let Some(range) = range { - range.with_ctxt(item.span.ctxt()) + + let generics_suggestion_span = if generics.span.is_dummy() { + if let Some(sp) = item.span.map_range(cx, |scx, range| { + range + .shrink_end_to(scx, body.params[0].pat.span.lo_ctxt())? + .map_range_text(scx, |src| { + src.split_once("fn") + .and_then(|(_, x)| x.split_once('(')) + .map(|(_, x)| x) + }) + }) { + sp } else { return; } - }); + } else { + generics.span + }; let mut ctr_vis = ImplicitHasherConstructorVisitor::new(cx, target); ctr_vis.visit_body(body); diff --git a/clippy_lints/src/ineffective_open_options.rs b/clippy_lints/src/ineffective_open_options.rs index aae847031bf6..d91501a42acd 100644 --- a/clippy_lints/src/ineffective_open_options.rs +++ b/clippy_lints/src/ineffective_open_options.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::res::MaybeDef; -use clippy_utils::source::SpanExt; +use clippy_utils::source::{FileRangeExt, SpanExt}; use clippy_utils::{peel_blocks, peel_hir_expr_while, sym}; use rustc_ast::LitKind; use rustc_errors::Applicability; @@ -68,15 +68,10 @@ impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions { match name.ident.name { sym::append => append = true, sym::write - if let Some(range) = call_span.map_range(cx, |_, text, range| { - if text.get(..range.start)?.ends_with('.') { - Some(range.start - 1..range.end) - } else { - None - } - }) => + if let Some(sp) = + call_span.map_range(cx, |scx, range| range.with_leading_match(scx, '.')) => { - write = Some(call_span.with_lo(range.start)); + write = Some(sp); }, _ => {}, } diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs index 2390c1ad95f8..42a9dcfab57f 100644 --- a/clippy_lints/src/let_with_type_underscore.rs +++ b/clippy_lints/src/let_with_type_underscore.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{IntoSpan, SpanExt}; +use clippy_utils::source::{FileRangeExt, SpanExt}; use rustc_ast::{Local, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; @@ -34,12 +34,12 @@ impl EarlyLintPass for UnderscoreTyped { && let sm = cx.sess().source_map() && !local.span.in_external_macro(sm) && !is_from_proc_macro(cx, &**ty) + && let Some(span_to_remove) = ty.span.map_range(cx, |scx, range| { + range.with_leading_whitespace(scx)? + .with_leading_match(scx, ':')? + .with_leading_whitespace(scx) + }) { - let span_to_remove = sm - .span_extend_to_prev_char_before(ty.span, ':', true) - .with_leading_whitespace(cx) - .into_span(); - span_lint_and_then( cx, LET_WITH_TYPE_UNDERSCORE, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 230d83dacc95..0b7615f9f1da 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1,15 +1,19 @@ -#![feature(array_windows)] -#![feature(box_patterns)] -#![feature(macro_metavar_expr_concat)] -#![feature(f128)] -#![feature(f16)] -#![feature(if_let_guard)] -#![feature(iter_intersperse)] -#![feature(iter_partition_in_place)] -#![feature(never_type)] -#![feature(rustc_private)] -#![feature(stmt_expr_attributes)] -#![feature(unwrap_infallible)] +#![feature( + array_try_map, + array_windows, + box_patterns, + f128, + f16, + if_let_guard, + iter_intersperse, + iter_partition_in_place, + macro_metavar_expr_concat, + never_type, + rustc_private, + stmt_expr_attributes, + str_split_remainder, + unwrap_infallible +)] #![recursion_limit = "512"] #![allow( clippy::missing_docs_in_private_items, diff --git a/clippy_lints/src/loops/unused_enumerate_index.rs b/clippy_lints/src/loops/unused_enumerate_index.rs index 930644ca17d1..d0c40cb2f661 100644 --- a/clippy_lints/src/loops/unused_enumerate_index.rs +++ b/clippy_lints/src/loops/unused_enumerate_index.rs @@ -1,7 +1,7 @@ use super::UNUSED_ENUMERATE_INDEX; use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::res::{MaybeDef, MaybeTypeckRes}; -use clippy_utils::source::{SpanExt, walk_span_to_context}; +use clippy_utils::source::{FileRangeExt, SpanExt, walk_span_to_context}; use clippy_utils::{expr_or_init, pat_is_wild}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Pat, PatKind, TyKind}; @@ -26,13 +26,8 @@ pub(super) fn check<'tcx>( && !pat.span.from_expansion() && !idx_pat.span.from_expansion() && !inner_pat.span.from_expansion() - && let Some(enumerate_range) = enumerate_span.map_range(cx, |_, text, range| { - text.get(..range.start)? - .ends_with('.') - .then_some(range.start - 1..range.end) - }) + && let Some(enumerate_span) = enumerate_span.map_range(cx, |scx, range| range.with_leading_match(scx, '.')) { - let enumerate_span = Span::new(enumerate_range.start, enumerate_range.end, SyntaxContext::root(), None); span_lint_hir_and_then( cx, UNUSED_ENUMERATE_INDEX, diff --git a/clippy_lints/src/methods/manual_inspect.rs b/clippy_lints/src/methods/manual_inspect.rs index 9ef18875b1e7..40b297627d1d 100644 --- a/clippy_lints/src/methods/manual_inspect.rs +++ b/clippy_lints/src/methods/manual_inspect.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::{MaybeDef, MaybeResPath}; -use clippy_utils::source::{IntoSpan, SpanExt}; +use clippy_utils::source::{FileRangeExt, SpanExt, StrExt}; use clippy_utils::ty::get_field_by_name; use clippy_utils::visitors::{for_each_expr, for_each_expr_without_closures}; use clippy_utils::{ExprUseNode, expr_use_ctxt, sym}; @@ -100,18 +100,22 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: let mut addr_of_edits = Vec::with_capacity(delayed.len()); for x in delayed { match x { - UseKind::Return(s) => edits.push((s.with_leading_whitespace(cx).with_ctxt(s.ctxt()), String::new())), + UseKind::Return(s) => { + if let Some(sp) = s.map_range(cx, |scx, range| range.with_leading_whitespace(scx)) { + edits.push((sp, String::new())); + } else { + return; + } + }, UseKind::Borrowed(s) => { - let range = s.map_range(cx, |_, src, range| { - let src = src.get(range.clone())?; - let trimmed = src.trim_start_matches([' ', '\t', '\n', '\r', '(']); - trimmed.starts_with('&').then(|| { - let pos = range.start + src.len() - trimmed.len(); - pos..pos + 1 + if let Some(sp) = s.map_range(cx, |scx, range| { + range.map_range_text(scx, |src| { + src.trim_start_matches([' ', '\t', '\n', '\r', '(']) + .split_prefix('&') + .map(|[x, _]| x) }) - }); - if let Some(range) = range { - addr_of_edits.push((range.with_ctxt(s.ctxt()), String::new())); + }) { + addr_of_edits.push((sp, String::new())); } else { requires_copy = true; requires_deref = true; @@ -162,6 +166,9 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: && (!requires_copy || cx.type_is_copy_modulo_regions(arg_ty)) // This case could be handled, but a fair bit of care would need to be taken. && (!requires_deref || arg_ty.is_freeze(cx.tcx, cx.typing_env())) + && let Some(final_expr_span) = final_expr + .span + .map_range(cx, |scx, range| range.with_leading_whitespace(scx)) { if requires_deref { edits.push((param.span.shrink_to_lo(), "&".into())); @@ -174,13 +181,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: _ => return, }; edits.push((name_span, edit.to_string())); - edits.push(( - final_expr - .span - .with_leading_whitespace(cx) - .with_ctxt(final_expr.span.ctxt()), - String::new(), - )); + edits.push((final_expr_span, String::new())); let app = if edits.iter().any(|(s, _)| s.from_expansion()) { Applicability::MaybeIncorrect } else { diff --git a/clippy_lints/src/multiple_bound_locations.rs b/clippy_lints/src/multiple_bound_locations.rs index 6b6f56e70ea9..4383c1399ff2 100644 --- a/clippy_lints/src/multiple_bound_locations.rs +++ b/clippy_lints/src/multiple_bound_locations.rs @@ -54,10 +54,8 @@ impl EarlyLintPass for MultipleBoundLocations { match &clause.kind { WherePredicateKind::BoundPredicate(pred) => { if (!pred.bound_generic_params.is_empty() || !pred.bounds.is_empty()) - && let Some(Some(bound_span)) = pred - .bounded_ty - .span - .with_source_text(cx, |src| generic_params_with_bounds.get(src)) + && let Some(src) = pred.bounded_ty.span.get_text(cx) + && let Some(bound_span) = generic_params_with_bounds.get(&*src) { emit_lint(cx, *bound_span, pred.bounded_ty.span); } diff --git a/clippy_lints/src/mutex_atomic.rs b/clippy_lints/src/mutex_atomic.rs index ef2b3eadc8e3..fd19faae8ddd 100644 --- a/clippy_lints/src/mutex_atomic.rs +++ b/clippy_lints/src/mutex_atomic.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::res::MaybeDef; -use clippy_utils::source::{IntoSpan, SpanExt}; +use clippy_utils::source::{FileRangeExt, SpanExt}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::ty_from_hir_ty; use rustc_errors::{Applicability, Diag}; use rustc_hir::{self as hir, Expr, ExprKind, Item, ItemKind, LetStmt, QPath}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::Mutability; use rustc_middle::ty::{self, IntTy, Ty, UintTy}; use rustc_session::declare_lint_pass; @@ -150,13 +150,16 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty_ascription: &T suggs.push((ty_ascription.span, format!("std::sync::atomic::{atomic_name}"))); }, TypeAscriptionKind::Optional(Some(ty_ascription)) => { - // See https://github.com/rust-lang/rust-clippy/pull/15386 for why this is - // required - let colon_ascription = (cx.sess().source_map()) - .span_extend_to_prev_char_before(ty_ascription.span, ':', true) - .with_leading_whitespace(cx) - .into_span(); - suggs.push((colon_ascription, String::new())); + if let Some(sp) = ty_ascription.span.map_range(cx, |scx, range| { + range + .with_leading_whitespace(scx)? + .with_leading_match(scx, ':')? + .with_leading_whitespace(scx) + }) { + suggs.push((sp, String::new())); + } else { + return; + } }, TypeAscriptionKind::Optional(None) => {}, // nothing to remove/replace } diff --git a/clippy_lints/src/needless_else.rs b/clippy_lints/src/needless_else.rs index 9b2ece9bb9ad..288d1d9f1744 100644 --- a/clippy_lints/src/needless_else.rs +++ b/clippy_lints/src/needless_else.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{IntoSpan, SpanExt}; +use clippy_utils::source::{FileRangeExt, SpanExt}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; @@ -38,19 +38,26 @@ impl EarlyLintPass for NeedlessElse { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if let ExprKind::If(_, then_block, Some(else_clause)) = &expr.kind && let ExprKind::Block(block, _) = &else_clause.kind + && !then_block.span.from_expansion() && !expr.span.from_expansion() && !else_clause.span.from_expansion() && block.stmts.is_empty() - && let range = (then_block.span.hi()..expr.span.hi()).trim_start(cx) - && range.clone().check_text(cx, |src| { - // Ignore else blocks that contain comments or #[cfg]s - !src.contains(['/', '#']) + // Only take the span of `else { .. }` if no comments/cfgs/macros exist. + && let Some(lint_sp) = else_clause.span.map_range(cx, |scx, range| { + range.extend_start_to(scx, then_block.span.hi_ctxt())? + .map_range_text(scx, |src| { + let src = src.trim_start(); + (src.strip_prefix("else")? + .trim_start() + .strip_prefix('{')? + .trim_start() == "}").then_some(src) + }) }) { span_lint_and_sugg( cx, NEEDLESS_ELSE, - range.with_ctxt(expr.span.ctxt()), + lint_sp, "this `else` branch is empty", "you can remove it", String::new(), diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 7ccdac4c3344..fc2d9275caf8 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -3,7 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::res::MaybeResPath; -use clippy_utils::source::{SpanExt, snippet, snippet_with_applicability}; +use clippy_utils::source::{FileRangeExt, SpanExt, snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::implements_trait; use clippy_utils::{expr_use_ctxt, fn_def_id, get_parent_expr, higher, is_in_const_context, is_integer_const}; @@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::ty::{self, ClauseKind, GenericArgKind, PredicatePolarity, Ty}; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::{DesugaringKind, Span, sym}; +use rustc_span::{DesugaringKind, Span, SyntaxContext, sym}; use std::cmp::Ordering; declare_clippy_lint! { @@ -185,8 +185,12 @@ impl<'tcx> LateLintPass<'tcx> for Ranges { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Binary(ref op, l, r) = expr.kind && self.msrv.meets(cx, msrvs::RANGE_CONTAINS) + && let ctxt = expr.span.ctxt() + && l.span.ctxt() == ctxt + && r.span.ctxt() == ctxt + && !ctxt.in_external_macro(cx.tcx.sess.source_map()) { - check_possible_range_contains(cx, op.node, l, r, expr, expr.span); + check_possible_range_contains(cx, op.node, l, r, expr.span, expr.span.ctxt()); } check_exclusive_range_plus_one(cx, expr); @@ -200,8 +204,8 @@ fn check_possible_range_contains( op: BinOpKind, left: &Expr<'_>, right: &Expr<'_>, - expr: &Expr<'_>, span: Span, + ctxt: SyntaxContext, ) { if is_in_const_context(cx) { return; @@ -287,13 +291,16 @@ fn check_possible_range_contains( // the same operator precedence if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind && op == lhs_op.node - && let new_span = Span::new(new_lhs.span.lo(), right.span.hi(), expr.span.ctxt(), expr.span.parent()) - && new_span.check_text(cx, |src| { - // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong - src.matches('(').count() == src.matches(')').count() + && let new_lhs_data = new_lhs.span.data() + && new_lhs_data.ctxt == ctxt + && let Some(new_sp) = new_lhs_data.map_range(cx, |scx, range| { + range.extend_end_to(scx, right.span.hi_ctxt()).filter(|range| { + scx.get_text(range.clone()) + .is_some_and(|src| src.matches('(').count() == src.matches(')').count()) + }) }) { - check_possible_range_contains(cx, op, new_lhs, right, expr, new_span); + check_possible_range_contains(cx, op, new_lhs, right, new_sp, ctxt); } } @@ -523,7 +530,7 @@ fn check_range_switch<'tcx>( .to_string() }); let end = Sugg::hir_with_applicability(cx, y, "", &mut app).maybe_paren(); - match span.with_source_text(cx, |src| src.starts_with('(') && src.ends_with(')')) { + match span.get_text(cx).map(|src| src.starts_with('(') && src.ends_with(')')) { Some(true) => { diag.span_suggestion(span, "use", format!("({start}{operator}{end})"), app); }, diff --git a/clippy_lints/src/transmute/missing_transmute_annotations.rs b/clippy_lints/src/transmute/missing_transmute_annotations.rs index 8566d4cfeaab..ba21172ed79d 100644 --- a/clippy_lints/src/transmute/missing_transmute_annotations.rs +++ b/clippy_lints/src/transmute/missing_transmute_annotations.rs @@ -1,12 +1,10 @@ -use std::borrow::Cow; - use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanExt as _; +use clippy_utils::source::{SpanExt as _, display}; +use rustc_data_structures::either::Either; use rustc_errors::Applicability; use rustc_hir::{Expr, GenericArg, HirId, LetStmt, Node, Path, TyKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::Span; use crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS; @@ -84,9 +82,18 @@ pub(super) fn check<'tcx>( let to_ty_no_name = ty_cannot_be_named(to_ty); if from_ty_no_name || to_ty_no_name { let to_name = match (from_ty_no_name, to_ty_no_name) { - (true, false) => maybe_name_by_expr(cx, arg.span, "the origin type"), - (false, true) => "the destination type".into(), - _ => "the source and destination types".into(), + (true, false) => { + let data = arg.span.data(); + if data.hi.0 - data.lo.0 < 6 + && let Some(src) = data.get_text(cx) + { + Either::Left(display(move |f| write!(f, "`{src}`'s type"))) + } else { + Either::Right("the origin type") + } + }, + (false, true) => Either::Right("the destination type"), + _ => Either::Right("the source and destination types"), }; diag.help(format!( "consider giving {to_name} a name, and adding missing type annotations" @@ -110,11 +117,3 @@ fn ty_cannot_be_named(ty: Ty<'_>) -> bool { ty::Alias(ty::AliasTyKind::Opaque | ty::AliasTyKind::Inherent, _) ) } - -fn maybe_name_by_expr<'a>(cx: &LateContext<'_>, span: Span, default: &'a str) -> Cow<'a, str> { - span.with_source_text(cx, |name| { - (name.len() + 9 < default.len()).then_some(format!("`{name}`'s type").into()) - }) - .flatten() - .unwrap_or(default.into()) -} diff --git a/clippy_lints/src/unnecessary_mut_passed.rs b/clippy_lints/src/unnecessary_mut_passed.rs index 7c921fed3e9e..d0dd3076f850 100644 --- a/clippy_lints/src/unnecessary_mut_passed.rs +++ b/clippy_lints/src/unnecessary_mut_passed.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::SpanExt; +use clippy_utils::source::{FileRangeExt, SpanExt}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability}; use rustc_lint::{LateContext, LateLintPass}; @@ -85,34 +85,32 @@ fn check_arguments<'tcx>( let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs(); for (argument, parameter) in iter::zip(arguments, parameters) { if let ty::Ref(_, _, Mutability::Not) | ty::RawPtr(_, Mutability::Not) = parameter.kind() - && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, arg) = argument.kind + && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind + && let Some(mut_span) = argument.span.map_range(cx, |scx, range| { + range.map_range_text(scx, |src| { + src.trim_start_matches(|c: char| c.is_whitespace() || c == '(') + .strip_prefix('&') + .and_then(|s| { + // Get just the `mut` and surrounding whitespace. + s.trim_start() + .strip_prefix("mut") + .map(|x| &s[..s.len() - x.trim_start().len()]) + }) + }) + }) { - let applicability = Applicability::MachineApplicable; - - let span_to_remove = { - let span_until_arg = argument.span.until(arg.span); - if let Some(Some(ref_pos)) = span_until_arg.with_source_text(cx, |src| { - src - // we don't use `strip_prefix` here, because `argument` might be enclosed in parens, in - // which case `&` is no longer the prefix - .find('&') - // just a sanity check, in case some proc-macro messes up the spans - .filter(|ref_pos| src[*ref_pos..].contains("mut")) - }) && let Ok(lo) = u32::try_from(ref_pos + '&'.len_utf8()) - { - span_until_arg.split_at(lo).1 - } else { - return; - } - }; - span_lint_and_then( cx, UNNECESSARY_MUT_PASSED, argument.span, format!("the {fn_kind} `{name}` doesn't need a mutable reference"), |diag| { - diag.span_suggestion_verbose(span_to_remove, "remove this `mut`", String::new(), applicability); + diag.span_suggestion_verbose( + mut_span, + "remove this `mut`", + String::new(), + Applicability::MachineApplicable, + ); }, ); } diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index bb2ad9f92157..d745daaed4ab 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanExt, position_before_rarrow}; +use clippy_utils::source::{FileRangeExt, SpanExt}; use clippy_utils::{is_never_expr, is_unit_expr}; use rustc_ast::{Block, StmtKind}; use rustc_errors::Applicability; @@ -12,7 +12,7 @@ use rustc_hir::{ use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::edition::Edition; -use rustc_span::{BytePos, Pos as _, Span, sym}; +use rustc_span::{Span, sym}; declare_clippy_lint! { /// ### What it does @@ -78,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedUnit { return; } - lint_unneeded_unit_return(cx, hir_ty.span, span); + lint_unneeded_unit_return(cx, hir_ty.span); } } @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedUnit { && args.span_ext.hi() != hir_ty.span.hi() && is_unit_ty(hir_ty) { - lint_unneeded_unit_return(cx, hir_ty.span, poly.span); + lint_unneeded_unit_return(cx, hir_ty.span); } } } @@ -158,24 +158,21 @@ fn get_def(span: Span) -> Option { } } -fn lint_unneeded_unit_return(cx: &LateContext<'_>, ty_span: Span, span: Span) { - let (ret_span, appl) = - if let Some(Some(rpos)) = span.with_hi(ty_span.hi()).with_source_text(cx, position_before_rarrow) { - ( - ty_span.with_lo(span.lo() + BytePos::from_usize(rpos)), - Applicability::MachineApplicable, - ) - } else { - (ty_span, Applicability::MaybeIncorrect) - }; - - span_lint_and_sugg( - cx, - UNUSED_UNIT, - ret_span, - "unneeded unit return type", - "remove the `-> ()`", - String::new(), - appl, - ); +fn lint_unneeded_unit_return(cx: &LateContext<'_>, ty_span: Span) { + if let Some(sp) = ty_span.map_range(cx, |scx, range| { + range + .with_leading_whitespace(scx)? + .with_leading_match(scx, "->")? + .with_leading_whitespace(scx) + }) { + span_lint_and_sugg( + cx, + UNUSED_UNIT, + sp, + "unneeded unit return type", + "remove the `-> ()`", + String::new(), + Applicability::MachineApplicable, + ); + } } diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index cc5c3138cee5..67f931aafd1c 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -5,7 +5,7 @@ #![expect(clippy::float_cmp)] use crate::res::MaybeDef; -use crate::source::{SpanExt, walk_span_to_context}; +use crate::source::{FileRangeExt, SpanExt}; use crate::{clip, is_direct_expn_of, sext, sym, unsext}; use rustc_abi::Size; @@ -897,11 +897,9 @@ impl<'tcx> ConstEvalCtxt<'tcx> { // Try to detect any `cfg`ed statements or empty macro expansions. let span = block.span.data(); if span.ctxt == SyntaxContext::root() { - if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) - && let expr_lo = expr_span.lo() - && expr_lo >= span.lo - && let Some(src) = (span.lo..expr_lo).get_source_range(self.tcx) - && let Some(src) = src.as_str() + if let Some((scx, range)) = span.mk_edit_cx(self.tcx) + && let Some(search_range) = range.shrink_end_to(&scx, expr.span.walk_to_root().lo_ctxt()) + && let Some(src) = scx.get_text(search_range) { use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; if !tokenize(src, FrontmatterAllowed::No) diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 015d1982534a..2d4a0adf7181 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -1,6 +1,6 @@ use crate::consts::ConstEvalCtxt; use crate::macros::macro_backtrace; -use crate::source::{SpanExt, SpanRange, walk_span_to_context}; +use crate::source::{SpanExt, walk_span_to_context}; use crate::tokenize_with_text; use rustc_ast::ast; use rustc_ast::ast::InlineAsmTemplatePiece; @@ -16,9 +16,8 @@ use rustc_hir::{ use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; use rustc_lint::LateContext; use rustc_middle::ty::TypeckResults; -use rustc_span::{BytePos, ExpnKind, MacroKind, Symbol, SyntaxContext, sym}; +use rustc_span::{ExpnKind, MacroKind, Symbol, SyntaxContext, sym}; use std::hash::{Hash, Hasher}; -use std::ops::Range; use std::slice; /// Callback that is called when two expressions are not equal in the sense of `SpanlessEq`, but @@ -191,6 +190,15 @@ impl HirEqInterExpr<'_, '_, '_> { return false; } + let Some((lscx, _)) = lspan.mk_edit_cx(self.inner.cx) else { + // Can't access the crate-local file, should be impossible. + return false; + }; + let Some((rscx, _)) = rspan.mk_edit_cx(self.inner.cx) else { + // Can't access the crate-local file, should be impossible. + return false; + }; + let mut lstart = lspan.lo; let mut rstart = rspan.lo; @@ -218,9 +226,11 @@ impl HirEqInterExpr<'_, '_, '_> { // Only one of the blocks had a weird macro. return false; } - if !eq_span_tokens(self.inner.cx, lstart..lstmt_span.lo, rstart..rstmt_span.lo, |t| { - !matches!(t, Whitespace | Semi) - }) { + if !eq_span_tokens( + lscx.get_text_by_src_range(lstart..lstmt_span.lo), + rscx.get_text_by_src_range(rstart..rstmt_span.lo), + |t| !matches!(t, Whitespace | Semi), + ) { return false; } @@ -253,9 +263,11 @@ impl HirEqInterExpr<'_, '_, '_> { // Only one of the blocks had a weird macro return false; } - eq_span_tokens(self.inner.cx, lstart..lend, rstart..rend, |t| { - !matches!(t, Whitespace | Semi) - }) + eq_span_tokens( + lscx.get_text_by_src_range(lstart..lend), + rscx.get_text_by_src_range(rstart..rend), + |t| !matches!(t, Whitespace | Semi), + ) } fn should_ignore(&self, expr: &Expr<'_>) -> bool { @@ -651,9 +663,11 @@ impl HirEqInterExpr<'_, '_, '_> { left_data.kind, ExpnKind::Macro(MacroKind::Bang, name) if name == sym::cfg || name == sym::option_env - ) && !eq_span_tokens(self.inner.cx, left_data.call_site, right_data.call_site, |t| { - !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. }) - })) + ) && !eq_span_tokens( + left_data.call_site.get_text(self.inner.cx).as_deref(), + right_data.call_site.get_text(self.inner.cx).as_deref(), + |t| !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. }), + )) { // Either a different chain of macro calls, or different arguments to the `cfg` macro. return false; @@ -1371,30 +1385,20 @@ pub fn hash_expr(cx: &LateContext<'_>, e: &Expr<'_>) -> u64 { h.finish() } -fn eq_span_tokens( - cx: &LateContext<'_>, - left: impl SpanRange, - right: impl SpanRange, - pred: impl Fn(TokenKind) -> bool, -) -> bool { - fn f(cx: &LateContext<'_>, left: Range, right: Range, pred: impl Fn(TokenKind) -> bool) -> bool { - if let Some(lsrc) = left.get_source_range(cx) - && let Some(lsrc) = lsrc.as_str() - && let Some(rsrc) = right.get_source_range(cx) - && let Some(rsrc) = rsrc.as_str() - { - let pred = |&(token, ..): &(TokenKind, _, _)| pred(token); - let map = |(_, source, _)| source; +fn eq_span_tokens(lsrc: Option<&str>, rsrc: Option<&str>, pred: impl Fn(TokenKind) -> bool) -> bool { + if let Some(lsrc) = lsrc + && let Some(rsrc) = rsrc + { + let pred = |&(token, ..): &(TokenKind, _, _)| pred(token); + let map = |(_, source, _)| source; - let ltok = tokenize_with_text(lsrc).filter(pred).map(map); - let rtok = tokenize_with_text(rsrc).filter(pred).map(map); - ltok.eq(rtok) - } else { - // Unable to access the source. Conservatively assume the blocks aren't equal. - false - } + let ltok = tokenize_with_text(lsrc).filter(pred).map(map); + let rtok = tokenize_with_text(rsrc).filter(pred).map(map); + ltok.eq(rtok) + } else { + // Unable to access the source. Conservatively assume the blocks aren't equal. + false } - f(cx, left.into_range(), right.into_range(), pred) } /// Returns true if the expression contains ambiguous literals (unsuffixed float or int literals) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 6b92a180752d..ad6496fbdfe2 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1,11 +1,14 @@ -#![feature(box_patterns)] -#![feature(if_let_guard)] -#![feature(macro_metavar_expr)] -#![feature(never_type)] -#![feature(rustc_private)] -#![feature(assert_matches)] -#![feature(unwrap_infallible)] -#![feature(array_windows)] +#![feature( + array_windows, + assert_matches, + box_patterns, + if_let_guard, + macro_metavar_expr, + never_type, + pattern, + rustc_private, + unwrap_infallible +)] #![recursion_limit = "512"] #![allow( clippy::missing_errors_doc, diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index dab2a19af41b..bb5a1938a88b 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -1,25 +1,63 @@ -//! Utils for extracting, inspecting or transforming source code - -#![allow(clippy::module_name_repetitions)] - -use std::sync::Arc; +//! Utilities for interacting with the source text and manipulating spans. +//! +//! The main entry points for working with the source text are on the [`SpanExt`] trait. This trait +//! is implemented on a few types and exists as a bridge between a [`Span`] and the source text +//! backing it. The following are the main functions: +//! +//! * [`SpanExt::get_text`]: Gets a `SourceText` representing the text the span refers to. It works +//! very similarly to an `Arc`. +//! * [`SpanExt::check_text`]: A slightly simpler way to check a predicate on the text than using +//! `get_text`. +//! * [`SpanExt::map_range`]: The main way to adjust the range portion of a span or to split a span +//! into multiple ranges. See [`SpanEditCx`] for range adjustment utilities. +//! +//! When working with `Span`s it's important to make sure the they are from the correct +//! [`SyntaxContext`]. A `SyntaxContext` roughly corresponds to which desugaring or macro expansion +//! a `Span` is from. e.g. if `m!()` expands to `1 + 2` the binary operation and both literals will +//! have a `Span` with a `SyntaxContext` indicating that particular expansion of `m!`. To handle +//! moving up the chain of expansions use [`SpanExt::walk_to_ctxt`] or [`SpanExt::walk_to_root`]. +//! +//! # Warnings +//! +//! You _cannot_ assume anything about the `Span` or source text of any item. The parser will apply +//! token substitution in some cases (e.g. replacing `(`, with `(`), macros can rearrange tokens, +//! proc-macros in particular can freely set the `Span` of any token to a different one. These can +//! only be detected by checking the source text. With this the source text of all AST/HIR item can +//! be almost anything. In short, validate all range adjustments against the source text. +use core::fmt; +use core::ops::{Deref, Index, Range, RangeFrom, RangeFull, RangeTo}; +use core::slice::SliceIndex; +use core::str::pattern::{Pattern, ReverseSearcher}; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; +use rustc_hir::def_id::LocalDefId; use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; use rustc_lexer::{FrontmatterAllowed, LiteralKind, TokenKind, tokenize}; -use rustc_lint::{EarlyContext, LateContext}; +use rustc_lint::{EarlyContext, LateContext, LintContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::source_map::{SourceMap, original_sp}; use rustc_span::{ - BytePos, DUMMY_SP, DesugaringKind, FileNameDisplayPreference, Pos, RelativeBytePos, SourceFile, SourceFileAndLine, - Span, SpanData, SyntaxContext, hygiene, + BytePos, DUMMY_SP, DesugaringKind, ExpnKind, FileNameDisplayPreference, Pos, RelativeBytePos, SourceFile, + SourceFileAndLine, Span, SpanData, SyntaxContext, hygiene, }; -use std::borrow::Cow; -use std::fmt; -use std::ops::{Deref, Index, Range}; +use std::borrow::{Borrow, Cow}; +/// Creates a type which implements `Display` by calling the specified function. +#[inline] +#[must_use] +pub fn display(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display { + struct S(T); + impl) -> fmt::Result> fmt::Display for S { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0(f) + } + } + S(f) +} + +/// A type which contains a `SourceMap`. pub trait HasSourceMap<'sm>: Copy { #[must_use] fn source_map(self) -> &'sm SourceMap; @@ -45,7 +83,7 @@ impl<'sm> HasSourceMap<'sm> for TyCtxt<'sm> { impl<'sm> HasSourceMap<'sm> for &'sm EarlyContext<'_> { #[inline] fn source_map(self) -> &'sm SourceMap { - ::rustc_lint::LintContext::sess(self).source_map() + self.sess().source_map() } } impl<'sm> HasSourceMap<'sm> for &LateContext<'sm> { @@ -55,158 +93,553 @@ impl<'sm> HasSourceMap<'sm> for &LateContext<'sm> { } } -/// Conversion of a value into the range portion of a `Span`. -pub trait SpanRange: Sized { - fn into_range(self) -> Range; +/// Conversion trait for a set of ranges within a file into `Span`s. +pub trait IntoSpans: Sized { + type Output; + #[must_use] + fn into_spans(self, scx: &SpanEditCx<'_>) -> Self::Output; + #[inline] + fn dbg_check(&self, _scx: &SpanEditCx<'_>, _old_range: FileRange) {} } -impl SpanRange for Span { - fn into_range(self) -> Range { - let data = self.data(); - data.lo..data.hi +impl IntoSpans for FileRange { + type Output = Span; + #[inline] + fn into_spans(self, scx: &SpanEditCx<'_>) -> Self::Output { + let offset = scx.file().start_pos.0; + Span::new( + BytePos(self.start.0.wrapping_add(offset)), + BytePos(self.end.0.wrapping_add(offset)), + scx.ctxt, + scx.parent, + ) + } + + #[cfg(debug_assertions)] + #[track_caller] + fn dbg_check(&self, scx: &SpanEditCx<'_>, old_range: FileRange) { + scx.dbg_check_range(Some(old_range), self.clone()); } } -impl SpanRange for SpanData { - fn into_range(self) -> Range { - self.lo..self.hi +impl IntoSpans for [FileRange; N] { + type Output = [Span; N]; + #[inline] + fn into_spans(self, scx: &SpanEditCx<'_>) -> Self::Output { + let offset = scx.file().start_pos.0; + self.map(|r| { + Span::new( + BytePos(r.start.0.wrapping_add(offset)), + BytePos(r.end.0.wrapping_add(offset)), + scx.ctxt, + scx.parent, + ) + }) + } + + #[cfg(debug_assertions)] + #[track_caller] + fn dbg_check(&self, scx: &SpanEditCx<'_>, old_range: FileRange) { + for r in self { + scx.dbg_check_range(Some(old_range.clone()), r.clone()); + } } } -impl SpanRange for Range { - fn into_range(self) -> Range { - self + +/// Conversion trait for a set of substrings into sub-ranges. +pub trait IntoSubRanges: Sized { + type Output; + #[must_use] + fn into_sub_ranges(self, base: &str) -> Self::Output; +} +impl IntoSubRanges for &str { + type Output = FileRange; + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + fn into_sub_ranges(self, base: &str) -> Self::Output { + let addr = base.as_ptr().addr(); + debug_assert!( + addr <= self.as_ptr().addr() && self.as_ptr().addr() + self.len() <= addr + base.len(), + "the string is not a valid substring", + ); + let start = self.as_ptr().addr() - addr; + RelativeBytePos::from_usize(start)..RelativeBytePos::from_usize(start + self.len()) + } +} +impl IntoSubRanges for [&str; N] { + type Output = [FileRange; N]; + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + fn into_sub_ranges(self, base: &str) -> Self::Output { + let addr = base.as_ptr().addr(); + #[cfg(debug_assertions)] + for &s in &self { + debug_assert!( + addr <= s.as_ptr().addr() && s.as_ptr().addr() + s.len() <= addr + base.len(), + "the string is not a valid substring", + ); + } + self.map(|s| { + let start = s.as_ptr().addr() - addr; + RelativeBytePos::from_usize(start)..RelativeBytePos::from_usize(start + s.len()) + }) } } -/// Conversion of a value into a `Span` -pub trait IntoSpan: Sized { - fn into_span(self) -> Span; - fn with_ctxt(self, ctxt: SyntaxContext) -> Span; +/// A position in the `SourceMap` and the `SyntaxContext` it came from. +#[derive(Clone, Copy)] +pub struct PosWithCtxt { + pub pos: BytePos, + pub ctxt: SyntaxContext, } -impl IntoSpan for Span { - fn into_span(self) -> Span { + +pub trait SpanLike: Copy { + /// Gets this value as an interned `Span`. + #[must_use] + fn span(self) -> Span; + /// Gets this `Span`'s data. + #[must_use] + fn data(self) -> SpanData; +} +impl SpanLike for Span { + #[inline] + fn span(self) -> Span { self } - fn with_ctxt(self, ctxt: SyntaxContext) -> Span { - self.with_ctxt(ctxt) + #[inline] + fn data(self) -> SpanData { + self.data() } } -impl IntoSpan for SpanData { - fn into_span(self) -> Span { - self.span() +impl SpanLike for SpanData { + #[inline] + fn span(self) -> Span { + Span::new(self.lo, self.hi, self.ctxt, self.parent) } - fn with_ctxt(self, ctxt: SyntaxContext) -> Span { - Span::new(self.lo, self.hi, ctxt, self.parent) + #[inline] + fn data(self) -> SpanData { + self } } -impl IntoSpan for Range { - fn into_span(self) -> Span { - Span::with_root_ctxt(self.start, self.end) + +/// A type representing a range in the `SourceMap`. +pub trait SourceRange: Sized { + #[must_use] + fn into_range(self) -> Range; +} +impl SourceRange for Range { + #[inline] + fn into_range(self) -> Range { + self } - fn with_ctxt(self, ctxt: SyntaxContext) -> Span { - Span::new(self.start, self.end, ctxt, None) +} +impl SourceRange for T { + #[inline] + fn into_range(self) -> Range { + let data = self.data(); + data.lo..data.hi } } -pub trait SpanExt: SpanRange { - /// Attempts to get a handle to the source text. Returns `None` if either the span is malformed, - /// or the source text is not accessible. - fn get_text<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { - get_source_range(sm.source_map(), self.into_range()).and_then(SourceText::new) +/// Helper functions to interact with the source text of a span/range. +pub trait SpanExt: SourceRange { + /// Gets the `lo` position and the `SyntaxContext` + #[inline] + #[must_use] + fn lo_ctxt(self) -> PosWithCtxt + where + Self: SpanLike, + { + let data = self.data(); + PosWithCtxt { + pos: data.lo, + ctxt: data.ctxt, + } } - /// Gets the source file, and range in the file, of the given span. Returns `None` if the span - /// extends through multiple files, or is malformed. - fn get_source_range<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { - get_source_range(sm.source_map(), self.into_range()) + /// Gets the `hi` position and the `SyntaxContext` + #[must_use] + fn hi_ctxt(self) -> PosWithCtxt + where + Self: SpanLike, + { + let data = self.data(); + PosWithCtxt { + pos: data.hi, + ctxt: data.ctxt, + } } - /// Calls the given function with the source text referenced and returns the value. Returns - /// `None` if the source text cannot be retrieved. - fn with_source_text<'sm, T>(self, sm: impl HasSourceMap<'sm>, f: impl for<'a> FnOnce(&'a str) -> T) -> Option { - with_source_text(sm.source_map(), self.into_range(), f) + /// Attempts to create a new edit context for a source range within a crate-local file. Returns + /// both the context and the adjusted range, or `None` if the range is within a non-local file. + /// + /// With debug assertions this will assert that the range: + /// * Is within a crate-local file. + /// * Does not start after it's end. + /// * Does not exceed the bounds of a single source file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn mk_edit_cx<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option<(SpanEditCx<'sm>, FileRange)> + where + Self: SpanLike, + { + SpanEditCx::for_local(sm.source_map(), self.data()) } - /// Checks if the referenced source text satisfies the given predicate. Returns `false` if the - /// source text cannot be retrieved. - fn check_text<'sm>(self, sm: impl HasSourceMap<'sm>, pred: impl for<'a> FnOnce(&'a str) -> bool) -> bool { - self.with_source_text(sm, pred).unwrap_or(false) + /// Attempts to get a handle to the source text of a crate-local file. Returns `None` if the + /// range is within a non-local file or cannot index the file's text. + /// + /// With debug assertions this will assert that the range: + /// * Is within a crate-local file. + /// * Does not start after it's end. + /// * Does not exceed the bounds of a single source file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn get_text<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { + // TODO(@Jarcho): Actually check all use sites so we can use `for_local` + // like the documentation says. + self.get_external_text(sm) } - /// Calls the given function with the both the text of the source file and the referenced range, - /// and returns the value. Returns `None` if the source text cannot be retrieved. - fn with_source_text_and_range<'sm, T>( - self, - sm: impl HasSourceMap<'sm>, - f: impl for<'a> FnOnce(&'a str, Range) -> T, - ) -> Option { - with_source_text_and_range(sm.source_map(), self.into_range(), f) + /// Attempts to get a handle to the source text. Returns `None` if an external file could not be + /// loaded or the range cannot index the file's text. + /// + /// With debug assertions this will assert that the range: + /// * Does not start after it's end. + /// * Does not exceed the bounds of a single source file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn get_external_text<'sm>(self, sm: impl HasSourceMap<'sm>) -> Option { + SourceText::for_external_range(sm.source_map(), self.into_range()) } - /// Calls the given function with the both the text of the source file and the referenced range, - /// and creates a new span with the returned range. Returns `None` if the source text cannot be - /// retrieved, or no result is returned. + /// Attempts to get a handle to the source text of a crate-local file after walking up the + /// specified context. Returns `None` if the context could not be reached; or the range is + /// within a non-local file or cannot index the file's text. /// - /// The new range must reside within the same source file. - fn map_range<'sm>( + /// With debug assertions this will assert that the range: + /// * Is within a crate-local file. + /// * Does not start after it's end. + /// * Does not exceed the bounds of a single source file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn get_text_at_ctxt<'sm>(self, sm: impl HasSourceMap<'sm>, ctxt: SyntaxContext) -> Option + where + Self: SpanLike, + { + self.walk_to_ctxt(ctxt).and_then(|sp| sp.get_text(sm)) + } + + /// Checks if the source text of a crate-local file satisfies the given predicate. Returns + /// `false` if the range is within a non-local file or cannot index the file's text. + /// + /// With debug assertions this will assert that the range: + /// * Does not start after it's end. + /// * Does not exceed the bounds of a single source file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn check_text<'sm>(self, sm: impl HasSourceMap<'sm>, pred: impl FnOnce(&str) -> bool) -> bool { + // TODO(@Jarcho): Actually check all use sites so we can use `get_text` like the + // documentation says. + self.get_external_text(sm).as_deref().is_some_and(pred) + } + + /// Maps or splits the range of the current span within a crate-local file. Returns `None` if + /// the given function returns `None`, or the span is within a non-local file. + /// + /// A span can be split into multiple parts by returning an array of `FileRange`s instead of a + /// single `FileRange`. Each range returned will be combined with the same parent and + /// `SyntaxContext` of the original span + /// + /// With debug assertions this will assert that both the initial and mapped ranges: + /// * Do not start after their respective ends. + /// * Do not exceed the bounds of a single source file. + /// * Lie on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn map_range<'sm, T: IntoSpans>( self, sm: impl HasSourceMap<'sm>, - f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range) -> Option>, - ) -> Option> { - map_range(sm.source_map(), self.into_range(), f) + f: impl for<'a> FnOnce(&'a SpanEditCx<'sm>, FileRange) -> Option, + ) -> Option + where + Self: SpanLike, + { + if let Some((scx, range)) = SpanEditCx::for_local(sm.source_map(), self.data()) + && let Some(ranges) = f(&scx, range.clone()) + { + ranges.dbg_check(&scx, range); + Some(ranges.into_spans(&scx)) + } else { + None + } } - /// Extends the range to include all preceding whitespace characters. + /// Walks this span up the macro call chain to the target context. Returns `None` if the target + /// context cannot be found. /// - /// The range will not be expanded if it would cross a line boundary, the line the range would - /// be extended to ends with a line comment and the text after the range contains a - /// non-whitespace character on the same line. e.g. + /// Since both early and late lint passes see the expanded code the only way to detect macro + /// expanded code is via a span's `SyntaxContext`. This function can be used to get e.g. the + /// span of function argument as typed at the caller rather than the span of macro generated + /// code that makes up the argument's value. /// - /// ```ignore - /// ( // Some comment - /// foo) + /// Given the following code: + /// + /// ```rust,ignore + /// macro_rules! m1 { ($e:expr) => { f1($e) }; } + /// macro_rules! m2 { ($e:expr) => { f2(m1!($e)) }; } + /// f3(m2!(0)) /// ``` /// - /// When the range points to `foo`, suggesting to remove the range after it's been extended will - /// cause the `)` to be placed inside the line comment as `( // Some comment)`. - fn with_leading_whitespace<'sm>(self, sm: impl HasSourceMap<'sm>) -> Range { - with_leading_whitespace(sm.source_map(), self.into_range()) + /// This expands to `f3(f2(f1(0)))` with the following `SyntaxContext`s: + /// + /// |Context |Contents | + /// |------------|------------| + /// |Root context|`f3(_)`, `0`| + /// |`m2!` |`f2(_)` | + /// |`m1!` |`f1(_)` | + /// + /// The following table lists the results of various possible argument combinations: + /// + /// |Span |Context |Result | + /// |-------|------------|--------| + /// |`f3(_)`|Root |`f3(_)` | + /// |`f3(_)`|`m1!`, `m2!`|None | + /// |`f2(_)`|Root |`m2!(0)`| + /// |`f2(_)`|`m2!` |`f2(_)` | + /// |`f2(_)`|`m1!` |None | + /// |`f1(_)`|Root |`m2!(0)`| + /// |`f1(_)`|`m2!` |`m1!(0)`| + /// |`f1(_)`|`m1!` |`f1(_)` | + /// |`0` |Root |`0` | + /// |`0` |`m1!`, `m2!`|None | + #[inline] + #[must_use] + fn walk_to_ctxt(self, ctxt: SyntaxContext) -> Option + where + Self: SpanLike, + { + #[inline] + fn fast(sp: Span, ctxt: SyntaxContext) -> Option { + if sp.ctxt() == ctxt { Some(sp) } else { slow(sp, ctxt) } + } + #[cold] + #[inline(never)] + fn slow(sp: Span, ctxt: SyntaxContext) -> Option { + let expn = sp.ctxt().outer_expn_data(); + if expn.call_site.ctxt() != ctxt { + let sp = hygiene::walk_chain(expn.call_site, ctxt); + (sp.ctxt() == ctxt).then_some(sp) + } else if matches!(expn.kind, ExpnKind::Desugaring(DesugaringKind::RangeExpr)) { + // This will include any parenthesis surrounding the range. + Some(if cfg!(debug_assertions) { + // The context change is only needed to satisfy debug assertions. + sp.with_ctxt(ctxt) + } else { + sp + }) + } else { + Some(expn.call_site) + } + } + + fast(self.span(), ctxt) } - /// Trims the leading whitespace from the range. - fn trim_start<'sm>(self, sm: impl HasSourceMap<'sm>) -> Range { - trim_start(sm.source_map(), self.into_range()) + /// Walks this span up the macro call chain to the root context. + /// + /// See `walk_to_ctxt` for details. + #[inline] + #[must_use] + fn walk_to_root(self) -> Span + where + Self: SpanLike, + { + #[inline] + fn fast(sp: Span) -> Span { + if sp.from_expansion() { slow(sp) } else { sp } + } + #[cold] + #[inline(never)] + fn slow(sp: Span) -> Span { + let expn = sp.ctxt().outer_expn_data(); + if expn.call_site.from_expansion() { + hygiene::walk_chain(expn.call_site, SyntaxContext::root()) + } else if matches!(expn.kind, ExpnKind::Desugaring(DesugaringKind::RangeExpr)) { + // This will include any parenthesis surrounding the range. + if cfg!(debug_assertions) { + // The context change is only needed to satisfy debug assertions. + sp.with_ctxt(SyntaxContext::root()) + } else { + sp + } + } else { + expn.call_site + } + } + + fast(self.span()) } } -impl SpanExt for T {} +impl SpanExt for T {} -/// Handle to a range of text in a source file. -pub struct SourceText(SourceFileRange); -impl SourceText { - /// Takes ownership of the source file handle if the source text is accessible. - pub fn new(text: SourceFileRange) -> Option { - if text.as_str().is_some() { - Some(Self(text)) - } else { - None - } +mod source_text { + use rustc_span::SourceFile; + use rustc_span::source_map::SourceMap; + use std::sync::Arc; + + /// Handle to a substring of text in a source file. + #[derive(Clone)] + pub struct SourceText { + file: Arc, + // This is a pointer into the text owned by the source file. If the source is external + // then the `FreezeLock` on the text must be frozen. + text: *const str, } + impl SourceText { + /// Gets the text of the given crate-local file. Returns `None` if the file is non-local. + /// + /// With debug assertions this will assert that the file is local. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn for_local_file(file: Arc) -> Option { + let text: *const str = if let Some(text) = &file.src { + &raw const ***text + } else { + debug_assert!( + false, + "attempted to access the non-local file `{}` as local.", + file.name.display(rustc_span::FileNameDisplayPreference::Local) + ); + return None; + }; + Some(Self { file, text }) + } + + /// Gets the text of the given file. Returns `None` if the file's text could not be loaded. + #[must_use] + pub fn for_external_file(sm: &SourceMap, file: Arc) -> Option { + let text: *const str = if let Some(text) = &file.src { + &raw const ***text + } else if !sm.ensure_source_file_source_present(&file) { + return None; + } + // `get` or `freeze` must be used to ensure the contents of the lock cannot change. + // Since `ensure_source_file_source_present` calls `freeze` when loading the source + // we use `get` to avoid the extra load. + else if let Some(src) = file.external_src.get() + && let Some(text) = src.get_source() + { + text + } else { + return None; + }; + Some(Self { file, text }) + } + + /// Gets the source text. + #[inline] + #[must_use] + pub fn as_str(&self) -> &str { + // SAFETY: `text` is owned by `sf` and comes from either an `Option>`, or a + // frozen `FeezeLock` (which ultimately contains an `Arc`). Neither + // of these can change so long as we own `sf`. + unsafe { &*self.text } + } + + /// Gets the source file containing the text. + #[inline] + #[must_use] + pub fn file(&self) -> &Arc { + &self.file + } - /// Gets the source text. - pub fn as_str(&self) -> &str { - self.0.as_str().unwrap() + /// Takes ownership of the source file handle. + #[inline] + #[must_use] + pub fn into_file(self) -> Arc { + self.file + } + + /// Applies the mapping function to the contained string. + #[inline] + #[must_use] + pub fn map_text(mut self, f: impl FnOnce(&SourceText) -> &str) -> Self { + // The only strings that `f` can return are those with a lifetime derived from it's + // input, and `'static` strings. Both are safe to use here. + self.text = f(&self); + self + } + + /// Applies the mapping function to the contained string. Returns `None` if the function + /// does. + #[inline] + #[must_use] + pub fn try_map_text(mut self, f: impl FnOnce(&SourceText) -> Option<&str>) -> Option { + // The only strings that `f` can return are those with a lifetime derived from it's + // input, and `'static` strings. Both are safe to use here. + match f(&self) { + Some(s) => { + self.text = s; + Some(self) + }, + None => None, + } + } + } +} +pub use self::source_text::SourceText; +impl SourceText { + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn for_external_range(sm: &SourceMap, range: Range) -> Option { + let sfp = sm.lookup_byte_offset(range.start); + let text = Self::for_external_file(sm, sfp.sf)?; + let range = RelativeBytePos(sfp.pos.0)..RelativeBytePos(range.end.0.wrapping_sub(text.file().start_pos.0)); + dbg_check_range(sm, &text, None, range.clone()); + text.apply_index(range.into_slice_idx()) } /// Converts this into an owned string. + #[inline] + #[must_use] pub fn to_owned(&self) -> String { self.as_str().to_owned() } + + /// Applies an indexing operation to the contained string. Returns `None` if the index is + /// not valid. + #[inline] + #[must_use] + pub fn apply_index(self, idx: impl SliceIndex) -> Option { + self.try_map_text(|s| s.get(idx)) + } } impl Deref for SourceText { type Target = str; + #[inline] fn deref(&self) -> &Self::Target { self.as_str() } } +impl Borrow for SourceText { + #[inline] + fn borrow(&self) -> &str { + self.as_str() + } +} impl AsRef for SourceText { + #[inline] fn as_ref(&self) -> &str { self.as_str() } @@ -216,81 +649,747 @@ where str: Index, { type Output = >::Output; + #[inline] fn index(&self, idx: T) -> &Self::Output { &self.as_str()[idx] } } impl fmt::Display for SourceText { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.as_str().fmt(f) } } impl fmt::Debug for SourceText { + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.as_str().fmt(f) } } -fn get_source_range(sm: &SourceMap, sp: Range) -> Option { - let start = sm.lookup_byte_offset(sp.start); - let end = sm.lookup_byte_offset(sp.end); - if !Arc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos { - return None; +/// Like `SliceIndex`, but for indexing a file's text rather than any string. This uses +/// `RelativeBytePos` instead of `usize`. +pub trait FileIndex { + type SliceRange: SliceIndex; + + #[must_use] + fn into_slice_idx(self) -> Self::SliceRange; + + /// Converts this into a bounded range by limiting unbounded ends to the file's bounds. + #[must_use] + fn into_file_range(self, scx: &SpanEditCx<'_>) -> FileRange; +} +impl FileIndex for RangeFull { + type SliceRange = Self; + #[inline] + fn into_slice_idx(self) -> Self::SliceRange { + self + } + #[inline] + fn into_file_range(self, scx: &SpanEditCx<'_>) -> FileRange { + RelativeBytePos(0)..scx.file().source_len + } +} +impl FileIndex for Range { + type SliceRange = Range; + #[inline] + fn into_slice_idx(self) -> Self::SliceRange { + self.start.to_usize()..self.end.to_usize() + } + #[inline] + fn into_file_range(self, _: &SpanEditCx<'_>) -> FileRange { + self + } +} +impl FileIndex for RangeTo { + type SliceRange = RangeTo; + #[inline] + fn into_slice_idx(self) -> Self::SliceRange { + ..self.end.to_usize() + } + #[inline] + fn into_file_range(self, _: &SpanEditCx<'_>) -> FileRange { + RelativeBytePos(0)..self.end + } +} +impl FileIndex for RangeFrom { + type SliceRange = RangeFrom; + #[inline] + fn into_slice_idx(self) -> Self::SliceRange { + self.start.to_usize().. + } + #[inline] + fn into_file_range(self, scx: &SpanEditCx<'_>) -> FileRange { + self.start..scx.file().source_len + } +} + +/// The range type used for specifying a range within a file. +pub type FileRange = Range; + +#[cfg_attr(not(debug_assertions), inline)] +#[cfg_attr(debug_assertions, track_caller)] +fn dbg_check_range(sm: &SourceMap, text: &SourceText, old: Option, new: FileRange) { + #[cfg(debug_assertions)] + if text.get(new.clone().into_slice_idx()).is_none() { + use core::fmt::Write; + + let file = &**text.file(); + let mut msg = String::with_capacity(512); + let _ = write!( + msg, + "error: invalid range `{}..{}`: ", + // Signed numbers will better show most errors. + new.start.0.cast_signed(), + new.end.0.cast_signed(), + ); + if new.start > file.source_len || new.end > file.source_len { + let _ = write!( + msg, + "the bounds are outside the current file (len: {})", + file.source_len.0, + ); + } else if new.start > new.end { + msg.push_str("the start and end overlap"); + } else { + msg.push_str("the ends are not on UTF-8 boundaries"); + } + + // Attempt to display the new range bounds as line and column positions. + let new_start = BytePos(new.start.0.wrapping_add(file.start_pos.0)); + let new_end = BytePos(new.end.0.wrapping_add(file.start_pos.0)); + let files_end = sm.files().last().map(|f| f.start_pos.0 + f.source_len.0); + let mut print_loc = |label: &str, pos: BytePos| { + if files_end.is_some_and(|end| pos.0 <= end) { + let sfp = sm.lookup_byte_offset(pos); + let file_name = sfp.sf.name.display(FileNameDisplayPreference::Local); + if let Some(text) = SourceText::for_external_file(sm, sfp.sf.clone()) + && text.get(sfp.pos.to_usize()..).is_some() + { + let (line, col, _) = sfp.sf.lookup_file_pos_with_col_display(pos); + let _ = write!(msg, "\n {label}: {file_name}:{line}:{}", col.to_u32()); + } else { + let line = sfp.sf.lookup_line(RelativeBytePos(sfp.pos.0)).unwrap_or(0); + let offset = sfp.pos.0 - file.lines()[line].0; + let _ = write!(msg, "\n {label}: {file_name}:{} + {}", line + 1, offset); + } + } else { + let _ = write!(msg, "\n {label}: not a file"); + } + }; + if old.as_ref().is_none_or(|old| new.start != old.start) { + print_loc("new start", new_start); + } + if old.as_ref().is_none_or(|old| new.end != old.end) { + print_loc("new end", new_end); + } + + // We aren't debug checking the old range, only using it to add additional context. + if let Some(old) = old + && let Some(old_text) = text.get(old.clone().into_slice_idx()) + { + let old_start = BytePos(old.start.0 + file.start_pos.0); + let old_end = BytePos(old.end.0 + file.start_pos.0); + let (start_line, start_col, _) = file.lookup_file_pos_with_col_display(old_start); + let (end_line, end_col, _) = file.lookup_file_pos_with_col_display(old_end); + let _ = write!( + msg, + "\n current: {}:{}:{}: {}:{}", + file.name.display(FileNameDisplayPreference::Local), + start_line, + start_col.to_u32(), + end_line, + end_col.to_u32(), + ); + // Display the old text indented. + msg.extend(old_text.split('\n').flat_map(|x| ["\n ", x])); + } else { + let _ = write!( + msg, + "\n current file: {}", + file.name.display(FileNameDisplayPreference::Local) + ); + } + + std::panic::panic_any(msg); + }; +} + +/// The context used to manipulate source ranges within a single file. +pub struct SpanEditCx<'sm> { + text: SourceText, + ctxt: SyntaxContext, + parent: Option, + + // Used only to create debug assertion messages. + #[cfg(debug_assertions)] + sm: &'sm SourceMap, + #[cfg(not(debug_assertions))] + sm: core::marker::PhantomData<&'sm SourceMap>, +} +impl<'sm> SpanEditCx<'sm> { + /// Creates a new edit context for a span within a single file. Returns `None` if the source + /// could not be loaded. + /// + /// With debug assertions this will validate that the span: + /// * Is contained within a single file. + /// * The start and end do not overlap. + /// * Lies on UTF-8 boundaries. + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn for_external(sm: &'sm SourceMap, data: SpanData) -> Option<(Self, FileRange)> { + let sfp = sm.lookup_byte_offset(data.lo); + let end = RelativeBytePos(data.hi.0.wrapping_sub(sfp.sf.start_pos.0)); + + let scx = Self { + text: SourceText::for_external_file(sm, sfp.sf)?, + ctxt: data.ctxt, + parent: data.parent, + + #[cfg(debug_assertions)] + sm, + #[cfg(not(debug_assertions))] + sm: core::marker::PhantomData, + }; + scx.dbg_check_range(None, RelativeBytePos(sfp.pos.0)..end); + Some((scx, RelativeBytePos(sfp.pos.0)..end)) + } + + /// Creates a new edit context for a span within a crate-local file. Returns `None` if span is + /// within a non-local file. + /// + /// With debug assertions this will validate that the span: + /// * Is within a single crate-local file. + /// * The start and end do not overlap. + /// * Lies on UTF-8 boundaries. + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn for_local(sm: &'sm SourceMap, data: SpanData) -> Option<(Self, FileRange)> { + let sfp = sm.lookup_byte_offset(data.lo); + let end = RelativeBytePos(data.hi.0.wrapping_sub(sfp.sf.start_pos.0)); + + let scx = Self { + text: SourceText::for_local_file(sfp.sf)?, + ctxt: data.ctxt, + parent: data.parent, + + #[cfg(debug_assertions)] + sm, + #[cfg(not(debug_assertions))] + sm: core::marker::PhantomData, + }; + scx.dbg_check_range(None, RelativeBytePos(sfp.pos.0)..end); + Some((scx, RelativeBytePos(sfp.pos.0)..end)) + } + + /// Converts this into the inner `SourceText`. + #[inline] + #[must_use] + pub fn into_file_text(self) -> SourceText { + self.text + } + + /// Converts this into the inner `SourceText` after slicing it. Returns `None` if the text can't + /// be indexed by the range. + #[inline] + #[must_use] + pub fn into_sliced_text(self, idx: impl FileIndex) -> Option { + self.text.apply_index(idx.into_slice_idx()) + } + + /// Gets a reference to the contained source file. + #[inline] + #[must_use] + pub fn file(&self) -> &SourceFile { + self.text.file() + } + + /// Gets the text of the whole file. + #[inline] + #[must_use] + pub fn file_text(&self) -> &str { + self.text.as_str() + } + + /// Gets a subslice of the file's text. Returns `None` if the range is invalid. + #[inline] + #[must_use] + pub fn get_text(&self, index: impl FileIndex) -> Option<&str> { + self.text.as_str().get(index.into_slice_idx()) + } + + /// Gets a subslice of the file's text. Returns `None` if the span is invalid. + /// + /// With debug assertions this will validate that the span: + /// * Is from the same syntax context. + /// * Is contained within the current file. + /// * The start and end do not overlap. + /// * Lies on UTF-8 boundaries. + #[inline] + #[must_use] + pub fn get_text_by_span(&self, sp: impl SpanLike) -> Option<&str> { + self.get_text(self.span_to_file_range(sp)) + } + + /// Gets a subslice of the file's text. Returns `None` if the range is invalid. + /// + /// With debug assertions this will validate that the range: + /// * Is contained within the current file. + /// * The start and end do not overlap. + /// * Lies on UTF-8 boundaries. + #[inline] + #[must_use] + pub fn get_text_by_src_range(&self, range: Range) -> Option<&str> { + self.get_text(self.src_to_file_range(range)) + } + + /// Gets the `SyntaxContext` this was created with. + #[inline] + #[must_use] + pub fn ctxt(&self) -> SyntaxContext { + self.ctxt + } + + /// Checks if this file contains the specified `SourceMap` position. + #[inline] + #[must_use] + pub fn contains_pos(&self, pos: BytePos) -> bool { + let file = self.file(); + pos.0.wrapping_sub(file.start_pos.0) <= file.source_len.0 + } + + /// Converts the file range into a `SourceMap` range. + /// + /// With debug assertions this will validate that the range: + /// * Is contained within the current file. + /// * The start and end do not overlap. + /// * Lies on UTF-8 boundaries. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn mk_source_range(&self, range: FileRange) -> Range { + self.dbg_check_range(None, range.clone()); + let offset = self.file().start_pos.0; + BytePos(range.start.0.wrapping_add(offset))..BytePos(range.end.0.wrapping_add(offset)) + } + + /// Converts the file range into a `Span`. + /// + /// With debug assertions this will validate that the range: + /// * Is contained within the current file. + /// * The start and end do not overlap. + /// * Lies on UTF-8 boundaries. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn mk_span(&self, range: FileRange) -> Span { + let range = self.mk_source_range(range); + Span::new(range.start, range.end, self.ctxt, self.parent) + } + + /// Converts the span into a file range. + /// + /// With debug assertions this will validate that the span: + /// * Is from the same syntax context. + /// * Is contained within the current file. + /// * The start and end do not overlap. + /// * Lies on UTF-8 boundaries. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn span_to_file_range(&self, sp: impl SpanLike) -> FileRange { + let data = sp.data(); + debug_assert_eq!(self.ctxt, data.ctxt); + self.src_to_file_range(data.lo..data.hi) + } + + /// Converts the `SourceMap` range into a file range. + /// + /// With debug assertions this will validate that the range: + /// * Is contained within the current file. + /// * The start and end do not overlap. + /// * Lies on UTF-8 boundaries. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + pub fn src_to_file_range(&self, range: Range) -> FileRange { + let offset = self.file().start_pos.0; + let range = + RelativeBytePos(range.start.0.wrapping_sub(offset))..RelativeBytePos(range.end.0.wrapping_sub(offset)); + self.dbg_check_range(None, range.clone()); + range + } + + /// Gets the indent text of the line containing the specified position. Returns `None` if the + /// position is outside the file's text. + /// + /// If the position is inside the line indent only the indent up to the position will be + /// retrieved. + #[must_use] + pub fn get_line_indent_before(&self, pos: RelativeBytePos) -> Option<&str> { + let file = self.file(); + let lines = file.lines(); + + // `lines` either starts with zero or is empty. If it's empty we can use zero as the line + // start. + let line = lines.partition_point(|&start| start <= pos); + let start = lines.get(line.wrapping_sub(1)).map_or(RelativeBytePos(0), |&x| x); + self.get_text(start..pos) + .map(|src| &src[..src.len() - src.trim_start().len()]) + } + + /// Runs debug checks on a range, panicking on failure. Does nothing if debug assertions are + /// disabled. + /// + /// A second range can be given as a previous range before a transformation occurred. This will + /// be displayed as additional context in the panic message, but will not cause additional + /// validation. + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + pub fn dbg_check_range(&self, old: Option, new: FileRange) { + // `cfg` since we only have a source map with debug assertions. + #[cfg(debug_assertions)] + dbg_check_range(self.sm, &self.text, old, new); } - sm.ensure_source_file_source_present(&start.sf); - let range = start.pos.to_usize()..end.pos.to_usize(); - Some(SourceFileRange { sf: start.sf, range }) } -fn with_source_text(sm: &SourceMap, sp: Range, f: impl for<'a> FnOnce(&'a str) -> T) -> Option { - if let Some(src) = get_source_range(sm, sp) - && let Some(src) = src.as_str() +/// A collection of helper functions for adjusting a range within a file. +pub trait FileRangeExt: Sized + FileIndex { + /// If the range doesn't overlap with the specified span returns the range between the two. + /// Returns `None` otherwise. + /// + /// With debug assertions enabled this will assert that the span: + /// * Is within the same `SyntaxContext` + /// * Is within the same file as the current range. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn get_range_between(self, scx: &SpanEditCx<'_>, other: impl SpanLike) -> Option { + ::get_range_between(self.into_file_range(scx), scx, other) + } + + /// If the range starts at or after the specified position returns the range from that position + /// to the end of the range. Returns `None` otherwise. + /// + /// With debug assertions enabled this will assert that the position: + /// * Is within the same `SyntaxContext` + /// * Is within the same file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn extend_start_to(self, scx: &SpanEditCx<'_>, pos: PosWithCtxt) -> Option { + ::extend_start_to(self.into_file_range(scx), scx, pos) + } + + /// If the range ends before or at the specified position returns the range from the start of + /// the range to that position. Returns `None` otherwise. + /// + /// With debug assertions enabled this will assert that the position: + /// * Is within the same `SyntaxContext` + /// * Is within the same file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn extend_end_to(self, scx: &SpanEditCx<'_>, pos: PosWithCtxt) -> Option { + ::extend_end_to(self.into_file_range(scx), scx, pos) + } + + /// If the specified position lies within or at the end of range returns the range from that + /// position to the end of the range. Returns `None` otherwise. + /// + /// With debug assertions enabled this will assert that the position: + /// * Is within the same `SyntaxContext` + /// * Is within the same file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn shrink_start_to(self, scx: &SpanEditCx<'_>, pos: PosWithCtxt) -> Option { + ::shrink_start_to(self.into_file_range(scx), scx, pos) + } + + /// If the specified position lies within or at the end of range returns the range from the + /// start of the range to that position. Returns `None` otherwise. + /// + /// With debug assertions enabled this will assert that the position: + /// * Is within the same `SyntaxContext` + /// * Is within the same file. + /// * Lies on a UTF-8 boundary. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn shrink_end_to(self, scx: &SpanEditCx<'_>, pos: PosWithCtxt) -> Option { + ::shrink_end_to(self.into_file_range(scx), scx, pos) + } + + /// Creates a new file range that represents the result of mapping the text of the specified + /// range. Returns `None` if either the mapping function returns `None`, or the range cannot + /// index the file's text. + /// + /// The string returned by the mapping function must be derived from the input string. A + /// `'static` lifetime string will not work. This will be asserted if debug assertions are + /// enabled. + #[inline] + #[must_use] + #[cfg_attr(debug_assertions, track_caller)] + fn map_range_text<'cx, T: IntoSubRanges>( + self, + scx: &'cx SpanEditCx<'_>, + f: impl FnOnce(&'cx str) -> Option, + ) -> Option { + ::map_range_text(self.into_file_range(scx), scx, f) + } + + /// Extends the range to include all immediately preceding whitespace. Returns `None` if the + /// range cannot index the file's text. + /// + /// The range will not be expanded if it would cross a line boundary, the line the range would + /// be extended to ends with a line comment and the text after the range contains a + /// non-whitespace character on the same line. e.g. + /// + /// ```ignore + /// ( // Some comment + /// foo) + /// ``` + /// + /// When the range points to `foo`, suggesting to remove the range after it's been extended will + /// cause the `)` to be placed inside the line comment as `( // Some comment)`. + #[inline] + #[must_use] + fn with_leading_whitespace(self, scx: &SpanEditCx<'_>) -> Option { + ::with_leading_whitespace(self.into_file_range(scx), scx) + } + + /// Extends the range to include all immediately proceeding whitespace. Returns `None` if the + /// range cannot index the file's text. + #[inline] + #[must_use] + fn with_trailing_whitespace(self, scx: &SpanEditCx<'_>) -> Option { + ::with_trailing_whitespace(self.into_file_range(scx), scx) + } + + // Extends the range to include the immediately preceding pattern. Returns `None` if the pattern + // does not immediately precede the range, or if the range cannot index the file's text. + #[inline] + #[must_use] + fn with_leading_match

(self, scx: &SpanEditCx<'_>, pat: P) -> Option + where + P: Pattern, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { - Some(f(src)) - } else { - None + ::with_leading_match(self.into_file_range(scx), scx, pat) + } + + // Extends the range to include the immediately proceeding pattern. Returns `None` if the pattern + // does not immediately proceed the range, or if the range cannot index the file's text. + #[inline] + #[must_use] + fn with_trailing_match(self, scx: &SpanEditCx<'_>, pat: impl Pattern) -> Option { + ::with_trailing_match(self.into_file_range(scx), scx, pat) } } +impl FileRangeExt for FileRange { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + fn get_range_between(self, scx: &SpanEditCx<'_>, sp: impl SpanLike) -> Option { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + fn f(self_: FileRange, scx: &SpanEditCx<'_>, sp: SpanData) -> Option { + debug_assert_eq!(scx.ctxt, sp.ctxt); + let file = scx.file(); + let other = RelativeBytePos(sp.lo.0.wrapping_sub(file.start_pos.0)) + ..RelativeBytePos(sp.hi.0.wrapping_sub(file.start_pos.0)); + scx.dbg_check_range(None, other.clone()); + if self_.end.0 <= other.start.0 { + Some(self_.end..other.start) + } else if self_.start.0 >= other.end.0 { + Some(other.end..self_.start) + } else { + None + } + } + f(self, scx, sp.data()) + } -fn with_source_text_and_range( - sm: &SourceMap, - sp: Range, - f: impl for<'a> FnOnce(&'a str, Range) -> T, -) -> Option { - if let Some(src) = get_source_range(sm, sp) - && let Some(text) = &src.sf.src + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + fn extend_start_to(self, scx: &SpanEditCx<'_>, pos: PosWithCtxt) -> Option { + debug_assert_eq!(scx.ctxt, pos.ctxt); + let file = scx.file(); + let pos = RelativeBytePos(pos.pos.0.wrapping_sub(file.start_pos.0)); + scx.dbg_check_range(None, pos..pos); + (pos <= self.start).then_some(pos..self.end) + } + + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + fn extend_end_to(self, scx: &SpanEditCx<'_>, pos: PosWithCtxt) -> Option { + debug_assert_eq!(scx.ctxt, pos.ctxt); + let file = scx.file(); + let pos = RelativeBytePos(pos.pos.0.wrapping_sub(file.start_pos.0)); + scx.dbg_check_range(None, pos..pos); + (pos >= self.end).then_some(self.start..pos) + } + + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + fn shrink_start_to(self, scx: &SpanEditCx<'_>, pos: PosWithCtxt) -> Option { + debug_assert_eq!(scx.ctxt, pos.ctxt); + let file = scx.file(); + let pos = RelativeBytePos(pos.pos.0.wrapping_sub(file.start_pos.0)); + scx.dbg_check_range(None, pos..pos); + (self.start <= pos && pos <= self.end).then_some(pos..self.end) + } + + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + fn shrink_end_to(self, scx: &SpanEditCx<'_>, pos: PosWithCtxt) -> Option { + debug_assert_eq!(scx.ctxt, pos.ctxt); + let file = scx.file(); + let pos = RelativeBytePos(pos.pos.0.wrapping_sub(file.start_pos.0)); + scx.dbg_check_range(None, pos..pos); + (self.start <= pos && pos <= self.end).then_some(self.start..pos) + } + + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + #[allow(clippy::manual_map, reason = "track_caller doesn't work through `map`")] + fn map_range_text<'cx, T: IntoSubRanges>( + self, + scx: &'cx SpanEditCx<'_>, + f: impl FnOnce(&'cx str) -> Option, + ) -> Option { + let file = scx.text.as_str(); + match file.get(self.start.to_usize()..self.end.to_usize()).and_then(f) { + Some(s) => Some(s.into_sub_ranges(file)), + None => None, + } + } + + fn with_leading_whitespace(self, scx: &SpanEditCx<'_>) -> Option { + let file = scx.file(); + let text = scx.file_text(); + let lines: &[RelativeBytePos] = file.lines(); + let text_before = text.get(..self.start.to_usize())?.trim_end(); + + // Start with the line after the extended range starts. + // Note `lines` either starts with zero or is empty. + let post_search_line = lines.partition_point(|&pos| pos.to_usize() <= text_before.len()); + // If this is `None` we're still on the final line. + if let Some(&search_line_end) = lines.get(post_search_line) + // Did we extend over a line boundary? + && search_line_end <= self.start + // `lines.get` shouldn't ever fail, but `0` always works as a start position. + && let search_start = lines.get(post_search_line - 1).map_or(0, |&x| x.to_usize()) + && ends_with_line_comment_or_broken(&text_before[search_start..]) + // We extended into a comment line, check if there's any non-whitespace that would be moved into it. + && let next_line = lines.partition_point(|&pos| pos < self.end) + && let next_start = lines.get(next_line).map_or(file.source_len, |&x| x) + && !text.get(self.end.to_usize()..next_start.to_usize())?.trim_start().is_empty() + { + // A non-whitespace character would be moved into a comment. Do not change the range. + Some(self) + } else { + Some(RelativeBytePos::from_usize(text_before.len())..self.end) + } + } + + fn with_trailing_whitespace(self, scx: &SpanEditCx<'_>) -> Option { + scx.get_text(self.end..) + .map(|s| self.start..RelativeBytePos::from_usize(scx.text.len() - s.trim_start().len())) + } + + fn with_leading_match

(self, scx: &SpanEditCx<'_>, pat: P) -> Option + where + P: Pattern, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { - Some(f(text, src.range)) - } else { - None + scx.get_text(..self.start) + .and_then(|s| s.strip_suffix(pat)) + .map(|s| RelativeBytePos::from_usize(s.len())..self.end) + } + + fn with_trailing_match(self, scx: &SpanEditCx<'_>, pat: impl Pattern) -> Option { + scx.get_text(self.end..) + .and_then(|s| s.strip_prefix(pat)) + .map(|s| self.start..RelativeBytePos::from_usize(scx.text.len() - s.len())) } } +impl FileRangeExt for RangeFull {} +impl FileRangeExt for RangeTo {} +impl FileRangeExt for RangeFrom {} -#[expect(clippy::cast_possible_truncation)] -fn map_range( - sm: &SourceMap, - sp: Range, - f: impl for<'a> FnOnce(&'a SourceFile, &'a str, Range) -> Option>, -) -> Option> { - if let Some(src) = get_source_range(sm, sp.clone()) - && let Some(text) = &src.sf.src - && let Some(range) = f(&src.sf, text, src.range.clone()) +pub trait StrExt { + /// Gets the substring which ranges from the start of the first match of the pattern to the end + /// of the second match. Returns `None` if the pattern doesn't occur twice. + fn find_bounded_inclusive(&self, pat: impl Pattern) -> Option<&Self>; + + /// Gets the non-overlapping prefix and suffix. Returns `None` if the string doesn't start with + /// the prefix or end with the suffix. + /// + /// The prefix will be taken first, with the suffix taken from the remainder of the string. + fn get_prefix_suffix

(&self, prefix: impl Pattern, suffix: P) -> Option<[&Self; 2]> + where + P: Pattern, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>; + + /// Splits a string into a prefix and everything proceeding it. Returns `None` if the string + /// doesn't start with the prefix. + fn split_prefix(&self, pat: impl Pattern) -> Option<[&Self; 2]>; + + /// Splits a string into a suffix and everything preceding it. Returns `None` if the string + /// doesn't end with the suffix. + fn split_suffix

(&self, pat: P) -> Option<[&Self; 2]> + where + P: Pattern, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>; +} +impl StrExt for str { + fn find_bounded_inclusive(&self, pat: impl Pattern) -> Option<&Self> { + let mut iter = self.match_indices(pat); + if let Some((first_pos, _)) = iter.next() + && let Some((second_pos, second)) = iter.next() + { + Some(&self[first_pos..second_pos + second.len()]) + } else { + None + } + } + + fn get_prefix_suffix

(&self, prefix: impl Pattern, suffix: P) -> Option<[&Self; 2]> + where + P: Pattern, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, { - debug_assert!( - range.start <= text.len() && range.end <= text.len(), - "Range `{range:?}` is outside the source file (file `{}`, length `{}`)", - src.sf.name.display(FileNameDisplayPreference::Local), - text.len(), - ); - debug_assert!(range.start <= range.end, "Range `{range:?}` has overlapping bounds"); - let dstart = (range.start as u32).wrapping_sub(src.range.start as u32); - let dend = (range.end as u32).wrapping_sub(src.range.start as u32); - Some(BytePos(sp.start.0.wrapping_add(dstart))..BytePos(sp.start.0.wrapping_add(dend))) - } else { - None + if let Some([pre, s]) = self.split_prefix(prefix) + && let Some([_, suf]) = s.split_suffix(suffix) + { + Some([pre, suf]) + } else { + None + } + } + + #[inline] + fn split_prefix(&self, pat: impl Pattern) -> Option<[&Self; 2]> { + self.strip_prefix(pat) + .map(|rest| [&self[..self.len() - rest.len()], rest]) + } + + #[inline] + fn split_suffix

(&self, pat: P) -> Option<[&Self; 2]> + where + P: Pattern, + for<'a> P::Searcher<'a>: ReverseSearcher<'a>, + { + self.strip_suffix(pat).map(|rest| [rest, &self[rest.len()..]]) } } +/// Checks if the last token of the string is either a line comment or an incomplete token. fn ends_with_line_comment_or_broken(text: &str) -> bool { let Some(last) = tokenize(text, FrontmatterAllowed::No).last() else { return false; @@ -314,55 +1413,6 @@ fn ends_with_line_comment_or_broken(text: &str) -> bool { } } -fn with_leading_whitespace_inner(lines: &[RelativeBytePos], src: &str, range: Range) -> Option { - debug_assert!(lines.is_empty() || lines[0].to_u32() == 0); - - let start = src.get(..range.start)?.trim_end(); - let next_line = lines.partition_point(|&pos| pos.to_usize() <= start.len()); - if let Some(line_end) = lines.get(next_line) - && line_end.to_usize() <= range.start - && let prev_start = lines.get(next_line - 1).map_or(0, |&x| x.to_usize()) - && ends_with_line_comment_or_broken(&start[prev_start..]) - && let next_line = lines.partition_point(|&pos| pos.to_usize() < range.end) - && let next_start = lines.get(next_line).map_or(src.len(), |&x| x.to_usize()) - && tokenize(src.get(range.end..next_start)?, FrontmatterAllowed::No) - .any(|t| !matches!(t.kind, TokenKind::Whitespace)) - { - Some(range.start) - } else { - Some(start.len()) - } -} - -fn with_leading_whitespace(sm: &SourceMap, sp: Range) -> Range { - map_range(sm, sp.clone(), |sf, src, range| { - Some(with_leading_whitespace_inner(sf.lines(), src, range.clone())?..range.end) - }) - .unwrap_or(sp) -} - -fn trim_start(sm: &SourceMap, sp: Range) -> Range { - map_range(sm, sp.clone(), |_, src, range| { - let src = src.get(range.clone())?; - Some(range.start + (src.len() - src.trim_start().len())..range.end) - }) - .unwrap_or(sp) -} - -pub struct SourceFileRange { - pub sf: Arc, - pub range: Range, -} -impl SourceFileRange { - /// Attempts to get the text from the source file. This can fail if the source text isn't - /// loaded. - pub fn as_str(&self) -> Option<&str> { - (self.sf.src.as_ref().map(|src| src.as_str())) - .or_else(|| self.sf.external_src.get()?.get_source()) - .and_then(|x| x.get(self.range.clone())) - } -} - /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block` with no label. pub fn expr_block<'sm>( sm: impl HasSourceMap<'sm>, From 06def100a5040cc01ef4cbf72e93c095e58b3866 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 22 Jun 2024 22:59:41 -0400 Subject: [PATCH 5/5] Rework the suspicious formatting lints. --- clippy_lints/src/formatting.rs | 419 +++++++++++------- clippy_utils/src/source.rs | 14 + tests/ui/formatting.rs | 88 ---- tests/ui/formatting.stderr | 53 --- .../formatting/possible_missing_comma.1.fixed | 74 ++++ .../formatting/possible_missing_comma.2.fixed | 74 ++++ tests/ui/formatting/possible_missing_comma.rs | 74 ++++ .../formatting/possible_missing_comma.stderr | 189 ++++++++ .../formatting/possible_missing_else.1.fixed | 69 +++ .../formatting/possible_missing_else.2.fixed | 73 +++ tests/ui/formatting/possible_missing_else.rs | 69 +++ .../formatting/possible_missing_else.stderr | 71 +++ .../suspicious_assignment_formatting.1.fixed | 71 +++ .../suspicious_assignment_formatting.2.fixed | 71 +++ .../suspicious_assignment_formatting.rs | 71 +++ .../suspicious_assignment_formatting.stderr | 89 ++++ .../suspicious_else_formatting.rs | 123 ++--- .../suspicious_else_formatting.stderr | 97 ++++ .../suspicious_unary_op_formatting.fixed | 64 +++ .../suspicious_unary_op_formatting.rs | 64 +++ .../suspicious_unary_op_formatting.stderr | 78 ++++ tests/ui/suspicious_else_formatting.stderr | 93 ---- tests/ui/suspicious_unary_op_formatting.rs | 32 -- .../ui/suspicious_unary_op_formatting.stderr | 36 -- 24 files changed, 1636 insertions(+), 520 deletions(-) delete mode 100644 tests/ui/formatting.rs delete mode 100644 tests/ui/formatting.stderr create mode 100644 tests/ui/formatting/possible_missing_comma.1.fixed create mode 100644 tests/ui/formatting/possible_missing_comma.2.fixed create mode 100644 tests/ui/formatting/possible_missing_comma.rs create mode 100644 tests/ui/formatting/possible_missing_comma.stderr create mode 100644 tests/ui/formatting/possible_missing_else.1.fixed create mode 100644 tests/ui/formatting/possible_missing_else.2.fixed create mode 100644 tests/ui/formatting/possible_missing_else.rs create mode 100644 tests/ui/formatting/possible_missing_else.stderr create mode 100644 tests/ui/formatting/suspicious_assignment_formatting.1.fixed create mode 100644 tests/ui/formatting/suspicious_assignment_formatting.2.fixed create mode 100644 tests/ui/formatting/suspicious_assignment_formatting.rs create mode 100644 tests/ui/formatting/suspicious_assignment_formatting.stderr rename tests/ui/{ => formatting}/suspicious_else_formatting.rs (52%) create mode 100644 tests/ui/formatting/suspicious_else_formatting.stderr create mode 100644 tests/ui/formatting/suspicious_unary_op_formatting.fixed create mode 100644 tests/ui/formatting/suspicious_unary_op_formatting.rs create mode 100644 tests/ui/formatting/suspicious_unary_op_formatting.stderr delete mode 100644 tests/ui/suspicious_else_formatting.stderr delete mode 100644 tests/ui/suspicious_unary_op_formatting.rs delete mode 100644 tests/ui/suspicious_unary_op_formatting.stderr diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index 3b9c70e23e20..93c467421536 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,10 +1,13 @@ -use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note}; -use clippy_utils::is_span_if; -use clippy_utils::source::snippet_opt; -use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind}; +use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_then}; +use clippy_utils::source::{FileRangeExt, SpanExt, StrExt}; +use clippy_utils::tokenize_with_text; +use core::mem; +use rustc_ast::{BinOp, BinOpKind, Block, Expr, ExprKind, MethodCall, StmtKind}; +use rustc_errors::Applicability; +use rustc_lexer::TokenKind; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::declare_lint_pass; -use rustc_span::Span; +use rustc_span::{Span, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -147,124 +150,157 @@ declare_lint_pass!(Formatting => [ impl EarlyLintPass for Formatting { fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) { - for w in block.stmts.windows(2) { - if let (StmtKind::Expr(first), StmtKind::Expr(second) | StmtKind::Semi(second)) = (&w[0].kind, &w[1].kind) { - check_missing_else(cx, first, second); + if block.stmts.len() >= 2 + && let ctxt = block.span.ctxt() + && !ctxt.in_external_macro(cx.sess().source_map()) + { + for [s1, s2] in block.stmts.array_windows::<2>() { + if let (StmtKind::Expr(first), StmtKind::Expr(second) | StmtKind::Semi(second)) = (&s1.kind, &s2.kind) { + check_missing_else(cx, ctxt, first, second); + } } } } fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - check_assign(cx, expr); - check_unop(cx, expr); - check_else(cx, expr); - check_array(cx, expr); + match expr.kind { + ExprKind::If(_, ref then, Some(ref else_)) => check_else(cx, expr, then, else_), + ExprKind::Assign(_, ref rhs, sp) => check_assign(cx, expr, rhs, sp), + ExprKind::Binary(ref bin_op, _, ref rhs) => check_un_op(cx, expr, bin_op, rhs), + ExprKind::Array(ref args) + | ExprKind::Tup(ref args) + | ExprKind::Call(_, ref args) + | ExprKind::MethodCall(box MethodCall { ref args, .. }) => { + let ctxt = expr.span.ctxt(); + if !ctxt.in_external_macro(cx.sess().source_map()) { + for e in args { + check_missing_comma(cx, ctxt, e); + } + } + }, + ExprKind::Paren(ref child) => { + let ctxt = expr.span.ctxt(); + if !ctxt.in_external_macro(cx.sess().source_map()) { + check_missing_comma(cx, expr.span.ctxt(), child); + } + }, + _ => {}, + } } } /// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint. -fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) { - if let ExprKind::Assign(ref lhs, ref rhs, _) = expr.kind - && !lhs.span.from_expansion() - && !rhs.span.from_expansion() +fn check_assign(cx: &EarlyContext<'_>, assign: &Expr, rhs: &Expr, op_sp: Span) { + if let ExprKind::Unary(op, _) = rhs.kind + && let assign_data = assign.span.data() + && rhs.span.ctxt() == assign_data.ctxt + && let op_data = op_sp.data() + && op_data.ctxt == assign_data.ctxt + && let op_str = op.as_str() + && let sm = cx.sess().source_map() + && !assign_data.ctxt.in_external_macro(sm) + && let Some([lint_sp, sep_sp]) = op_data.map_range(sm, |scx, range| { + let lint_range = range + .extend_end_to(scx, assign_data.hi_ctxt())? + .map_range_text(scx, |src| { + src.split_multipart_prefix(["=", op_str]) + .and_then(|[s, rest]| rest.starts_with(char::is_whitespace).then_some(s)) + })?; + lint_range + .clone() + .with_trailing_whitespace(scx) + .map(|sep_range| [lint_range, sep_range]) + }) { - let eq_span = lhs.span.between(rhs.span); - if let ExprKind::Unary(op, ref sub_rhs) = rhs.kind - && let Some(eq_snippet) = snippet_opt(cx, eq_span) - { - let op = op.as_str(); - let eqop_span = lhs.span.between(sub_rhs.span); - if eq_snippet.ends_with('=') { - span_lint_and_note( - cx, - SUSPICIOUS_ASSIGNMENT_FORMATTING, - eqop_span, - format!( - "this looks like you are trying to use `.. {op}= ..`, but you \ - really are doing `.. = ({op} ..)`" - ), - None, - format!("to remove this lint, use either `{op}=` or `= {op}`"), + span_lint_and_then( + cx, + SUSPICIOUS_ASSIGNMENT_FORMATTING, + lint_sp, + "this looks similar to a compound assignment operator", + |diag| { + diag.span_suggestion( + lint_sp, + "reverse the characters", + format!("{op_str}="), + Applicability::MaybeIncorrect, + ) + .span_suggestion( + sep_sp, + "separate the characters", + format!("= {op_str}"), + Applicability::MaybeIncorrect, ); - } - } + }, + ); } } /// Implementation of the `SUSPICIOUS_UNARY_OP_FORMATTING` lint. -fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) { - if let ExprKind::Binary(ref binop, ref lhs, ref rhs) = expr.kind - && !lhs.span.from_expansion() && !rhs.span.from_expansion() - // span between BinOp LHS and RHS - && let binop_span = lhs.span.between(rhs.span) - // if RHS is an UnOp - && let ExprKind::Unary(op, ref un_rhs) = rhs.kind - // from UnOp operator to UnOp operand - && let unop_operand_span = rhs.span.until(un_rhs.span) - && let Some(binop_snippet) = snippet_opt(cx, binop_span) - && let Some(unop_operand_snippet) = snippet_opt(cx, unop_operand_span) - && let binop_str = binop.node.as_str() - // no space after BinOp operator and space after UnOp operator - && binop_snippet.ends_with(binop_str) && unop_operand_snippet.ends_with(' ') +fn check_un_op(cx: &EarlyContext<'_>, bin_expr: &Expr, bin_op: &BinOp, rhs: &Expr) { + if let ExprKind::Unary(un_op, _) = rhs.kind + && let bin_op_data = bin_op.span.data() + && bin_op_data.ctxt == bin_expr.span.ctxt() + && let rhs_data = rhs.span.data() + && rhs_data.ctxt == bin_op_data.ctxt + && let bin_op_str = bin_op.node.as_str() + && let un_op_str = un_op.as_str() + && let sm = cx.sess().source_map() + && !bin_op_data.ctxt.in_external_macro(sm) + && let Some([lint_sp, sugg_sp]) = bin_op_data.map_range(sm, |scx, range| { + let lint_range = range + .extend_end_to(scx, rhs_data.hi_ctxt())? + .map_range_text(scx, |src| { + src.split_multipart_prefix([bin_op_str, un_op_str]) + .and_then(|[s, rest]| rest.starts_with(char::is_whitespace).then_some(s)) + })?; + lint_range + .clone() + .with_trailing_whitespace(scx) + .map(|sugg_range| [lint_range, sugg_range]) + }) { - let unop_str = op.as_str(); - let eqop_span = lhs.span.between(un_rhs.span); - span_lint_and_help( + span_lint_and_then( cx, SUSPICIOUS_UNARY_OP_FORMATTING, - eqop_span, - format!( - "by not having a space between `{binop_str}` and `{unop_str}` it looks like \ - `{binop_str}{unop_str}` is a single operator" - ), - None, - format!("put a space between `{binop_str}` and `{unop_str}` and remove the space after `{unop_str}`"), + lint_sp, + "this formatting makes the binary and unary operators look like a single operator", + |diag| { + diag.span_suggestion( + sugg_sp, + "add a space between", + format!("{bin_op_str} {un_op_str}"), + if bin_op_data.ctxt.is_root() { + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }, + ); + }, ); } } /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for weird `else`. -fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { - if let ExprKind::If(_, then, Some(else_)) = &expr.kind - && (is_block(else_) || is_if(else_)) - && !then.span.from_expansion() && !else_.span.from_expansion() - && !expr.span.in_external_macro(cx.sess().source_map()) - - // workaround for rust-lang/rust#43081 - && expr.span.lo().0 != 0 && expr.span.hi().0 != 0 - - // this will be a span from the closing ‘}’ of the “then” block (excluding) to - // the “if” of the “else if” block (excluding) - && let else_span = then.span.between(else_.span) - - // the snippet should look like " else \n " with maybe comments anywhere - // it’s bad when there is a ‘\n’ after the “else” - && let Some(else_snippet) = snippet_opt(cx, else_span) - && let Some((pre_else, post_else)) = else_snippet.split_once("else") - && !else_snippet.contains('/') - && let Some((_, post_else_post_eol)) = post_else.split_once('\n') +fn check_else(cx: &EarlyContext<'_>, expr: &Expr, then: &Block, else_: &Expr) { + let then_data = then.span.data(); + if then_data.ctxt == expr.span.ctxt() + && let else_data = else_.span.data() + && then_data.ctxt == else_data.ctxt + && let sm = cx.sess().source_map() + && !then_data.ctxt.in_external_macro(sm) + && let is_else_block = matches!(else_.kind, ExprKind::Block(..)) + && let Some(lint_sp) = then_data.map_range(sm, |scx, range| { + range.get_range_between(scx, else_data).filter(|range| { + scx.get_text(range.clone()) + .is_some_and(|src| check_else_formatting(src, is_else_block)) + }) + }) { - // Allow allman style braces `} \n else \n {` - if is_block(else_) - && let Some((_, pre_else_post_eol)) = pre_else.split_once('\n') - // Exactly one eol before and after the else - && !pre_else_post_eol.contains('\n') - && !post_else_post_eol.contains('\n') - { - return; - } - - // Don't warn if the only thing inside post_else_post_eol is a comment block. - let trimmed_post_else_post_eol = post_else_post_eol.trim(); - if trimmed_post_else_post_eol.starts_with("/*") && trimmed_post_else_post_eol.ends_with("*/") { - return; - } - - let else_desc = if is_if(else_) { "if" } else { "{..}" }; + let else_desc = if is_else_block { "{..}" } else { "if" }; span_lint_and_note( cx, SUSPICIOUS_ELSE_FORMATTING, - else_span, + lint_sp, format!("this is an `else {else_desc}` but the formatting might hide it"), None, format!( @@ -275,78 +311,145 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) { } } -#[must_use] -fn has_unary_equivalent(bin_op: BinOpKind) -> bool { - // &, *, - - bin_op == BinOpKind::And || bin_op == BinOpKind::Mul || bin_op == BinOpKind::Sub -} - -fn indentation(cx: &EarlyContext<'_>, span: Span) -> usize { - cx.sess().source_map().lookup_char_pos(span.lo()).col.0 +fn check_else_formatting(src: &str, is_else_block: bool) -> bool { + // Check for any of the following: + // * A blank line between the end of the previous block and the `else`. + // * A blank line between the `else` and the start of it's block. + // * A block comment preceding the `else`, `if` or block if it's the first thing on the line. + // * The `else` and `if` are on separate lines unless separated by multiple lines with every + // intervening line containing only block comments. This is due to rustfmt splitting + // `else/*comment*/if` into three lines. + // * The `else` and it's block are on separate lines unless every intervening line containing only + // block comments. There must be one such line unless the `else` and the preceding block are on + // separate lines. + let mut tokens = tokenize_with_text(src); + let mut lf_count = 0; + let mut skip_lf = false; + loop { + match tokens.next() { + Some((TokenKind::Whitespace, text, _)) => match text.bytes().filter(|&c| c == b'\n').count() { + 0 => {}, + x => lf_count += x - usize::from(mem::replace(&mut skip_lf, false)), + }, + Some((TokenKind::LineComment { .. }, _, _)) => skip_lf = lf_count != 0, + Some((TokenKind::BlockComment { .. }, text, _)) => { + if lf_count == 0 { + lf_count = usize::from(text.contains('\n')); + } + skip_lf = lf_count != 0; + }, + Some((TokenKind::Ident, "else", _)) if skip_lf || lf_count > 1 => return true, + Some((TokenKind::Ident, "else", _)) => break, + _ => return false, + } + } + let mut allow_lf = is_else_block && lf_count != 0; + skip_lf = false; + lf_count = 0; + for (kind, text, _) in tokens { + match kind { + TokenKind::Whitespace => match text.bytes().filter(|&c| c == b'\n').count() { + 0 => {}, + x => lf_count += x - usize::from(mem::replace(&mut skip_lf, false)), + }, + TokenKind::BlockComment { .. } => { + skip_lf = lf_count != 0; + allow_lf |= skip_lf; + }, + TokenKind::LineComment { .. } => return true, + _ => return false, + } + } + skip_lf || lf_count > usize::from(allow_lf) } -/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array -fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { - if let ExprKind::Array(ref array) = expr.kind { - for element in array { - if let ExprKind::Binary(ref op, ref lhs, _) = element.kind - && has_unary_equivalent(op.node) - && lhs.span.eq_ctxt(op.span) - && let space_span = lhs.span.between(op.span) - && let Some(space_snippet) = snippet_opt(cx, space_span) - && let lint_span = lhs.span.with_lo(lhs.span.hi()) - && space_snippet.contains('\n') - && indentation(cx, op.span) <= indentation(cx, lhs.span) - { - span_lint_and_note( - cx, - POSSIBLE_MISSING_COMMA, - lint_span, - "possibly missing a comma here", - None, - "to remove this lint, add a comma or write the expr in a single line", - ); +fn check_missing_comma(cx: &EarlyContext<'_>, ctxt: SyntaxContext, e: &Expr) { + if let ExprKind::Binary(op, lhs, rhs) = &e.kind + && let e_data = e.span.data() + && e_data.ctxt == ctxt + { + if matches!( + op.node, + BinOpKind::And | BinOpKind::Mul | BinOpKind::Sub | BinOpKind::BitAnd + ) && let op_data = op.span.data() + && op_data.ctxt == e_data.ctxt + && let Some(insert_sp) = op_data.map_range(cx, |scx, range| { + range + .extend_end_to(scx, e_data.hi_ctxt()) + .filter(|range| { + scx.get_text(..range.start) + .is_some_and(|src| src.ends_with(char::is_whitespace)) + && scx + .get_text(range.clone()) + .and_then(|src| src.strip_prefix(op.node.as_str())) + .is_some_and(|src| src.starts_with(|c: char| !c.is_whitespace() && c != '/')) + })? + .with_leading_whitespace(scx) + .map(|range| range.start..range.start) + }) + && let Some(insert_sp) = match lhs.span.walk_to_ctxt(ctxt) { + Some(lhs_sp) => { + let lhs_data = lhs_sp.data(); + // Sanity check that the lhs actually comes first. + (lhs_data.hi <= insert_sp.hi()) + .then(|| Span::new(lhs_data.hi, lhs_data.hi, lhs_data.ctxt, lhs_data.parent)) + }, + None => Some(insert_sp), } + { + span_lint_and_then( + cx, + POSSIBLE_MISSING_COMMA, + op.span, + "the is formatted like a unary operator, but it's parsed as a binary operator", + |diag| { + diag.span_suggestion(insert_sp, "add a comma before", ",", Applicability::MaybeIncorrect) + .span_suggestion( + Span::new(op_data.hi, op_data.hi, op_data.ctxt, op_data.parent), + "add a space after", + " ", + Applicability::MaybeIncorrect, + ); + }, + ); } + check_missing_comma(cx, ctxt, lhs); + check_missing_comma(cx, ctxt, rhs); } } -fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { - if !first.span.from_expansion() && !second.span.from_expansion() - && matches!(first.kind, ExprKind::If(..)) - && (is_block(second) || is_if(second)) - - // Proc-macros can give weird spans. Make sure this is actually an `if`. - && is_span_if(cx, first.span) - - // If there is a line break between the two expressions, don't lint. - // If there is a non-whitespace character, this span came from a proc-macro. - && let else_span = first.span.between(second.span) - && let Some(else_snippet) = snippet_opt(cx, else_span) - && !else_snippet.chars().any(|c| c == '\n' || !c.is_whitespace()) +fn check_missing_else(cx: &EarlyContext<'_>, ctxt: SyntaxContext, first: &Expr, second: &Expr) { + if matches!(first.kind, ExprKind::If(..)) + && matches!(second.kind, ExprKind::If(..) | ExprKind::Block(..)) + && let first_data = first.span.data() + && let second_data = second.span.data() + && first_data.ctxt == ctxt + && second_data.ctxt == ctxt + && let Some((scx, range)) = first_data.mk_edit_cx(cx) + && scx + .get_text(range.clone()) + .is_some_and(|src| src.starts_with("if") && src.ends_with('}')) + && let Some(range) = range.get_range_between(&scx, second_data) + && scx + .get_text(range.clone()) + .is_some_and(|src| src.chars().all(|c| c != '\n' && c.is_whitespace())) + && let Some(indent) = scx.get_line_indent_before(range.start) { - let (looks_like, next_thing) = if is_if(second) { - ("an `else if`", "the second `if`") - } else { - ("an `else {..}`", "the next block") - }; - - span_lint_and_note( + let lint_sp = scx.mk_span(range); + span_lint_and_then( cx, POSSIBLE_MISSING_ELSE, - else_span, - format!("this looks like {looks_like} but the `else` is missing"), - None, - format!("to remove this lint, add the missing `else` or add a new line before {next_thing}",), + lint_sp, + "this is formatted as though there should be an `else`", + |diag| { + diag.span_suggestion(lint_sp, "add an `else`", " else ", Applicability::MaybeIncorrect) + .span_suggestion( + lint_sp, + "add a line break", + format!("\n{indent}"), + Applicability::MaybeIncorrect, + ); + }, ); } } - -fn is_block(expr: &Expr) -> bool { - matches!(expr.kind, ExprKind::Block(..)) -} - -/// Check if the expression is an `if` or `if let` -fn is_if(expr: &Expr) -> bool { - matches!(expr.kind, ExprKind::If(..)) -} diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index bb5a1938a88b..250b0d46ab26 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -1346,6 +1346,10 @@ pub trait StrExt { where P: Pattern, for<'a> P::Searcher<'a>: ReverseSearcher<'a>; + + /// Splits a string into a prefix and everything proceeding it. Returns `None` if the string + /// doesn't start with the prefix. + fn split_multipart_prefix(&self, pats: impl IntoIterator) -> Option<[&Self; 2]>; } impl StrExt for str { fn find_bounded_inclusive(&self, pat: impl Pattern) -> Option<&Self> { @@ -1387,6 +1391,16 @@ impl StrExt for str { { self.strip_suffix(pat).map(|rest| [rest, &self[rest.len()..]]) } + + /// Splits a string into a prefix and everything proceeding it. Returns `None` if the string + /// doesn't start with the prefix. + fn split_multipart_prefix(&self, pats: impl IntoIterator) -> Option<[&Self; 2]> { + let mut s = self; + for pat in pats { + s = s.strip_prefix(pat)?; + } + Some([&self[..self.len() - s.len()], s]) + } } /// Checks if the last token of the string is either a line comment or an incomplete token. diff --git a/tests/ui/formatting.rs b/tests/ui/formatting.rs deleted file mode 100644 index 009815633d75..000000000000 --- a/tests/ui/formatting.rs +++ /dev/null @@ -1,88 +0,0 @@ -#![allow(clippy::if_same_then_else)] -#![allow(clippy::deref_addrof)] -#![allow(clippy::nonminimal_bool)] - -fn foo() -> bool { - true -} - -#[rustfmt::skip] -fn main() { - // weird op_eq formatting: - let mut a = 42; - a =- 35; - //~^ suspicious_assignment_formatting - - - a =* &191; - //~^ suspicious_assignment_formatting - - - - let mut b = true; - b =! false; - //~^ suspicious_assignment_formatting - - - - // those are ok: - a = -35; - a = *&191; - b = !false; - - // possible missing comma in an array - let _ = &[ - -1, -2, -3 // <= no comma here - //~^ possible_missing_comma - - - -4, -5, -6 - ]; - let _ = &[ - -1, -2, -3 // <= no comma here - //~^ possible_missing_comma - - - *4, -5, -6 - ]; - - // those are ok: - let _ = &[ - -1, -2, -3, - -4, -5, -6 - ]; - let _ = &[ - -1, -2, -3, - -4, -5, -6, - ]; - let _ = &[ - 1 + 2, 3 + - 4, 5 + 6, - ]; - - // don't lint for bin op without unary equiv - // issue 3244 - vec![ - 1 - / 2, - ]; - // issue 3396 - vec![ - true - | false, - ]; - - // don't lint if the indentation suggests not to - let _ = &[ - 1 + 2, 3 - - 4, 5 - ]; - // lint if it doesn't - let _ = &[ - -1 - //~^ possible_missing_comma - - - -4, - ]; -} diff --git a/tests/ui/formatting.stderr b/tests/ui/formatting.stderr deleted file mode 100644 index d9dc2a55f5b6..000000000000 --- a/tests/ui/formatting.stderr +++ /dev/null @@ -1,53 +0,0 @@ -error: this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)` - --> tests/ui/formatting.rs:13:6 - | -LL | a =- 35; - | ^^^^ - | - = note: to remove this lint, use either `-=` or `= -` - = note: `-D clippy::suspicious-assignment-formatting` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::suspicious_assignment_formatting)]` - -error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)` - --> tests/ui/formatting.rs:17:6 - | -LL | a =* &191; - | ^^^^ - | - = note: to remove this lint, use either `*=` or `= *` - -error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)` - --> tests/ui/formatting.rs:23:6 - | -LL | b =! false; - | ^^^^ - | - = note: to remove this lint, use either `!=` or `= !` - -error: possibly missing a comma here - --> tests/ui/formatting.rs:35:19 - | -LL | -1, -2, -3 // <= no comma here - | ^ - | - = note: to remove this lint, add a comma or write the expr in a single line - = note: `#[deny(clippy::possible_missing_comma)]` on by default - -error: possibly missing a comma here - --> tests/ui/formatting.rs:42:19 - | -LL | -1, -2, -3 // <= no comma here - | ^ - | - = note: to remove this lint, add a comma or write the expr in a single line - -error: possibly missing a comma here - --> tests/ui/formatting.rs:82:11 - | -LL | -1 - | ^ - | - = note: to remove this lint, add a comma or write the expr in a single line - -error: aborting due to 6 previous errors - diff --git a/tests/ui/formatting/possible_missing_comma.1.fixed b/tests/ui/formatting/possible_missing_comma.1.fixed new file mode 100644 index 000000000000..286fa748b1cd --- /dev/null +++ b/tests/ui/formatting/possible_missing_comma.1.fixed @@ -0,0 +1,74 @@ +//@aux-build:../auxiliary/proc_macros.rs +#![deny(clippy::possible_missing_comma)] + +use proc_macros::{external, inline_macros, with_span}; + +#[rustfmt::skip] +#[inline_macros] +fn main() { + { + let x = 20; + let y = &32; + + let _ = [1, 2, *y]; //~ possible_missing_comma + let _ = [1, 2, -x]; //~ possible_missing_comma + let _ = [1, x - 2, -x]; //~ possible_missing_comma + let _ = [1, 2, -x - 2]; //~ possible_missing_comma + let _ = [1, 2 * x * 2, -x]; //~ possible_missing_comma + + let _ = [ + 1, + x, + -2 * x * 2, //~ possible_missing_comma + -x, //~ possible_missing_comma + ]; + + let _ = (1, &x); //~ possible_missing_comma + let _ = (1, x, -1); //~ possible_missing_comma + + let _ = (1-x); + let _ = (1- x); + let _ = (1 -/* comment */x); + let _ = (1, 2*y - 5); + let _ = (1, 2 /x); + let _ = (1, 2 tests/ui/formatting/possible_missing_comma.rs:13:23 + | +LL | let _ = [1, 2 *y]; + | ^ + | +note: the lint level is defined here + --> tests/ui/formatting/possible_missing_comma.rs:2:9 + | +LL | #![deny(clippy::possible_missing_comma)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a comma before + | +LL | let _ = [1, 2, *y]; + | + +help: add a space after + | +LL | let _ = [1, 2 * y]; + | + + +error: the is formatted like a unary operator, but it's parsed as a binary operator + --> tests/ui/formatting/possible_missing_comma.rs:14:23 + | +LL | let _ = [1, 2 -x]; + | ^ + | +help: add a comma before + | +LL | let _ = [1, 2, -x]; + | + +help: add a space after + | +LL | let _ = [1, 2 - x]; + | + + +error: the is formatted like a unary operator, but it's parsed as a binary operator + --> tests/ui/formatting/possible_missing_comma.rs:15:27 + | +LL | let _ = [1, x - 2 -x]; + | ^ + | +help: add a comma before + | +LL | let _ = [1, x - 2, -x]; + | + +help: add a space after + | +LL | let _ = [1, x - 2 - x]; + | + + +error: the is formatted like a unary operator, but it's parsed as a binary operator + --> tests/ui/formatting/possible_missing_comma.rs:16:23 + | +LL | let _ = [1, 2 -x - 2]; + | ^ + | +help: add a comma before + | +LL | let _ = [1, 2, -x - 2]; + | + +help: add a space after + | +LL | let _ = [1, 2 - x - 2]; + | + + +error: the is formatted like a unary operator, but it's parsed as a binary operator + --> tests/ui/formatting/possible_missing_comma.rs:17:31 + | +LL | let _ = [1, 2 * x * 2 -x]; + | ^ + | +help: add a comma before + | +LL | let _ = [1, 2 * x * 2, -x]; + | + +help: add a space after + | +LL | let _ = [1, 2 * x * 2 - x]; + | + + +error: the is formatted like a unary operator, but it's parsed as a binary operator + --> tests/ui/formatting/possible_missing_comma.rs:23:13 + | +LL | -x, + | ^ + | +help: add a comma before + | +LL | -2 * x * 2, + | + +help: add a space after + | +LL | - x, + | + + +error: the is formatted like a unary operator, but it's parsed as a binary operator + --> tests/ui/formatting/possible_missing_comma.rs:22:13 + | +LL | -2 * x * 2 + | ^ + | +help: add a comma before + | +LL | x, + | + +help: add a space after + | +LL | - 2 * x * 2 + | + + +error: the is formatted like a unary operator, but it's parsed as a binary operator + --> tests/ui/formatting/possible_missing_comma.rs:26:20 + | +LL | let _ = (1 &x); + | ^ + | +help: add a comma before + | +LL | let _ = (1, &x); + | + +help: add a space after + | +LL | let _ = (1 & x); + | + + +error: the is formatted like a unary operator, but it's parsed as a binary operator + --> tests/ui/formatting/possible_missing_comma.rs:27:23 + | +LL | let _ = (1, x -1); + | ^ + | +help: add a comma before + | +LL | let _ = (1, x, -1); + | + +help: add a space after + | +LL | let _ = (1, x - 1); + | + + +error: the is formatted like a unary operator, but it's parsed as a binary operator + --> tests/ui/formatting/possible_missing_comma.rs:51:20 + | +LL | let _ = (y &&x); + | ^^ + | +help: add a comma before + | +LL | let _ = (y, &&x); + | + +help: add a space after + | +LL | let _ = (y && x); + | + + +error: the is formatted like a unary operator, but it's parsed as a binary operator + --> tests/ui/formatting/possible_missing_comma.rs:69:20 + | +LL | let _ = (x -1); + | ^ + | + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) +help: add a comma before + | +LL | let _ = (x, -1); + | + +help: add a space after + | +LL | let _ = (x - 1); + | + + +error: the is formatted like a unary operator, but it's parsed as a binary operator + --> tests/ui/formatting/possible_missing_comma.rs:70:20 + | +LL | let _ = (x -$(@tt 1)); + | ^ + | + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) +help: add a comma before + | +LL | let _ = (x, -$(@tt 1)); + | + +help: add a space after + | +LL | let _ = (x - $(@tt 1)); + | + + +error: aborting due to 12 previous errors + diff --git a/tests/ui/formatting/possible_missing_else.1.fixed b/tests/ui/formatting/possible_missing_else.1.fixed new file mode 100644 index 000000000000..0584fe01b566 --- /dev/null +++ b/tests/ui/formatting/possible_missing_else.1.fixed @@ -0,0 +1,69 @@ +//@aux-build:../auxiliary/proc_macros.rs +#![deny(clippy::possible_missing_else)] +#![allow( + clippy::if_same_then_else, + clippy::let_unit_value, + clippy::needless_ifs, + clippy::needless_else +)] + +use proc_macros::{external, with_span}; + +fn foo() -> bool { + true +} + +#[rustfmt::skip] +fn main() { + //~vv possible_missing_else + if foo() { + } else { + } + + //~vv possible_missing_else + if foo() { + } else if foo() { + } + + let _ = { + let _ = 0; + + //~vv possible_missing_else + if foo() { + } else if foo() { + } + else { + } + }; + + let _ = { + //~vv possible_missing_else + if foo() { + } else if foo() { + } + else { + } + + let _ = 0; + }; + + // those are ok: + if foo() { + } + { + } + + if foo() { + } else { + } + + if foo() { + } + else { + } + + if foo() { + } + if foo() { + } +} diff --git a/tests/ui/formatting/possible_missing_else.2.fixed b/tests/ui/formatting/possible_missing_else.2.fixed new file mode 100644 index 000000000000..816f7ad357a3 --- /dev/null +++ b/tests/ui/formatting/possible_missing_else.2.fixed @@ -0,0 +1,73 @@ +//@aux-build:../auxiliary/proc_macros.rs +#![deny(clippy::possible_missing_else)] +#![allow( + clippy::if_same_then_else, + clippy::let_unit_value, + clippy::needless_ifs, + clippy::needless_else +)] + +use proc_macros::{external, with_span}; + +fn foo() -> bool { + true +} + +#[rustfmt::skip] +fn main() { + //~vv possible_missing_else + if foo() { + } + { + } + + //~vv possible_missing_else + if foo() { + } + if foo() { + } + + let _ = { + let _ = 0; + + //~vv possible_missing_else + if foo() { + } + if foo() { + } + else { + } + }; + + let _ = { + //~vv possible_missing_else + if foo() { + } + if foo() { + } + else { + } + + let _ = 0; + }; + + // those are ok: + if foo() { + } + { + } + + if foo() { + } else { + } + + if foo() { + } + else { + } + + if foo() { + } + if foo() { + } +} diff --git a/tests/ui/formatting/possible_missing_else.rs b/tests/ui/formatting/possible_missing_else.rs new file mode 100644 index 000000000000..f6d3d86b30a1 --- /dev/null +++ b/tests/ui/formatting/possible_missing_else.rs @@ -0,0 +1,69 @@ +//@aux-build:../auxiliary/proc_macros.rs +#![deny(clippy::possible_missing_else)] +#![allow( + clippy::if_same_then_else, + clippy::let_unit_value, + clippy::needless_ifs, + clippy::needless_else +)] + +use proc_macros::{external, with_span}; + +fn foo() -> bool { + true +} + +#[rustfmt::skip] +fn main() { + //~vv possible_missing_else + if foo() { + } { + } + + //~vv possible_missing_else + if foo() { + } if foo() { + } + + let _ = { + let _ = 0; + + //~vv possible_missing_else + if foo() { + } if foo() { + } + else { + } + }; + + let _ = { + //~vv possible_missing_else + if foo() { + } if foo() { + } + else { + } + + let _ = 0; + }; + + // those are ok: + if foo() { + } + { + } + + if foo() { + } else { + } + + if foo() { + } + else { + } + + if foo() { + } + if foo() { + } +} diff --git a/tests/ui/formatting/possible_missing_else.stderr b/tests/ui/formatting/possible_missing_else.stderr new file mode 100644 index 000000000000..9e41ce1e4505 --- /dev/null +++ b/tests/ui/formatting/possible_missing_else.stderr @@ -0,0 +1,71 @@ +error: this is formatted as though there should be an `else` + --> tests/ui/formatting/possible_missing_else.rs:20:6 + | +LL | } { + | ^ + | +note: the lint level is defined here + --> tests/ui/formatting/possible_missing_else.rs:2:9 + | +LL | #![deny(clippy::possible_missing_else)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add an `else` + | +LL | } else { + | ++++ +help: add a line break + | +LL ~ } +LL ~ { + | + +error: this is formatted as though there should be an `else` + --> tests/ui/formatting/possible_missing_else.rs:25:6 + | +LL | } if foo() { + | ^ + | +help: add an `else` + | +LL | } else if foo() { + | ++++ +help: add a line break + | +LL ~ } +LL ~ if foo() { + | + +error: this is formatted as though there should be an `else` + --> tests/ui/formatting/possible_missing_else.rs:33:10 + | +LL | } if foo() { + | ^ + | +help: add an `else` + | +LL | } else if foo() { + | ++++ +help: add a line break + | +LL ~ } +LL ~ if foo() { + | + +error: this is formatted as though there should be an `else` + --> tests/ui/formatting/possible_missing_else.rs:42:10 + | +LL | } if foo() { + | ^ + | +help: add an `else` + | +LL | } else if foo() { + | ++++ +help: add a line break + | +LL ~ } +LL ~ if foo() { + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/formatting/suspicious_assignment_formatting.1.fixed b/tests/ui/formatting/suspicious_assignment_formatting.1.fixed new file mode 100644 index 000000000000..dd9eff1443a9 --- /dev/null +++ b/tests/ui/formatting/suspicious_assignment_formatting.1.fixed @@ -0,0 +1,71 @@ +//@aux-build:../auxiliary/proc_macros.rs +#![deny(clippy::suspicious_assignment_formatting)] +#![allow(clippy::no_effect)] + +use proc_macros::{external, inline_macros, with_span}; + +#[rustfmt::skip] +#[inline_macros] +fn main() { + { + let mut x = 42; + let y = &45; + + x -= 35; //~ suspicious_assignment_formatting + x *= y; //~ suspicious_assignment_formatting + + x=-32; + x =-32; + x =(-32); + x =-/* comment */32; + } + + { + let mut x = false; + let y = false; + x != y; //~ suspicious_assignment_formatting + } + + with_span! { + span + let mut x = 42; + x =- 35; + } + + external! { + let mut x = 42; + x =- 35; + } + + inline! { + let mut x = 42; + x -= 35; //~ suspicious_assignment_formatting + } + + { + let mut x = 42; + inline! { + $x -= $35; //~ suspicious_assignment_formatting + } + } + + { + macro_rules! m { + ($($t:tt)*) => { + let mut x = 42; + x $($t)* 35; + } + } + m!(=-); + } + + { + macro_rules! m { + ($($t:tt)*) => { + let mut x = 42; + x $($t)*; + } + } + m!(=- 35); + } +} diff --git a/tests/ui/formatting/suspicious_assignment_formatting.2.fixed b/tests/ui/formatting/suspicious_assignment_formatting.2.fixed new file mode 100644 index 000000000000..050c4e3694f1 --- /dev/null +++ b/tests/ui/formatting/suspicious_assignment_formatting.2.fixed @@ -0,0 +1,71 @@ +//@aux-build:../auxiliary/proc_macros.rs +#![deny(clippy::suspicious_assignment_formatting)] +#![allow(clippy::no_effect)] + +use proc_macros::{external, inline_macros, with_span}; + +#[rustfmt::skip] +#[inline_macros] +fn main() { + { + let mut x = 42; + let y = &45; + + x = -35; //~ suspicious_assignment_formatting + x = *y; //~ suspicious_assignment_formatting + + x=-32; + x =-32; + x =(-32); + x =-/* comment */32; + } + + { + let mut x = false; + let y = false; + x = !y; //~ suspicious_assignment_formatting + } + + with_span! { + span + let mut x = 42; + x =- 35; + } + + external! { + let mut x = 42; + x =- 35; + } + + inline! { + let mut x = 42; + x = -35; //~ suspicious_assignment_formatting + } + + { + let mut x = 42; + inline! { + $x = -$35; //~ suspicious_assignment_formatting + } + } + + { + macro_rules! m { + ($($t:tt)*) => { + let mut x = 42; + x $($t)* 35; + } + } + m!(=-); + } + + { + macro_rules! m { + ($($t:tt)*) => { + let mut x = 42; + x $($t)*; + } + } + m!(=- 35); + } +} diff --git a/tests/ui/formatting/suspicious_assignment_formatting.rs b/tests/ui/formatting/suspicious_assignment_formatting.rs new file mode 100644 index 000000000000..b726903911e4 --- /dev/null +++ b/tests/ui/formatting/suspicious_assignment_formatting.rs @@ -0,0 +1,71 @@ +//@aux-build:../auxiliary/proc_macros.rs +#![deny(clippy::suspicious_assignment_formatting)] +#![allow(clippy::no_effect)] + +use proc_macros::{external, inline_macros, with_span}; + +#[rustfmt::skip] +#[inline_macros] +fn main() { + { + let mut x = 42; + let y = &45; + + x =- 35; //~ suspicious_assignment_formatting + x =* y; //~ suspicious_assignment_formatting + + x=-32; + x =-32; + x =(-32); + x =-/* comment */32; + } + + { + let mut x = false; + let y = false; + x =! y; //~ suspicious_assignment_formatting + } + + with_span! { + span + let mut x = 42; + x =- 35; + } + + external! { + let mut x = 42; + x =- 35; + } + + inline! { + let mut x = 42; + x =- 35; //~ suspicious_assignment_formatting + } + + { + let mut x = 42; + inline! { + $x =- $35; //~ suspicious_assignment_formatting + } + } + + { + macro_rules! m { + ($($t:tt)*) => { + let mut x = 42; + x $($t)* 35; + } + } + m!(=-); + } + + { + macro_rules! m { + ($($t:tt)*) => { + let mut x = 42; + x $($t)*; + } + } + m!(=- 35); + } +} diff --git a/tests/ui/formatting/suspicious_assignment_formatting.stderr b/tests/ui/formatting/suspicious_assignment_formatting.stderr new file mode 100644 index 000000000000..f96785e41c26 --- /dev/null +++ b/tests/ui/formatting/suspicious_assignment_formatting.stderr @@ -0,0 +1,89 @@ +error: this looks similar to a compound assignment operator + --> tests/ui/formatting/suspicious_assignment_formatting.rs:14:11 + | +LL | x =- 35; + | ^^ + | +note: the lint level is defined here + --> tests/ui/formatting/suspicious_assignment_formatting.rs:2:9 + | +LL | #![deny(clippy::suspicious_assignment_formatting)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: reverse the characters + | +LL - x =- 35; +LL + x -= 35; + | +help: separate the characters + | +LL | x = -35; + | ~~~ + +error: this looks similar to a compound assignment operator + --> tests/ui/formatting/suspicious_assignment_formatting.rs:15:11 + | +LL | x =* y; + | ^^ + | +help: reverse the characters + | +LL - x =* y; +LL + x *= y; + | +help: separate the characters + | +LL | x = *y; + | ~~~ + +error: this looks similar to a compound assignment operator + --> tests/ui/formatting/suspicious_assignment_formatting.rs:26:11 + | +LL | x =! y; + | ^^ + | +help: reverse the characters + | +LL - x =! y; +LL + x != y; + | +help: separate the characters + | +LL | x = !y; + | ~~~ + +error: this looks similar to a compound assignment operator + --> tests/ui/formatting/suspicious_assignment_formatting.rs:42:11 + | +LL | x =- 35; + | ^^ + | + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) +help: reverse the characters + | +LL - x =- 35; +LL + x -= 35; + | +help: separate the characters + | +LL | x = -35; + | ~~~ + +error: this looks similar to a compound assignment operator + --> tests/ui/formatting/suspicious_assignment_formatting.rs:48:16 + | +LL | $x =- $35; + | ^^ + | + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) +help: reverse the characters + | +LL - $x =- $35; +LL + $x -= $35; + | +help: separate the characters + | +LL | $x = -$35; + | ~~~ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/suspicious_else_formatting.rs b/tests/ui/formatting/suspicious_else_formatting.rs similarity index 52% rename from tests/ui/suspicious_else_formatting.rs rename to tests/ui/formatting/suspicious_else_formatting.rs index 8574cf1c20a1..d66ad07bb1f3 100644 --- a/tests/ui/suspicious_else_formatting.rs +++ b/tests/ui/formatting/suspicious_else_formatting.rs @@ -1,6 +1,5 @@ -//@aux-build:proc_macro_suspicious_else_formatting.rs - -#![warn(clippy::suspicious_else_formatting, clippy::possible_missing_else)] +//@aux-build:../auxiliary/proc_macros.rs +#![deny(clippy::suspicious_else_formatting)] #![allow( clippy::if_same_then_else, clippy::let_unit_value, @@ -8,8 +7,7 @@ clippy::needless_else )] -extern crate proc_macro_suspicious_else_formatting; -use proc_macro_suspicious_else_formatting::DeriveBadSpan; +use proc_macros::{external, with_span}; fn foo() -> bool { true @@ -17,44 +15,11 @@ fn foo() -> bool { #[rustfmt::skip] fn main() { - // weird `else` formatting: - if foo() { - } { - //~^ possible_missing_else - } - - if foo() { - } if foo() { - //~^ possible_missing_else - } - - let _ = { // if as the last expression - let _ = 0; - - if foo() { - } if foo() { - //~^ possible_missing_else - } - else { - } - }; - - let _ = { // if in the middle of a block - if foo() { - } if foo() { - //~^ possible_missing_else - } - else { - } - - let _ = 0; - }; - + //~vv suspicious_else_formatting if foo() { } else { } - //~^^^ suspicious_else_formatting // This is fine, though weird. Allman style braces on the else. if foo() { @@ -63,25 +28,20 @@ fn main() { { } + //~vv suspicious_else_formatting if foo() { } else - if foo() { // the span of the above error should continue here + if foo() { } - //~^^^ suspicious_else_formatting + //~vv suspicious_else_formatting if foo() { } else - if foo() { // the span of the above error should continue here - } - //~^^^^ suspicious_else_formatting - - // those are ok: if foo() { } - { - } + // those are ok: if foo() { } else { } @@ -91,20 +51,16 @@ fn main() { else { } - if foo() { - } - if foo() { - } - - // Almost Allman style braces. Lint these. + //~vv suspicious_else_formatting if foo() { } else { + } - //~^^^^^ suspicious_else_formatting + //~vv suspicious_else_formatting if foo() { } else @@ -112,7 +68,6 @@ fn main() { { } - //~^^^^^^ suspicious_else_formatting // #3864 - Allman style braces if foo() @@ -156,8 +111,56 @@ fn main() { println!("false"); } -} + with_span! { + span + if true { + let _ = 0; + } else + + { + let _ = 1; + } + } + + + external! { + if true { + let _ = 0; + } else + + { + let _ = 1; + } + } + + //~vvv suspicious_else_formatting + if true { + let _ = 0; + } /* comment */ else + + { + let _ = 1; + } -// #7650 - Don't lint. Proc-macro using bad spans for `if` expressions. -#[derive(DeriveBadSpan)] -struct _Foo(u32, u32); + //~vvv suspicious_else_formatting + if true { + let _ = 0; + } + // comment + else + + + { + let _ = 1; + } + + + //~vvv suspicious_else_formatting + if true { + let _ = 0; + } /* + * some comment */ else + { + let _ = 1; + } +} diff --git a/tests/ui/formatting/suspicious_else_formatting.stderr b/tests/ui/formatting/suspicious_else_formatting.stderr new file mode 100644 index 000000000000..f30ceb19eccb --- /dev/null +++ b/tests/ui/formatting/suspicious_else_formatting.stderr @@ -0,0 +1,97 @@ +error: this is an `else {..}` but the formatting might hide it + --> tests/ui/formatting/suspicious_else_formatting.rs:20:6 + | +LL | } else + | ______^ +LL | | { + | |____^ + | + = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` +note: the lint level is defined here + --> tests/ui/formatting/suspicious_else_formatting.rs:2:9 + | +LL | #![deny(clippy::suspicious_else_formatting)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this is an `else if` but the formatting might hide it + --> tests/ui/formatting/suspicious_else_formatting.rs:33:6 + | +LL | } else + | ______^ +LL | | if foo() { + | |____^ + | + = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` + +error: this is an `else if` but the formatting might hide it + --> tests/ui/formatting/suspicious_else_formatting.rs:39:6 + | +LL | } + | ______^ +LL | | else +LL | | if foo() { + | |____^ + | + = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` + +error: this is an `else {..}` but the formatting might hide it + --> tests/ui/formatting/suspicious_else_formatting.rs:56:6 + | +LL | } + | ______^ +LL | | +LL | | else +LL | | { + | |____^ + | + = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` + +error: this is an `else {..}` but the formatting might hide it + --> tests/ui/formatting/suspicious_else_formatting.rs:65:6 + | +LL | } + | ______^ +LL | | else +LL | | +LL | | { + | |____^ + | + = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` + +error: this is an `else {..}` but the formatting might hide it + --> tests/ui/formatting/suspicious_else_formatting.rs:139:6 + | +LL | } /* comment */ else + | ______^ +LL | | +LL | | { + | |____^ + | + = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` + +error: this is an `else {..}` but the formatting might hide it + --> tests/ui/formatting/suspicious_else_formatting.rs:148:6 + | +LL | } + | ______^ +LL | | // comment +LL | | else +... | +LL | | { + | |____^ + | + = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` + +error: this is an `else {..}` but the formatting might hide it + --> tests/ui/formatting/suspicious_else_formatting.rs:161:6 + | +LL | } /* + | ______^ +LL | | * some comment */ else +LL | | { + | |____^ + | + = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` + +error: aborting due to 8 previous errors + diff --git a/tests/ui/formatting/suspicious_unary_op_formatting.fixed b/tests/ui/formatting/suspicious_unary_op_formatting.fixed new file mode 100644 index 000000000000..24d3818507ca --- /dev/null +++ b/tests/ui/formatting/suspicious_unary_op_formatting.fixed @@ -0,0 +1,64 @@ +//@aux-build:../auxiliary/proc_macros.rs +#![deny(clippy::suspicious_unary_op_formatting)] + +use proc_macros::{external, inline_macros, with_span}; + +#[rustfmt::skip] +#[inline_macros] +fn main() { + { + let x = 42; + let y = &42; + + let _ = x - -30; //~ suspicious_unary_op_formatting + let _ = x * *y; //~ suspicious_unary_op_formatting + let _ = x + !30; //~ suspicious_unary_op_formatting + let _ = x << *y; //~ suspicious_unary_op_formatting + let _ = x == !30; //~ suspicious_unary_op_formatting + + let _ = x+-30; + let _ = x +-30; + let _ = x +-/* comment */30; + } + + with_span! { + span + let x = 42; + let _ = x -- 30; + } + + external! { + let x = 42; + let _ = x -- 30; + } + + inline! { + let x = 42; + let _ = x & -30; //~ suspicious_unary_op_formatting + let _ = x | -$30; //~ suspicious_unary_op_formatting + } + + inline! { + let _ = $x > -$30; //~ suspicious_unary_op_formatting + } + + { + macro_rules! m { + ($($t:tt)*) => { + let mut x = 42; + let _ = x $($t)* 35; + } + } + m!(--); + } + + { + macro_rules! m { + ($($t:tt)*) => { + let mut x = 42; + let _ = x $($t)*; + } + } + m!(-- 35); + } +} diff --git a/tests/ui/formatting/suspicious_unary_op_formatting.rs b/tests/ui/formatting/suspicious_unary_op_formatting.rs new file mode 100644 index 000000000000..6772799f1c3b --- /dev/null +++ b/tests/ui/formatting/suspicious_unary_op_formatting.rs @@ -0,0 +1,64 @@ +//@aux-build:../auxiliary/proc_macros.rs +#![deny(clippy::suspicious_unary_op_formatting)] + +use proc_macros::{external, inline_macros, with_span}; + +#[rustfmt::skip] +#[inline_macros] +fn main() { + { + let x = 42; + let y = &42; + + let _ = x -- 30; //~ suspicious_unary_op_formatting + let _ = x ** y; //~ suspicious_unary_op_formatting + let _ = x +! 30; //~ suspicious_unary_op_formatting + let _ = x <<* y; //~ suspicious_unary_op_formatting + let _ = x ==! 30; //~ suspicious_unary_op_formatting + + let _ = x+-30; + let _ = x +-30; + let _ = x +-/* comment */30; + } + + with_span! { + span + let x = 42; + let _ = x -- 30; + } + + external! { + let x = 42; + let _ = x -- 30; + } + + inline! { + let x = 42; + let _ = x &- 30; //~ suspicious_unary_op_formatting + let _ = x |- $30; //~ suspicious_unary_op_formatting + } + + inline! { + let _ = $x >- $30; //~ suspicious_unary_op_formatting + } + + { + macro_rules! m { + ($($t:tt)*) => { + let mut x = 42; + let _ = x $($t)* 35; + } + } + m!(--); + } + + { + macro_rules! m { + ($($t:tt)*) => { + let mut x = 42; + let _ = x $($t)*; + } + } + m!(-- 35); + } +} diff --git a/tests/ui/formatting/suspicious_unary_op_formatting.stderr b/tests/ui/formatting/suspicious_unary_op_formatting.stderr new file mode 100644 index 000000000000..4ed0515ca6cd --- /dev/null +++ b/tests/ui/formatting/suspicious_unary_op_formatting.stderr @@ -0,0 +1,78 @@ +error: this formatting makes the binary and unary operators look like a single operator + --> tests/ui/formatting/suspicious_unary_op_formatting.rs:13:19 + | +LL | let _ = x -- 30; + | ^^- + | | + | help: add a space between: `- -` + | +note: the lint level is defined here + --> tests/ui/formatting/suspicious_unary_op_formatting.rs:2:9 + | +LL | #![deny(clippy::suspicious_unary_op_formatting)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: this formatting makes the binary and unary operators look like a single operator + --> tests/ui/formatting/suspicious_unary_op_formatting.rs:14:19 + | +LL | let _ = x ** y; + | ^^- + | | + | help: add a space between: `* *` + +error: this formatting makes the binary and unary operators look like a single operator + --> tests/ui/formatting/suspicious_unary_op_formatting.rs:15:19 + | +LL | let _ = x +! 30; + | ^^- + | | + | help: add a space between: `+ !` + +error: this formatting makes the binary and unary operators look like a single operator + --> tests/ui/formatting/suspicious_unary_op_formatting.rs:16:19 + | +LL | let _ = x <<* y; + | ^^^- + | | + | help: add a space between: `<< *` + +error: this formatting makes the binary and unary operators look like a single operator + --> tests/ui/formatting/suspicious_unary_op_formatting.rs:17:19 + | +LL | let _ = x ==! 30; + | ^^^- + | | + | help: add a space between: `== !` + +error: this formatting makes the binary and unary operators look like a single operator + --> tests/ui/formatting/suspicious_unary_op_formatting.rs:37:19 + | +LL | let _ = x &- 30; + | ^^- + | | + | help: add a space between: `& -` + | + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: this formatting makes the binary and unary operators look like a single operator + --> tests/ui/formatting/suspicious_unary_op_formatting.rs:38:19 + | +LL | let _ = x |- $30; + | ^^- + | | + | help: add a space between: `| -` + | + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: this formatting makes the binary and unary operators look like a single operator + --> tests/ui/formatting/suspicious_unary_op_formatting.rs:42:20 + | +LL | let _ = $x >- $30; + | ^^- + | | + | help: add a space between: `> -` + | + = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 8 previous errors + diff --git a/tests/ui/suspicious_else_formatting.stderr b/tests/ui/suspicious_else_formatting.stderr deleted file mode 100644 index 04555c6edbd3..000000000000 --- a/tests/ui/suspicious_else_formatting.stderr +++ /dev/null @@ -1,93 +0,0 @@ -error: this looks like an `else {..}` but the `else` is missing - --> tests/ui/suspicious_else_formatting.rs:22:6 - | -LL | } { - | ^ - | - = note: to remove this lint, add the missing `else` or add a new line before the next block - = note: `-D clippy::possible-missing-else` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::possible_missing_else)]` - -error: this looks like an `else if` but the `else` is missing - --> tests/ui/suspicious_else_formatting.rs:27:6 - | -LL | } if foo() { - | ^ - | - = note: to remove this lint, add the missing `else` or add a new line before the second `if` - -error: this looks like an `else if` but the `else` is missing - --> tests/ui/suspicious_else_formatting.rs:35:10 - | -LL | } if foo() { - | ^ - | - = note: to remove this lint, add the missing `else` or add a new line before the second `if` - -error: this looks like an `else if` but the `else` is missing - --> tests/ui/suspicious_else_formatting.rs:44:10 - | -LL | } if foo() { - | ^ - | - = note: to remove this lint, add the missing `else` or add a new line before the second `if` - -error: this is an `else {..}` but the formatting might hide it - --> tests/ui/suspicious_else_formatting.rs:54:6 - | -LL | } else - | ______^ -LL | | { - | |____^ - | - = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` - = note: `-D clippy::suspicious-else-formatting` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::suspicious_else_formatting)]` - -error: this is an `else if` but the formatting might hide it - --> tests/ui/suspicious_else_formatting.rs:67:6 - | -LL | } else - | ______^ -LL | | if foo() { // the span of the above error should continue here - | |____^ - | - = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` - -error: this is an `else if` but the formatting might hide it - --> tests/ui/suspicious_else_formatting.rs:73:6 - | -LL | } - | ______^ -LL | | else -LL | | if foo() { // the span of the above error should continue here - | |____^ - | - = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` - -error: this is an `else {..}` but the formatting might hide it - --> tests/ui/suspicious_else_formatting.rs:101:6 - | -LL | } - | ______^ -LL | | -LL | | else -LL | | { - | |____^ - | - = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` - -error: this is an `else {..}` but the formatting might hide it - --> tests/ui/suspicious_else_formatting.rs:109:6 - | -LL | } - | ______^ -LL | | else -LL | | -LL | | { - | |____^ - | - = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` - -error: aborting due to 9 previous errors - diff --git a/tests/ui/suspicious_unary_op_formatting.rs b/tests/ui/suspicious_unary_op_formatting.rs deleted file mode 100644 index 19f8b231925b..000000000000 --- a/tests/ui/suspicious_unary_op_formatting.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![warn(clippy::suspicious_unary_op_formatting)] -#![allow(clippy::needless_ifs)] - -#[rustfmt::skip] -fn main() { - // weird binary operator formatting: - let a = 42; - - if a >- 30 {} - //~^ suspicious_unary_op_formatting - - if a >=- 30 {} - //~^ suspicious_unary_op_formatting - - - let b = true; - let c = false; - - if b &&! c {} - //~^ suspicious_unary_op_formatting - - - if a >- 30 {} - //~^ suspicious_unary_op_formatting - - - // those are ok: - if a >-30 {} - if a < -30 {} - if b && !c {} - if a > - 30 {} -} diff --git a/tests/ui/suspicious_unary_op_formatting.stderr b/tests/ui/suspicious_unary_op_formatting.stderr deleted file mode 100644 index 5fe18aa82435..000000000000 --- a/tests/ui/suspicious_unary_op_formatting.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error: by not having a space between `>` and `-` it looks like `>-` is a single operator - --> tests/ui/suspicious_unary_op_formatting.rs:9:9 - | -LL | if a >- 30 {} - | ^^^^ - | - = help: put a space between `>` and `-` and remove the space after `-` - = note: `-D clippy::suspicious-unary-op-formatting` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::suspicious_unary_op_formatting)]` - -error: by not having a space between `>=` and `-` it looks like `>=-` is a single operator - --> tests/ui/suspicious_unary_op_formatting.rs:12:9 - | -LL | if a >=- 30 {} - | ^^^^^ - | - = help: put a space between `>=` and `-` and remove the space after `-` - -error: by not having a space between `&&` and `!` it looks like `&&!` is a single operator - --> tests/ui/suspicious_unary_op_formatting.rs:19:9 - | -LL | if b &&! c {} - | ^^^^^ - | - = help: put a space between `&&` and `!` and remove the space after `!` - -error: by not having a space between `>` and `-` it looks like `>-` is a single operator - --> tests/ui/suspicious_unary_op_formatting.rs:23:9 - | -LL | if a >- 30 {} - | ^^^^^^ - | - = help: put a space between `>` and `-` and remove the space after `-` - -error: aborting due to 4 previous errors -