]> git.lizzy.rs Git - rust.git/blobdiff - clippy_utils/src/source.rs
Merge commit 'f4850f7292efa33759b4f7f9b7621268979e9914' into clippyup
[rust.git] / clippy_utils / src / source.rs
index f88a92fb11c111146851e4213a6508c0ec26b2ac..eacfa91ba556d41d454f2b3a63c5a325ae4311cd 100644 (file)
@@ -2,33 +2,14 @@
 
 #![allow(clippy::module_name_repetitions)]
 
-use crate::line_span;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LintContext};
 use rustc_span::hygiene;
-use rustc_span::source_map::SourceMap;
-use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext};
+use rustc_span::source_map::{original_sp, SourceMap};
+use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP};
 use std::borrow::Cow;
 
-/// Checks if the span starts with the given text. This will return false if the span crosses
-/// multiple files or if source is not available.
-///
-/// This is used to check for proc macros giving unhelpful spans to things.
-pub fn span_starts_with<T: LintContext>(cx: &T, span: Span, text: &str) -> bool {
-    fn helper(sm: &SourceMap, span: Span, text: &str) -> bool {
-        let pos = sm.lookup_byte_offset(span.lo());
-        let Some(ref src) = pos.sf.src else {
-            return false;
-        };
-        let end = span.hi() - pos.sf.start_pos;
-        src.get(pos.pos.0 as usize..end.0 as usize)
-            // Expression spans can include wrapping parenthesis. Remove them first.
-            .map_or(false, |s| s.trim_start_matches('(').starts_with(text))
-    }
-    helper(cx.sess().source_map(), span, text)
-}
-
 /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
 /// Also takes an `Option<String>` which can be put inside the braces.
 pub fn expr_block<'a, T: LintContext>(
@@ -43,11 +24,11 @@ pub fn expr_block<'a, T: LintContext>(
     if expr.span.from_expansion() {
         Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default)))
     } else if let ExprKind::Block(_, _) = expr.kind {
-        Cow::Owned(format!("{}{}", code, string))
+        Cow::Owned(format!("{code}{string}"))
     } else if string.is_empty() {
-        Cow::Owned(format!("{{ {} }}", code))
+        Cow::Owned(format!("{{ {code} }}"))
     } else {
-        Cow::Owned(format!("{{\n{};\n{}\n}}", code, string))
+        Cow::Owned(format!("{{\n{code};\n{string}\n}}"))
     }
 }
 
@@ -73,6 +54,23 @@ fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePo
     })
 }
 
+/// Extends the span to the beginning of the spans line, incl. whitespaces.
+///
+/// ```rust
+///        let x = ();
+/// //             ^^
+/// // will be converted to
+///        let x = ();
+/// // ^^^^^^^^^^^^^^
+/// ```
+fn line_span<T: LintContext>(cx: &T, span: Span) -> Span {
+    let span = original_sp(span, DUMMY_SP);
+    let source_map_and_line = cx.sess().source_map().lookup_line(span.lo()).unwrap();
+    let line_no = source_map_and_line.line;
+    let line_start = source_map_and_line.sf.lines(|lines| lines[line_no]);
+    span.with_lo(line_start)
+}
+
 /// Returns the indentation of the line of a span
 ///
 /// ```rust,ignore
@@ -353,7 +351,7 @@ pub fn snippet_with_context<'a>(
 /// span containing `m!(0)`.
 pub fn walk_span_to_context(span: Span, outer: SyntaxContext) -> Option<Span> {
     let outer_span = hygiene::walk_chain(span, outer);
-    (outer_span.ctxt() == outer).then(|| outer_span)
+    (outer_span.ctxt() == outer).then_some(outer_span)
 }
 
 /// Removes block comments from the given `Vec` of lines.
@@ -410,6 +408,16 @@ pub fn trim_span(sm: &SourceMap, span: Span) -> Span {
     .span()
 }
 
+/// Expand a span to include a preceding comma
+/// ```rust,ignore
+/// writeln!(o, "")   ->   writeln!(o, "")
+///             ^^                   ^^^^
+/// ```
+pub fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span {
+    let extended = cx.sess().source_map().span_extend_to_prev_char(span, ',', true);
+    extended.with_lo(extended.lo() - BytePos(1))
+}
+
 #[cfg(test)]
 mod test {
     use super::{reindent_multiline, without_block_comments};
@@ -484,7 +492,7 @@ fn test_reindent_multiline_lines_deeper() {
     #[test]
     fn test_without_block_comments_lines_without_block_comments() {
         let result = without_block_comments(vec!["/*", "", "*/"]);
-        println!("result: {:?}", result);
+        println!("result: {result:?}");
         assert!(result.is_empty());
 
         let result = without_block_comments(vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]);