]> git.lizzy.rs Git - rust.git/commitdiff
Add macro call support for type_of
authorEdwin Cheng <edwin0cheng@gmail.com>
Mon, 23 Dec 2019 05:18:28 +0000 (13:18 +0800)
committerEdwin Cheng <edwin0cheng@gmail.com>
Mon, 23 Dec 2019 05:19:01 +0000 (13:19 +0800)
crates/ra_assists/src/assists/add_explicit_type.rs
crates/ra_hir/src/source_binder.rs
crates/ra_hir_def/src/body.rs
crates/ra_hir_def/src/lib.rs

index eeb4ff39f4c27842ffafa43d53ee5fe618b2b069..2c602a79eee211dd6d306316ae756fad5a1d407c 100644 (file)
@@ -73,6 +73,24 @@ fn add_explicit_type_works_for_simple_expr() {
         );
     }
 
+    #[test]
+    fn add_explicit_type_works_for_macro_call() {
+        check_assist(
+            add_explicit_type,
+            "macro_rules! v { () => {0u64} } fn f() { let a<|> = v!(); }",
+            "macro_rules! v { () => {0u64} } fn f() { let a<|>: u64 = v!(); }",
+        );
+    }
+
+    #[test]
+    fn add_explicit_type_works_for_macro_call_recursive() {
+        check_assist(
+            add_explicit_type,
+            "macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|> = v!(); }",
+            "macro_rules! u { () => {0u64} } macro_rules! v { () => {u!()} } fn f() { let a<|>: u64 = v!(); }",
+        );
+    }
+
     #[test]
     fn add_explicit_type_not_applicable_if_ty_not_inferred() {
         check_assist_not_applicable(add_explicit_type, "fn f() { let a<|> = None; }");
index 85b378483c65540003c3a454c2695871b26c605e..3af477818a3b228a3b2e6743528318107b933c00 100644 (file)
@@ -17,7 +17,7 @@
     nameres::ModuleSource,
     path::path,
     resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs},
-    AssocItemId, DefWithBodyId,
+    AssocItemId, DefWithBodyId, Expander,
 };
 use hir_expand::{
     hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind,
@@ -216,7 +216,14 @@ fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
     }
 
     pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option<Type> {
-        let expr_id = self.expr_id(expr)?;
+        let expr_id = if let Some(macro_call) = ast::MacroCall::cast(expr.syntax().clone()) {
+            let mut expander = Expander::new(db, self.file_id, self.body_owner?.module(db).id);
+            let expr = expand_macro_call_to_expr(db, &mut expander, macro_call)?;
+            self.body_source_map.as_ref()?.node_expr(expr.as_ref())?
+        } else {
+            self.expr_id(expr)?
+        };
+
         let ty = self.infer.as_ref()?[expr_id].clone();
         let environment = TraitEnvironment::lower(db, &self.resolver);
         Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } })
@@ -501,6 +508,21 @@ fn scope_for_offset(
         })
 }
 
+fn expand_macro_call_to_expr(
+    db: &impl HirDatabase,
+    expander: &mut Expander,
+    macro_call: ast::MacroCall,
+) -> Option<InFile<ast::Expr>> {
+    let (mark, expr): (_, ast::Expr) = expander.enter_expand(db, macro_call)?;
+    let expr = if let Some(child) = ast::MacroCall::cast(expr.syntax().clone()) {
+        expand_macro_call_to_expr(db, expander, child)
+    } else {
+        Some(expander.to_source(expr))
+    };
+    expander.exit(db, mark);
+    expr
+}
+
 // XXX: during completion, cursor might be outside of any particular
 // expression. Try to figure out the correct scope...
 fn adjust(
index d3e4c50ae0608825b01f766b0e9007b8ec7efbc8..8ab92b23a86b833b4cf43b0b95843d8d52a578a2 100644 (file)
@@ -26,7 +26,7 @@
     DefWithBodyId, HasModule, Lookup, ModuleId,
 };
 
-pub(crate) struct Expander {
+pub struct Expander {
     crate_def_map: Arc<CrateDefMap>,
     current_file_id: HirFileId,
     hygiene: Hygiene,
@@ -35,18 +35,14 @@ pub(crate) struct Expander {
 }
 
 impl Expander {
-    pub(crate) fn new(
-        db: &impl DefDatabase,
-        current_file_id: HirFileId,
-        module: ModuleId,
-    ) -> Expander {
+    pub fn new(db: &impl DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
         let crate_def_map = db.crate_def_map(module.krate);
         let hygiene = Hygiene::new(db, current_file_id);
         let ast_id_map = db.ast_id_map(current_file_id);
         Expander { crate_def_map, current_file_id, hygiene, ast_id_map, module }
     }
 
-    pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>(
+    pub fn enter_expand<T: ast::AstNode, DB: DefDatabase>(
         &mut self,
         db: &DB,
         macro_call: ast::MacroCall,
@@ -84,14 +80,14 @@ pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>(
         None
     }
 
-    pub(crate) fn exit(&mut self, db: &impl DefDatabase, mut mark: Mark) {
+    pub fn exit(&mut self, db: &impl DefDatabase, mut mark: Mark) {
         self.hygiene = Hygiene::new(db, mark.file_id);
         self.current_file_id = mark.file_id;
         self.ast_id_map = mem::take(&mut mark.ast_id_map);
         mark.bomb.defuse();
     }
 
-    pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> {
+    pub fn to_source<T>(&self, value: T) -> InFile<T> {
         InFile { file_id: self.current_file_id, value }
     }
 
@@ -116,7 +112,7 @@ fn ast_id<N: AstNode>(&self, item: &N) -> AstId<N> {
     }
 }
 
-pub(crate) struct Mark {
+pub struct Mark {
     file_id: HirFileId,
     ast_id_map: Arc<AstIdMap>,
     bomb: DropBomb,
index f6c7f38d171c2e06812bc79f8de962672966951c..f58ce9a955c0587380338ce99aee1349dd8e4671 100644 (file)
@@ -48,7 +48,7 @@
 use ra_db::{impl_intern_key, salsa, CrateId};
 use ra_syntax::{ast, AstNode};
 
-use crate::body::Expander;
+pub use crate::body::Expander;
 use crate::builtin_type::BuiltinType;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]