From 8198e13c26fe985af5893af7bdac04041880b461 Mon Sep 17 00:00:00 2001
From: Lenard Pratt <l3np27@gmail.com>
Date: Wed, 24 Apr 2019 21:16:50 +0100
Subject: Added local macro goto

---
 .../ra_ide_api/src/completion/completion_item.rs   |  1 +
 crates/ra_ide_api/src/display/navigation_target.rs | 10 ++++++
 crates/ra_ide_api/src/goto_definition.rs           | 40 ++++++++++++++++++++++
 crates/ra_ide_api/src/marks.rs                     |  1 +
 4 files changed, 52 insertions(+)

(limited to 'crates/ra_ide_api/src')

diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs
index f515fcc14..6f1392231 100644
--- a/crates/ra_ide_api/src/completion/completion_item.rs
+++ b/crates/ra_ide_api/src/completion/completion_item.rs
@@ -89,6 +89,7 @@ pub enum CompletionItemKind {
     TypeAlias,
     Method,
     TypeParam,
+    Macro,
 }
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs
index 84645287d..765cf883b 100644
--- a/crates/ra_ide_api/src/display/navigation_target.rs
+++ b/crates/ra_ide_api/src/display/navigation_target.rs
@@ -213,6 +213,15 @@ impl NavigationTarget {
         }
     }
 
+    pub(crate) fn from_macro_def(
+        db: &RootDatabase,
+        macro_call: hir::MacroByExampleDef,
+    ) -> NavigationTarget {
+        let (file_id, node) = macro_call.source(db);
+        log::debug!("nav target {}", node.syntax().debug_dump());
+        NavigationTarget::from_named(file_id.original_file(db), &*node)
+    }
+
     #[cfg(test)]
     pub(crate) fn assert_match(&self, expected: &str) {
         let actual = self.debug_render();
@@ -289,6 +298,7 @@ impl NavigationTarget {
             .visit(doc_comments::<ast::StaticDef>)
             .visit(doc_comments::<ast::NamedFieldDef>)
             .visit(doc_comments::<ast::EnumVariant>)
+            .visit(doc_comments::<ast::MacroCall>)
             .accept(&node)?
     }
 
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 163781f88..533c229fe 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -59,6 +59,21 @@ pub(crate) fn reference_definition(
             return Exact(NavigationTarget::from_function(db, func));
         }
     }
+
+    //it could be a macro call
+    if let Some(macro_call) = name_ref
+        .syntax()
+        .parent()
+        .and_then(|node| node.parent())
+        .and_then(|node| node.parent())
+        .and_then(ast::MacroCall::cast)
+    {
+        tested_by!(goto_definition_works_for_macros);
+        if let Some(macro_call) = analyzer.resolve_macro_call(db, file_id, macro_call) {
+            return Exact(NavigationTarget::from_macro_def(db, macro_call));
+        }
+    }
+
     // It could also be a field access
     if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast) {
         tested_by!(goto_definition_works_for_fields);
@@ -97,6 +112,10 @@ pub(crate) fn reference_definition(
                 hir::PathResolution::GenericParam(..) => {
                     // FIXME: go to the generic param def
                 }
+                hir::PathResolution::Macro(def) => {
+                    let nav = NavigationTarget::from_macro_def(db, def);
+                    return Exact(nav);
+                }
                 hir::PathResolution::SelfType(impl_block) => {
                     let ty = impl_block.target_ty(db);
 
@@ -156,6 +175,7 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget>
         .visit(|node: &ast::TraitDef| NavigationTarget::from_named(file_id, node))
         .visit(|node: &ast::NamedFieldDef| NavigationTarget::from_named(file_id, node))
         .visit(|node: &ast::Module| NavigationTarget::from_named(file_id, node))
+        .visit(|node: &ast::MacroCall| NavigationTarget::from_named(file_id, node))
         .accept(node)
 }
 
@@ -227,6 +247,26 @@ mod tests {
         );
     }
 
+    #[test]
+    fn goto_definition_works_for_macros() {
+        covers!(goto_definition_works_for_macros);
+        check_goto(
+            "
+            //- /lib.rs
+            macro_rules! foo {
+                () => {
+                    {}
+                };
+            }
+
+            fn bar() {
+                <|>foo!();
+            }
+            ",
+            "foo MACRO_CALL FileId(1) [0; 50) [13; 16)",
+        );
+    }
+
     #[test]
     fn goto_definition_works_for_methods() {
         covers!(goto_definition_works_for_methods);
diff --git a/crates/ra_ide_api/src/marks.rs b/crates/ra_ide_api/src/marks.rs
index bcbe0d21b..cc894a7df 100644
--- a/crates/ra_ide_api/src/marks.rs
+++ b/crates/ra_ide_api/src/marks.rs
@@ -1,5 +1,6 @@
 test_utils::marks!(
     inserts_parens_for_function_calls
+    goto_definition_works_for_macros
     goto_definition_works_for_methods
     goto_definition_works_for_fields
     goto_definition_works_for_named_fields
-- 
cgit v1.2.3