Repository: rust-analyzer/rust-analyzer
Pull request #4843 (2020-06-11 10:14:36)

Don't guess macro expansion crate


bors r+
🤖


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index df79334c96..22483516ad 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1010,6 +1010,7 @@ dependencies = [
  "ra_prof",
  "ra_syntax",
  "ra_tt",
+ "rustc-hash",
  "test_utils",
 ]
 
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index a8d6466eac..bf26048f2a 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -15,12 +15,10 @@ use std::{
 
 use ra_cfg::CfgOptions;
 use ra_syntax::SmolStr;
-use rustc_hash::FxHashMap;
-use rustc_hash::FxHashSet;
+use ra_tt::TokenExpander;
+use rustc_hash::{FxHashMap, FxHashSet};
 
 use crate::{RelativePath, RelativePathBuf};
-use fmt::Display;
-use ra_tt::TokenExpander;
 
 /// `FileId` is an integer which uniquely identifies a file. File paths are
 /// messy and system-dependent, so most of the code should work directly with
@@ -111,7 +109,7 @@ impl CrateName {
     }
 }
 
-impl Display for CrateName {
+impl fmt::Display for CrateName {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}", self.0)
     }
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 2ab3148840..80ddb6058a 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -7,6 +7,7 @@ use std::{panic, sync::Arc};
 
 use ra_prof::profile;
 use ra_syntax::{ast, Parse, SourceFile, TextRange, TextSize};
+use rustc_hash::FxHashSet;
 
 pub use crate::{
     cancellation::Canceled,
@@ -95,7 +96,7 @@ pub trait FileLoader {
     /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we
     /// get by with a `&str` for the time being.
     fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>;
-    fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>;
+    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>;
 }
 
 /// Database which stores all significant input facts: source code and project
@@ -133,16 +134,21 @@ pub trait SourceDatabaseExt: SourceDatabase {
     #[salsa::input]
     fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
 
-    fn source_root_crates(&self, id: SourceRootId) -> Arc<Vec<CrateId>>;
+    fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>;
 }
 
 fn source_root_crates(
     db: &(impl SourceDatabaseExt + SourceDatabase),
     id: SourceRootId,
-) -> Arc<Vec<CrateId>> {
-    let root = db.source_root(id);
+) -> Arc<FxHashSet<CrateId>> {
     let graph = db.crate_graph();
-    let res = root.walk().filter_map(|it| graph.crate_id_for_crate_root(it)).collect::<Vec<_>>();
+    let res = graph
+        .iter()
+        .filter(|&krate| {
+            let root_file = graph[krate].root_file_id;
+            db.file_source_root(root_file) == id
+        })
+        .collect::<FxHashSet<_>>();
     Arc::new(res)
 }
 
@@ -156,7 +162,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
     fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
         // FIXME: this *somehow* should be platform agnostic...
         if std::path::Path::new(path).is_absolute() {
-            let krate = *self.relevant_crates(anchor).get(0)?;
+            let krate = *self.relevant_crates(anchor).iter().next()?;
             let (extern_source_id, relative_file) =
                 self.0.crate_graph()[krate].extern_source.extern_path(path.as_ref())?;
 
@@ -175,7 +181,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
         }
     }
 
-    fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
+    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
         let source_root = self.0.file_source_root(file_id);
         self.0.source_root_crates(source_root)
     }
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 7c1f79f279..a232a58567 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -122,8 +122,9 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         let macro_call =
             self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call);
         let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
+        let krate = sa.resolver.krate()?;
         let macro_call_id = macro_call
-            .as_call_id(self.db, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?;
+            .as_call_id(self.db, krate, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?;
         hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map)
     }
 
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index 4b509f07c6..7c6bbea13c 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -307,7 +307,8 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         macro_call: InFile<&ast::MacroCall>,
     ) -> Option<HirFileId> {
-        let macro_call_id = macro_call.as_call_id(db.upcast(), |path| {
+        let krate = self.resolver.krate()?;
+        let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
             self.resolver.resolve_path_as_macro(db.upcast(), &path)
         })?;
         Some(macro_call_id.as_file())
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index 273036cee1..4f2350915d 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -97,7 +97,7 @@ impl Expander {
 
         let macro_call = InFile::new(self.current_file_id, &macro_call);
 
-        if let Some(call_id) = macro_call.as_call_id(db, |path| {
+        if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, |path| {
             if let Some(local_scope) = local_scope {
                 if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) {
                     return Some(def);
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index de490fcc58..edc59e5a80 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -417,6 +417,7 @@ pub trait AsMacroCall {
     fn as_call_id(
         &self,
         db: &dyn db::DefDatabase,
+        krate: CrateId,
         resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
     ) -> Option<MacroCallId>;
 }
@@ -425,13 +426,14 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
     fn as_call_id(
         &self,
         db: &dyn db::DefDatabase,
+        krate: CrateId,
         resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
     ) -> Option<MacroCallId> {
         let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
         let h = Hygiene::new(db.upcast(), self.file_id);
         let path = path::ModPath::from_src(self.value.path()?, &h)?;
 
-        AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, resolver)
+        AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, krate, resolver)
     }
 }
 
@@ -452,6 +454,7 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
     fn as_call_id(
         &self,
         db: &dyn db::DefDatabase,
+        krate: CrateId,
         resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
     ) -> Option<MacroCallId> {
         let def: MacroDefId = resolver(self.path.clone())?;
@@ -461,13 +464,13 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> {
             let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id);
 
             Some(
-                expand_eager_macro(db.upcast(), macro_call, def, &|path: ast::Path| {
+                expand_eager_macro(db.upcast(), krate, macro_call, def, &|path: ast::Path| {
                     resolver(path::ModPath::from_src(path, &hygiene)?)
                 })?
                 .into(),
             )
         } else {
-            Some(def.as_lazy_macro(db.upcast(), MacroCallKind::FnLike(self.ast_id)).into())
+            Some(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(self.ast_id)).into())
         }
     }
 }
@@ -476,12 +479,14 @@ impl AsMacroCall for AstIdWithPath<ast::ModuleItem> {
     fn as_call_id(
         &self,
         db: &dyn db::DefDatabase,
+        krate: CrateId,
         resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
     ) -> Option<MacroCallId> {
         let def = resolver(self.path.clone())?;
         Some(
             def.as_lazy_macro(
                 db.upcast(),
+                krate,
                 MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()),
             )
             .into(),
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 353a31ad47..976e5e5850 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -571,16 +571,18 @@ impl DefCollector<'_> {
                 return false;
             }
 
-            if let Some(call_id) = directive.ast_id.as_call_id(self.db, |path| {
-                let resolved_res = self.def_map.resolve_path_fp_with_macro(
-                    self.db,
-                    ResolveMode::Other,
-                    directive.module_id,
-                    &path,
-                    BuiltinShadowMode::Module,
-                );
-                resolved_res.resolved_def.take_macros()
-            }) {
+            if let Some(call_id) =
+                directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| {
+                    let resolved_res = self.def_map.resolve_path_fp_with_macro(
+                        self.db,
+                        ResolveMode::Other,
+                        directive.module_id,
+                        &path,
+                        BuiltinShadowMode::Module,
+                    );
+                    resolved_res.resolved_def.take_macros()
+                })
+            {
                 resolved.push((directive.module_id, call_id, directive.depth));
                 res = ReachedFixedPoint::No;
                 return false;
@@ -589,9 +591,10 @@ impl DefCollector<'_> {
             true
         });
         attribute_macros.retain(|directive| {
-            if let Some(call_id) = directive
-                .ast_id
-                .as_call_id(self.db, |path| self.resolve_attribute_macro(&directive, &path))
+            if let Some(call_id) =
+                directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| {
+                    self.resolve_attribute_macro(&directive, &path)
+                })
             {
                 resolved.push((directive.module_id, call_id, 0));
                 res = ReachedFixedPoint::No;
@@ -957,11 +960,13 @@ impl ModCollector<'_, '_> {
         }
 
         // Case 2: try to resolve in legacy scope and expand macro_rules
-        if let Some(macro_call_id) = ast_id.as_call_id(self.def_collector.db, |path| {
-            path.as_ident().and_then(|name| {
-                self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
+        if let Some(macro_call_id) =
+            ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| {
+                path.as_ident().and_then(|name| {
+                    self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
+                })
             })
-        }) {
+        {
             self.def_collector.unexpanded_macros.push(MacroDirective {
                 module_id: self.module_id,
                 ast_id,
diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml
index 2cd5227660..e5c9f3e997 100644
--- a/crates/ra_hir_expand/Cargo.toml
+++ b/crates/ra_hir_expand/Cargo.toml
@@ -10,6 +10,7 @@ doctest = false
 [dependencies]
 log = "0.4.8"
 either = "1.5.3"
+rustc-hash = "1.0.0"
 
 ra_arena = { path = "../ra_arena" }
 ra_db = { path = "../ra_db" }
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs
index 1dc9cac665..26b667b557 100644
--- a/crates/ra_hir_expand/src/builtin_derive.rs
+++ b/crates/ra_hir_expand/src/builtin_derive.rs
@@ -8,8 +8,7 @@ use ra_syntax::{
     match_ast,
 };
 
-use crate::db::AstDatabase;
-use crate::{name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind};
+use crate::{db::AstDatabase, name, quote, LazyMacroId, MacroDefId, MacroDefKind};
 
 macro_rules! register_builtin {
     ( $($trait:ident => $expand:ident),* ) => {
@@ -156,23 +155,13 @@ fn expand_simple_derive(
 fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree {
     // FIXME: make hygiene works for builtin derive macro
     // such that $crate can be used here.
-
-    let m: MacroCallId = id.into();
-    let file_id = m.as_file().original_file(db);
     let cg = db.crate_graph();
-    let krates = db.relevant_crates(file_id);
-    let krate = match krates.get(0) {
-        Some(krate) => krate,
-        None => {
-            let tt = quote! { core };
-            return tt.token_trees[0].clone();
-        }
-    };
+    let krate = db.lookup_intern_macro(id).krate;
 
     // XXX
     //  All crates except core itself should have a dependency on core,
     //  We detect `core` by seeing whether it doesn't have such a dependency.
-    let tt = if cg[*krate].dependencies.iter().any(|dep| dep.name == "core") {
+    let tt = if cg[krate].dependencies.iter().any(|dep| dep.name == "core") {
         quote! { core }
     } else {
         quote! { crate }
@@ -264,10 +253,12 @@ fn partial_ord_expand(
 
 #[cfg(test)]
 mod tests {
-    use super::*;
-    use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc};
     use name::{known, Name};
-    use ra_db::{fixture::WithFixture, SourceDatabase};
+    use ra_db::{fixture::WithFixture, CrateId, SourceDatabase};
+
+    use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc};
+
+    use super::*;
 
     fn expand_builtin_derive(s: &str, name: Name) -> String {
         let def = find_builtin_derive(&name).unwrap();
@@ -291,7 +282,11 @@ mod tests {
 
         let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]));
 
-        let loc = MacroCallLoc { def, kind: MacroCallKind::Attr(attr_id, name.to_string()) };
+        let loc = MacroCallLoc {
+            def,
+            krate: CrateId(0),
+            kind: MacroCallKind::Attr(attr_id, name.to_string()),
+        };
 
         let id: MacroCallId = db.intern_macro(loc).into();
         let parsed = db.parse_or_expand(id.as_file()).unwrap();
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index 7579546d2f..b50eb347c8 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -1,15 +1,14 @@
 //! Builtin macro
-use crate::db::AstDatabase;
 use crate::{
-    ast::{self, AstToken, HasStringValue},
-    name, AstId, CrateId, MacroDefId, MacroDefKind, TextSize,
+    db::AstDatabase, name, quote, AstId, CrateId, EagerMacroId, LazyMacroId, MacroCallId,
+    MacroDefId, MacroDefKind, TextSize,
 };
 
-use crate::{quote, EagerMacroId, LazyMacroId, MacroCallId};
 use either::Either;
 use mbe::parse_to_token_tree;
 use ra_db::FileId;
 use ra_parser::FragmentKind;
+use ra_syntax::ast::{self, AstToken, HasStringValue};
 
 macro_rules! register_builtin {
     ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),*  ) => {
@@ -333,10 +332,7 @@ fn include_expand(
 }
 
 fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> {
-    let call_id: MacroCallId = arg_id.into();
-    let original_file = call_id.as_file().original_file(db);
-
-    let krate = *db.relevant_crates(original_file).get(0)?;
+    let krate = db.lookup_intern_eager_expansion(arg_id).krate;
     db.crate_graph()[krate].env.get(key)
 }
 
@@ -395,6 +391,7 @@ mod tests {
 
         let expander = find_by_name(&macro_calls[0].name().unwrap().as_name()).unwrap();
 
+        let krate = CrateId(0);
         let file_id = match expander {
             Either::Left(expander) => {
                 // the first one should be a macro_rules
@@ -407,6 +404,7 @@ mod tests {
 
                 let loc = MacroCallLoc {
                     def,
+                    krate,
                     kind: MacroCallKind::FnLike(AstId::new(
                         file_id.into(),
                         ast_id_map.ast_id(&macro_calls[1]),
@@ -419,7 +417,7 @@ mod tests {
             Either::Right(expander) => {
                 // the first one should be a macro_rules
                 let def = MacroDefId {
-                    krate: Some(CrateId(0)),
+                    krate: Some(krate),
                     ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0]))),
                     kind: MacroDefKind::BuiltInEager(expander),
                     local_inner: false,
@@ -433,6 +431,7 @@ mod tests {
                         def,
                         fragment: FragmentKind::Expr,
                         subtree: Arc::new(parsed_args.clone()),
+                        krate,
                         file_id: file_id.into(),
                     }
                 });
@@ -442,6 +441,7 @@ mod tests {
                     def,
                     fragment,
                     subtree: Arc::new(subtree),
+                    krate,
                     file_id: file_id.into(),
                 };
 
diff --git a/crates/ra_hir_expand/src/eager.rs b/crates/ra_hir_expand/src/eager.rs
index 932f47c309..302d2b3e09 100644
--- a/crates/ra_hir_expand/src/eager.rs
+++ b/crates/ra_hir_expand/src/eager.rs
@@ -25,12 +25,14 @@ use crate::{
     EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
 };
 
+use ra_db::CrateId;
 use ra_parser::FragmentKind;
 use ra_syntax::{algo::SyntaxRewriter, SyntaxNode};
 use std::sync::Arc;
 
 pub fn expand_eager_macro(
     db: &dyn AstDatabase,
+    krate: CrateId,
     macro_call: InFile<ast::MacroCall>,
     def: MacroDefId,
     resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
@@ -47,6 +49,7 @@ pub fn expand_eager_macro(
             def,
             fragment: FragmentKind::Expr,
             subtree: Arc::new(parsed_args.clone()),
+            krate,
             file_id: macro_call.file_id,
         }
     });
@@ -56,14 +59,20 @@ pub fn expand_eager_macro(
     let result = eager_macro_recur(
         db,
         InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()),
+        krate,
         resolver,
     )?;
     let subtree = to_subtree(&result)?;
 
     if let MacroDefKind::BuiltInEager(eager) = def.kind {
         let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?;
-        let eager =
-            EagerCallLoc { def, fragment, subtree: Arc::new(subtree), file_id: macro_call.file_id };
+        let eager = EagerCallLoc {
+            def,
+            fragment,
+            subtree: Arc::new(subtree),
+            krate,
+            file_id: macro_call.file_id,
+        };
 
         Some(db.intern_eager_expansion(eager))
     } else {
@@ -81,11 +90,12 @@ fn lazy_expand(
     db: &dyn AstDatabase,
     def: &MacroDefId,
     macro_call: InFile<ast::MacroCall>,
+    krate: CrateId,
 ) -> Option<InFile<SyntaxNode>> {
     let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);
 
     let id: MacroCallId =
-        def.as_lazy_macro(db, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into();
+        def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into();
 
     db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node))
 }
@@ -93,6 +103,7 @@ fn lazy_expand(
 fn eager_macro_recur(
     db: &dyn AstDatabase,
     curr: InFile<SyntaxNode>,
+    krate: CrateId,
     macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
 ) -> Option<SyntaxNode> {
     let original = curr.value.clone();
@@ -105,18 +116,23 @@ fn eager_macro_recur(
         let def: MacroDefId = macro_resolver(child.path()?)?;
         let insert = match def.kind {
             MacroDefKind::BuiltInEager(_) => {
-                let id: MacroCallId =
-                    expand_eager_macro(db, curr.with_value(child.clone()), def, macro_resolver)?
-                        .into();
+                let id: MacroCallId = expand_eager_macro(
+                    db,
+                    krate,
+                    curr.with_value(child.clone()),
+                    def,
+                    macro_resolver,
+                )?
+                .into();
                 db.parse_or_expand(id.as_file())?
             }
             MacroDefKind::Declarative
             | MacroDefKind::BuiltIn(_)
             | MacroDefKind::BuiltInDerive(_)
             | MacroDefKind::CustomDerive(_) => {
-                let expanded = lazy_expand(db, &def, curr.with_value(child.clone()))?;
+                let expanded = lazy_expand(db, &def, curr.with_value(child.clone()), krate)?;
                 // replace macro inside
-                eager_macro_recur(db, expanded, macro_resolver)?
+                eager_macro_recur(db, expanded, krate, macro_resolver)?
             }
         };
 
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index f440c073ba..5eac2605b9 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -209,8 +209,13 @@ pub struct MacroDefId {
 }
 
 impl MacroDefId {
-    pub fn as_lazy_macro(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> LazyMacroId {
-        db.intern_macro(MacroCallLoc { def: self, kind })
+    pub fn as_lazy_macro(
+        self,
+        db: &dyn db::AstDatabase,
+        krate: CrateId,
+        kind: MacroCallKind,
+    ) -> LazyMacroId {
+        db.intern_macro(MacroCallLoc { def: self, krate, kind })
     }
 }
 
@@ -227,6 +232,7 @@ pub enum MacroDefKind {
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct MacroCallLoc {
     pub(crate) def: MacroDefId,
+    pub(crate) krate: CrateId,
     pub(crate) kind: MacroCallKind,
 }
 
@@ -274,6 +280,7 @@ pub struct EagerCallLoc {
     pub(crate) def: MacroDefId,
     pub(crate) fragment: FragmentKind,
     pub(crate) subtree: Arc<tt::Subtree>,
+    pub(crate) krate: CrateId,
     pub(crate) file_id: HirFileId,
 }
 
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs
index 727d743b5f..480fd45764 100644
--- a/crates/ra_ide_db/src/lib.rs
+++ b/crates/ra_ide_db/src/lib.rs
@@ -19,7 +19,7 @@ use ra_db::{
     Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
     SourceRootId, Upcast,
 };
-use rustc_hash::FxHashMap;
+use rustc_hash::{FxHashMap, FxHashSet};
 
 use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
 
@@ -60,7 +60,7 @@ impl FileLoader for RootDatabase {
     fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
         FileLoaderDelegate(self).resolve_path(anchor, path)
     }
-    fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
+    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
         FileLoaderDelegate(self).relevant_crates(file_id)
     }
 }
diff --git a/docs/dev/README.md b/docs/dev/README.md
index ef5ffbf597..0330939b6e 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -303,17 +303,6 @@ Rather than talking in definitions and references, it talks in Strings and textu
 In general, API is centered around UI concerns -- the result of the call is what the user sees in the editor, and not what the compiler sees underneath.
 The results are 100% Rust specific though.
 
-## Parser Tests
-
-Test for parser (`ra_parser`) live in `ra_syntax` crate (see `test_data` direcotory).
-There are two kinds of tests:
-
-* Manually written test cases in `parser/ok` and `parser/err`
-* "Inline" tests in `parser/inline` (these are generated) from comments in `ra_parser` crate.
-
-The purpose of inline tests is not to achieve full coverage by test cases, but to explain to the reader of the code what each particular `if` and `match` is responsible for.
-If you are tempted to add a large inline test, it might be a good idea to leave only the simplest example in place, and move the test to a manual `parser/ok` test.
-
 # Logging
 
 Logging is done by both rust-analyzer and VS Code, so it might be tricky to


Test patch:
diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs
index bcfa66ac95..4581d87453 100644
--- a/crates/ra_hir_def/src/test_db.rs
+++ b/crates/ra_hir_def/src/test_db.rs
@@ -7,6 +7,7 @@ use std::{
 
 use hir_expand::db::AstDatabase;
 use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast};
+use rustc_hash::FxHashSet;
 
 use crate::db::DefDatabase;
 
@@ -59,7 +60,7 @@ impl FileLoader for TestDB {
     fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
         FileLoaderDelegate(self).resolve_path(anchor, path)
     }
-    fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
+    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
         FileLoaderDelegate(self).relevant_crates(file_id)
     }
 }
diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs
index fdf225f55b..09fc18c360 100644
--- a/crates/ra_hir_expand/src/test_db.rs
+++ b/crates/ra_hir_expand/src/test_db.rs
@@ -6,6 +6,7 @@ use std::{
 };
 
 use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate};
+use rustc_hash::FxHashSet;
 
 #[salsa::database(
     ra_db::SourceDatabaseExtStorage,
@@ -44,7 +45,7 @@ impl FileLoader for TestDB {
     fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
         FileLoaderDelegate(self).resolve_path(anchor, path)
     }
-    fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
+    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
         FileLoaderDelegate(self).relevant_crates(file_id)
     }
 }
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index e484968a09..ad04e3e0f9 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -8,6 +8,7 @@ use std::{
 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId};
 use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink};
 use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast};
+use rustc_hash::FxHashSet;
 use stdx::format_to;
 
 use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator};
@@ -73,7 +74,7 @@ impl FileLoader for TestDB {
     fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
         FileLoaderDelegate(self).resolve_path(anchor, path)
     }
-    fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
+    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
         FileLoaderDelegate(self).relevant_crates(file_id)
     }
 }