Repository: rust-analyzer/rust-analyzer
Pull request #8095 (2021-03-18 20:37:20)

Fix associated items not being appended to paths in import_assets


Patch:
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index d57fad9ed3..2620026713 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -6,7 +6,7 @@ use hir_def::{
     src::{HasChildSource, HasSource as _},
     Lookup, VariantId,
 };
-use hir_expand::{InFile, MacroDefKind};
+use hir_expand::InFile;
 use syntax::ast;
 
 use crate::{
@@ -111,17 +111,10 @@ impl HasSource for TypeAlias {
     }
 }
 impl HasSource for MacroDef {
-    type Ast = Either<ast::Macro, ast::Fn>;
+    type Ast = ast::Macro;
     fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
-        Some(match &self.id.kind {
-            MacroDefKind::Declarative(id)
-            | MacroDefKind::BuiltIn(_, id)
-            | MacroDefKind::BuiltInDerive(_, id)
-            | MacroDefKind::BuiltInEager(_, id) => {
-                id.with_value(Either::Left(id.to_node(db.upcast())))
-            }
-            MacroDefKind::ProcMacro(_, id) => id.map(|_| Either::Right(id.to_node(db.upcast()))),
-        })
+        let ast_id = self.id.ast_id?;
+        Some(InFile { file_id: ast_id.file_id, value: ast_id.to_node(db.upcast()) })
     }
 }
 impl HasSource for Impl {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 95cfde61c0..b41a36a781 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1144,21 +1144,17 @@ impl MacroDef {
 
     /// XXX: this parses the file
     pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
-        match self.source(db)?.value {
-            Either::Left(it) => it.name().map(|it| it.as_name()),
-            Either::Right(it) => it.name().map(|it| it.as_name()),
-        }
+        self.source(db)?.value.name().map(|it| it.as_name())
     }
 
     /// Indicate it is a proc-macro
     pub fn is_proc_macro(&self) -> bool {
-        matches!(self.id.kind, MacroDefKind::ProcMacro(..))
+        matches!(self.id.kind, MacroDefKind::ProcMacro(_))
     }
 
     /// Indicate it is a derive macro
     pub fn is_derive_macro(&self) -> bool {
-        // FIXME: wrong for `ProcMacro`
-        matches!(self.id.kind, MacroDefKind::ProcMacro(..) | MacroDefKind::BuiltInDerive(..))
+        matches!(self.id.kind, MacroDefKind::ProcMacro(_) | MacroDefKind::BuiltInDerive(_))
     }
 }
 
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 762809fcd0..c6ad5ecb5f 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -195,12 +195,12 @@ impl SourceToDefCtx<'_, '_> {
         &mut self,
         src: InFile<ast::MacroRules>,
     ) -> Option<MacroDefId> {
-        let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
-        let ast_id = AstId::new(src.file_id, file_ast_id.upcast());
-        let kind = MacroDefKind::Declarative(ast_id);
+        let kind = MacroDefKind::Declarative;
         let file_id = src.file_id.original_file(self.db.upcast());
         let krate = self.file_to_def(file_id).get(0).copied()?.krate();
-        Some(MacroDefId { krate, kind, local_inner: false })
+        let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value);
+        let ast_id = Some(AstId::new(src.file_id, file_ast_id.upcast()));
+        Some(MacroDefId { krate, ast_id, kind, local_inner: false })
     }
 
     pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> {
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 1cab0e363f..e4c84afbfa 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -209,7 +209,7 @@ impl Attrs {
             },
             AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
             AttrDefId::MacroDefId(it) => {
-                it.ast_id().map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
+                it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
             }
             AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
             AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
@@ -283,51 +283,8 @@ impl Attrs {
     /// Constructs a map that maps the lowered `Attr`s in this `Attrs` back to its original syntax nodes.
     ///
     /// `owner` must be the original owner of the attributes.
-    // FIXME: figure out a better api that doesnt require the for_module hack
-    pub fn source_map(&self, owner: InFile<&dyn ast::AttrsOwner>) -> AttrSourceMap {
-        // FIXME: This doesn't work correctly for modules, as the attributes there can have up to
-        // two different owners
-        AttrSourceMap {
-            attrs: collect_attrs(owner.value)
-                .map(|attr| InFile::new(owner.file_id, attr))
-                .collect(),
-        }
-    }
-
-    pub fn source_map_for_module(
-        &self,
-        db: &dyn DefDatabase,
-        module: crate::ModuleId,
-    ) -> AttrSourceMap {
-        let def_map = module.def_map(db);
-        let mod_data = &def_map[module.local_id];
-        let attrs = match mod_data.declaration_source(db) {
-            Some(it) => {
-                let mut attrs: Vec<_> = collect_attrs(&it.value as &dyn ast::AttrsOwner)
-                    .map(|attr| InFile::new(it.file_id, attr))
-                    .collect();
-                if let InFile { file_id, value: ModuleSource::SourceFile(file) } =
-                    mod_data.definition_source(db)
-                {
-                    attrs.extend(
-                        collect_attrs(&file as &dyn ast::AttrsOwner)
-                            .map(|attr| InFile::new(file_id, attr)),
-                    )
-                }
-                attrs
-            }
-            None => {
-                let InFile { file_id, value } = mod_data.definition_source(db);
-                match &value {
-                    ModuleSource::SourceFile(file) => collect_attrs(file as &dyn ast::AttrsOwner),
-                    ModuleSource::Module(module) => collect_attrs(module as &dyn ast::AttrsOwner),
-                    ModuleSource::BlockExpr(block) => collect_attrs(block as &dyn ast::AttrsOwner),
-                }
-                .map(|attr| InFile::new(file_id, attr))
-                .collect()
-            }
-        };
-        AttrSourceMap { attrs }
+    pub fn source_map(&self, owner: &dyn ast::AttrsOwner) -> AttrSourceMap {
+        AttrSourceMap { attrs: collect_attrs(owner).collect() }
     }
 
     pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
@@ -422,7 +379,7 @@ fn inner_attributes(
 }
 
 pub struct AttrSourceMap {
-    attrs: Vec<InFile<Either<ast::Attr, ast::Comment>>>,
+    attrs: Vec<Either<ast::Attr, ast::Comment>>,
 }
 
 impl AttrSourceMap {
@@ -432,11 +389,10 @@ impl AttrSourceMap {
     ///
     /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of
     /// the attribute represented by `Attr`.
-    pub fn source_of(&self, attr: &Attr) -> InFile<&Either<ast::Attr, ast::Comment>> {
+    pub fn source_of(&self, attr: &Attr) -> &Either<ast::Attr, ast::Comment> {
         self.attrs
             .get(attr.index as usize)
             .unwrap_or_else(|| panic!("cannot find `Attr` at index {}", attr.index))
-            .as_ref()
     }
 }
 
@@ -472,6 +428,18 @@ impl Attr {
         Some(Attr { index, path, input })
     }
 
+    /// Maps this lowered `Attr` back to its original syntax node.
+    ///
+    /// `owner` must be the original owner of the attribute.
+    ///
+    /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of
+    /// the attribute represented by `Attr`.
+    pub fn to_src(&self, owner: &dyn ast::AttrsOwner) -> Either<ast::Attr, ast::Comment> {
+        collect_attrs(owner).nth(self.index as usize).unwrap_or_else(|| {
+            panic!("cannot find `Attr` at index {} in {}", self.index, owner.syntax())
+        })
+    }
+
     /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths
     /// to derive macros.
     ///
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index 960cabb5fd..369bc3350b 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -912,10 +912,10 @@ mod tests {
                 dep::fmt (t)
                 dep::format (f)
                 dep::Fmt (v)
-                dep::Fmt (m)
+                dep::fmt::Display (t)
                 dep::Fmt (t)
                 dep::fmt::Display::fmt (a)
-                dep::fmt::Display (t)
+                dep::Fmt (m)
             "#]],
         );
 
@@ -926,9 +926,9 @@ mod tests {
             expect![[r#"
                 dep::fmt (t)
                 dep::Fmt (v)
-                dep::Fmt (m)
                 dep::Fmt (t)
                 dep::fmt::Display::fmt (a)
+                dep::Fmt (m)
             "#]],
         );
 
@@ -939,10 +939,10 @@ mod tests {
             expect![[r#"
                 dep::fmt (t)
                 dep::Fmt (v)
-                dep::Fmt (m)
+                dep::fmt::Display (t)
                 dep::Fmt (t)
                 dep::fmt::Display::fmt (a)
-                dep::fmt::Display (t)
+                dep::Fmt (m)
             "#]],
         );
     }
@@ -980,10 +980,10 @@ mod tests {
             expect![[r#"
                 dep::fmt (t)
                 dep::Fmt (v)
-                dep::Fmt (m)
+                dep::fmt::Display (t)
                 dep::Fmt (t)
                 dep::fmt::Display::fmt (a)
-                dep::fmt::Display (t)
+                dep::Fmt (m)
             "#]],
         );
 
@@ -994,9 +994,9 @@ mod tests {
             expect![[r#"
                 dep::fmt (t)
                 dep::Fmt (v)
-                dep::Fmt (m)
                 dep::Fmt (t)
                 dep::fmt::Display::fmt (a)
+                dep::Fmt (m)
             "#]],
         );
     }
@@ -1058,8 +1058,8 @@ mod tests {
             Query::new("".to_string()).limit(2),
             expect![[r#"
                 dep::fmt (t)
-                dep::Fmt (m)
                 dep::Fmt (t)
+                dep::Fmt (m)
                 dep::Fmt (v)
             "#]],
         );
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index f3ebe7c727..aafd73b606 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -252,7 +252,7 @@ impl ItemScope {
             .for_each(|vis| *vis = Visibility::Module(this_module));
 
         for (mac, vis) in self.macros.values_mut() {
-            if let MacroDefKind::ProcMacro(..) = mac.kind {
+            if let MacroDefKind::ProcMacro(_) = mac.kind {
                 // FIXME: Technically this is insufficient since reexports of proc macros are also
                 // forbidden. Practically nobody does that.
                 continue;
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 21add086d0..6758411a0c 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -650,7 +650,7 @@ fn macro_call_as_call_id(
 ) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
     let def: MacroDefId = resolver(call.path.clone()).ok_or(UnresolvedMacro)?;
 
-    let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
+    let res = if let MacroDefKind::BuiltInEager(_) = def.kind {
         let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast()));
         let hygiene = Hygiene::new(db.upcast(), call.ast_id.file_id);
 
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 1ac326f971..c97be584e2 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -53,12 +53,11 @@ mod path_resolution;
 
 #[cfg(test)]
 mod tests;
-mod proc_macro;
 
 use std::sync::Arc;
 
 use base_db::{CrateId, Edition, FileId};
-use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile, MacroDefId};
+use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile};
 use la_arena::Arena;
 use profile::Count;
 use rustc_hash::FxHashMap;
@@ -74,8 +73,6 @@ use crate::{
     AstId, BlockId, BlockLoc, LocalModuleId, ModuleDefId, ModuleId,
 };
 
-use self::proc_macro::ProcMacroDef;
-
 /// Contains the results of (early) name resolution.
 ///
 /// A `DefMap` stores the module tree and the definitions that are in scope in every module after
@@ -98,12 +95,6 @@ pub struct DefMap {
     prelude: Option<ModuleId>,
     extern_prelude: FxHashMap<Name, ModuleDefId>,
 
-    /// Side table with additional proc. macro info, for use by name resolution in downstream
-    /// crates.
-    ///
-    /// (the primary purpose is to resolve derive helpers)
-    exported_proc_macros: FxHashMap<MacroDefId, ProcMacroDef>,
-
     edition: Edition,
     diagnostics: Vec<DefDiagnostic>,
 }
@@ -246,7 +237,6 @@ impl DefMap {
             krate,
             edition,
             extern_prelude: FxHashMap::default(),
-            exported_proc_macros: FxHashMap::default(),
             prelude: None,
             root,
             modules,
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index dcedf7766d..d0fefb5afd 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -18,6 +18,7 @@ use hir_expand::{
 use hir_expand::{InFile, MacroCallLoc};
 use rustc_hash::{FxHashMap, FxHashSet};
 use syntax::ast;
+use tt::{Leaf, TokenTree};
 
 use crate::{
     attr::Attrs,
@@ -41,8 +42,6 @@ use crate::{
     UnresolvedMacro,
 };
 
-use super::proc_macro::ProcMacroDef;
-
 const GLOB_RECURSION_LIMIT: usize = 100;
 const EXPANSION_DEPTH_LIMIT: usize = 128;
 const FIXED_POINT_LIMIT: usize = 8192;
@@ -354,23 +353,24 @@ impl DefCollector<'_> {
     /// use a dummy expander that always errors. This comes with the drawback of macros potentially
     /// going out of sync with what the build system sees (since we resolve using VFS state, but
     /// Cargo builds only on-disk files). We could and probably should add diagnostics for that.
-    fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>) {
+    fn resolve_proc_macro(&mut self, name: &Name) {
         self.exports_proc_macros = true;
-        let macro_def = match self.proc_macros.iter().find(|(n, _)| n == &def.name) {
+        let macro_def = match self.proc_macros.iter().find(|(n, _)| n == name) {
             Some((_, expander)) => MacroDefId {
+                ast_id: None,
                 krate: self.def_map.krate,
-                kind: MacroDefKind::ProcMacro(*expander, ast_id),
+                kind: MacroDefKind::ProcMacro(*expander),
                 local_inner: false,
             },
             None => MacroDefId {
+                ast_id: None,
                 krate: self.def_map.krate,
-                kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate), ast_id),
+                kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate)),
                 local_inner: false,
             },
         };
 
-        self.define_proc_macro(def.name.clone(), macro_def);
-        self.def_map.exported_proc_macros.insert(macro_def, def);
+        self.define_proc_macro(name.clone(), macro_def);
     }
 
     /// Define a macro with `macro_rules`.
@@ -1118,8 +1118,7 @@ impl ModCollector<'_, '_> {
                 ModItem::Function(id) => {
                     let func = &self.item_tree[id];
 
-                    let ast_id = InFile::new(self.file_id, func.ast_id);
-                    self.collect_proc_macro_def(&func.name, ast_id, &attrs);
+                    self.collect_proc_macro_def(&func.name, &attrs);
 
                     def = Some(DefData {
                         id: FunctionLoc {
@@ -1386,11 +1385,28 @@ impl ModCollector<'_, '_> {
     }
 
     /// If `attrs` registers a procedural macro, collects its definition.
-    fn collect_proc_macro_def(&mut self, func_name: &Name, ast_id: AstId<ast::Fn>, attrs: &Attrs) {
+    fn collect_proc_macro_def(&mut self, func_name: &Name, attrs: &Attrs) {
         // FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere
-        if let Some(proc_macro) = attrs.parse_proc_macro_decl(func_name) {
-            self.def_collector.export_proc_macro(proc_macro, ast_id);
-        }
+        // FIXME: distinguish the type of macro
+        let macro_name = if attrs.by_key("proc_macro").exists()
+            || attrs.by_key("proc_macro_attribute").exists()
+        {
+            func_name.clone()
+        } else {
+            let derive = attrs.by_key("proc_macro_derive");
+            if let Some(arg) = derive.tt_values().next() {
+                if let [TokenTree::Leaf(Leaf::Ident(trait_name)), ..] = &*arg.token_trees {
+                    trait_name.as_name()
+                } else {
+                    log::trace!("malformed `#[proc_macro_derive]`: {}", arg);
+                    return;
+                }
+            } else {
+                return;
+            }
+        };
+
+        self.def_collector.resolve_proc_macro(&macro_name);
     }
 
     fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) {
@@ -1429,8 +1445,9 @@ impl ModCollector<'_, '_> {
 
         // Case 2: normal `macro_rules!` macro
         let macro_id = MacroDefId {
+            ast_id: Some(ast_id),
             krate: self.def_collector.def_map.krate,
-            kind: MacroDefKind::Declarative(ast_id),
+            kind: MacroDefKind::Declarative,
             local_inner: is_local_inner,
         };
         self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, is_export);
diff --git a/crates/hir_def/src/nameres/proc_macro.rs b/crates/hir_def/src/nameres/proc_macro.rs
deleted file mode 100644
index 156598f195..0000000000
--- a/crates/hir_def/src/nameres/proc_macro.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-//! Nameres-specific procedural macro data and helpers.
-
-use hir_expand::name::{AsName, Name};
-use tt::{Leaf, TokenTree};
-
-use crate::attr::Attrs;
-
-#[derive(Debug, PartialEq, Eq)]
-pub(super) struct ProcMacroDef {
-    pub(super) name: Name,
-    pub(super) kind: ProcMacroKind,
-}
-
-#[derive(Debug, PartialEq, Eq)]
-pub(super) enum ProcMacroKind {
-    CustomDerive { helpers: Box<[Name]> },
-    FnLike,
-    Attr,
-}
-
-impl Attrs {
-    #[rustfmt::skip]
-    pub(super) fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> {
-        if self.by_key("proc_macro").exists() {
-            Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::FnLike })
-        } else if self.by_key("proc_macro_attribute").exists() {
-            Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Attr })
-        } else if self.by_key("proc_macro_derive").exists() {
-            let derive = self.by_key("proc_macro_derive").tt_values().next().unwrap();
-
-            match &*derive.token_trees {
-                // `#[proc_macro_derive(Trait)]`
-                [TokenTree::Leaf(Leaf::Ident(trait_name))] => Some(ProcMacroDef {
-                    name: trait_name.as_name(),
-                    kind: ProcMacroKind::CustomDerive { helpers: Box::new([]) },
-                }),
-
-                // `#[proc_macro_derive(Trait, attibutes(helper1, helper2, ...))]`
-                [
-                    TokenTree::Leaf(Leaf::Ident(trait_name)),
-                    TokenTree::Leaf(Leaf::Punct(comma)),
-                    TokenTree::Leaf(Leaf::Ident(attributes)),
-                    TokenTree::Subtree(helpers)
-                ] if comma.char == ',' && attributes.text == "attributes" =>
-                {
-                    let helpers = helpers.token_trees.iter()
-                        .filter(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Punct(comma)) if comma.char == ','))
-                        .map(|tt| {
-                            match tt {
-                                TokenTree::Leaf(Leaf::Ident(helper)) => Some(helper.as_name()),
-                                _ => None
-                            }
-                        })
-                        .collect::<Option<Box<[_]>>>()?;
-
-                    Some(ProcMacroDef {
-                        name: trait_name.as_name(),
-                        kind: ProcMacroKind::CustomDerive { helpers },
-                    })
-                }
-
-                _ => {
-                    log::trace!("malformed `#[proc_macro_derive]`: {}", derive);
-                    None
-                }
-            }
-        } else {
-            None
-        }
-    }
-}
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs
index 60fd2ebdd4..a8d267c30e 100644
--- a/crates/hir_expand/src/builtin_derive.rs
+++ b/crates/hir_expand/src/builtin_derive.rs
@@ -61,7 +61,8 @@ pub fn find_builtin_derive(
     let expander = BuiltinDeriveExpander::find_by_name(ident)?;
     Some(MacroDefId {
         krate,
-        kind: MacroDefKind::BuiltInDerive(expander, ast_id),
+        ast_id: Some(ast_id),
+        kind: MacroDefKind::BuiltInDerive(expander),
         local_inner: false,
     })
 }
@@ -313,7 +314,8 @@ $0
         let loc = MacroCallLoc {
             def: MacroDefId {
                 krate: CrateId(0),
-                kind: MacroDefKind::BuiltInDerive(expander, macro_ast_id),
+                ast_id: Some(macro_ast_id),
+                kind: MacroDefKind::BuiltInDerive(expander),
                 local_inner: false,
             },
             krate: CrateId(0),
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 8529b43b6d..fce09a9e71 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -71,12 +71,14 @@ pub fn find_builtin_macro(
     match kind {
         Either::Left(kind) => Some(MacroDefId {
             krate,
-            kind: MacroDefKind::BuiltIn(kind, ast_id),
+            ast_id: Some(ast_id),
+            kind: MacroDefKind::BuiltIn(kind),
             local_inner: false,
         }),
         Either::Right(kind) => Some(MacroDefId {
             krate,
-            kind: MacroDefKind::BuiltInEager(kind, ast_id),
+            ast_id: Some(ast_id),
+            kind: MacroDefKind::BuiltInEager(kind),
             local_inner: false,
         }),
     }
@@ -510,7 +512,6 @@ mod tests {
         let macro_call = macro_calls.pop().unwrap();
 
         let expander = find_by_name(&macro_rules.name().unwrap().as_name()).unwrap();
-        let ast_id = AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules));
 
         let krate = CrateId(0);
         let file_id = match expander {
@@ -518,7 +519,8 @@ mod tests {
                 // the first one should be a macro_rules
                 let def = MacroDefId {
                     krate: CrateId(0),
-                    kind: MacroDefKind::BuiltIn(expander, ast_id),
+                    ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules))),
+                    kind: MacroDefKind::BuiltIn(expander),
                     local_inner: false,
                 };
 
@@ -538,7 +540,8 @@ mod tests {
                 // the first one should be a macro_rules
                 let def = MacroDefId {
                     krate,
-                    kind: MacroDefKind::BuiltInEager(expander, ast_id),
+                    ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_rules))),
+                    kind: MacroDefKind::BuiltInEager(expander),
                     local_inner: false,
                 };
 
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 2748e25cf3..a3070f1f94 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -130,8 +130,8 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
 
 fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
     match id.kind {
-        MacroDefKind::Declarative(ast_id) => {
-            let macro_rules = match ast_id.to_node(db) {
+        MacroDefKind::Declarative => {
+            let macro_rules = match id.ast_id?.to_node(db) {
                 syntax::ast::Macro::MacroRules(mac) => mac,
                 syntax::ast::Macro::MacroDef(_) => return None,
             };
@@ -150,14 +150,14 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander,
             };
             Some(Arc::new((TokenExpander::MacroRules(rules), tmap)))
         }
-        MacroDefKind::BuiltIn(expander, _) => {
+        MacroDefKind::BuiltIn(expander) => {
             Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default())))
         }
-        MacroDefKind::BuiltInDerive(expander, _) => {
+        MacroDefKind::BuiltInDerive(expander) => {
             Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default())))
         }
-        MacroDefKind::BuiltInEager(..) => None,
-        MacroDefKind::ProcMacro(expander, ..) => {
+        MacroDefKind::BuiltInEager(_) => None,
+        MacroDefKind::ProcMacro(expander) => {
             Some(Arc::new((TokenExpander::ProcMacro(expander), mbe::TokenMap::default())))
         }
     }
@@ -269,7 +269,7 @@ fn expand_proc_macro(
     };
 
     let expander = match loc.def.kind {
-        MacroDefKind::ProcMacro(expander, ..) => expander,
+        MacroDefKind::ProcMacro(expander) => expander,
         _ => unreachable!(),
     };
 
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index 04f374a29f..dc618a9ee1 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -140,7 +140,7 @@ pub fn expand_eager_macro(
     let subtree =
         diagnostic_sink.option(to_subtree(&result), || err("failed to parse macro result"))?;
 
-    if let MacroDefKind::BuiltInEager(eager, _) = def.kind {
+    if let MacroDefKind::BuiltInEager(eager) = def.kind {
         let res = eager.expand(db, arg_id, &subtree);
 
         let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?;
@@ -193,7 +193,7 @@ fn eager_macro_recur(
         let def = diagnostic_sink
             .option_with(|| macro_resolver(child.path()?), || err("failed to resolve macro"))?;
         let insert = match def.kind {
-            MacroDefKind::BuiltInEager(..) => {
+            MacroDefKind::BuiltInEager(_) => {
                 let id: MacroCallId = expand_eager_macro(
                     db,
                     krate,
@@ -206,10 +206,10 @@ fn eager_macro_recur(
                 db.parse_or_expand(id.as_file())
                     .expect("successful macro expansion should be parseable")
             }
-            MacroDefKind::Declarative(_)
-            | MacroDefKind::BuiltIn(..)
-            | MacroDefKind::BuiltInDerive(..)
-            | MacroDefKind::ProcMacro(..) => {
+            MacroDefKind::Declarative
+            | MacroDefKind::BuiltIn(_)
+            | MacroDefKind::BuiltInDerive(_)
+            | MacroDefKind::ProcMacro(_) => {
                 let res = lazy_expand(db, &def, curr.with_value(child.clone()), krate);
                 let val = diagnostic_sink.expand_result_option(res)?;
 
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index 20cda1683a..87cad326d1 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -145,7 +145,7 @@ fn make_hygiene_info(
 ) -> Option<HygieneInfo> {
     let arg_tt = loc.kind.arg(db)?;
 
-    let def_offset = loc.def.ast_id().and_then(|id| {
+    let def_offset = loc.def.ast_id.and_then(|id| {
         let def_tt = match id.to_node(db) {
             ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(),
             ast::Macro::MacroDef(_) => return None,
@@ -176,13 +176,13 @@ impl HygieneFrame {
                     let loc = db.lookup_intern_macro(id);
                     let info = make_hygiene_info(db, macro_file, &loc);
                     match loc.def.kind {
-                        MacroDefKind::Declarative(_) => {
+                        MacroDefKind::Declarative => {
                             (info, Some(loc.def.krate), loc.def.local_inner)
                         }
-                        MacroDefKind::BuiltIn(..) => (info, Some(loc.def.krate), false),
-                        MacroDefKind::BuiltInDerive(..) => (info, None, false),
-                        MacroDefKind::BuiltInEager(..) => (info, None, false),
-                        MacroDefKind::ProcMacro(..) => (info, None, false),
+                        MacroDefKind::BuiltIn(_) => (info, Some(loc.def.krate), false),
+                        MacroDefKind::BuiltInDerive(_) => (info, None, false),
+                        MacroDefKind::BuiltInEager(_) => (info, None, false),
+                        MacroDefKind::ProcMacro(_) => (info, None, false),
                     }
                 }
             },
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 0a379651f0..7532d00b83 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -143,7 +143,7 @@ impl HirFileId {
 
                 let arg_tt = loc.kind.arg(db)?;
 
-                let def = loc.def.ast_id().and_then(|id| {
+                let def = loc.def.ast_id.and_then(|id| {
                     let def_tt = match id.to_node(db) {
                         ast::Macro::MacroRules(mac) => mac.token_tree()?,
                         ast::Macro::MacroDef(_) => return None,
@@ -180,7 +180,7 @@ impl HirFileId {
                 };
                 let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id);
                 let item = match loc.def.kind {
-                    MacroDefKind::BuiltInDerive(..) => loc.kind.node(db),
+                    MacroDefKind::BuiltInDerive(_) => loc.kind.node(db),
                     _ => return None,
                 };
                 Some(item.with_value(ast::Item::cast(item.value.clone())?))
@@ -224,6 +224,7 @@ impl From<EagerMacroId> for MacroCallId {
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct MacroDefId {
     pub krate: CrateId,
+    pub ast_id: Option<AstId<ast::Macro>>,
     pub kind: MacroDefKind,
 
     pub local_inner: bool,
@@ -238,27 +239,16 @@ impl MacroDefId {
     ) -> LazyMacroId {
         db.intern_macro(MacroCallLoc { def: self, krate, kind })
     }
-
-    pub fn ast_id(&self) -> Option<AstId<ast::Macro>> {
-        let id = match &self.kind {
-            MacroDefKind::Declarative(id) => id,
-            MacroDefKind::BuiltIn(_, id) => id,
-            MacroDefKind::BuiltInDerive(_, id) => id,
-            MacroDefKind::BuiltInEager(_, id) => id,
-            MacroDefKind::ProcMacro(..) => return None,
-        };
-        Some(*id)
-    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum MacroDefKind {
-    Declarative(AstId<ast::Macro>),
-    BuiltIn(BuiltinFnLikeExpander, AstId<ast::Macro>),
+    Declarative,
+    BuiltIn(BuiltinFnLikeExpander),
     // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander
-    BuiltInDerive(BuiltinDeriveExpander, AstId<ast::Macro>),
-    BuiltInEager(EagerExpander, AstId<ast::Macro>),
-    ProcMacro(ProcMacroExpander, AstId<ast::Fn>),
+    BuiltInDerive(BuiltinDeriveExpander),
+    BuiltInEager(EagerExpander),
+    ProcMacro(ProcMacroExpander),
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index 33a0f4d7d4..bfe239793c 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -102,7 +102,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
         let db = self.db;
         for block_def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) {
             for (_, module) in block_def_map.modules() {
-                for def_id in module.scope.declarations() {
+                for (def_id, _) in module.scope.values() {
                     let mut validator = DeclValidator::new(self.db, self.krate, self.sink);
                     validator.validate_item(def_id);
                 }
@@ -902,17 +902,4 @@ extern {
             "#,
         );
     }
-
-    #[test]
-    fn infinite_loop_inner_items() {
-        check_diagnostics(
-            r#"
-fn qualify() {
-    mod foo {
-        use super::*;
-    }
-}
-            "#,
-        )
-    }
 }
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 364be260c6..c086de163f 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -339,14 +339,10 @@ impl TryToNav for hir::Field {
 impl TryToNav for hir::MacroDef {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
         let src = self.source(db)?;
-        let name_owner: &dyn ast::NameOwner = match &src.value {
-            Either::Left(it) => it,
-            Either::Right(it) => it,
-        };
-        log::debug!("nav target {:#?}", name_owner.syntax());
+        log::debug!("nav target {:#?}", src.value.syntax());
         let mut res = NavigationTarget::from_named(
             db,
-            src.as_ref().with_value(name_owner),
+            src.as_ref().map(|it| it as &dyn ast::NameOwner),
             SymbolKind::Macro,
         );
         res.docs = self.docs(db);
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 473d48c2fc..598b47e417 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1176,21 +1176,4 @@ fn foo() { A { a$0: }; }
 "#,
         )
     }
-
-    #[test]
-    fn goto_proc_macro() {
-        check(
-            r#"
-//- /main.rs crate:main deps:mac
-use mac::fn_macro;
-
-fn_macro$0!();
-
-//- /mac.rs crate:mac
-#[proc_macro]
-fn fn_macro() {}
- //^^^^^^^^
-            "#,
-        )
-    }
 }
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index a3fb17c0a6..15d309d7d6 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -331,16 +331,10 @@ fn hover_for_definition(
 ) -> Option<Markup> {
     let mod_path = definition_mod_path(db, &def);
     return match def {
-        Definition::Macro(it) => match &it.source(db)?.value {
-            Either::Left(mac) => {
-                let label = macro_label(&mac);
-                from_def_source_labeled(db, it, Some(label), mod_path)
-            }
-            Either::Right(_) => {
-                // FIXME
-                None
-            }
-        },
+        Definition::Macro(it) => {
+            let label = macro_label(&it.source(db)?.value);
+            from_def_source_labeled(db, it, Some(label), mod_path)
+        }
         Definition::Field(def) => from_hir_fmt(db, def, mod_path),
         Definition::ModuleDef(it) => match it {
             ModuleDef::Module(it) => from_hir_fmt(db, it, mod_path),
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index e25b698e0c..ba3447b3a3 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -12,7 +12,7 @@ mod html;
 #[cfg(test)]
 mod tests;
 
-use hir::{InFile, Name, Semantics};
+use hir::{Name, Semantics};
 use ide_db::{RootDatabase, SymbolKind};
 use rustc_hash::FxHashMap;
 use syntax::{
@@ -73,20 +73,14 @@ pub(crate) fn highlight(
     };
 
     let mut hl = highlights::Highlights::new(root.text_range());
-    traverse(
-        &mut hl,
-        &sema,
-        InFile::new(file_id.into(), &root),
-        range_to_highlight,
-        syntactic_name_ref_highlighting,
-    );
+    traverse(&mut hl, &sema, &root, range_to_highlight, syntactic_name_ref_highlighting);
     hl.to_vec()
 }
 
 fn traverse(
     hl: &mut Highlights,
     sema: &Semantics<RootDatabase>,
-    root: InFile<&SyntaxNode>,
+    root: &SyntaxNode,
     range_to_highlight: TextRange,
     syntactic_name_ref_highlighting: bool,
 ) {
@@ -99,7 +93,7 @@ fn traverse(
 
     // Walk all nodes, keeping track of whether we are inside a macro or not.
     // If in macro, expand it first and highlight the expanded code.
-    for event in root.value.preorder_with_tokens() {
+    for event in root.preorder_with_tokens() {
         let event_range = match &event {
             WalkEvent::Enter(it) | WalkEvent::Leave(it) => it.text_range(),
         };
@@ -156,7 +150,7 @@ fn traverse(
             WalkEvent::Enter(it) => it,
             WalkEvent::Leave(it) => {
                 if let Some(node) = it.as_node() {
-                    inject::doc_comment(hl, sema, root.with_value(node));
+                    inject::doc_comment(hl, sema, node);
                 }
                 continue;
             }
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index e6dbd307ec..947cc974ce 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -3,7 +3,7 @@
 use std::{mem, ops::Range};
 
 use either::Either;
-use hir::{HasAttrs, InFile, Semantics};
+use hir::{HasAttrs, Semantics};
 use ide_db::{call_info::ActiveParameter, defs::Definition};
 use syntax::{
     ast::{self, AstNode, AttrsOwner, DocCommentsOwner},
@@ -148,12 +148,8 @@ fn doc_attributes<'node>(
 }
 
 /// Injection of syntax highlighting of doctests.
-pub(super) fn doc_comment(
-    hl: &mut Highlights,
-    sema: &Semantics<RootDatabase>,
-    node: InFile<&SyntaxNode>,
-) {
-    let (owner, attributes, def) = match doc_attributes(sema, node.value) {
+pub(super) fn doc_comment(hl: &mut Highlights, sema: &Semantics<RootDatabase>, node: &SyntaxNode) {
+    let (owner, attributes, def) = match doc_attributes(sema, node) {
         Some(it) => it,
         None => return,
     };
@@ -161,12 +157,7 @@ pub(super) fn doc_comment(
     let mut inj = Injector::default();
     inj.add_unmapped("fn doctest() {\n");
 
-    let attrs_source_map = match def {
-        Definition::ModuleDef(hir::ModuleDef::Module(module)) => {
-            attributes.source_map_for_module(sema.db, module.into())
-        }
-        _ => attributes.source_map(node.with_value(&owner)),
-    };
+    let attrs_source_map = attributes.source_map(&owner);
 
     let mut is_codeblock = false;
     let mut is_doctest = false;
@@ -177,10 +168,7 @@ pub(super) fn doc_comment(
     let mut intra_doc_links = Vec::new();
     let mut string;
     for attr in attributes.by_key("doc").attrs() {
-        let InFile { file_id, value: src } = attrs_source_map.source_of(&attr);
-        if file_id != node.file_id {
-            continue;
-        }
+        let src = attrs_source_map.source_of(&attr);
         let (line, range, prefix) = match &src {
             Either::Left(it) => {
                 string = match find_doc_string_in_attr(attr, it) {
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs
index 30b23da6ca..40571e52b3 100644
--- a/crates/ide_assists/src/handlers/qualify_path.rs
+++ b/crates/ide_assists/src/handlers/qualify_path.rs
@@ -208,8 +208,10 @@ fn label(candidate: &ImportCandidate, import: &LocatedImport) -> String {
                 format!("Qualify as `{}`", import.import_path)
             }
         }
-        ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", import.import_path),
-        ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", import.import_path),
+        ImportCandidate::TraitAssocItem(_) => {
+            format!("Qualify with `{}`", import.import_path)
+        }
+        ImportCandidate::TraitMethod(_) => format!("Qualify with `{}`", import.import_path),
     }
 }
 
@@ -543,6 +545,37 @@ fn main() {
         );
     }
 
+    #[test]
+    fn associated_struct_const_unqualified() {
+        check_assist(
+            qualify_path,
+            r"
+            mod test_mod {
+                pub struct TestStruct {}
+                impl TestStruct {
+                    const TEST_CONST: u8 = 42;
+                }
+            }
+
+            fn main() {
+                TEST_CONST$0
+            }
+            ",
+            r"
+            mod test_mod {
+                pub struct TestStruct {}
+                impl TestStruct {
+                    const TEST_CONST: u8 = 42;
+                }
+            }
+
+            fn main() {
+                test_mod::TestStruct::TEST_CONST
+            }
+            ",
+        );
+    }
+
     #[test]
     fn associated_trait_function() {
         check_assist(
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index 7578ad50b4..3fa21ba7c9 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -91,7 +91,7 @@ impl<'a> MacroRender<'a> {
     }
 
     fn detail(&self) -> Option<String> {
-        let ast_node = self.macro_.source(self.ctx.db())?.value.left()?;
+        let ast_node = self.macro_.source(self.ctx.db())?.value;
         Some(macro_label(&ast_node))
     }
 }
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index e03ccd3515..7c8844e959 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -304,7 +304,11 @@ fn path_applicable_imports(
             return items_with_candidate_name
                 .into_iter()
                 .filter_map(|item| {
-                    Some(LocatedImport::new(mod_path(item)?, item, item, mod_path(item)))
+                    let mut mod_path = mod_path(item)?;
+                    if let Some(assoc_item) = item_as_assoc(db, item) {
+                        mod_path.push_segment(assoc_item.name(db)?);
+                    }
+                    Some(LocatedImport::new(mod_path.clone(), item, item, Some(mod_path)))
                 })
                 .collect();
         }
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index dba2197de9..f4c37353cd 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -384,9 +384,11 @@ If the LSP binary is not available, GNOME Builder can install it when opening a
 
 === Eclipse IDE
 
+Prerequisites: You have installed the <<rust-analyzer-language-server-binary,`rust-analyzer` binary>>.
+
 Support for Rust development in the Eclipse IDE is provided by link:https://github.com/eclipse/corrosion[Eclipse Corrosion].
-If available in PATH or in some standard location, `rust-analyzer` is detected and powers editing of Rust files without further configuration.
-If `rust-analyzer` is not detected, Corrosion will prompt you for configuration of your Rust toolchain and language server with a link to the __Window > Preferences > Rust__ preference page; from here a button allows to download and configure `rust-analyzer`, but you can also reference another installation.
+While it currently uses RLS as default, you can successfully configure it so the IDE will use `rust-analyzer` instead.
+To do so, with an Eclipse IDE where Corrosion is installed, just go to __Window > Preferences > Rust__ and edit the __Path to Rust Language Server__ entry to reference the path to `rust-analyzer`.
 You'll need to close and reopen all .rs and Cargo files, or to restart the IDE, for this change to take effect.
 
 == Configuration


Test patch:
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs
index d59d3c0db1..f65a655bf5 100644
--- a/crates/hir_def/src/nameres/tests/macros.rs
+++ b/crates/hir_def/src/nameres/tests/macros.rs
@@ -1,5 +1,4 @@
 use super::*;
-use crate::nameres::proc_macro::{ProcMacroDef, ProcMacroKind};
 
 #[test]
 fn macro_rules_are_globally_visible() {
@@ -791,28 +790,3 @@ fn proc_macro_censoring() {
         "#]],
     );
 }
-
-#[test]
-fn collects_derive_helpers() {
-    let def_map = compute_crate_def_map(
-        r"
-        struct TokenStream;
-
-        #[proc_macro_derive(AnotherTrait, attributes(helper_attr))]
-        pub fn derive_macro_2(_item: TokenStream) -> TokenStream {
-            TokenStream
-        }
-        ",
-    );
-
-    assert_eq!(def_map.exported_proc_macros.len(), 1);
-    match def_map.exported_proc_macros.values().next() {
-        Some(ProcMacroDef { kind: ProcMacroKind::CustomDerive { helpers }, .. }) => {
-            match &**helpers {
-                [attr] => assert_eq!(attr.to_string(), "helper_attr"),
-                _ => unreachable!(),
-            }
-        }
-        _ => unreachable!(),
-    }
-}