Repository: rust-analyzer/rust-analyzer
Pull request #6056 (2020-09-22 05:52:43)

Add dbgr postfix completion
Expanding to `dbg!(&e)`.

lnicola: As seen in https://intellij-rust.github.io/2020/09/21/changelog-131.html.

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index cf88c4e170..72ec686246 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -140,9 +140,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.60"
+version = "1.0.59"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c"
+checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381"
 
 [[package]]
 name = "cfg"
@@ -311,9 +311,9 @@ checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
 
 [[package]]
 name = "either"
-version = "1.6.1"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f"
 
 [[package]]
 name = "ena"
@@ -775,9 +775,9 @@ dependencies = [
 
 [[package]]
 name = "lsp-types"
-version = "0.81.0"
+version = "0.80.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e02724627e9ef8ba91f461ebc01d48aebbd13a4b7c9dc547a0a2890f53e2171"
+checksum = "f4265e2715bdacbb4dad029fce525e420cd66dc0af24ff9cb996a8ab48ac92ef"
 dependencies = [
  "base64",
  "bitflags",
@@ -1187,9 +1187,9 @@ dependencies = [
 
 [[package]]
 name = "rayon-core"
-version = "1.8.1"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8c4fec834fb6e6d2dd5eece3c7b432a52f0ba887cf40e595190c4107edc08bf"
+checksum = "91739a34c4355b5434ce54c9086c5895604a9c278586d1f1aa95e04f66b525a0"
 dependencies = [
  "crossbeam-channel",
  "crossbeam-deque",
@@ -1493,9 +1493,9 @@ version = "0.0.0"
 
 [[package]]
 name = "syn"
-version = "1.0.41"
+version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b"
+checksum = "963f7d3cc59b59b9325165add223142bbf1df27655d07789f109896d353d8350"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/crates/assists/src/ast_transform.rs b/crates/assists/src/ast_transform.rs
index 835da3bb26..bbcd2d4883 100644
--- a/crates/assists/src/ast_transform.rs
+++ b/crates/assists/src/ast_transform.rs
@@ -18,34 +18,6 @@ pub fn apply<'a, N: AstNode>(transformer: &dyn AstTransform<'a>, node: N) -> N {
     .rewrite_ast(&node)
 }
 
-/// `AstTransform` helps with applying bulk transformations to syntax nodes.
-///
-/// This is mostly useful for IDE code generation. If you paste some existing
-/// code into a new context (for example, to add method overrides to an `impl`
-/// block), you generally want to appropriately qualify the names, and sometimes
-/// you might want to substitute generic parameters as well:
-///
-/// ```
-/// mod x {
-///   pub struct A;
-///   pub trait T<U> { fn foo(&self, _: U) -> A; }
-/// }
-///
-/// mod y {
-///   use x::T;
-///
-///   impl T<()> for () {
-///      // If we invoke **Add Missing Members** here, we want to copy-paste `foo`.
-///      // But we want a slightly-modified version of it:
-///      fn foo(&self, _: ()) -> x::A {}
-///   }
-/// }
-/// ```
-///
-/// So, a single `AstTransform` describes such function from `SyntaxNode` to
-/// `SyntaxNode`. Note that the API here is a bit too high-order and high-brow.
-/// We'd want to somehow express this concept simpler, but so far nobody got to
-/// simplifying this!
 pub trait AstTransform<'a> {
     fn get_substitution(&self, node: &syntax::SyntaxNode) -> Option<syntax::SyntaxNode>;
 
diff --git a/crates/assists/src/handlers/add_missing_impl_members.rs b/crates/assists/src/handlers/add_missing_impl_members.rs
index 8df1d786b1..83a2ada9a2 100644
--- a/crates/assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/assists/src/handlers/add_missing_impl_members.rs
@@ -111,6 +111,8 @@ fn add_missing_impl_members_inner(
 ) -> Option<()> {
     let _p = profile::span("add_missing_impl_members_inner");
     let impl_def = ctx.find_node_at_offset::<ast::Impl>()?;
+    let impl_item_list = impl_def.assoc_item_list()?;
+
     let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?;
 
     let def_name = |item: &ast::AssocItem| -> Option<SmolStr> {
@@ -146,14 +148,11 @@ fn add_missing_impl_members_inner(
 
     let target = impl_def.syntax().text_range();
     acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |builder| {
-        let impl_item_list = impl_def.assoc_item_list().unwrap_or(make::assoc_item_list());
-
         let n_existing_items = impl_item_list.assoc_items().count();
         let source_scope = ctx.sema.scope_for_def(trait_);
-        let target_scope = ctx.sema.scope(impl_def.syntax());
+        let target_scope = ctx.sema.scope(impl_item_list.syntax());
         let ast_transform = QualifyPaths::new(&target_scope, &source_scope)
-            .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def.clone()));
-
+            .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def));
         let items = missing_items
             .into_iter()
             .map(|it| ast_transform::apply(&*ast_transform, it))
@@ -163,14 +162,12 @@ fn add_missing_impl_members_inner(
                 _ => it,
             })
             .map(|it| edit::remove_attrs_and_docs(&it));
-
         let new_impl_item_list = impl_item_list.append_items(items);
-        let new_impl_def = impl_def.with_assoc_item_list(new_impl_item_list);
-        let first_new_item =
-            new_impl_def.assoc_item_list().unwrap().assoc_items().nth(n_existing_items).unwrap();
+        let first_new_item = new_impl_item_list.assoc_items().nth(n_existing_items).unwrap();
 
+        let original_range = impl_item_list.syntax().text_range();
         match ctx.config.snippet_cap {
-            None => builder.replace(target, new_impl_def.to_string()),
+            None => builder.replace(original_range, new_impl_item_list.to_string()),
             Some(cap) => {
                 let mut cursor = Cursor::Before(first_new_item.syntax());
                 let placeholder;
@@ -184,8 +181,8 @@ fn add_missing_impl_members_inner(
                 }
                 builder.replace_snippet(
                     cap,
-                    target,
-                    render_snippet(cap, new_impl_def.syntax(), cursor),
+                    original_range,
+                    render_snippet(cap, new_impl_item_list.syntax(), cursor),
                 )
             }
         };
@@ -313,25 +310,6 @@ impl Foo for S {
         );
     }
 
-    #[test]
-    fn test_impl_def_without_braces() {
-        check_assist(
-            add_missing_impl_members,
-            r#"
-trait Foo { fn foo(&self); }
-struct S;
-impl Foo for S<|>"#,
-            r#"
-trait Foo { fn foo(&self); }
-struct S;
-impl Foo for S {
-    fn foo(&self) {
-        ${0:todo!()}
-    }
-}"#,
-        );
-    }
-
     #[test]
     fn fill_in_type_params_1() {
         check_assist(
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index 849c8f6d09..7a9747fc71 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -908,12 +908,12 @@ impl MacroDef {
 
     /// Indicate it is a proc-macro
     pub fn is_proc_macro(&self) -> bool {
-        matches!(self.id.kind, MacroDefKind::ProcMacro(_))
+        matches!(self.id.kind, MacroDefKind::CustomDerive(_))
     }
 
     /// Indicate it is a derive macro
     pub fn is_derive_macro(&self) -> bool {
-        matches!(self.id.kind, MacroDefKind::ProcMacro(_) | MacroDefKind::BuiltInDerive(_))
+        matches!(self.id.kind, MacroDefKind::CustomDerive(_) | MacroDefKind::BuiltInDerive(_))
     }
 }
 
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index c61a430e11..0516a05b41 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -697,25 +697,6 @@ fn find_root(node: &SyntaxNode) -> SyntaxNode {
     node.ancestors().last().unwrap()
 }
 
-/// `SemanticScope` encapsulates the notion of a scope (the set of visible
-/// names) at a particular program point.
-///
-/// It is a bit tricky, as scopes do not really exist inside the compiler.
-/// Rather, the compiler directly computes for each reference the definition it
-/// refers to. It might transiently compute the explicit scope map while doing
-/// so, but, generally, this is not something left after the analysis.
-///
-/// However, we do very much need explicit scopes for IDE purposes --
-/// completion, at its core, lists the contents of the current scope. The notion
-/// of scope is also useful to answer questions like "what would be the meaning
-/// of this piece of code if we inserted it into this position?".
-///
-/// So `SemanticsScope` is constructed from a specific program point (a syntax
-/// node or just a raw offset) and provides access to the set of visible names
-/// on a somewhat best-effort basis.
-///
-/// Note that if you are wondering "what does this specific existing name mean?",
-/// you'd better use the `resolve_` family of methods.
 #[derive(Debug)]
 pub struct SemanticsScope<'a> {
     pub db: &'a dyn HirDatabase,
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs
index 2ec0fd3fb7..3e19d9117a 100644
--- a/crates/hir_def/src/diagnostics.rs
+++ b/crates/hir_def/src/diagnostics.rs
@@ -28,45 +28,3 @@ impl Diagnostic for UnresolvedModule {
         self
     }
 }
-
-#[derive(Debug)]
-pub struct UnresolvedExternCrate {
-    pub file: HirFileId,
-    pub item: AstPtr<ast::ExternCrate>,
-}
-
-impl Diagnostic for UnresolvedExternCrate {
-    fn code(&self) -> DiagnosticCode {
-        DiagnosticCode("unresolved-extern-crate")
-    }
-    fn message(&self) -> String {
-        "unresolved extern crate".to_string()
-    }
-    fn display_source(&self) -> InFile<SyntaxNodePtr> {
-        InFile::new(self.file, self.item.clone().into())
-    }
-    fn as_any(&self) -> &(dyn Any + Send + 'static) {
-        self
-    }
-}
-
-#[derive(Debug)]
-pub struct UnresolvedImport {
-    pub file: HirFileId,
-    pub node: AstPtr<ast::UseTree>,
-}
-
-impl Diagnostic for UnresolvedImport {
-    fn code(&self) -> DiagnosticCode {
-        DiagnosticCode("unresolved-import")
-    }
-    fn message(&self) -> String {
-        "unresolved import".to_string()
-    }
-    fn display_source(&self) -> InFile<SyntaxNodePtr> {
-        InFile::new(self.file, self.node.clone().into())
-    }
-    fn as_any(&self) -> &(dyn Any + Send + 'static) {
-        self
-    }
-}
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 0fd91b9d01..52abb8e7f1 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -291,6 +291,7 @@ pub enum AttrOwner {
 
     Variant(Idx<Variant>),
     Field(Idx<Field>),
+    // FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`.
 }
 
 macro_rules! from_attrs {
@@ -482,16 +483,11 @@ pub struct Import {
     /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many
     /// `Import`s can map to the same `use` item.
     pub ast_id: FileAstId<ast::Use>,
-    /// Index of this `Import` when the containing `Use` is visited via `ModPath::expand_use_item`.
-    ///
-    /// This can be used to get the `UseTree` this `Import` corresponds to and allows emitting
-    /// precise diagnostics.
-    pub index: usize,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct ExternCrate {
-    pub name: Name,
+    pub path: ModPath,
     pub alias: Option<ImportAlias>,
     pub visibility: RawVisibilityId,
     /// Whether this is a `#[macro_use] extern crate ...`.
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 54814f1414..d93377c3bd 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -483,7 +483,7 @@ impl Ctx {
         ModPath::expand_use_item(
             InFile::new(self.file, use_item.clone()),
             &self.hygiene,
-            |path, _use_tree, is_glob, alias| {
+            |path, _tree, is_glob, alias| {
                 imports.push(id(tree.imports.alloc(Import {
                     path,
                     alias,
@@ -491,7 +491,6 @@ impl Ctx {
                     is_glob,
                     is_prelude,
                     ast_id,
-                    index: imports.len(),
                 })));
             },
         );
@@ -503,7 +502,7 @@ impl Ctx {
         &mut self,
         extern_crate: &ast::ExternCrate,
     ) -> Option<FileItemTreeId<ExternCrate>> {
-        let name = extern_crate.name_ref()?.as_name();
+        let path = ModPath::from_name_ref(&extern_crate.name_ref()?);
         let alias = extern_crate.rename().map(|a| {
             a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
         });
@@ -512,7 +511,7 @@ impl Ctx {
         // FIXME: cfg_attr
         let is_macro_use = extern_crate.has_atom_attr("macro_use");
 
-        let res = ExternCrate { name, alias, visibility, is_macro_use, ast_id };
+        let res = ExternCrate { path, alias, visibility, is_macro_use, ast_id };
         Some(id(self.data().extern_crates.alloc(res)))
     }
 
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 5e4d73c1ff..bf302172d0 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -288,70 +288,31 @@ pub enum ModuleSource {
 
 mod diagnostics {
     use hir_expand::diagnostics::DiagnosticSink;
-    use hir_expand::hygiene::Hygiene;
-    use hir_expand::InFile;
     use syntax::{ast, AstPtr};
 
-    use crate::path::ModPath;
-    use crate::{db::DefDatabase, diagnostics::*, nameres::LocalModuleId, AstId};
+    use crate::{db::DefDatabase, diagnostics::UnresolvedModule, nameres::LocalModuleId, AstId};
 
     #[derive(Debug, PartialEq, Eq)]
-    enum DiagnosticKind {
-        UnresolvedModule { declaration: AstId<ast::Module>, candidate: String },
-
-        UnresolvedExternCrate { ast: AstId<ast::ExternCrate> },
-
-        UnresolvedImport { ast: AstId<ast::Use>, index: usize },
-    }
-
-    #[derive(Debug, PartialEq, Eq)]
-    pub(super) struct DefDiagnostic {
-        in_module: LocalModuleId,
-        kind: DiagnosticKind,
-    }
-
-    impl DefDiagnostic {
-        pub(super) fn unresolved_module(
-            container: LocalModuleId,
+    pub(super) enum DefDiagnostic {
+        UnresolvedModule {
+            module: LocalModuleId,
             declaration: AstId<ast::Module>,
             candidate: String,
-        ) -> Self {
-            Self {
-                in_module: container,
-                kind: DiagnosticKind::UnresolvedModule { declaration, candidate },
-            }
-        }
-
-        pub(super) fn unresolved_extern_crate(
-            container: LocalModuleId,
-            declaration: AstId<ast::ExternCrate>,
-        ) -> Self {
-            Self {
-                in_module: container,
-                kind: DiagnosticKind::UnresolvedExternCrate { ast: declaration },
-            }
-        }
-
-        pub(super) fn unresolved_import(
-            container: LocalModuleId,
-            ast: AstId<ast::Use>,
-            index: usize,
-        ) -> Self {
-            Self { in_module: container, kind: DiagnosticKind::UnresolvedImport { ast, index } }
-        }
+        },
+    }
 
+    impl DefDiagnostic {
         pub(super) fn add_to(
             &self,
             db: &dyn DefDatabase,
             target_module: LocalModuleId,
             sink: &mut DiagnosticSink,
         ) {
-            if self.in_module != target_module {
-                return;
-            }
-
-            match &self.kind {
-                DiagnosticKind::UnresolvedModule { declaration, candidate } => {
+            match self {
+                DefDiagnostic::UnresolvedModule { module, declaration, candidate } => {
+                    if *module != target_module {
+                        return;
+                    }
                     let decl = declaration.to_node(db.upcast());
                     sink.push(UnresolvedModule {
                         file: declaration.file_id,
@@ -359,36 +320,6 @@ mod diagnostics {
                         candidate: candidate.clone(),
                     })
                 }
-
-                DiagnosticKind::UnresolvedExternCrate { ast } => {
-                    let item = ast.to_node(db.upcast());
-                    sink.push(UnresolvedExternCrate {
-                        file: ast.file_id,
-                        item: AstPtr::new(&item),
-                    });
-                }
-
-                DiagnosticKind::UnresolvedImport { ast, index } => {
-                    let use_item = ast.to_node(db.upcast());
-                    let hygiene = Hygiene::new(db.upcast(), ast.file_id);
-                    let mut cur = 0;
-                    let mut tree = None;
-                    ModPath::expand_use_item(
-                        InFile::new(ast.file_id, use_item),
-                        &hygiene,
-                        |_mod_path, use_tree, _is_glob, _alias| {
-                            if cur == *index {
-                                tree = Some(use_tree.clone());
-                            }
-
-                            cur += 1;
-                        },
-                    );
-
-                    if let Some(tree) = tree {
-                        sink.push(UnresolvedImport { file: ast.file_id, node: AstPtr::new(&tree) });
-                    }
-                }
             }
         }
     }
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 4c3993ff01..3e99c87737 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -3,11 +3,8 @@
 //! `DefCollector::collect` contains the fixed-point iteration loop which
 //! resolves imports and expands macros.
 
-use std::iter;
-
 use base_db::{CrateId, FileId, ProcMacroId};
 use cfg::CfgOptions;
-use hir_expand::InFile;
 use hir_expand::{
     ast_id_map::FileAstId,
     builtin_derive::find_builtin_derive,
@@ -17,7 +14,6 @@ use hir_expand::{
     HirFileId, MacroCallId, MacroDefId, MacroDefKind,
 };
 use rustc_hash::FxHashMap;
-use rustc_hash::FxHashSet;
 use syntax::ast;
 use test_utils::mark;
 
@@ -25,7 +21,9 @@ use crate::{
     attr::Attrs,
     db::DefDatabase,
     item_scope::{ImportType, PerNsGlobImports},
-    item_tree::{self, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind},
+    item_tree::{
+        self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind,
+    },
     nameres::{
         diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
         BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode,
@@ -113,12 +111,6 @@ impl PartialResolvedImport {
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq)]
-enum ImportSource {
-    Import(ItemTreeId<item_tree::Import>),
-    ExternCrate(ItemTreeId<item_tree::ExternCrate>),
-}
-
 #[derive(Clone, Debug, Eq, PartialEq)]
 struct Import {
     pub path: ModPath,
@@ -128,12 +120,11 @@ struct Import {
     pub is_prelude: bool,
     pub is_extern_crate: bool,
     pub is_macro_use: bool,
-    source: ImportSource,
 }
 
 impl Import {
-    fn from_use(tree: &ItemTree, id: ItemTreeId<item_tree::Import>) -> Self {
-        let it = &tree[id.value];
+    fn from_use(tree: &ItemTree, id: FileItemTreeId<item_tree::Import>) -> Self {
+        let it = &tree[id];
         let visibility = &tree[it.visibility];
         Self {
             path: it.path.clone(),
@@ -143,22 +134,20 @@ impl Import {
             is_prelude: it.is_prelude,
             is_extern_crate: false,
             is_macro_use: false,
-            source: ImportSource::Import(id),
         }
     }
 
-    fn from_extern_crate(tree: &ItemTree, id: ItemTreeId<item_tree::ExternCrate>) -> Self {
-        let it = &tree[id.value];
+    fn from_extern_crate(tree: &ItemTree, id: FileItemTreeId<item_tree::ExternCrate>) -> Self {
+        let it = &tree[id];
         let visibility = &tree[it.visibility];
         Self {
-            path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())),
+            path: it.path.clone(),
             alias: it.alias.clone(),
             visibility: visibility.clone(),
             is_glob: false,
             is_prelude: false,
             is_extern_crate: true,
             is_macro_use: it.is_macro_use,
-            source: ImportSource::ExternCrate(id),
         }
     }
 }
@@ -256,10 +245,9 @@ impl DefCollector<'_> {
 
         let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
         // show unresolved imports in completion, etc
-        for directive in &unresolved_imports {
-            self.record_resolved_import(directive)
+        for directive in unresolved_imports {
+            self.record_resolved_import(&directive)
         }
-        self.unresolved_imports = unresolved_imports;
 
         // Record proc-macros
         self.collect_proc_macro();
@@ -273,7 +261,7 @@ impl DefCollector<'_> {
             let macro_id = MacroDefId {
                 ast_id: None,
                 krate: Some(krate),
-                kind: MacroDefKind::ProcMacro(expander),
+                kind: MacroDefKind::CustomDerive(expander),
                 local_inner: false,
             };
 
@@ -358,15 +346,20 @@ impl DefCollector<'_> {
     fn import_macros_from_extern_crate(
         &mut self,
         current_module_id: LocalModuleId,
-        extern_crate: &item_tree::ExternCrate,
+        import: &item_tree::ExternCrate,
     ) {
         log::debug!(
             "importing macros from extern crate: {:?} ({:?})",
-            extern_crate,
+            import,
             self.def_map.edition,
         );
 
-        let res = self.def_map.resolve_name_in_extern_prelude(&extern_crate.name);
+        let res = self.def_map.resolve_name_in_extern_prelude(
+            &import
+                .path
+                .as_ident()
+                .expect("extern crate should have been desugared to one-element path"),
+        );
 
         if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
             mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
@@ -427,11 +420,7 @@ impl DefCollector<'_> {
                     .as_ident()
                     .expect("extern crate should have been desugared to one-element path"),
             );
-            if res.is_none() {
-                PartialResolvedImport::Unresolved
-            } else {
-                PartialResolvedImport::Resolved(res)
-            }
+            PartialResolvedImport::Resolved(res)
         } else {
             let res = self.def_map.resolve_path_fp_with_macro(
                 self.db,
@@ -785,51 +774,7 @@ impl DefCollector<'_> {
         .collect(item_tree.top_level_items());
     }
 
-    fn finish(mut self) -> CrateDefMap {
-        // Emit diagnostics for all remaining unresolved imports.
-
-        // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't
-        // resolve. We first emit diagnostics for unresolved extern crates and collect the missing
-        // crate names. Then we emit diagnostics for unresolved imports, but only if the import
-        // doesn't start with an unresolved crate's name. Due to renaming and reexports, this is a
-        // heuristic, but it works in practice.
-        let mut diagnosed_extern_crates = FxHashSet::default();
-        for directive in &self.unresolved_imports {
-            if let ImportSource::ExternCrate(krate) = directive.import.source {
-                let item_tree = self.db.item_tree(krate.file_id);
-                let extern_crate = &item_tree[krate.value];
-
-                diagnosed_extern_crates.insert(extern_crate.name.clone());
-
-                self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate(
-                    directive.module_id,
-                    InFile::new(krate.file_id, extern_crate.ast_id),
-                ));
-            }
-        }
-
-        for directive in &self.unresolved_imports {
-            if let ImportSource::Import(import) = &directive.import.source {
-                let item_tree = self.db.item_tree(import.file_id);
-                let import_data = &item_tree[import.value];
-
-                match (import_data.path.segments.first(), &import_data.path.kind) {
-                    (Some(krate), PathKind::Plain) | (Some(krate), PathKind::Abs) => {
-                        if diagnosed_extern_crates.contains(krate) {
-                            continue;
-                        }
-                    }
-                    _ => {}
-                }
-
-                self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
-                    directive.module_id,
-                    InFile::new(import.file_id, import_data.ast_id),
-                    import_data.index,
-                ));
-            }
-        }
-
+    fn finish(self) -> CrateDefMap {
         self.def_map
     }
 }
@@ -874,184 +819,179 @@ impl ModCollector<'_, '_> {
 
         for &item in items {
             let attrs = self.item_tree.attrs(item.into());
-            if !self.is_cfg_enabled(attrs) {
-                continue;
-            }
-            let module =
-                ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
-            let container = ContainerId::ModuleId(module);
-
-            let mut def = None;
-            match item {
-                ModItem::Mod(m) => self.collect_module(&self.item_tree[m], attrs),
-                ModItem::Import(import_id) => {
-                    self.def_collector.unresolved_imports.push(ImportDirective {
-                        module_id: self.module_id,
-                        import: Import::from_use(
-                            &self.item_tree,
-                            InFile::new(self.file_id, import_id),
-                        ),
-                        status: PartialResolvedImport::Unresolved,
-                    })
-                }
-                ModItem::ExternCrate(import_id) => {
-                    self.def_collector.unresolved_imports.push(ImportDirective {
-                        module_id: self.module_id,
-                        import: Import::from_extern_crate(
-                            &self.item_tree,
-                            InFile::new(self.file_id, import_id),
-                        ),
-                        status: PartialResolvedImport::Unresolved,
-                    })
-                }
-                ModItem::MacroCall(mac) => self.collect_macro(&self.item_tree[mac]),
-                ModItem::Impl(imp) => {
-                    let module = ModuleId {
-                        krate: self.def_collector.def_map.krate,
-                        local_id: self.module_id,
-                    };
-                    let container = ContainerId::ModuleId(module);
-                    let impl_id = ImplLoc { container, id: ItemTreeId::new(self.file_id, imp) }
-                        .intern(self.def_collector.db);
-                    self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id)
-                }
-                ModItem::Function(id) => {
-                    let func = &self.item_tree[id];
-                    def = Some(DefData {
-                        id: FunctionLoc {
-                            container: container.into(),
-                            id: ItemTreeId::new(self.file_id, id),
-                        }
-                        .intern(self.def_collector.db)
-                        .into(),
-                        name: &func.name,
-                        visibility: &self.item_tree[func.visibility],
-                        has_constructor: false,
-                    });
-                }
-                ModItem::Struct(id) => {
-                    let it = &self.item_tree[id];
-
-                    // FIXME: check attrs to see if this is an attribute macro invocation;
-                    // in which case we don't add the invocation, just a single attribute
-                    // macro invocation
-                    self.collect_derives(attrs, it.ast_id.upcast());
-
-                    def = Some(DefData {
-                        id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) }
+            if self.is_cfg_enabled(attrs) {
+                let module =
+                    ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
+                let container = ContainerId::ModuleId(module);
+
+                let mut def = None;
+                match item {
+                    ModItem::Mod(m) => self.collect_module(&self.item_tree[m], attrs),
+                    ModItem::Import(import_id) => {
+                        self.def_collector.unresolved_imports.push(ImportDirective {
+                            module_id: self.module_id,
+                            import: Import::from_use(&self.item_tree, import_id),
+                            status: PartialResolvedImport::Unresolved,
+                        })
+                    }
+                    ModItem::ExternCrate(import_id) => {
+                        self.def_collector.unresolved_imports.push(ImportDirective {
+                            module_id: self.module_id,
+                            import: Import::from_extern_crate(&self.item_tree, import_id),
+                            status: PartialResolvedImport::Unresolved,
+                        })
+                    }
+                    ModItem::MacroCall(mac) => self.collect_macro(&self.item_tree[mac]),
+                    ModItem::Impl(imp) => {
+                        let module = ModuleId {
+                            krate: self.def_collector.def_map.krate,
+                            local_id: self.module_id,
+                        };
+                        let container = ContainerId::ModuleId(module);
+                        let impl_id = ImplLoc { container, id: ItemTreeId::new(self.file_id, imp) }
+                            .intern(self.def_collector.db);
+                        self.def_collector.def_map.modules[self.module_id]
+                            .scope
+                            .define_impl(impl_id)
+                    }
+                    ModItem::Function(id) => {
+                        let func = &self.item_tree[id];
+                        def = Some(DefData {
+                            id: FunctionLoc {
+                                container: container.into(),
+                                id: ItemTreeId::new(self.file_id, id),
+                            }
                             .intern(self.def_collector.db)
                             .into(),
-                        name: &it.name,
-                        visibility: &self.item_tree[it.visibility],
-                        has_constructor: it.kind != StructDefKind::Record,
-                    });
-                }
-                ModItem::Union(id) => {
-                    let it = &self.item_tree[id];
+                            name: &func.name,
+                            visibility: &self.item_tree[func.visibility],
+                            has_constructor: false,
+                        });
+                    }
+                    ModItem::Struct(id) => {
+                        let it = &self.item_tree[id];
 
-                    // FIXME: check attrs to see if this is an attribute macro invocation;
-                    // in which case we don't add the invocation, just a single attribute
-                    // macro invocation
-                    self.collect_derives(attrs, it.ast_id.upcast());
+                        // FIXME: check attrs to see if this is an attribute macro invocation;
+                        // in which case we don't add the invocation, just a single attribute
+                        // macro invocation
+                        self.collect_derives(attrs, it.ast_id.upcast());
 
-                    def = Some(DefData {
-                        id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) }
-                            .intern(self.def_collector.db)
-                            .into(),
-                        name: &it.name,
-                        visibility: &self.item_tree[it.visibility],
-                        has_constructor: false,
-                    });
-                }
-                ModItem::Enum(id) => {
-                    let it = &self.item_tree[id];
+                        def = Some(DefData {
+                            id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) }
+                                .intern(self.def_collector.db)
+                                .into(),
+                            name: &it.name,
+                            visibility: &self.item_tree[it.visibility],
+                            has_constructor: it.kind != StructDefKind::Record,
+                        });
+                    }
+                    ModItem::Union(id) => {
+                        let it = &self.item_tree[id];
 
-                    // FIXME: check attrs to see if this is an attribute macro invocation;
-                    // in which case we don't add the invocation, just a single attribute
-                    // macro invocation
-                    self.collect_derives(attrs, it.ast_id.upcast());
+                        // FIXME: check attrs to see if this is an attribute macro invocation;
+                        // in which case we don't add the invocation, just a single attribute
+                        // macro invocation
+                        self.collect_derives(attrs, it.ast_id.upcast());
 
-                    def = Some(DefData {
-                        id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) }
-                            .intern(self.def_collector.db)
-                            .into(),
-                        name: &it.name,
-                        visibility: &self.item_tree[it.visibility],
-                        has_constructor: false,
-                    });
-                }
-                ModItem::Const(id) => {
-                    let it = &self.item_tree[id];
+                        def = Some(DefData {
+                            id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) }
+                                .intern(self.def_collector.db)
+                                .into(),
+                            name: &it.name,
+                            visibility: &self.item_tree[it.visibility],
+                            has_constructor: false,
+                        });
+                    }
+                    ModItem::Enum(id) => {
+                        let it = &self.item_tree[id];
+
+                        // FIXME: check attrs to see if this is an attribute macro invocation;
+                        // in which case we don't add the invocation, just a single attribute
+                        // macro invocation
+                        self.collect_derives(attrs, it.ast_id.upcast());
+
+                        def = Some(DefData {
+                            id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) }
+                                .intern(self.def_collector.db)
+                                .into(),
+                            name: &it.name,
+                            visibility: &self.item_tree[it.visibility],
+                            has_constructor: false,
+                        });
+                    }
+                    ModItem::Const(id) => {
+                        let it = &self.item_tree[id];
+
+                        if let Some(name) = &it.name {
+                            def = Some(DefData {
+                                id: ConstLoc {
+                                    container: container.into(),
+                                    id: ItemTreeId::new(self.file_id, id),
+                                }
+                                .intern(self.def_collector.db)
+                                .into(),
+                                name,
+                                visibility: &self.item_tree[it.visibility],
+                                has_constructor: false,
+                            });
+                        }
+                    }
+                    ModItem::Static(id) => {
+                        let it = &self.item_tree[id];
 
-                    if let Some(name) = &it.name {
                         def = Some(DefData {
-                            id: ConstLoc {
+                            id: StaticLoc { container, id: ItemTreeId::new(self.file_id, id) }
+                                .intern(self.def_collector.db)
+                                .into(),
+                            name: &it.name,
+                            visibility: &self.item_tree[it.visibility],
+                            has_constructor: false,
+                        });
+                    }
+                    ModItem::Trait(id) => {
+                        let it = &self.item_tree[id];
+
+                        def = Some(DefData {
+                            id: TraitLoc { container, id: ItemTreeId::new(self.file_id, id) }
+                                .intern(self.def_collector.db)
+                                .into(),
+                            name: &it.name,
+                            visibility: &self.item_tree[it.visibility],
+                            has_constructor: false,
+                        });
+                    }
+                    ModItem::TypeAlias(id) => {
+                        let it = &self.item_tree[id];
+
+                        def = Some(DefData {
+                            id: TypeAliasLoc {
                                 container: container.into(),
                                 id: ItemTreeId::new(self.file_id, id),
                             }
                             .intern(self.def_collector.db)
                             .into(),
-                            name,
+                            name: &it.name,
                             visibility: &self.item_tree[it.visibility],
                             has_constructor: false,
                         });
                     }
                 }
-                ModItem::Static(id) => {
-                    let it = &self.item_tree[id];
-
-                    def = Some(DefData {
-                        id: StaticLoc { container, id: ItemTreeId::new(self.file_id, id) }
-                            .intern(self.def_collector.db)
-                            .into(),
-                        name: &it.name,
-                        visibility: &self.item_tree[it.visibility],
-                        has_constructor: false,
-                    });
-                }
-                ModItem::Trait(id) => {
-                    let it = &self.item_tree[id];
 
-                    def = Some(DefData {
-                        id: TraitLoc { container, id: ItemTreeId::new(self.file_id, id) }
-                            .intern(self.def_collector.db)
-                            .into(),
-                        name: &it.name,
-                        visibility: &self.item_tree[it.visibility],
-                        has_constructor: false,
-                    });
-                }
-                ModItem::TypeAlias(id) => {
-                    let it = &self.item_tree[id];
-
-                    def = Some(DefData {
-                        id: TypeAliasLoc {
-                            container: container.into(),
-                            id: ItemTreeId::new(self.file_id, id),
-                        }
-                        .intern(self.def_collector.db)
-                        .into(),
-                        name: &it.name,
-                        visibility: &self.item_tree[it.visibility],
-                        has_constructor: false,
-                    });
+                if let Some(DefData { id, name, visibility, has_constructor }) = def {
+                    self.def_collector.def_map.modules[self.module_id].scope.define_def(id);
+                    let vis = self
+                        .def_collector
+                        .def_map
+                        .resolve_visibility(self.def_collector.db, self.module_id, visibility)
+                        .unwrap_or(Visibility::Public);
+                    self.def_collector.update(
+                        self.module_id,
+                        &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
+                        vis,
+                        ImportType::Named,
+                    )
                 }
             }
-
-            if let Some(DefData { id, name, visibility, has_constructor }) = def {
-                self.def_collector.def_map.modules[self.module_id].scope.define_def(id);
-                let vis = self
-                    .def_collector
-                    .def_map
-                    .resolve_visibility(self.def_collector.db, self.module_id, visibility)
-                    .unwrap_or(Visibility::Public);
-                self.def_collector.update(
-                    self.module_id,
-                    &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
-                    vis,
-                    ImportType::Named,
-                )
-            }
         }
     }
 
@@ -1111,11 +1051,13 @@ impl ModCollector<'_, '_> {
                             self.import_all_legacy_macros(module_id);
                         }
                     }
-                    Err(candidate) => {
-                        self.def_collector.def_map.diagnostics.push(
-                            DefDiagnostic::unresolved_module(self.module_id, ast_id, candidate),
-                        );
-                    }
+                    Err(candidate) => self.def_collector.def_map.diagnostics.push(
+                        DefDiagnostic::UnresolvedModule {
+                            module: self.module_id,
+                            declaration: ast_id,
+                            candidate,
+                        },
+                    ),
                 };
             }
         }
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 734310458f..99395667de 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -56,6 +56,10 @@ impl ModPath {
         ModPath { kind, segments }
     }
 
+    pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> ModPath {
+        name_ref.as_name().into()
+    }
+
     /// Converts an `tt::Ident` into a single-identifier `Path`.
     pub(crate) fn from_tt_ident(ident: &tt::Ident) -> ModPath {
         ident.as_name().into()
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index b591130ca4..710694a347 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -143,7 +143,7 @@ pub(crate) fn macro_def(
             Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default())))
         }
         MacroDefKind::BuiltInEager(_) => None,
-        MacroDefKind::ProcMacro(expander) => {
+        MacroDefKind::CustomDerive(expander) => {
             Some(Arc::new((TokenExpander::ProcMacro(expander), mbe::TokenMap::default())))
         }
     }
@@ -249,7 +249,7 @@ pub(crate) fn expand_proc_macro(
     };
 
     let expander = match loc.def.kind {
-        MacroDefKind::ProcMacro(expander) => expander,
+        MacroDefKind::CustomDerive(expander) => expander,
         _ => unreachable!(),
     };
 
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index 2f37d7189c..10c45646f0 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -129,7 +129,7 @@ fn eager_macro_recur(
             MacroDefKind::Declarative
             | MacroDefKind::BuiltIn(_)
             | MacroDefKind::BuiltInDerive(_)
-            | MacroDefKind::ProcMacro(_) => {
+            | MacroDefKind::CustomDerive(_) => {
                 let expanded = lazy_expand(db, &def, curr.with_value(child.clone()), krate)?;
                 // replace macro inside
                 eager_macro_recur(db, expanded, krate, macro_resolver)?
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index d383b968da..845e9cbc19 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -33,7 +33,7 @@ impl Hygiene {
                         MacroDefKind::BuiltIn(_) => (None, false),
                         MacroDefKind::BuiltInDerive(_) => (None, false),
                         MacroDefKind::BuiltInEager(_) => (None, false),
-                        MacroDefKind::ProcMacro(_) => (None, false),
+                        MacroDefKind::CustomDerive(_) => (None, false),
                     }
                 }
                 MacroCallId::EagerMacro(_id) => (None, false),
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 17f1178ed7..2be15e8413 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -246,7 +246,7 @@ pub enum MacroDefKind {
     // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander
     BuiltInDerive(BuiltinDeriveExpander),
     BuiltInEager(EagerExpander),
-    ProcMacro(ProcMacroExpander),
+    CustomDerive(ProcMacroExpander),
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/crates/ide/src/completion/complete_postfix.rs b/crates/ide/src/completion/complete_postfix.rs
index 84c4e129d2..29d38661bb 100644
--- a/crates/ide/src/completion/complete_postfix.rs
+++ b/crates/ide/src/completion/complete_postfix.rs
@@ -185,6 +185,16 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
     )
     .add_to(acc);
 
+    postfix_snippet(
+        ctx,
+        cap,
+        &dot_receiver,
+        "dbgr",
+        "dbg!(&expr)",
+        &format!("dbg!(&{})", receiver_text),
+    )
+    .add_to(acc);
+
     postfix_snippet(
         ctx,
         cap,
@@ -263,6 +273,7 @@ fn main() {
                 sn box   Box::new(expr)
                 sn call  function(expr)
                 sn dbg   dbg!(expr)
+                sn dbgr  dbg!(&expr)
                 sn if    if expr {}
                 sn match match expr {}
                 sn not   !expr
@@ -286,6 +297,7 @@ fn main() {
                 sn box   Box::new(expr)
                 sn call  function(expr)
                 sn dbg   dbg!(expr)
+                sn dbgr  dbg!(&expr)
                 sn match match expr {}
                 sn ref   &expr
                 sn refm  &mut expr
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index dc815a4838..b2b972b02c 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -622,65 +622,13 @@ pub struct Foo { pub a: i32, pub b: i32 }
             r#"
 use a;
 use a::{c, d::e};
-
-mod a {
-    mod c {}
-    mod d {
-        mod e {}
-    }
-}
 "#,
         );
-        check_fix(
-            r"
-            mod b {}
-            use {<|>b};
-            ",
-            r"
-            mod b {}
-            use b;
-            ",
-        );
-        check_fix(
-            r"
-            mod b {}
-            use {b<|>};
-            ",
-            r"
-            mod b {}
-            use b;
-            ",
-        );
-        check_fix(
-            r"
-            mod a { mod c {} }
-            use a::{c<|>};
-            ",
-            r"
-            mod a { mod c {} }
-            use a::c;
-            ",
-        );
-        check_fix(
-            r"
-            mod a {}
-            use a::{self<|>};
-            ",
-            r"
-            mod a {}
-            use a;
-            ",
-        );
-        check_fix(
-            r"
-            mod a { mod c {} mod d { mod e {} } }
-            use a::{c, d::{e<|>}};
-            ",
-            r"
-            mod a { mod c {} mod d { mod e {} } }
-            use a::{c, d::e};
-            ",
-        );
+        check_fix(r#"use {<|>b};"#, r#"use b;"#);
+        check_fix(r#"use {b<|>};"#, r#"use b;"#);
+        check_fix(r#"use a::{c<|>};"#, r#"use a::c;"#);
+        check_fix(r#"use a::{self<|>};"#, r#"use a;"#);
+        check_fix(r#"use a::{c, d::{e<|>}};"#, r#"use a::{c, d::e};"#);
     }
 
     #[test]
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs
index 258f60e28b..288c39e494 100644
--- a/crates/project_model/src/lib.rs
+++ b/crates/project_model/src/lib.rs
@@ -308,13 +308,7 @@ impl ProjectWorkspace {
                     .crates()
                     .filter_map(|(crate_id, krate)| {
                         let file_path = &krate.root_module;
-                        let file_id = match load(&file_path) {
-                            Some(id) => id,
-                            None => {
-                                log::error!("failed to load crate root {}", file_path.display());
-                                return None;
-                            }
-                        };
+                        let file_id = load(&file_path)?;
 
                         let env = krate.env.clone().into_iter().collect();
                         let proc_macro = krate
diff --git a/crates/project_model/src/project_json.rs b/crates/project_model/src/project_json.rs
index a6895ecdd5..545f254aae 100644
--- a/crates/project_model/src/project_json.rs
+++ b/crates/project_model/src/project_json.rs
@@ -13,7 +13,7 @@ use crate::cfg_flag::CfgFlag;
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct ProjectJson {
     pub(crate) sysroot_src: Option<AbsPathBuf>,
-    project_root: AbsPathBuf,
+    project_root: Option<AbsPathBuf>,
     crates: Vec<Crate>,
 }
 
@@ -34,17 +34,10 @@ pub struct Crate {
 }
 
 impl ProjectJson {
-    /// Create a new ProjectJson instance.
-    ///
-    /// # Arguments
-    ///
-    /// * `base` - The path to the workspace root (i.e. the folder containing `rust-project.json`)
-    /// * `data` - The parsed contents of `rust-project.json`, or project json that's passed via
-    ///            configuration.
     pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson {
         ProjectJson {
             sysroot_src: data.sysroot_src.map(|it| base.join(it)),
-            project_root: base.to_path_buf(),
+            project_root: base.parent().map(AbsPath::to_path_buf),
             crates: data
                 .crates
                 .into_iter()
@@ -92,17 +85,17 @@ impl ProjectJson {
                 .collect::<Vec<_>>(),
         }
     }
-    /// Returns the number of crates in the project.
     pub fn n_crates(&self) -> usize {
         self.crates.len()
     }
-    /// Returns an iterator over the crates in the project.
     pub fn crates(&self) -> impl Iterator<Item = (CrateId, &Crate)> + '_ {
         self.crates.iter().enumerate().map(|(idx, krate)| (CrateId(idx as u32), krate))
     }
-    /// Returns the path to the project's root folder.
-    pub fn path(&self) -> &AbsPath {
-        &self.project_root
+    pub fn path(&self) -> Option<&AbsPath> {
+        match &self.project_root {
+            Some(p) => Some(p.as_path()),
+            None => None,
+        }
     }
 }
 
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 0fbb9cb0d2..8db0b0d72f 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -21,7 +21,7 @@ env_logger = { version = "0.7.1", default-features = false }
 itertools = "0.9.0"
 jod-thread = "0.1.0"
 log = "0.4.8"
-lsp-types = { version = "0.81.0", features = ["proposed"] }
+lsp-types = { version = "0.80.0", features = ["proposed"] }
 parking_lot = "0.11.0"
 pico-args = "0.3.1"
 oorandom = "11.1.2"
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 97b246a322..ba4402ade3 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -134,10 +134,6 @@ fn run_server() -> Result<()> {
 
             let discovered = ProjectManifest::discover_all(&workspace_roots);
             log::info!("discovered projects: {:?}", discovered);
-            if discovered.is_empty() {
-                log::error!("failed to find any projects in {:?}", workspace_roots);
-            }
-
             config.linked_projects = discovered.into_iter().map(LinkedProject::from).collect();
         }
 
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 69d05aed5a..1a74286f53 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -288,10 +288,7 @@ impl Config {
                         let path = self.root_path.join(it);
                         match ProjectManifest::from_manifest_file(path) {
                             Ok(it) => it.into(),
-                            Err(e) => {
-                                log::error!("failed to load linked project: {}", e);
-                                continue;
-                            }
+                            Err(_) => continue,
                         }
                     }
                     ManifestOrProjectJson::ProjectJson(it) => {
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index c0943a54dc..64cb4d96cb 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -748,15 +748,10 @@ pub(crate) fn handle_formatting(
         }
     }
 
-    if *file == captured_stdout {
-        // The document is already formatted correctly -- no edits needed.
-        Ok(None)
-    } else {
-        Ok(Some(vec![lsp_types::TextEdit {
-            range: Range::new(Position::new(0, 0), end_position),
-            new_text: captured_stdout,
-        }]))
-    }
+    Ok(Some(vec![lsp_types::TextEdit {
+        range: Range::new(Position::new(0, 0), end_position),
+        new_text: captured_stdout,
+    }]))
 }
 
 fn handle_fixes(
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index b070087a4f..b819618cb4 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -201,14 +201,11 @@ impl GlobalState {
             let mut crate_graph = CrateGraph::default();
             let vfs = &mut self.vfs.write().0;
             let loader = &mut self.loader;
-            let mem_docs = &self.mem_docs;
             let mut load = |path: &AbsPath| {
-                let vfs_path = vfs::VfsPath::from(path.to_path_buf());
-                if !mem_docs.contains_key(&vfs_path) {
-                    let contents = loader.handle.load_sync(path);
-                    vfs.set_file_contents(vfs_path.clone(), contents);
-                }
-                vfs.file_id(&vfs_path)
+                let contents = loader.handle.load_sync(path);
+                let path = vfs::VfsPath::from(path.to_path_buf());
+                vfs.set_file_contents(path.clone(), contents);
+                vfs.file_id(&path)
             };
             for ws in workspaces.iter() {
                 crate_graph.extend(ws.to_crate_graph(
@@ -252,7 +249,7 @@ impl GlobalState {
                     // Enable flychecks for json projects if a custom flycheck command was supplied
                     // in the workspace configuration.
                     match config {
-                        FlycheckConfig::CustomCommand { .. } => Some(project.path()),
+                        FlycheckConfig::CustomCommand { .. } => project.path(),
                         _ => None,
                     }
                 }
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 59e780b7d2..dcbf837d65 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -285,18 +285,12 @@ pub(crate) fn signature_help(
         })
     };
 
-    let active_parameter = call_info.active_parameter.map(|it| it as i64);
-
-    let signature = lsp_types::SignatureInformation {
-        label,
-        documentation,
-        parameters: Some(parameters),
-        active_parameter,
-    };
+    let signature =
+        lsp_types::SignatureInformation { label, documentation, parameters: Some(parameters) };
     lsp_types::SignatureHelp {
         signatures: vec![signature],
         active_signature: None,
-        active_parameter,
+        active_parameter: call_info.active_parameter.map(|it| it as i64),
     }
 }
 
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs
index dda0a03190..45cf31f130 100644
--- a/crates/syntax/src/ast/edit.rs
+++ b/crates/syntax/src/ast/edit.rs
@@ -93,22 +93,6 @@ where
     }
 }
 
-impl ast::Impl {
-    #[must_use]
-    pub fn with_assoc_item_list(&self, items: ast::AssocItemList) -> ast::Impl {
-        let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new();
-        if let Some(old_items) = self.assoc_item_list() {
-            let to_replace: SyntaxElement = old_items.syntax().clone().into();
-            to_insert.push(items.syntax().clone().into());
-            self.replace_children(single_node(to_replace), to_insert)
-        } else {
-            to_insert.push(make::tokens::single_space().into());
-            to_insert.push(items.syntax().clone().into());
-            self.insert_children(InsertPosition::Last, to_insert)
-        }
-    }
-}
-
 impl ast::AssocItemList {
     #[must_use]
     pub fn append_items(
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 4a0ffcbb07..6868feed99 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -21,10 +21,6 @@ pub fn ty(text: &str) -> ast::Type {
     ast_from_text(&format!("impl {} for D {{}};", text))
 }
 
-pub fn assoc_item_list() -> ast::AssocItemList {
-    ast_from_text("impl C for D {};")
-}
-
 pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
     ast_from_text(&format!("use {};", name_ref))
 }
diff --git a/docs/dev/syntax.md b/docs/dev/syntax.md
index 2eb08b7cab..c08062ef4d 100644
--- a/docs/dev/syntax.md
+++ b/docs/dev/syntax.md
@@ -72,7 +72,7 @@ Points of note:
 * Trivia and non-trivia tokens are not distinguished on the type level.
 * Each token carries its full text.
 * The original text can be recovered by concatenating the texts of all tokens in order.
-* Accessing a child of particular type (for example, parameter list of a function) generally involves linearly traversing the children, looking for a specific `kind`.
+* Accessing a child of particular type (for example, parameter list of a function) generally involves linerary traversing the children, looking for a specific `kind`.
 * Modifying the tree is roughly `O(depth)`.
   We don't make special efforts to guarantee that the depth is not linear, but, in practice, syntax trees are branchy and shallow.
 * If mandatory (grammar wise) node is missing from the input, it's just missing from the tree.
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index d3e6b23aef..b15c9ee7f5 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -44,11 +44,6 @@ https://github.com/rust-analyzer/rust-analyzer/tree/master/editors/code[in tree]
 
 You can install the latest release of the plugin from
 https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer[the marketplace].
-
-Note that the plugin may cause conflicts with the
-https://marketplace.visualstudio.com/items?itemName=rust-lang.rust[official Rust plugin]. It is
-recommended to disable the Rust plugin when using the rust-analyzer extension.
-
 By default, the plugin will prompt you to download the matching version of the server as well:
 
 image::https://user-images.githubusercontent.com/9021944/75067008-17502500-54ba-11ea-835a-f92aac50e866.png[]
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index e9581a9b59..4321de244d 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -21,7 +21,7 @@ export function analyzerStatus(ctx: Ctx): Cmd {
         provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
             if (!vscode.window.activeTextEditor) return '';
 
-            return ctx.client.sendRequest(ra.analyzerStatus);
+            return ctx.client.sendRequest(ra.analyzerStatus, null);
         }
 
         get onDidChange(): vscode.Event<vscode.Uri> {
@@ -63,7 +63,7 @@ export function memoryUsage(ctx: Ctx): Cmd {
         provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
             if (!vscode.window.activeTextEditor) return '';
 
-            return ctx.client.sendRequest(ra.memoryUsage).then((mem: any) => {
+            return ctx.client.sendRequest(ra.memoryUsage, null).then((mem: any) => {
                 return 'Per-query memory usage:\n' + mem + '\n(note: database has been cleared)';
             });
         }
@@ -372,7 +372,7 @@ export function expandMacro(ctx: Ctx): Cmd {
 }
 
 export function reloadWorkspace(ctx: Ctx): Cmd {
-    return async () => ctx.client.sendRequest(ra.reloadWorkspace);
+    return async () => ctx.client.sendRequest(ra.reloadWorkspace, null);
 }
 
 export function showReferences(ctx: Ctx): Cmd {
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index d167041c4c..f280bba3d2 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -4,8 +4,8 @@
 
 import * as lc from "vscode-languageclient";
 
-export const analyzerStatus = new lc.RequestType0<string, void>("rust-analyzer/analyzerStatus");
-export const memoryUsage = new lc.RequestType0<string, void>("rust-analyzer/memoryUsage");
+export const analyzerStatus = new lc.RequestType<null, string, void>("rust-analyzer/analyzerStatus");
+export const memoryUsage = new lc.RequestType<null, string, void>("rust-analyzer/memoryUsage");
 
 export type Status = "loading" | "ready" | "invalid" | "needsReload";
 export interface StatusParams {
@@ -13,7 +13,7 @@ export interface StatusParams {
 }
 export const status = new lc.NotificationType<StatusParams>("rust-analyzer/status");
 
-export const reloadWorkspace = new lc.RequestType0<null, void>("rust-analyzer/reloadWorkspace");
+export const reloadWorkspace = new lc.RequestType<null, null, void>("rust-analyzer/reloadWorkspace");
 
 export interface SyntaxTreeParams {
     textDocument: lc.TextDocumentIdentifier;


Test patch:
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index 1a806cda52..eed3d0d6ff 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -228,11 +228,11 @@ fn smoke() {
 
             top-level items:
             #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }]
-            Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::<syntax::ast::generated::nodes::Use>(0), index: 0 }
+            Import { path: ModPath { kind: Plain, segments: [Name(Text("a"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: false, is_prelude: false, ast_id: FileAstId::<syntax::ast::generated::nodes::Use>(0) }
             #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("attr_on_use"))] }, input: None }]) }]
-            Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::<syntax::ast::generated::nodes::Use>(0), index: 1 }
+            Import { path: ModPath { kind: Plain, segments: [Name(Text("b"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_glob: true, is_prelude: false, ast_id: FileAstId::<syntax::ast::generated::nodes::Use>(0) }
             #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("ext_crate"))] }, input: None }]) }]
-            ExternCrate { name: Name(Text("krate")), alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::<syntax::ast::generated::nodes::ExternCrate>(1) }
+            ExternCrate { path: ModPath { kind: Plain, segments: [Name(Text("krate"))] }, alias: None, visibility: RawVisibilityId("pub(self)"), is_macro_use: false, ast_id: FileAstId::<syntax::ast::generated::nodes::ExternCrate>(1) }
             #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("on_trait"))] }, input: None }]) }]
             Trait { name: Name(Text("Tr")), visibility: RawVisibilityId("pub(self)"), generic_params: GenericParamsId(0), auto: false, items: [TypeAlias(Idx::<TypeAlias>(0)), Const(Idx::<Const>(0)), Function(Idx::<Function>(0)), Function(Idx::<Function>(1))], ast_id: FileAstId::<syntax::ast::generated::nodes::Trait>(2) }
             > #[Attrs { entries: Some([Attr { path: ModPath { kind: Plain, segments: [Name(Text("assoc_ty"))] }, input: None }]) }]
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index 11d84f8082..5ca30dac90 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -2,7 +2,6 @@ mod globs;
 mod incremental;
 mod macros;
 mod mod_resolution;
-mod diagnostics;
 mod primitives;
 
 use std::sync::Arc;
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
deleted file mode 100644
index 576b813d2a..0000000000
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ /dev/null
@@ -1,131 +0,0 @@
-use base_db::fixture::WithFixture;
-use base_db::FileId;
-use base_db::SourceDatabaseExt;
-use hir_expand::db::AstDatabase;
-use rustc_hash::FxHashMap;
-use syntax::TextRange;
-use syntax::TextSize;
-
-use crate::test_db::TestDB;
-
-fn check_diagnostics(ra_fixture: &str) {
-    let db: TestDB = TestDB::with_files(ra_fixture);
-    let annotations = db.extract_annotations();
-    assert!(!annotations.is_empty());
-
-    let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
-    db.diagnostics(|d| {
-        let src = d.display_source();
-        let root = db.parse_or_expand(src.file_id).unwrap();
-        // FIXME: macros...
-        let file_id = src.file_id.original_file(&db);
-        let range = src.value.to_node(&root).text_range();
-        let message = d.message().to_owned();
-        actual.entry(file_id).or_default().push((range, message));
-    });
-
-    for (file_id, diags) in actual.iter_mut() {
-        diags.sort_by_key(|it| it.0.start());
-        let text = db.file_text(*file_id);
-        // For multiline spans, place them on line start
-        for (range, content) in diags {
-            if text[*range].contains('\n') {
-                *range = TextRange::new(range.start(), range.start() + TextSize::from(1));
-                *content = format!("... {}", content);
-            }
-        }
-    }
-
-    assert_eq!(annotations, actual);
-}
-
-#[test]
-fn unresolved_import() {
-    check_diagnostics(
-        r"
-        use does_exist;
-        use does_not_exist;
-          //^^^^^^^^^^^^^^ unresolved import
-
-        mod does_exist {}
-        ",
-    );
-}
-
-#[test]
-fn unresolved_import_in_use_tree() {
-    // Only the relevant part of a nested `use` item should be highlighted.
-    check_diagnostics(
-        r"
-        use does_exist::{Exists, DoesntExist};
-                               //^^^^^^^^^^^ unresolved import
-
-        use {does_not_exist::*, does_exist};
-           //^^^^^^^^^^^^^^^^^ unresolved import
-
-        use does_not_exist::{
-            a,
-          //^ unresolved import
-            b,
-          //^ unresolved import
-            c,
-          //^ unresolved import
-        };
-
-        mod does_exist {
-            pub struct Exists;
-        }
-        ",
-    );
-}
-
-#[test]
-fn unresolved_extern_crate() {
-    check_diagnostics(
-        r"
-        //- /main.rs crate:main deps:core
-        extern crate core;
-          extern crate doesnotexist;
-        //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate
-        //- /lib.rs crate:core
-        ",
-    );
-}
-
-#[test]
-fn dedup_unresolved_import_from_unresolved_crate() {
-    check_diagnostics(
-        r"
-        //- /main.rs crate:main
-        mod a {
-            extern crate doesnotexist;
-          //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate
-
-            // Should not error, since we already errored for the missing crate.
-            use doesnotexist::{self, bla, *};
-
-            use crate::doesnotexist;
-              //^^^^^^^^^^^^^^^^^^^ unresolved import
-        }
-
-        mod m {
-            use super::doesnotexist;
-              //^^^^^^^^^^^^^^^^^^^ unresolved import
-        }
-        ",
-    );
-}
-
-#[test]
-fn unresolved_module() {
-    check_diagnostics(
-        r"
-        //- /lib.rs
-        mod foo;
-          mod bar;
-        //^^^^^^^^ unresolved module
-        mod baz {}
-        //- /foo.rs
-        ",
-    );
-}
diff --git a/crates/hir_def/src/nameres/tests/mod_resolution.rs b/crates/hir_def/src/nameres/tests/mod_resolution.rs
index f93337a6ea..1f619787e1 100644
--- a/crates/hir_def/src/nameres/tests/mod_resolution.rs
+++ b/crates/hir_def/src/nameres/tests/mod_resolution.rs
@@ -671,6 +671,42 @@ pub struct Baz;
     );
 }
 
+#[test]
+fn unresolved_module_diagnostics() {
+    let db = TestDB::with_files(
+        r"
+        //- /lib.rs
+        mod foo;
+        mod bar;
+        mod baz {}
+        //- /foo.rs
+        ",
+    );
+    let krate = db.test_crate();
+
+    let crate_def_map = db.crate_def_map(krate);
+
+    expect![[r#"
+        [
+            UnresolvedModule {
+                module: Idx::<ModuleData>(0),
+                declaration: InFile {
+                    file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    value: FileAstId::<syntax::ast::generated::nodes::Module>(1),
+                },
+                candidate: "bar.rs",
+            },
+        ]
+    "#]]
+    .assert_debug_eq(&crate_def_map.diagnostics);
+}
+
 #[test]
 fn module_resolution_decl_inside_module_in_non_crate_root_2() {
     check(
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs
index fb1d3c9743..42a762936d 100644
--- a/crates/hir_def/src/test_db.rs
+++ b/crates/hir_def/src/test_db.rs
@@ -5,15 +5,9 @@ use std::{
     sync::{Arc, Mutex},
 };
 
-use base_db::SourceDatabase;
 use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast};
 use hir_expand::db::AstDatabase;
-use hir_expand::diagnostics::Diagnostic;
-use hir_expand::diagnostics::DiagnosticSinkBuilder;
-use rustc_hash::FxHashMap;
 use rustc_hash::FxHashSet;
-use syntax::TextRange;
-use test_utils::extract_annotations;
 
 use crate::db::DefDatabase;
 
@@ -104,40 +98,4 @@ impl TestDB {
             })
             .collect()
     }
-
-    pub fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
-        let mut files = Vec::new();
-        let crate_graph = self.crate_graph();
-        for krate in crate_graph.iter() {
-            let crate_def_map = self.crate_def_map(krate);
-            for (module_id, _) in crate_def_map.modules.iter() {
-                let file_id = crate_def_map[module_id].origin.file_id();
-                files.extend(file_id)
-            }
-        }
-        assert!(!files.is_empty());
-        files
-            .into_iter()
-            .filter_map(|file_id| {
-                let text = self.file_text(file_id);
-                let annotations = extract_annotations(&text);
-                if annotations.is_empty() {
-                    return None;
-                }
-                Some((file_id, annotations))
-            })
-            .collect()
-    }
-
-    pub fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) {
-        let crate_graph = self.crate_graph();
-        for krate in crate_graph.iter() {
-            let crate_def_map = self.crate_def_map(krate);
-
-            let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
-            for (module_id, _) in crate_def_map.modules.iter() {
-                crate_def_map.add_diagnostics(self, module_id, &mut sink);
-            }
-        }
-    }
 }
diff --git a/crates/rust-analyzer/tests/rust-analyzer/main.rs b/crates/rust-analyzer/tests/rust-analyzer/main.rs
index 06726f9576..0880d04253 100644
--- a/crates/rust-analyzer/tests/rust-analyzer/main.rs
+++ b/crates/rust-analyzer/tests/rust-analyzer/main.rs
@@ -259,42 +259,6 @@ pub use std::collections::HashMap;
     );
 }
 
-#[test]
-fn test_format_document_unchanged() {
-    if skip_slow_tests() {
-        return;
-    }
-
-    let server = project(
-        r#"
-//- /Cargo.toml
-[package]
-name = "foo"
-version = "0.0.0"
-
-//- /src/lib.rs
-fn main() {}
-"#,
-    )
-    .wait_until_workspace_is_loaded();
-
-    server.request::<Formatting>(
-        DocumentFormattingParams {
-            text_document: server.doc_id("src/lib.rs"),
-            options: FormattingOptions {
-                tab_size: 4,
-                insert_spaces: false,
-                insert_final_newline: None,
-                trim_final_newlines: None,
-                trim_trailing_whitespace: None,
-                properties: HashMap::new(),
-            },
-            work_done_progress_params: WorkDoneProgressParams::default(),
-        },
-        json!(null),
-    );
-}
-
 #[test]
 fn test_missing_module_code_action() {
     if skip_slow_tests() {