diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-04 19:38:10 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-04 19:38:10 +0100 |
commit | aa7bdfd37f999607806cf47c0108d33a5b44b3e5 (patch) | |
tree | 83e606dd367454ce65262b77e0a64d723c858d35 /crates | |
parent | 9c49f6c36e1e097f938946811d1e2f5eb70edca9 (diff) | |
parent | 8198e13c26fe985af5893af7bdac04041880b461 (diff) |
Merge #1208
1208: [WIP] Goto for Macro's r=matklad a=Lapz
Adds goto definition for macros. Currently only works for macros in the current crate ~~otherwise it panics~~. Proper macro resolution needs to be added for it to resolve macros in other crates.
Todo
- [X] Allow goto from macro calls
- [X] Fix panics
- [x] Add tests
![Screen Recording 2019-04-25 at 18 00 24](https://user-images.githubusercontent.com/19998186/56754499-1dd01c00-6785-11e9-9e9a-1e36de70cfa3.gif)
Co-authored-by: Lenard Pratt <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 43 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/completion_item.rs | 1 | ||||
-rw-r--r-- | crates/ra_ide_api/src/display/navigation_target.rs | 10 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_definition.rs | 40 | ||||
-rw-r--r-- | crates/ra_ide_api/src/marks.rs | 1 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/conv.rs | 1 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 1 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 2 |
9 files changed, 97 insertions, 6 deletions
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 4411715de..03b1063b6 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -69,7 +69,7 @@ pub use self::{ | |||
69 | expr::ExprScopes, | 69 | expr::ExprScopes, |
70 | resolve::Resolution, | 70 | resolve::Resolution, |
71 | generics::{GenericParams, GenericParam, HasGenericParams}, | 71 | generics::{GenericParams, GenericParam, HasGenericParams}, |
72 | source_binder::{SourceAnalyzer, PathResolution, ScopeEntryWithSyntax}, | 72 | source_binder::{SourceAnalyzer, PathResolution, ScopeEntryWithSyntax,MacroByExampleDef}, |
73 | }; | 73 | }; |
74 | 74 | ||
75 | pub use self::code_model_api::{ | 75 | pub use self::code_model_api::{ |
@@ -80,5 +80,5 @@ pub use self::code_model_api::{ | |||
80 | Function, FnSignature, | 80 | Function, FnSignature, |
81 | StructField, FieldSource, | 81 | StructField, FieldSource, |
82 | Static, Const, ConstSignature, | 82 | Static, Const, ConstSignature, |
83 | Trait, TypeAlias, Container, | 83 | Trait, TypeAlias, Container |
84 | }; | 84 | }; |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 2ec1a7692..31bf13425 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -10,7 +10,7 @@ use std::sync::Arc; | |||
10 | use rustc_hash::{FxHashSet, FxHashMap}; | 10 | use rustc_hash::{FxHashSet, FxHashMap}; |
11 | use ra_db::{FileId, FilePosition}; | 11 | use ra_db::{FileId, FilePosition}; |
12 | use ra_syntax::{ | 12 | use ra_syntax::{ |
13 | SyntaxNode, AstPtr, TextUnit, SyntaxNodePtr, TextRange, | 13 | SyntaxNode, AstPtr, TextUnit, SyntaxNodePtr, TextRange,TreeArc, |
14 | ast::{self, AstNode, NameOwner}, | 14 | ast::{self, AstNode, NameOwner}, |
15 | algo::find_node_at_offset, | 15 | algo::find_node_at_offset, |
16 | SyntaxKind::*, | 16 | SyntaxKind::*, |
@@ -18,9 +18,10 @@ use ra_syntax::{ | |||
18 | 18 | ||
19 | use crate::{ | 19 | use crate::{ |
20 | HirDatabase, Function, Struct, Enum, Const, Static, Either, DefWithBody, PerNs, Name, | 20 | HirDatabase, Function, Struct, Enum, Const, Static, Either, DefWithBody, PerNs, Name, |
21 | AsName, Module, HirFileId, Crate, Trait, Resolver, Ty, | 21 | AsName, Module, HirFileId, Crate, Trait, Resolver, Ty,Path, |
22 | expr::{BodySourceMap, scope::{ScopeId, ExprScopes}}, | 22 | expr::{BodySourceMap, scope::{ScopeId, ExprScopes}}, |
23 | ids::LocationCtx, | 23 | ids::{LocationCtx,MacroCallId}, |
24 | docs::{docs_from_ast,Documentation}, | ||
24 | expr, AstId, | 25 | expr, AstId, |
25 | }; | 26 | }; |
26 | 27 | ||
@@ -184,9 +185,28 @@ pub enum PathResolution { | |||
184 | /// A generic parameter | 185 | /// A generic parameter |
185 | GenericParam(u32), | 186 | GenericParam(u32), |
186 | SelfType(crate::ImplBlock), | 187 | SelfType(crate::ImplBlock), |
188 | Macro(MacroByExampleDef), | ||
187 | AssocItem(crate::ImplItem), | 189 | AssocItem(crate::ImplItem), |
188 | } | 190 | } |
189 | 191 | ||
192 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
193 | pub struct MacroByExampleDef { | ||
194 | pub(crate) id: MacroCallId, | ||
195 | } | ||
196 | |||
197 | impl MacroByExampleDef { | ||
198 | pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::MacroCall>) { | ||
199 | let loc = self.id.loc(db); | ||
200 | (self.id.into(), loc.def.0.to_node(db)) | ||
201 | } | ||
202 | } | ||
203 | |||
204 | impl crate::Docs for MacroByExampleDef { | ||
205 | fn docs(&self, db: &impl HirDatabase) -> Option<Documentation> { | ||
206 | docs_from_ast(&*self.source(db).1) | ||
207 | } | ||
208 | } | ||
209 | |||
190 | #[derive(Debug, Clone, PartialEq, Eq)] | 210 | #[derive(Debug, Clone, PartialEq, Eq)] |
191 | pub struct ScopeEntryWithSyntax { | 211 | pub struct ScopeEntryWithSyntax { |
192 | pub(crate) name: Name, | 212 | pub(crate) name: Name, |
@@ -264,6 +284,23 @@ impl SourceAnalyzer { | |||
264 | self.infer.as_ref()?.field_resolution(expr_id) | 284 | self.infer.as_ref()?.field_resolution(expr_id) |
265 | } | 285 | } |
266 | 286 | ||
287 | pub fn resolve_macro_call( | ||
288 | &self, | ||
289 | db: &impl HirDatabase, | ||
290 | file_id: FileId, | ||
291 | macro_call: &ast::MacroCall, | ||
292 | ) -> Option<MacroByExampleDef> { | ||
293 | let hir_id = file_id.into(); | ||
294 | let ast_id = db.ast_id_map(hir_id).ast_id(macro_call).with_file_id(hir_id); | ||
295 | let call_id = self.resolver.resolve_macro_call( | ||
296 | db, | ||
297 | macro_call.path().and_then(Path::from_ast), | ||
298 | ast_id, | ||
299 | ); | ||
300 | |||
301 | call_id.map(|id| MacroByExampleDef { id }) | ||
302 | } | ||
303 | |||
267 | pub fn resolve_hir_path( | 304 | pub fn resolve_hir_path( |
268 | &self, | 305 | &self, |
269 | db: &impl HirDatabase, | 306 | db: &impl HirDatabase, |
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 { | |||
89 | TypeAlias, | 89 | TypeAlias, |
90 | Method, | 90 | Method, |
91 | TypeParam, | 91 | TypeParam, |
92 | Macro, | ||
92 | } | 93 | } |
93 | 94 | ||
94 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] | 95 | #[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 { | |||
213 | } | 213 | } |
214 | } | 214 | } |
215 | 215 | ||
216 | pub(crate) fn from_macro_def( | ||
217 | db: &RootDatabase, | ||
218 | macro_call: hir::MacroByExampleDef, | ||
219 | ) -> NavigationTarget { | ||
220 | let (file_id, node) = macro_call.source(db); | ||
221 | log::debug!("nav target {}", node.syntax().debug_dump()); | ||
222 | NavigationTarget::from_named(file_id.original_file(db), &*node) | ||
223 | } | ||
224 | |||
216 | #[cfg(test)] | 225 | #[cfg(test)] |
217 | pub(crate) fn assert_match(&self, expected: &str) { | 226 | pub(crate) fn assert_match(&self, expected: &str) { |
218 | let actual = self.debug_render(); | 227 | let actual = self.debug_render(); |
@@ -289,6 +298,7 @@ impl NavigationTarget { | |||
289 | .visit(doc_comments::<ast::StaticDef>) | 298 | .visit(doc_comments::<ast::StaticDef>) |
290 | .visit(doc_comments::<ast::NamedFieldDef>) | 299 | .visit(doc_comments::<ast::NamedFieldDef>) |
291 | .visit(doc_comments::<ast::EnumVariant>) | 300 | .visit(doc_comments::<ast::EnumVariant>) |
301 | .visit(doc_comments::<ast::MacroCall>) | ||
292 | .accept(&node)? | 302 | .accept(&node)? |
293 | } | 303 | } |
294 | 304 | ||
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( | |||
59 | return Exact(NavigationTarget::from_function(db, func)); | 59 | return Exact(NavigationTarget::from_function(db, func)); |
60 | } | 60 | } |
61 | } | 61 | } |
62 | |||
63 | //it could be a macro call | ||
64 | if let Some(macro_call) = name_ref | ||
65 | .syntax() | ||
66 | .parent() | ||
67 | .and_then(|node| node.parent()) | ||
68 | .and_then(|node| node.parent()) | ||
69 | .and_then(ast::MacroCall::cast) | ||
70 | { | ||
71 | tested_by!(goto_definition_works_for_macros); | ||
72 | if let Some(macro_call) = analyzer.resolve_macro_call(db, file_id, macro_call) { | ||
73 | return Exact(NavigationTarget::from_macro_def(db, macro_call)); | ||
74 | } | ||
75 | } | ||
76 | |||
62 | // It could also be a field access | 77 | // It could also be a field access |
63 | if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast) { | 78 | if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast) { |
64 | tested_by!(goto_definition_works_for_fields); | 79 | tested_by!(goto_definition_works_for_fields); |
@@ -97,6 +112,10 @@ pub(crate) fn reference_definition( | |||
97 | hir::PathResolution::GenericParam(..) => { | 112 | hir::PathResolution::GenericParam(..) => { |
98 | // FIXME: go to the generic param def | 113 | // FIXME: go to the generic param def |
99 | } | 114 | } |
115 | hir::PathResolution::Macro(def) => { | ||
116 | let nav = NavigationTarget::from_macro_def(db, def); | ||
117 | return Exact(nav); | ||
118 | } | ||
100 | hir::PathResolution::SelfType(impl_block) => { | 119 | hir::PathResolution::SelfType(impl_block) => { |
101 | let ty = impl_block.target_ty(db); | 120 | let ty = impl_block.target_ty(db); |
102 | 121 | ||
@@ -156,6 +175,7 @@ fn named_target(file_id: FileId, node: &SyntaxNode) -> Option<NavigationTarget> | |||
156 | .visit(|node: &ast::TraitDef| NavigationTarget::from_named(file_id, node)) | 175 | .visit(|node: &ast::TraitDef| NavigationTarget::from_named(file_id, node)) |
157 | .visit(|node: &ast::NamedFieldDef| NavigationTarget::from_named(file_id, node)) | 176 | .visit(|node: &ast::NamedFieldDef| NavigationTarget::from_named(file_id, node)) |
158 | .visit(|node: &ast::Module| NavigationTarget::from_named(file_id, node)) | 177 | .visit(|node: &ast::Module| NavigationTarget::from_named(file_id, node)) |
178 | .visit(|node: &ast::MacroCall| NavigationTarget::from_named(file_id, node)) | ||
159 | .accept(node) | 179 | .accept(node) |
160 | } | 180 | } |
161 | 181 | ||
@@ -228,6 +248,26 @@ mod tests { | |||
228 | } | 248 | } |
229 | 249 | ||
230 | #[test] | 250 | #[test] |
251 | fn goto_definition_works_for_macros() { | ||
252 | covers!(goto_definition_works_for_macros); | ||
253 | check_goto( | ||
254 | " | ||
255 | //- /lib.rs | ||
256 | macro_rules! foo { | ||
257 | () => { | ||
258 | {} | ||
259 | }; | ||
260 | } | ||
261 | |||
262 | fn bar() { | ||
263 | <|>foo!(); | ||
264 | } | ||
265 | ", | ||
266 | "foo MACRO_CALL FileId(1) [0; 50) [13; 16)", | ||
267 | ); | ||
268 | } | ||
269 | |||
270 | #[test] | ||
231 | fn goto_definition_works_for_methods() { | 271 | fn goto_definition_works_for_methods() { |
232 | covers!(goto_definition_works_for_methods); | 272 | covers!(goto_definition_works_for_methods); |
233 | check_goto( | 273 | check_goto( |
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 @@ | |||
1 | test_utils::marks!( | 1 | test_utils::marks!( |
2 | inserts_parens_for_function_calls | 2 | inserts_parens_for_function_calls |
3 | goto_definition_works_for_macros | ||
3 | goto_definition_works_for_methods | 4 | goto_definition_works_for_methods |
4 | goto_definition_works_for_fields | 5 | goto_definition_works_for_fields |
5 | goto_definition_works_for_named_fields | 6 | goto_definition_works_for_named_fields |
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index 4d6ede316..50a12ddbc 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs | |||
@@ -73,6 +73,7 @@ impl Conv for CompletionItemKind { | |||
73 | CompletionItemKind::Static => Value, | 73 | CompletionItemKind::Static => Value, |
74 | CompletionItemKind::Method => Method, | 74 | CompletionItemKind::Method => Method, |
75 | CompletionItemKind::TypeParam => TypeParameter, | 75 | CompletionItemKind::TypeParam => TypeParameter, |
76 | CompletionItemKind::Macro => Method, | ||
76 | } | 77 | } |
77 | } | 78 | } |
78 | } | 79 | } |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 19a3362ca..89d3a35c5 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -1761,6 +1761,7 @@ impl ToOwned for MacroCall { | |||
1761 | 1761 | ||
1762 | impl ast::NameOwner for MacroCall {} | 1762 | impl ast::NameOwner for MacroCall {} |
1763 | impl ast::AttrsOwner for MacroCall {} | 1763 | impl ast::AttrsOwner for MacroCall {} |
1764 | impl ast::DocCommentsOwner for MacroCall {} | ||
1764 | impl MacroCall { | 1765 | impl MacroCall { |
1765 | pub fn token_tree(&self) -> Option<&TokenTree> { | 1766 | pub fn token_tree(&self) -> Option<&TokenTree> { |
1766 | super::child_opt(self) | 1767 | super::child_opt(self) |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 011ef0616..c7abdd6dc 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -552,7 +552,7 @@ Grammar( | |||
552 | "Name": (), | 552 | "Name": (), |
553 | "NameRef": (), | 553 | "NameRef": (), |
554 | "MacroCall": ( | 554 | "MacroCall": ( |
555 | traits: [ "NameOwner", "AttrsOwner" ], | 555 | traits: [ "NameOwner", "AttrsOwner","DocCommentsOwner" ], |
556 | options: [ "TokenTree", "Path" ], | 556 | options: [ "TokenTree", "Path" ], |
557 | ), | 557 | ), |
558 | "Attr": ( options: [ ["value", "TokenTree"] ] ), | 558 | "Attr": ( options: [ ["value", "TokenTree"] ] ), |