about summary refs log tree commit diff
diff options
context:
space:
mode:
authorA4-Tacks <wdsjxhno1001@163.com>2025-07-25 10:57:38 +0800
committerA4-Tacks <wdsjxhno1001@163.com>2025-07-25 11:00:32 +0800
commit35404461e29343ec61eb79ca8408ae31f8941452 (patch)
tree301f9412d005dbe2e22e262c47ecfa669453c15c
parentd976ef8ae494cc8fd6672d43c49377e43c2876b5 (diff)
downloadrust-35404461e29343ec61eb79ca8408ae31f8941452.tar.gz
rust-35404461e29343ec61eb79ca8408ae31f8941452.zip
Fix gen panics doc template for debug_assert
And add assert_eq, assert_ne, assert_matches support

Input:

```rust
pub fn $0foo(x: bool) {
    debug_assert!(x);
}
```

Old:

```rust
/// .
///
/// # Panics
///
/// Panics if .
pub fn foo(x: bool) {
    debug_assert!(x);
}
```

This PR fixes:

```rust
/// .
pub fn foo(x: bool) {
    debug_assert!(x);
}
```
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs68
1 files changed, 62 insertions, 6 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
index d4d1b3490cb..68587f0cb5b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
@@ -313,12 +313,28 @@ fn crate_name(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option<String> {
 /// `None` if function without a body; some bool to guess if function can panic
 fn can_panic(ast_func: &ast::Fn) -> Option<bool> {
     let body = ast_func.body()?.to_string();
-    let can_panic = body.contains("panic!(")
-        // FIXME it would be better to not match `debug_assert*!` macro invocations
-        || body.contains("assert!(")
-        || body.contains(".unwrap()")
-        || body.contains(".expect(");
-    Some(can_panic)
+    let mut iter = body.chars();
+    let assert_postfix = |s| {
+        ["!(", "_eq!(", "_ne!(", "_matches!("].iter().any(|postfix| str::starts_with(s, postfix))
+    };
+
+    while !iter.as_str().is_empty() {
+        let s = iter.as_str();
+        iter.next();
+        if s.strip_prefix("debug_assert").is_some_and(assert_postfix) {
+            iter.nth(10);
+            continue;
+        }
+        if s.strip_prefix("assert").is_some_and(assert_postfix)
+            || s.starts_with("panic!(")
+            || s.starts_with(".unwrap()")
+            || s.starts_with(".expect(")
+        {
+            return Some(true);
+        }
+    }
+
+    Some(false)
 }
 
 /// Helper function to get the name that should be given to `self` arguments
@@ -678,6 +694,24 @@ pub fn panics_if(a: bool) {
     }
 
     #[test]
+    fn guesses_debug_assert_macro_cannot_panic() {
+        check_assist(
+            generate_documentation_template,
+            r#"
+pub fn $0debug_panics_if_not(a: bool) {
+    debug_assert!(a == true);
+}
+"#,
+            r#"
+/// .
+pub fn debug_panics_if_not(a: bool) {
+    debug_assert!(a == true);
+}
+"#,
+        );
+    }
+
+    #[test]
     fn guesses_assert_macro_can_panic() {
         check_assist(
             generate_documentation_template,
@@ -700,6 +734,28 @@ pub fn panics_if_not(a: bool) {
     }
 
     #[test]
+    fn guesses_assert_eq_macro_can_panic() {
+        check_assist(
+            generate_documentation_template,
+            r#"
+pub fn $0panics_if_not(a: bool) {
+    assert_eq!(a, true);
+}
+"#,
+            r#"
+/// .
+///
+/// # Panics
+///
+/// Panics if .
+pub fn panics_if_not(a: bool) {
+    assert_eq!(a, true);
+}
+"#,
+        );
+    }
+
+    #[test]
     fn guesses_unwrap_can_panic() {
         check_assist(
             generate_documentation_template,