aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdwin Cheng <[email protected]>2019-12-23 05:18:28 +0000
committerEdwin Cheng <[email protected]>2019-12-23 05:19:01 +0000
commit16156d766dd8a5624d9455ffded6358fe879c416 (patch)
tree5e76885085a5a566cb1f946afd20bc5d2547334e
parent60aa4d12f95477565d5b01f122d2c9dd845015b4 (diff)
Add macro call support for type_of
-rw-r--r--crates/ra_assists/src/assists/add_explicit_type.rs18
-rw-r--r--crates/ra_hir/src/source_binder.rs26
-rw-r--r--crates/ra_hir_def/src/body.rs16
-rw-r--r--crates/ra_hir_def/src/lib.rs2
4 files changed, 49 insertions, 13 deletions
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs
index eeb4ff39f..2c602a79e 100644
--- a/crates/ra_assists/src/assists/add_explicit_type.rs
+++ b/crates/ra_assists/src/assists/add_explicit_type.rs
@@ -74,6 +74,24 @@ mod tests {
74 } 74 }
75 75
76 #[test] 76 #[test]
77 fn add_explicit_type_works_for_macro_call() {
78 check_assist(
79 add_explicit_type,
80 "macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }",
81 "macro_rules! v { () => {0u64} } fn f() { let a<|>: u64 = v!(); }",
82 );
83 }
84
85 #[test]
86 fn add_explicit_type_works_for_macro_call_recursive() {
87 check_assist(
88 add_explicit_type,
89 "macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|> = v!(); }",
90 "macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|>: u64 = v!(); }",
91 );
92 }
93
94 #[test]
77 fn add_explicit_type_not_applicable_if_ty_not_inferred() { 95 fn add_explicit_type_not_applicable_if_ty_not_inferred() {
78 check_assist_not_applicable(add_explicit_type, "fn f() { let a<|> = None; }"); 96 check_assist_not_applicable(add_explicit_type, "fn f() { let a<|> = None; }");
79 } 97 }
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 85b378483..3af477818 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -17,7 +17,7 @@ use hir_def::{
17 nameres::ModuleSource, 17 nameres::ModuleSource,
18 path::path, 18 path::path,
19 resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs}, 19 resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs},
20 AssocItemId, DefWithBodyId, 20 AssocItemId, DefWithBodyId, Expander,
21}; 21};
22use hir_expand::{ 22use hir_expand::{
23 hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind, 23 hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind,
@@ -216,7 +216,14 @@ impl SourceAnalyzer {
216 } 216 }
217 217
218 pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option<Type> { 218 pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option<Type> {
219 let expr_id = self.expr_id(expr)?; 219 let expr_id = if let Some(macro_call) = ast::MacroCall::cast(expr.syntax().clone()) {
220 let mut expander = Expander::new(db, self.file_id, self.body_owner?.module(db).id);
221 let expr = expand_macro_call_to_expr(db, &mut expander, macro_call)?;
222 self.body_source_map.as_ref()?.node_expr(expr.as_ref())?
223 } else {
224 self.expr_id(expr)?
225 };
226
220 let ty = self.infer.as_ref()?[expr_id].clone(); 227 let ty = self.infer.as_ref()?[expr_id].clone();
221 let environment = TraitEnvironment::lower(db, &self.resolver); 228 let environment = TraitEnvironment::lower(db, &self.resolver);
222 Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) 229 Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } })
@@ -501,6 +508,21 @@ fn scope_for_offset(
501 }) 508 })
502} 509}
503 510
511fn expand_macro_call_to_expr(
512 db: &impl HirDatabase,
513 expander: &mut Expander,
514 macro_call: ast::MacroCall,
515) -> Option<InFile<ast::Expr>> {
516 let (mark, expr): (_, ast::Expr) = expander.enter_expand(db, macro_call)?;
517 let expr = if let Some(child) = ast::MacroCall::cast(expr.syntax().clone()) {
518 expand_macro_call_to_expr(db, expander, child)
519 } else {
520 Some(expander.to_source(expr))
521 };
522 expander.exit(db, mark);
523 expr
524}
525
504// XXX: during completion, cursor might be outside of any particular 526// XXX: during completion, cursor might be outside of any particular
505// expression. Try to figure out the correct scope... 527// expression. Try to figure out the correct scope...
506fn adjust( 528fn adjust(
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index d3e4c50ae..8ab92b23a 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -26,7 +26,7 @@ use crate::{
26 DefWithBodyId, HasModule, Lookup, ModuleId, 26 DefWithBodyId, HasModule, Lookup, ModuleId,
27}; 27};
28 28
29pub(crate) struct Expander { 29pub struct Expander {
30 crate_def_map: Arc<CrateDefMap>, 30 crate_def_map: Arc<CrateDefMap>,
31 current_file_id: HirFileId, 31 current_file_id: HirFileId,
32 hygiene: Hygiene, 32 hygiene: Hygiene,
@@ -35,18 +35,14 @@ pub(crate) struct Expander {
35} 35}
36 36
37impl Expander { 37impl Expander {
38 pub(crate) fn new( 38 pub fn new(db: &impl DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
39 db: &impl DefDatabase,
40 current_file_id: HirFileId,
41 module: ModuleId,
42 ) -> Expander {
43 let crate_def_map = db.crate_def_map(module.krate); 39 let crate_def_map = db.crate_def_map(module.krate);
44 let hygiene = Hygiene::new(db, current_file_id); 40 let hygiene = Hygiene::new(db, current_file_id);
45 let ast_id_map = db.ast_id_map(current_file_id); 41 let ast_id_map = db.ast_id_map(current_file_id);
46 Expander { crate_def_map, current_file_id, hygiene, ast_id_map, module } 42 Expander { crate_def_map, current_file_id, hygiene, ast_id_map, module }
47 } 43 }
48 44
49 pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>( 45 pub fn enter_expand<T: ast::AstNode, DB: DefDatabase>(
50 &mut self, 46 &mut self,
51 db: &DB, 47 db: &DB,
52 macro_call: ast::MacroCall, 48 macro_call: ast::MacroCall,
@@ -84,14 +80,14 @@ impl Expander {
84 None 80 None
85 } 81 }
86 82
87 pub(crate) fn exit(&mut self, db: &impl DefDatabase, mut mark: Mark) { 83 pub fn exit(&mut self, db: &impl DefDatabase, mut mark: Mark) {
88 self.hygiene = Hygiene::new(db, mark.file_id); 84 self.hygiene = Hygiene::new(db, mark.file_id);
89 self.current_file_id = mark.file_id; 85 self.current_file_id = mark.file_id;
90 self.ast_id_map = mem::take(&mut mark.ast_id_map); 86 self.ast_id_map = mem::take(&mut mark.ast_id_map);
91 mark.bomb.defuse(); 87 mark.bomb.defuse();
92 } 88 }
93 89
94 pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> { 90 pub fn to_source<T>(&self, value: T) -> InFile<T> {
95 InFile { file_id: self.current_file_id, value } 91 InFile { file_id: self.current_file_id, value }
96 } 92 }
97 93
@@ -116,7 +112,7 @@ impl Expander {
116 } 112 }
117} 113}
118 114
119pub(crate) struct Mark { 115pub struct Mark {
120 file_id: HirFileId, 116 file_id: HirFileId,
121 ast_id_map: Arc<AstIdMap>, 117 ast_id_map: Arc<AstIdMap>,
122 bomb: DropBomb, 118 bomb: DropBomb,
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index f6c7f38d1..f58ce9a95 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -48,7 +48,7 @@ use ra_arena::{impl_arena_id, RawId};
48use ra_db::{impl_intern_key, salsa, CrateId}; 48use ra_db::{impl_intern_key, salsa, CrateId};
49use ra_syntax::{ast, AstNode}; 49use ra_syntax::{ast, AstNode};
50 50
51use crate::body::Expander; 51pub use crate::body::Expander;
52use crate::builtin_type::BuiltinType; 52use crate::builtin_type::BuiltinType;
53 53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 54#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]