about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2025-03-26 19:38:09 +0100
committerSamuel Tardieu <sam@rfc1149.net>2025-03-26 21:10:09 +0100
commit9b1945d9fb57516c585f7aea9dfe638ad3c7a397 (patch)
tree5ee7cb0272a52cad567338d4a771fa76435fc8e4
parentfe4dd5b92e603555594b9abef58405fc9f4f260e (diff)
downloadrust-9b1945d9fb57516c585f7aea9dfe638ad3c7a397.tar.gz
rust-9b1945d9fb57516c585f7aea9dfe638ad3c7a397.zip
Prevent including preceeding whitespaces if line contains non blanks
This extra condition prevents a problem when removing the '}' in:
```rust
  ( // There was an opening bracket after the parenthesis, which has been removed
    // This is a comment
   })
```
Removing the whitespaces, including the linefeed, before the '}', would put the
closing parenthesis at the end of the `// This is a comment` line, which would
make it part of the comment as well. In this case, it is best to keep the span
on the '}' alone.
-rw-r--r--clippy_utils/src/source.rs25
-rw-r--r--tests/ui-toml/collapsible_if/collapsible_if.fixed4
-rw-r--r--tests/ui-toml/collapsible_if/collapsible_if.stderr4
-rw-r--r--tests/ui/collapsible_if.fixed10
-rw-r--r--tests/ui/collapsible_if.rs10
-rw-r--r--tests/ui/collapsible_if.stderr20
-rw-r--r--tests/ui/manual_inspect.fixed11
-rw-r--r--tests/ui/manual_inspect.rs9
-rw-r--r--tests/ui/manual_inspect.stderr17
9 files changed, 98 insertions, 12 deletions
diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs
index 80066e9702d..f15906df627 100644
--- a/clippy_utils/src/source.rs
+++ b/clippy_utils/src/source.rs
@@ -142,7 +142,19 @@ pub trait SpanRangeExt: SpanRange {
         map_range(cx.sess().source_map(), self.into_range(), f)
     }
 
-    /// Extends the range to include all preceding whitespace characters.
+    /// Extends the range to include all preceding whitespace characters, unless there
+    /// are non-whitespace characters left on the same line after `self`.
+    ///
+    /// This extra condition prevents a problem when removing the '}' in:
+    /// ```ignore
+    ///   ( // There was an opening bracket after the parenthesis, which has been removed
+    ///     // This is a comment
+    ///    })
+    /// ```
+    /// Removing the whitespaces, including the linefeed, before the '}', would put the
+    /// closing parenthesis at the end of the `// This is a comment` line, which would
+    /// make it part of the comment as well. In this case, it is best to keep the span
+    /// on the '}' alone.
     fn with_leading_whitespace(self, cx: &impl HasSession) -> Range<BytePos> {
         with_leading_whitespace(cx.sess().source_map(), self.into_range())
     }
@@ -263,10 +275,15 @@ fn map_range(
 }
 
 fn with_leading_whitespace(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> {
-    map_range(sm, sp.clone(), |src, range| {
-        Some(src.get(..range.start)?.trim_end().len()..range.end)
+    map_range(sm, sp, |src, range| {
+        let non_blank_after = src.len() - src.get(range.end..)?.trim_start().len();
+        if src.get(range.end..non_blank_after)?.contains(['\r', '\n']) {
+            Some(src.get(..range.start)?.trim_end().len()..range.end)
+        } else {
+            Some(range)
+        }
     })
-    .unwrap_or(sp)
+    .unwrap()
 }
 
 fn trim_start(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> {
diff --git a/tests/ui-toml/collapsible_if/collapsible_if.fixed b/tests/ui-toml/collapsible_if/collapsible_if.fixed
index f695f9804d5..6f5cc47ba6c 100644
--- a/tests/ui-toml/collapsible_if/collapsible_if.fixed
+++ b/tests/ui-toml/collapsible_if/collapsible_if.fixed
@@ -13,7 +13,7 @@ fn main() {
     //~^^^^^^ collapsible_if
 
     // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798
-    if x == "hello" // Inner comment
+    if x == "hello"  // Inner comment
         && y == "world" {
             println!("Hello world!");
         }
@@ -26,7 +26,7 @@ fn main() {
         }
     //~^^^^^^ collapsible_if
 
-    if x == "hello" /* Inner comment */
+    if x == "hello"  /* Inner comment */
         && y == "world" {
             println!("Hello world!");
         }
diff --git a/tests/ui-toml/collapsible_if/collapsible_if.stderr b/tests/ui-toml/collapsible_if/collapsible_if.stderr
index a12c2112f58..357ce4ad32d 100644
--- a/tests/ui-toml/collapsible_if/collapsible_if.stderr
+++ b/tests/ui-toml/collapsible_if/collapsible_if.stderr
@@ -32,7 +32,7 @@ LL | |     }
    |
 help: collapse nested if block
    |
-LL ~     if x == "hello" // Inner comment
+LL ~     if x == "hello"  // Inner comment
 LL ~         && y == "world" {
 LL |             println!("Hello world!");
 LL ~         }
@@ -70,7 +70,7 @@ LL | |     }
    |
 help: collapse nested if block
    |
-LL ~     if x == "hello" /* Inner comment */
+LL ~     if x == "hello"  /* Inner comment */
 LL ~         && y == "world" {
 LL |             println!("Hello world!");
 LL ~         }
diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed
index df281651ab1..e1ceb04f9cb 100644
--- a/tests/ui/collapsible_if.fixed
+++ b/tests/ui/collapsible_if.fixed
@@ -152,3 +152,13 @@ fn main() {
         }
     }
 }
+
+#[rustfmt::skip]
+fn layout_check() -> u32 {
+    if true
+        && true {
+        }
+        // This is a comment, do not collapse code to it
+    ; 3
+    //~^^^^^ collapsible_if
+}
diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs
index ce979568cc8..0b996dca22e 100644
--- a/tests/ui/collapsible_if.rs
+++ b/tests/ui/collapsible_if.rs
@@ -162,3 +162,13 @@ fn main() {
         }
     }
 }
+
+#[rustfmt::skip]
+fn layout_check() -> u32 {
+    if true {
+        if true {
+        }
+        // This is a comment, do not collapse code to it
+    }; 3
+    //~^^^^^ collapsible_if
+}
diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr
index 559db238cb1..53281146239 100644
--- a/tests/ui/collapsible_if.stderr
+++ b/tests/ui/collapsible_if.stderr
@@ -172,5 +172,23 @@ LL |             println!("No comment, linted");
 LL ~         }
    |
 
-error: aborting due to 10 previous errors
+error: this `if` statement can be collapsed
+  --> tests/ui/collapsible_if.rs:168:5
+   |
+LL | /     if true {
+LL | |         if true {
+...  |
+LL | |     }; 3
+   | |_____^
+   |
+help: collapse nested if block
+   |
+LL ~     if true
+LL ~         && true {
+LL |         }
+LL |         // This is a comment, do not collapse code to it
+LL ~     ; 3
+   |
+
+error: aborting due to 11 previous errors
 
diff --git a/tests/ui/manual_inspect.fixed b/tests/ui/manual_inspect.fixed
index 8d045c48ceb..ec87fe217ae 100644
--- a/tests/ui/manual_inspect.fixed
+++ b/tests/ui/manual_inspect.fixed
@@ -107,7 +107,7 @@ fn main() {
             let _ = || {
                 let _x = x;
             };
-            return;
+            return ;
         }
         println!("test");
     });
@@ -185,3 +185,12 @@ fn main() {
         });
     }
 }
+
+#[rustfmt::skip]
+fn layout_check() {
+    if let Some(x) = Some(1).inspect(|&x| { println!("{x}"); //~ manual_inspect
+        // Do not collapse code into this comment
+         }) {
+        println!("{x}");
+    }
+}
diff --git a/tests/ui/manual_inspect.rs b/tests/ui/manual_inspect.rs
index a89d28dab68..e679636201e 100644
--- a/tests/ui/manual_inspect.rs
+++ b/tests/ui/manual_inspect.rs
@@ -197,3 +197,12 @@ fn main() {
         });
     }
 }
+
+#[rustfmt::skip]
+fn layout_check() {
+    if let Some(x) = Some(1).map(|x| { println!("{x}"); //~ manual_inspect
+        // Do not collapse code into this comment
+        x }) {
+        println!("{x}");
+    }
+}
diff --git a/tests/ui/manual_inspect.stderr b/tests/ui/manual_inspect.stderr
index 510325d2baa..eb98f9f5995 100644
--- a/tests/ui/manual_inspect.stderr
+++ b/tests/ui/manual_inspect.stderr
@@ -98,7 +98,7 @@ LL |         if x.is_empty() {
 LL |             let _ = || {
 LL ~                 let _x = x;
 LL |             };
-LL ~             return;
+LL ~             return ;
 LL |         }
 LL ~         println!("test");
    |
@@ -187,5 +187,18 @@ LL |
 LL ~             println!("{}", x);
    |
 
-error: aborting due to 13 previous errors
+error: using `map` over `inspect`
+  --> tests/ui/manual_inspect.rs:203:30
+   |
+LL |     if let Some(x) = Some(1).map(|x| { println!("{x}");
+   |                              ^^^
+   |
+help: try
+   |
+LL ~     if let Some(x) = Some(1).inspect(|&x| { println!("{x}");
+LL |         // Do not collapse code into this comment
+LL ~          }) {
+   |
+
+error: aborting due to 14 previous errors