about summary refs log tree commit diff
diff options
context:
space:
mode:
authorChayim Refael Friedman <chayimfr@gmail.com>2022-09-04 13:26:00 +0000
committerChayim Refael Friedman <chayimfr@gmail.com>2022-09-04 14:33:15 +0000
commite295f0c29cc41be34fee364fe1fcf1a1b0bbd31a (patch)
treef13bd960e64d1e5018b71dbc1ae75f584ecb524b
parent989b09d20cafc2b1eb9198e25701b9e2234d8ba0 (diff)
downloadrust-e295f0c29cc41be34fee364fe1fcf1a1b0bbd31a.tar.gz
rust-e295f0c29cc41be34fee364fe1fcf1a1b0bbd31a.zip
Insert whitespaces into static & const bodies if they are expanded from macro on hover
Macro expansion erases whitespace information, and so we end with invalid Rust code.
-rw-r--r--crates/ide/src/hover/render.rs21
-rw-r--r--crates/ide/src/hover/tests.rs59
2 files changed, 77 insertions, 3 deletions
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index d52adaee535..c5c50d88dd2 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -2,12 +2,13 @@
 use std::fmt::Display;
 
 use either::Either;
-use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HirDisplay, Semantics, TypeInfo};
+use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo};
 use ide_db::{
     base_db::SourceDatabase,
     defs::Definition,
     famous_defs::FamousDefs,
     generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
+    syntax_helpers::insert_whitespace_into_node,
     RootDatabase,
 };
 use itertools::Itertools;
@@ -350,10 +351,24 @@ pub(super) fn definition(
             let body = it.eval(db);
             match body {
                 Ok(x) => Some(format!("{}", x)),
-                Err(_) => it.value(db).map(|x| format!("{}", x)),
+                Err(_) => {
+                    let source = it.source(db)?;
+                    let mut body = source.value.body()?.syntax().clone();
+                    if source.file_id.is_macro() {
+                        body = insert_whitespace_into_node::insert_ws_into(body);
+                    }
+                    Some(body.to_string())
+                }
+            }
+        }),
+        Definition::Static(it) => label_value_and_docs(db, it, |it| {
+            let source = it.source(db)?;
+            let mut body = source.value.body()?.syntax().clone();
+            if source.file_id.is_macro() {
+                body = insert_whitespace_into_node::insert_ws_into(body);
             }
+            Some(body.to_string())
         }),
-        Definition::Static(it) => label_value_and_docs(db, it, |it| it.value(db)),
         Definition::Trait(it) => label_and_docs(db, it),
         Definition::TypeAlias(it) => label_and_docs(db, it),
         Definition::BuiltinType(it) => {
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 685eb4521eb..d49bc4f99cf 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -5113,3 +5113,62 @@ fn f() {
         "#]],
     );
 }
+
+#[test]
+fn static_const_macro_expanded_body() {
+    check(
+        r#"
+macro_rules! m {
+    () => {
+        pub const V: i8 = {
+            let e = 123;
+            f(e) // Prevent const eval from evaluating this constant, we want to print the body's code.
+        };
+    };
+}
+m!();
+fn main() { $0V; }
+"#,
+        expect![[r#"
+            *V*
+
+            ```rust
+            test
+            ```
+            
+            ```rust
+            pub const V: i8 = {
+              let e = 123;
+              f(e)
+            }
+            ```
+        "#]],
+    );
+    check(
+        r#"
+macro_rules! m {
+    () => {
+        pub static V: i8 = {
+            let e = 123;
+        };
+    };
+}
+m!();
+fn main() { $0V; }
+"#,
+        expect![[r#"
+            *V*
+
+            ```rust
+            test
+            ```
+            
+            ```rust
+            pub static V: i8 = {
+              let e = 123;
+              
+            }
+            ```
+        "#]],
+    );
+}