about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/annotations.rs82
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/navigation_target.rs2
2 files changed, 76 insertions, 8 deletions
diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
index 3d71da985b2..05196ac98c0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
@@ -10,6 +10,7 @@ use crate::{
     NavigationTarget, RunnableKind,
     annotations::fn_references::find_all_methods,
     goto_implementation::goto_implementation,
+    navigation_target,
     references::find_all_refs,
     runnables::{Runnable, runnables},
 };
@@ -148,15 +149,32 @@ pub(crate) fn annotations(
             node: InFile<T>,
             source_file_id: FileId,
         ) -> Option<(TextRange, Option<TextRange>)> {
-            if let Some(InRealFile { file_id, value }) = node.original_ast_node_rooted(db) {
-                if file_id.file_id(db) == source_file_id {
-                    return Some((
-                        value.syntax().text_range(),
-                        value.name().map(|name| name.syntax().text_range()),
-                    ));
+            if let Some(name) = node.value.name().map(|name| name.syntax().text_range()) {
+                // if we have a name, try mapping that out of the macro expansion as we can put the
+                // annotation on that name token
+                // See `test_no_annotations_macro_struct_def` vs `test_annotations_macro_struct_def_call_site`
+                let res = navigation_target::orig_range_with_focus_r(
+                    db,
+                    node.file_id,
+                    node.value.syntax().text_range(),
+                    Some(name),
+                );
+                if res.call_site.0.file_id == source_file_id {
+                    if let Some(name_range) = res.call_site.1 {
+                        return Some((res.call_site.0.range, Some(name_range)));
+                    }
                 }
+            };
+            // otherwise try upmapping the entire node out of attributes
+            let InRealFile { file_id, value } = node.original_ast_node_rooted(db)?;
+            if file_id.file_id(db) == source_file_id {
+                Some((
+                    value.syntax().text_range(),
+                    value.name().map(|name| name.syntax().text_range()),
+                ))
+            } else {
+                None
             }
-            None
         }
     });
 
@@ -914,6 +932,56 @@ m!();
     }
 
     #[test]
+    fn test_annotations_macro_struct_def_call_site() {
+        check(
+            r#"
+//- /lib.rs
+macro_rules! m {
+    ($name:ident) => {
+        struct $name {}
+    };
+}
+
+m! {
+    Name
+};
+"#,
+            expect![[r#"
+                [
+                    Annotation {
+                        range: 83..87,
+                        kind: HasImpls {
+                            pos: FilePositionWrapper {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 83,
+                            },
+                            data: Some(
+                                [],
+                            ),
+                        },
+                    },
+                    Annotation {
+                        range: 83..87,
+                        kind: HasReferences {
+                            pos: FilePositionWrapper {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 83,
+                            },
+                            data: Some(
+                                [],
+                            ),
+                        },
+                    },
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
     fn test_annotations_appear_above_whole_item_when_configured_to_do_so() {
         check_with_config(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
index 9334b73fc7b..4c7c597e684 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -867,7 +867,7 @@ pub(crate) fn orig_range_with_focus_r(
             }
 
             // def site name
-            // FIXME: This can be de improved
+            // FIXME: This can be improved
             Some((focus_range, _ctxt)) => {
                 match value_range {
                     // but overall node is in macro input