about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml2
-rw-r--r--crates/hir/src/attrs.rs2
-rw-r--r--crates/hir/src/lib.rs2
-rw-r--r--crates/hir/src/source_analyzer.rs2
-rw-r--r--crates/hir_def/src/attr.rs21
-rw-r--r--crates/hir_def/src/body.rs6
-rw-r--r--crates/hir_def/src/body/lower.rs28
-rw-r--r--crates/hir_def/src/find_path.rs2
-rw-r--r--crates/hir_def/src/item_tree.rs2
-rw-r--r--crates/hir_def/src/item_tree/lower.rs34
-rw-r--r--crates/hir_def/src/lib.rs4
-rw-r--r--crates/hir_def/src/nameres.rs1
-rw-r--r--crates/hir_def/src/nameres/tests/incremental.rs52
-rw-r--r--crates/hir_def/src/path.rs9
-rw-r--r--crates/hir_def/src/path/lower.rs4
-rw-r--r--crates/hir_def/src/path/lower/lower_use.rs23
-rw-r--r--crates/hir_def/src/visibility.rs8
-rw-r--r--crates/hir_expand/src/hygiene.rs57
-rw-r--r--crates/hir_ty/src/display.rs2
19 files changed, 180 insertions, 81 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 46c64d35c22..d34251fc010 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,3 +27,5 @@ debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger.
 # chalk-recursive = { path = "../chalk/chalk-recursive" }
 
 # ungrammar = { path = "../ungrammar" }
+
+# salsa = { path = "../salsa" }
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 4a11622fc91..e8fa3c56eca 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -112,7 +112,7 @@ fn resolve_doc_path(
         AttrDefId::MacroDefId(_) => return None,
     };
     let path = ast::Path::parse(link).ok()?;
-    let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap();
+    let modpath = ModPath::from_src(db.upcast(), path, &Hygiene::new_unhygienic()).unwrap();
     let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath);
     if resolved == PerNs::none() {
         if let Some(trait_id) = resolver.resolve_module_path_in_trait_items(db.upcast(), &modpath) {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 6fcc58f612e..f876339decb 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1666,7 +1666,7 @@ impl Impl {
             .value
             .attrs()
             .filter_map(|it| {
-                let path = ModPath::from_src(it.path()?, &hygenic)?;
+                let path = ModPath::from_src(db.upcast(), it.path()?, &hygenic)?;
                 if path.as_ident()?.to_string() == "derive" {
                     Some(it)
                 } else {
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 0895bd6f1f1..b5c65808e60 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -283,7 +283,7 @@ impl SourceAnalyzer {
 
         // This must be a normal source file rather than macro file.
         let hygiene = Hygiene::new(db.upcast(), self.file_id);
-        let ctx = body::LowerCtx::with_hygiene(&hygiene);
+        let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
         let hir_path = Path::from_src(path.clone(), &ctx)?;
 
         // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 0171d8a92a1..a2479016e57 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -95,13 +95,17 @@ impl ops::Deref for AttrsWithOwner {
 impl RawAttrs {
     pub(crate) const EMPTY: Self = Self { entries: None };
 
-    pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self {
+    pub(crate) fn new(
+        db: &dyn DefDatabase,
+        owner: &dyn ast::AttrsOwner,
+        hygiene: &Hygiene,
+    ) -> Self {
         let entries = collect_attrs(owner)
             .enumerate()
             .flat_map(|(i, attr)| {
                 let index = AttrId(i as u32);
                 match attr {
-                    Either::Left(attr) => Attr::from_src(attr, hygiene, index),
+                    Either::Left(attr) => Attr::from_src(db, attr, hygiene, index),
                     Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
                         id: index,
                         input: Some(AttrInput::Literal(SmolStr::new(doc))),
@@ -116,7 +120,7 @@ impl RawAttrs {
 
     fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::AttrsOwner>) -> Self {
         let hygiene = Hygiene::new(db.upcast(), owner.file_id);
-        Self::new(owner.value, &hygiene)
+        Self::new(db, owner.value, &hygiene)
     }
 
     pub(crate) fn merge(&self, other: Self) -> Self {
@@ -170,7 +174,7 @@ impl RawAttrs {
                     let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?;
                     // FIXME hygiene
                     let hygiene = Hygiene::new_unhygienic();
-                    Attr::from_src(attr, &hygiene, index)
+                    Attr::from_src(db, attr, &hygiene, index)
                 });
 
                 let cfg_options = &crate_graph[krate].cfg_options;
@@ -627,8 +631,13 @@ pub enum AttrInput {
 }
 
 impl Attr {
-    fn from_src(ast: ast::Attr, hygiene: &Hygiene, id: AttrId) -> Option<Attr> {
-        let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?);
+    fn from_src(
+        db: &dyn DefDatabase,
+        ast: ast::Attr,
+        hygiene: &Hygiene,
+        id: AttrId,
+    ) -> Option<Attr> {
+        let path = Interned::new(ModPath::from_src(db, ast.path()?, hygiene)?);
         let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
             let value = match lit.kind() {
                 ast::LiteralKind::String(string) => string.value()?.into(),
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 131f424cc8b..8360426f139 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -72,7 +72,7 @@ impl CfgExpander {
     }
 
     pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> Attrs {
-        RawAttrs::new(owner, &self.hygiene).filter(db, self.krate)
+        RawAttrs::new(db, owner, &self.hygiene).filter(db, self.krate)
     }
 
     pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> bool {
@@ -192,8 +192,8 @@ impl Expander {
         self.current_file_id
     }
 
-    fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
-        let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene);
+    fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> {
+        let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene);
         Path::from_src(path, &ctx)
     }
 
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index c11da30d2e0..75dc19c117a 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -40,23 +40,25 @@ use crate::{
 
 use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
 
-pub struct LowerCtx {
+pub struct LowerCtx<'a> {
+    pub db: &'a dyn DefDatabase,
     hygiene: Hygiene,
     file_id: Option<HirFileId>,
     source_ast_id_map: Option<Arc<AstIdMap>>,
 }
 
-impl LowerCtx {
-    pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self {
+impl<'a> LowerCtx<'a> {
+    pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
         LowerCtx {
+            db,
             hygiene: Hygiene::new(db.upcast(), file_id),
             file_id: Some(file_id),
             source_ast_id_map: Some(db.ast_id_map(file_id)),
         }
     }
 
-    pub fn with_hygiene(hygiene: &Hygiene) -> Self {
-        LowerCtx { hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None }
+    pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self {
+        LowerCtx { db, hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None }
     }
 
     pub(crate) fn hygiene(&self) -> &Hygiene {
@@ -145,7 +147,7 @@ impl ExprCollector<'_> {
         (self.body, self.source_map)
     }
 
-    fn ctx(&self) -> LowerCtx {
+    fn ctx(&self) -> LowerCtx<'_> {
         LowerCtx::new(self.db, self.expander.current_file_id)
     }
 
@@ -376,7 +378,7 @@ impl ExprCollector<'_> {
             ast::Expr::PathExpr(e) => {
                 let path = e
                     .path()
-                    .and_then(|path| self.expander.parse_path(path))
+                    .and_then(|path| self.expander.parse_path(self.db, path))
                     .map(Expr::Path)
                     .unwrap_or(Expr::Missing);
                 self.alloc_expr(path, syntax_ptr)
@@ -408,7 +410,8 @@ impl ExprCollector<'_> {
                 self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
             }
             ast::Expr::RecordExpr(e) => {
-                let path = e.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
+                let path =
+                    e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
                 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
                     let fields = nfl
                         .fields()
@@ -791,7 +794,8 @@ impl ExprCollector<'_> {
                 }
             }
             ast::Pat::TupleStructPat(p) => {
-                let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
+                let path =
+                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
                 let (args, ellipsis) = self.collect_tuple_pat(p.fields());
                 Pat::TupleStruct { path, args, ellipsis }
             }
@@ -801,7 +805,8 @@ impl ExprCollector<'_> {
                 Pat::Ref { pat, mutability }
             }
             ast::Pat::PathPat(p) => {
-                let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
+                let path =
+                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
                 path.map(Pat::Path).unwrap_or(Pat::Missing)
             }
             ast::Pat::OrPat(p) => {
@@ -815,7 +820,8 @@ impl ExprCollector<'_> {
             }
             ast::Pat::WildcardPat(_) => Pat::Wild,
             ast::Pat::RecordPat(p) => {
-                let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
+                let path =
+                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
                 let args: Vec<_> = p
                     .record_pat_field_list()
                     .expect("every struct should have a field list")
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index c06a372948d..858e8803810 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -386,7 +386,7 @@ mod tests {
         let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path));
         let ast_path =
             parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap();
-        let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap();
+        let mod_path = ModPath::from_src(&db, ast_path, &Hygiene::new_unhygienic()).unwrap();
 
         let def_map = module.def_map(&db);
         let resolved = def_map
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index eaeca01bd06..8d13c7e047a 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -88,7 +88,7 @@ impl ItemTree {
         let mut item_tree = match_ast! {
             match syntax {
                 ast::SourceFile(file) => {
-                    top_attrs = Some(RawAttrs::new(&file, &hygiene));
+                    top_attrs = Some(RawAttrs::new(db, &file, &hygiene));
                     ctx.lower_module_items(&file)
                 },
                 ast::MacroItems(items) => {
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 45b099cf319..5743b338626 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -31,18 +31,20 @@ where
     }
 }
 
-pub(super) struct Ctx {
+pub(super) struct Ctx<'a> {
+    db: &'a dyn DefDatabase,
     tree: ItemTree,
     hygiene: Hygiene,
     file: HirFileId,
     source_ast_id_map: Arc<AstIdMap>,
-    body_ctx: crate::body::LowerCtx,
+    body_ctx: crate::body::LowerCtx<'a>,
     forced_visibility: Option<RawVisibilityId>,
 }
 
-impl Ctx {
-    pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self {
+impl<'a> Ctx<'a> {
+    pub(super) fn new(db: &'a dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self {
         Self {
+            db,
             tree: ItemTree::default(),
             hygiene,
             file,
@@ -126,7 +128,7 @@ impl Ctx {
             | ast::Item::MacroDef(_) => {}
         };
 
-        let attrs = RawAttrs::new(item, &self.hygiene);
+        let attrs = RawAttrs::new(self.db, item, &self.hygiene);
         let items = match item {
             ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into),
             ast::Item::Union(ast) => self.lower_union(ast).map(Into::into),
@@ -256,7 +258,7 @@ impl Ctx {
         for field in fields.fields() {
             if let Some(data) = self.lower_record_field(&field) {
                 let idx = self.data().fields.alloc(data);
-                self.add_attrs(idx.into(), RawAttrs::new(&field, &self.hygiene));
+                self.add_attrs(idx.into(), RawAttrs::new(self.db, &field, &self.hygiene));
             }
         }
         let end = self.next_field_idx();
@@ -276,7 +278,7 @@ impl Ctx {
         for (i, field) in fields.fields().enumerate() {
             let data = self.lower_tuple_field(i, &field);
             let idx = self.data().fields.alloc(data);
-            self.add_attrs(idx.into(), RawAttrs::new(&field, &self.hygiene));
+            self.add_attrs(idx.into(), RawAttrs::new(self.db, &field, &self.hygiene));
         }
         let end = self.next_field_idx();
         IdRange::new(start..end)
@@ -321,7 +323,7 @@ impl Ctx {
         for variant in variants.variants() {
             if let Some(data) = self.lower_variant(&variant) {
                 let idx = self.data().variants.alloc(data);
-                self.add_attrs(idx.into(), RawAttrs::new(&variant, &self.hygiene));
+                self.add_attrs(idx.into(), RawAttrs::new(self.db, &variant, &self.hygiene));
             }
         }
         let end = self.next_variant_idx();
@@ -364,7 +366,7 @@ impl Ctx {
                 };
                 let ty = Interned::new(self_type);
                 let idx = self.data().params.alloc(Param::Normal(ty));
-                self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene));
+                self.add_attrs(idx.into(), RawAttrs::new(self.db, &self_param, &self.hygiene));
                 has_self_param = true;
             }
             for param in param_list.params() {
@@ -376,7 +378,7 @@ impl Ctx {
                         self.data().params.alloc(Param::Normal(ty))
                     }
                 };
-                self.add_attrs(idx.into(), RawAttrs::new(&param, &self.hygiene));
+                self.add_attrs(idx.into(), RawAttrs::new(self.db, &param, &self.hygiene));
             }
         }
         let end_param = self.next_param_idx();
@@ -522,10 +524,11 @@ impl Ctx {
         let is_unsafe = trait_def.unsafe_token().is_some();
         let bounds = self.lower_type_bounds(trait_def);
         let items = trait_def.assoc_item_list().map(|list| {
+            let db = self.db;
             self.with_inherited_visibility(visibility, |this| {
                 list.assoc_items()
                     .filter_map(|item| {
-                        let attrs = RawAttrs::new(&item, &this.hygiene);
+                        let attrs = RawAttrs::new(db, &item, &this.hygiene);
                         this.collect_inner_items(item.syntax());
                         this.lower_assoc_item(&item).map(|item| {
                             this.add_attrs(ModItem::from(item).into(), attrs);
@@ -567,7 +570,7 @@ impl Ctx {
             .filter_map(|item| {
                 self.collect_inner_items(item.syntax());
                 let assoc = self.lower_assoc_item(&item)?;
-                let attrs = RawAttrs::new(&item, &self.hygiene);
+                let attrs = RawAttrs::new(self.db, &item, &self.hygiene);
                 self.add_attrs(ModItem::from(assoc).into(), attrs);
                 Some(assoc)
             })
@@ -585,6 +588,7 @@ impl Ctx {
         let mut imports = Vec::new();
         let tree = self.tree.data_mut();
         ModPath::expand_use_item(
+            self.db,
             InFile::new(self.file, use_item.clone()),
             &self.hygiene,
             |path, _use_tree, is_glob, alias| {
@@ -618,7 +622,7 @@ impl Ctx {
     }
 
     fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
-        let path = Interned::new(ModPath::from_src(m.path()?, &self.hygiene)?);
+        let path = Interned::new(ModPath::from_src(self.db, m.path()?, &self.hygiene)?);
         let ast_id = self.source_ast_id_map.ast_id(m);
         let res = MacroCall { path, ast_id };
         Some(id(self.data().macro_calls.alloc(res)))
@@ -647,7 +651,7 @@ impl Ctx {
             list.extern_items()
                 .filter_map(|item| {
                     self.collect_inner_items(item.syntax());
-                    let attrs = RawAttrs::new(&item, &self.hygiene);
+                    let attrs = RawAttrs::new(self.db, &item, &self.hygiene);
                     let id: ModItem = match item {
                         ast::ExternItem::Fn(ast) => {
                             let func_id = self.lower_function(&ast)?;
@@ -755,7 +759,7 @@ impl Ctx {
     fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId {
         let vis = match self.forced_visibility {
             Some(vis) => return vis,
-            None => RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene),
+            None => RawVisibility::from_ast_with_hygiene(self.db, item.visibility(), &self.hygiene),
         };
 
         self.data().vis.alloc(vis)
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 25694f0372b..da46f16f7a1 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -654,7 +654,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
     ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
         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 = self.value.path().and_then(|path| path::ModPath::from_src(path, &h));
+        let path = self.value.path().and_then(|path| path::ModPath::from_src(db, path, &h));
 
         let path = match error_sink
             .option(path, || mbe::ExpandError::Other("malformed macro invocation".into()))
@@ -712,7 +712,7 @@ fn macro_call_as_call_id(
             krate,
             macro_call,
             def,
-            &|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?),
+            &|path: ast::Path| resolver(path::ModPath::from_src(db, path, &hygiene)?),
             error_sink,
         )
         .map(MacroCallId::from)
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index ba027c44a65..1bc72ec1f05 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -599,6 +599,7 @@ mod diagnostics {
                     let mut cur = 0;
                     let mut tree = None;
                     ModPath::expand_use_item(
+                        db,
                         InFile::new(ast.file_id, use_item),
                         &hygiene,
                         |_mod_path, use_tree, _is_glob, _alias| {
diff --git a/crates/hir_def/src/nameres/tests/incremental.rs b/crates/hir_def/src/nameres/tests/incremental.rs
index 509e1bbbc08..227ecd162f6 100644
--- a/crates/hir_def/src/nameres/tests/incremental.rs
+++ b/crates/hir_def/src/nameres/tests/incremental.rs
@@ -105,3 +105,55 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
         assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
     }
 }
+
+#[test]
+fn typing_inside_a_function_should_not_invalidate_expansions() {
+    let (mut db, pos) = TestDB::with_position(
+        r#"
+//- /lib.rs
+macro_rules! m {
+    ($ident:ident) => {
+        fn $ident() { };
+    }
+}
+mod foo;
+
+//- /foo/mod.rs
+pub mod bar;
+
+//- /foo/bar.rs
+m!(X);
+fn quux() { 1$0 }
+m!(Y);
+m!(Z);
+"#,
+    );
+    let krate = db.test_crate();
+    {
+        let events = db.log_executed(|| {
+            let crate_def_map = db.crate_def_map(krate);
+            let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
+            assert_eq!(module_data.scope.resolutions().count(), 4);
+        });
+        let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
+        assert_eq!(n_recalculated_item_trees, 6);
+    }
+
+    let new_text = r#"
+m!(X);
+fn quux() { 92 }
+m!(Y);
+m!(Z);
+"#;
+    db.set_file_text(pos.file_id, Arc::new(new_text.to_string()));
+
+    {
+        let events = db.log_executed(|| {
+            let crate_def_map = db.crate_def_map(krate);
+            let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
+            assert_eq!(module_data.scope.resolutions().count(), 4);
+        });
+        let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
+        assert_eq!(n_recalculated_item_trees, 1);
+    }
+}
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 509f77850a3..a43441b1c2c 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -7,7 +7,7 @@ use std::{
     sync::Arc,
 };
 
-use crate::{body::LowerCtx, intern::Interned, type_ref::LifetimeRef};
+use crate::{body::LowerCtx, db::DefDatabase, intern::Interned, type_ref::LifetimeRef};
 use base_db::CrateId;
 use hir_expand::{
     hygiene::Hygiene,
@@ -47,8 +47,8 @@ pub enum ImportAlias {
 }
 
 impl ModPath {
-    pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
-        let ctx = LowerCtx::with_hygiene(hygiene);
+    pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
+        let ctx = LowerCtx::with_hygiene(db, hygiene);
         lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone())
     }
 
@@ -64,12 +64,13 @@ impl ModPath {
 
     /// Calls `cb` with all paths, represented by this use item.
     pub(crate) fn expand_use_item(
+        db: &dyn DefDatabase,
         item_src: InFile<ast::Use>,
         hygiene: &Hygiene,
         mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>),
     ) {
         if let Some(tree) = item_src.value.use_tree() {
-            lower::lower_use_tree(None, tree, hygiene, &mut cb);
+            lower::lower_use_tree(db, None, tree, hygiene, &mut cb);
         }
     }
 
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index 1df6db5250e..a873325b24b 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -36,7 +36,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
         match segment.kind()? {
             ast::PathSegmentKind::Name(name_ref) => {
                 // FIXME: this should just return name
-                match hygiene.name_ref_to_name(name_ref) {
+                match hygiene.name_ref_to_name(ctx.db.upcast(), name_ref) {
                     Either::Left(name) => {
                         let args = segment
                             .generic_arg_list()
@@ -133,7 +133,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
     // We follow what it did anyway :)
     if segments.len() == 1 && kind == PathKind::Plain {
         if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
-            if let Some(crate_id) = hygiene.local_inner_macros(path) {
+            if let Some(crate_id) = hygiene.local_inner_macros(ctx.db.upcast(), path) {
                 kind = PathKind::DollarCrate(crate_id);
             }
         }
diff --git a/crates/hir_def/src/path/lower/lower_use.rs b/crates/hir_def/src/path/lower/lower_use.rs
index e2965b03365..ee80e3df3ca 100644
--- a/crates/hir_def/src/path/lower/lower_use.rs
+++ b/crates/hir_def/src/path/lower/lower_use.rs
@@ -7,9 +7,13 @@ use either::Either;
 use hir_expand::{hygiene::Hygiene, name::AsName};
 use syntax::ast::{self, NameOwner};
 
-use crate::path::{ImportAlias, ModPath, PathKind};
+use crate::{
+    db::DefDatabase,
+    path::{ImportAlias, ModPath, PathKind},
+};
 
 pub(crate) fn lower_use_tree(
+    db: &dyn DefDatabase,
     prefix: Option<ModPath>,
     tree: ast::UseTree,
     hygiene: &Hygiene,
@@ -21,13 +25,13 @@ pub(crate) fn lower_use_tree(
             None => prefix,
             // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
             // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
-            Some(path) => match convert_path(prefix, path, hygiene) {
+            Some(path) => match convert_path(db, prefix, path, hygiene) {
                 Some(it) => Some(it),
                 None => return, // FIXME: report errors somewhere
             },
         };
         for child_tree in use_tree_list.use_trees() {
-            lower_use_tree(prefix.clone(), child_tree, hygiene, cb);
+            lower_use_tree(db, prefix.clone(), child_tree, hygiene, cb);
         }
     } else {
         let alias = tree.rename().map(|a| {
@@ -47,7 +51,7 @@ pub(crate) fn lower_use_tree(
                     }
                 }
             }
-            if let Some(path) = convert_path(prefix, ast_path, hygiene) {
+            if let Some(path) = convert_path(db, prefix, ast_path, hygiene) {
                 cb(path, &tree, is_glob, alias)
             }
         // FIXME: report errors somewhere
@@ -61,9 +65,14 @@ pub(crate) fn lower_use_tree(
     }
 }
 
-fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
+fn convert_path(
+    db: &dyn DefDatabase,
+    prefix: Option<ModPath>,
+    path: ast::Path,
+    hygiene: &Hygiene,
+) -> Option<ModPath> {
     let prefix = if let Some(qual) = path.qualifier() {
-        Some(convert_path(prefix, qual, hygiene)?)
+        Some(convert_path(db, prefix, qual, hygiene)?)
     } else {
         prefix
     };
@@ -71,7 +80,7 @@ fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) ->
     let segment = path.segment()?;
     let res = match segment.kind()? {
         ast::PathSegmentKind::Name(name_ref) => {
-            match hygiene.name_ref_to_name(name_ref) {
+            match hygiene.name_ref_to_name(db.upcast(), name_ref) {
                 Either::Left(name) => {
                     // no type args in use
                     let mut res = prefix.unwrap_or_else(|| {
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs
index d4b7c9970ce..83500f54ee3 100644
--- a/crates/hir_def/src/visibility.rs
+++ b/crates/hir_def/src/visibility.rs
@@ -33,17 +33,19 @@ impl RawVisibility {
         db: &dyn DefDatabase,
         node: InFile<Option<ast::Visibility>>,
     ) -> RawVisibility {
-        Self::from_ast_with_hygiene(node.value, &Hygiene::new(db.upcast(), node.file_id))
+        Self::from_ast_with_hygiene(db, node.value, &Hygiene::new(db.upcast(), node.file_id))
     }
 
     pub(crate) fn from_ast_with_hygiene(
+        db: &dyn DefDatabase,
         node: Option<ast::Visibility>,
         hygiene: &Hygiene,
     ) -> RawVisibility {
-        Self::from_ast_with_hygiene_and_default(node, RawVisibility::private(), hygiene)
+        Self::from_ast_with_hygiene_and_default(db, node, RawVisibility::private(), hygiene)
     }
 
     pub(crate) fn from_ast_with_hygiene_and_default(
+        db: &dyn DefDatabase,
         node: Option<ast::Visibility>,
         default: RawVisibility,
         hygiene: &Hygiene,
@@ -54,7 +56,7 @@ impl RawVisibility {
         };
         match node.kind() {
             ast::VisibilityKind::In(path) => {
-                let path = ModPath::from_src(path, hygiene);
+                let path = ModPath::from_src(db, path, hygiene);
                 let path = match path {
                     None => return RawVisibility::private(),
                     Some(path) => path,
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index ed61ebca3ad..aca69e35abf 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -32,10 +32,14 @@ impl Hygiene {
     }
 
     // FIXME: this should just return name
-    pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> {
+    pub fn name_ref_to_name(
+        &self,
+        db: &dyn AstDatabase,
+        name_ref: ast::NameRef,
+    ) -> Either<Name, CrateId> {
         if let Some(frames) = &self.frames {
             if name_ref.text() == "$crate" {
-                if let Some(krate) = frames.root_crate(name_ref.syntax()) {
+                if let Some(krate) = frames.root_crate(db, name_ref.syntax()) {
                     return Either::Right(krate);
                 }
             }
@@ -44,15 +48,19 @@ impl Hygiene {
         Either::Left(name_ref.as_name())
     }
 
-    pub fn local_inner_macros(&self, path: ast::Path) -> Option<CrateId> {
+    pub fn local_inner_macros(&self, db: &dyn AstDatabase, path: ast::Path) -> Option<CrateId> {
         let mut token = path.syntax().first_token()?.text_range();
         let frames = self.frames.as_ref()?;
         let mut current = frames.0.clone();
 
         loop {
-            let (mapped, origin) = current.expansion.as_ref()?.map_ident_up(token)?;
+            let (mapped, origin) = current.expansion.as_ref()?.map_ident_up(db, token)?;
             if origin == Origin::Def {
-                return if current.local_inner { frames.root_crate(path.syntax()) } else { None };
+                return if current.local_inner {
+                    frames.root_crate(db, path.syntax())
+                } else {
+                    None
+                };
             }
             current = current.call_site.as_ref()?.clone();
             token = mapped.value;
@@ -82,13 +90,13 @@ impl HygieneFrames {
         HygieneFrames(Arc::new(HygieneFrame::new(db, file_id)))
     }
 
-    fn root_crate(&self, node: &SyntaxNode) -> Option<CrateId> {
+    fn root_crate(&self, db: &dyn AstDatabase, node: &SyntaxNode) -> Option<CrateId> {
         let mut token = node.first_token()?.text_range();
         let mut result = self.0.krate;
         let mut current = self.0.clone();
 
         while let Some((mapped, origin)) =
-            current.expansion.as_ref().and_then(|it| it.map_ident_up(token))
+            current.expansion.as_ref().and_then(|it| it.map_ident_up(db, token))
         {
             result = current.krate;
 
@@ -112,7 +120,7 @@ impl HygieneFrames {
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 struct HygieneInfo {
-    arg_start: InFile<TextSize>,
+    file: MacroFile,
     /// The `macro_rules!` arguments.
     def_start: Option<InFile<TextSize>>,
 
@@ -122,12 +130,24 @@ struct HygieneInfo {
 }
 
 impl HygieneInfo {
-    fn map_ident_up(&self, token: TextRange) -> Option<(InFile<TextRange>, Origin)> {
+    fn map_ident_up(
+        &self,
+        db: &dyn AstDatabase,
+        token: TextRange,
+    ) -> Option<(InFile<TextRange>, Origin)> {
         let token_id = self.exp_map.token_by_range(token)?;
 
         let (token_id, origin) = self.macro_def.map_id_up(token_id);
         let (token_map, tt) = match origin {
-            mbe::Origin::Call => (&self.macro_arg.1, self.arg_start),
+            mbe::Origin::Call => {
+                let call_id = match self.file.macro_call_id {
+                    MacroCallId::LazyMacro(lazy) => lazy,
+                    MacroCallId::EagerMacro(_) => unreachable!(),
+                };
+                let loc: MacroCallLoc = db.lookup_intern_macro(call_id);
+                let arg_start = loc.kind.arg(db)?.text_range().start();
+                (&self.macro_arg.1, InFile::new(loc.kind.file_id(), arg_start))
+            }
             mbe::Origin::Def => match (&*self.macro_def, self.def_start) {
                 (TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt))
                 | (TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) => {
@@ -147,8 +167,6 @@ fn make_hygiene_info(
     macro_file: MacroFile,
     loc: &MacroCallLoc,
 ) -> Option<HygieneInfo> {
-    let arg_tt = loc.kind.arg(db)?;
-
     let def_offset = loc.def.ast_id().left().and_then(|id| {
         let def_tt = match id.to_node(db) {
             ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(),
@@ -161,13 +179,7 @@ fn make_hygiene_info(
     let (_, exp_map) = db.parse_macro_expansion(macro_file).value?;
     let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
 
-    Some(HygieneInfo {
-        arg_start: InFile::new(loc.kind.file_id(), arg_tt.text_range().start()),
-        def_start: def_offset,
-        macro_arg,
-        macro_def,
-        exp_map,
-    })
+    Some(HygieneInfo { file: macro_file, def_start: def_offset, macro_arg, macro_def, exp_map })
 }
 
 impl HygieneFrame {
@@ -178,7 +190,8 @@ impl HygieneFrame {
                 MacroCallId::EagerMacro(_id) => (None, None, false),
                 MacroCallId::LazyMacro(id) => {
                     let loc = db.lookup_intern_macro(id);
-                    let info = make_hygiene_info(db, macro_file, &loc);
+                    let info = make_hygiene_info(db, macro_file, &loc)
+                        .map(|info| (loc.kind.file_id(), info));
                     match loc.def.kind {
                         MacroDefKind::Declarative(_) => {
                             (info, Some(loc.def.krate), loc.def.local_inner)
@@ -192,7 +205,7 @@ impl HygieneFrame {
             },
         };
 
-        let info = match info {
+        let (calling_file, info) = match info {
             None => {
                 return HygieneFrame {
                     expansion: None,
@@ -206,7 +219,7 @@ impl HygieneFrame {
         };
 
         let def_site = info.def_start.map(|it| db.hygiene_frame(it.file_id));
-        let call_site = Some(db.hygiene_frame(info.arg_start.file_id));
+        let call_site = Some(db.hygiene_frame(calling_file));
 
         HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site }
     }
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 4fb7d9cf2fd..1f6edf7a28b 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -1000,7 +1000,7 @@ impl HirDisplay for TypeRef {
             }
             TypeRef::Macro(macro_call) => {
                 let macro_call = macro_call.to_node(f.db.upcast());
-                let ctx = body::LowerCtx::with_hygiene(&Hygiene::new_unhygienic());
+                let ctx = body::LowerCtx::with_hygiene(f.db.upcast(), &Hygiene::new_unhygienic());
                 match macro_call.path() {
                     Some(path) => match Path::from_src(path, &ctx) {
                         Some(path) => path.hir_fmt(f)?,