From 16156d766dd8a5624d9455ffded6358fe879c416 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Mon, 23 Dec 2019 13:18:28 +0800 Subject: Add macro call support for type_of --- crates/ra_assists/src/assists/add_explicit_type.rs | 18 +++++++++++++++ crates/ra_hir/src/source_binder.rs | 26 ++++++++++++++++++++-- crates/ra_hir_def/src/body.rs | 16 +++++-------- crates/ra_hir_def/src/lib.rs | 2 +- 4 files changed, 49 insertions(+), 13 deletions(-) (limited to 'crates') 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 @@ -73,6 +73,24 @@ mod tests { ); } + #[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; }"); 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::{ 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 @@ impl SourceAnalyzer { } pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option { - 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> { + 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( 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::{ DefWithBodyId, HasModule, Lookup, ModuleId, }; -pub(crate) struct Expander { +pub struct Expander { crate_def_map: Arc, 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( + pub fn enter_expand( &mut self, db: &DB, macro_call: ast::MacroCall, @@ -84,14 +80,14 @@ impl Expander { 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(&self, value: T) -> InFile { + pub fn to_source(&self, value: T) -> InFile { InFile { file_id: self.current_file_id, value } } @@ -116,7 +112,7 @@ impl Expander { } } -pub(crate) struct Mark { +pub struct Mark { file_id: HirFileId, ast_id_map: Arc, 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}; 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)] -- cgit v1.2.3