1221: Use correct FileId when expanding macros in expressions r=matklad a=matklad



Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2019-05-01 12:56:02 +00:00
commit c368b147e3
2 changed files with 44 additions and 33 deletions

View file

@ -10,7 +10,7 @@ use ra_syntax::{
}; };
use crate::{ use crate::{
Path, Name, HirDatabase, Resolver,DefWithBody, Either, Path, Name, HirDatabase, Resolver,DefWithBody, Either, HirFileId,
name::AsName, name::AsName,
ids::{MacroCallId}, ids::{MacroCallId},
type_ref::{Mutability, TypeRef}, type_ref::{Mutability, TypeRef},
@ -488,15 +488,19 @@ pub(crate) struct ExprCollector<DB> {
params: Vec<PatId>, params: Vec<PatId>,
body_expr: Option<ExprId>, body_expr: Option<ExprId>,
resolver: Resolver, resolver: Resolver,
// FIXEME: Its a quick hack,see issue #1196 // Expr collector expands macros along the way. original points to the file
is_in_macro: bool, // we started with, current points to the current macro expansion. source
// maps don't support macros yet, so we only record info into source map if
// current == original (see #1196)
original_file_id: HirFileId,
current_file_id: HirFileId,
} }
impl<'a, DB> ExprCollector<&'a DB> impl<'a, DB> ExprCollector<&'a DB>
where where
DB: HirDatabase, DB: HirDatabase,
{ {
fn new(owner: DefWithBody, resolver: Resolver, db: &'a DB) -> Self { fn new(owner: DefWithBody, file_id: HirFileId, resolver: Resolver, db: &'a DB) -> Self {
ExprCollector { ExprCollector {
owner, owner,
resolver, resolver,
@ -506,23 +510,23 @@ where
source_map: BodySourceMap::default(), source_map: BodySourceMap::default(),
params: Vec::new(), params: Vec::new(),
body_expr: None, body_expr: None,
is_in_macro: false, original_file_id: file_id,
current_file_id: file_id,
} }
} }
fn alloc_expr(&mut self, expr: Expr, syntax_ptr: SyntaxNodePtr) -> ExprId { fn alloc_expr(&mut self, expr: Expr, syntax_ptr: SyntaxNodePtr) -> ExprId {
let id = self.exprs.alloc(expr); let id = self.exprs.alloc(expr);
if !self.is_in_macro { if self.current_file_id == self.original_file_id {
self.source_map.expr_map.insert(syntax_ptr, id); self.source_map.expr_map.insert(syntax_ptr, id);
self.source_map.expr_map_back.insert(id, syntax_ptr); self.source_map.expr_map_back.insert(id, syntax_ptr);
} }
id id
} }
fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
let id = self.pats.alloc(pat); let id = self.pats.alloc(pat);
if !self.is_in_macro { if self.current_file_id == self.original_file_id {
self.source_map.pat_map.insert(ptr, id); self.source_map.pat_map.insert(ptr, id);
self.source_map.pat_map_back.insert(id, ptr); self.source_map.pat_map_back.insert(id, ptr);
} }
@ -815,12 +819,19 @@ where
// very hacky.FIXME change to use the macro resolution // very hacky.FIXME change to use the macro resolution
let path = e.path().and_then(Path::from_ast); let path = e.path().and_then(Path::from_ast);
if let Some(call_id) = self.resolver.resolve_macro_call(self.db, path, e) { let ast_id = self
.db
.ast_id_map(self.current_file_id)
.ast_id(e)
.with_file_id(self.current_file_id);
if let Some(call_id) = self.resolver.resolve_macro_call(self.db, path, ast_id) {
if let Some(expr) = expand_macro_to_expr(self.db, call_id, e.token_tree()) { if let Some(expr) = expand_macro_to_expr(self.db, call_id, e.token_tree()) {
log::debug!("macro expansion {}", expr.syntax().debug_dump()); log::debug!("macro expansion {}", expr.syntax().debug_dump());
let old = std::mem::replace(&mut self.is_in_macro, true); let old_file_id =
std::mem::replace(&mut self.current_file_id, call_id.into());
let id = self.collect_expr(&expr); let id = self.collect_expr(&expr);
self.is_in_macro = old; self.current_file_id = old_file_id;
id id
} else { } else {
// FIXME: Instead of just dropping the error from expansion // FIXME: Instead of just dropping the error from expansion
@ -1006,12 +1017,24 @@ pub(crate) fn body_with_source_map_query(
db: &impl HirDatabase, db: &impl HirDatabase,
def: DefWithBody, def: DefWithBody,
) -> (Arc<Body>, Arc<BodySourceMap>) { ) -> (Arc<Body>, Arc<BodySourceMap>) {
let mut collector = ExprCollector::new(def, def.resolver(db), db); let mut collector;
match def { match def {
DefWithBody::Const(ref c) => collector.collect_const_body(&c.source(db).1), DefWithBody::Const(ref c) => {
DefWithBody::Function(ref f) => collector.collect_fn_body(&f.source(db).1), let (file_id, src) = c.source(db);
DefWithBody::Static(ref s) => collector.collect_static_body(&s.source(db).1), collector = ExprCollector::new(def, file_id, def.resolver(db), db);
collector.collect_const_body(&src)
}
DefWithBody::Function(ref f) => {
let (file_id, src) = f.source(db);
collector = ExprCollector::new(def, file_id, def.resolver(db), db);
collector.collect_fn_body(&src)
}
DefWithBody::Static(ref s) => {
let (file_id, src) = s.source(db);
collector = ExprCollector::new(def, file_id, def.resolver(db), db);
collector.collect_static_body(&src)
}
} }
let (body, source_map) = collector.finish(); let (body, source_map) = collector.finish();

View file

@ -10,6 +10,7 @@ use crate::{
code_model_api::Crate, code_model_api::Crate,
MacroCallId, MacroCallId,
MacroCallLoc, MacroCallLoc,
AstId,
db::HirDatabase, db::HirDatabase,
name::{Name, KnownName}, name::{Name, KnownName},
nameres::{PerNs, CrateDefMap, CrateModuleId}, nameres::{PerNs, CrateDefMap, CrateModuleId},
@ -17,7 +18,7 @@ use crate::{
expr::{scope::{ExprScopes, ScopeId}, PatId}, expr::{scope::{ExprScopes, ScopeId}, PatId},
impl_block::ImplBlock, impl_block::ImplBlock,
path::Path, path::Path,
Trait Trait,
}; };
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
@ -138,25 +139,12 @@ impl Resolver {
&self, &self,
db: &impl HirDatabase, db: &impl HirDatabase,
path: Option<Path>, path: Option<Path>,
call: &ast::MacroCall, ast_id: AstId<ast::MacroCall>,
) -> Option<MacroCallId> { ) -> Option<MacroCallId> {
let name = path.and_then(|path| path.expand_macro_expr()).unwrap_or_else(Name::missing); let name = path.and_then(|path| path.expand_macro_expr()).unwrap_or_else(Name::missing);
let macro_def_id = self.module().and_then(|(module, _)| module.find_macro(&name)); let def_id = self.module().and_then(|(module, _)| module.find_macro(&name))?;
if let Some(def_id) = macro_def_id {
self.module().and_then(|(module, _)| {
// we do this to get the ast_id for the macro call
// if we used the ast_id from the def_id variable
// it gives us the ast_id of the defenition site
let module = module.mk_module(module.root());
let hir_file_id = module.definition_source(db).0;
let ast_id = db.ast_id_map(hir_file_id).ast_id(call).with_file_id(hir_file_id);
let call_loc = MacroCallLoc { def: *def_id, ast_id }.id(db); let call_loc = MacroCallLoc { def: *def_id, ast_id }.id(db);
Some(call_loc) Some(call_loc)
})
} else {
None
}
} }
/// Returns the resolved path segments /// Returns the resolved path segments