Repository: rust-analyzer/rust-analyzer
Pull request #10689 (2021-11-03 23:57:52)

Handle pub tuple fields in tuple structs
The current implementation will throw a parser error for tuple structs
that contain a pub tuple field. For example,
```rust
struct Foo(pub (u32, u32));
```
is valid Rust, but rust-analyzer will throw a parser error.  This is
because the parens after `pub` is treated as a visibility context.
Allowing a tuple type to follow `pub` in the special case when we are
defining fields in a tuple struct can fix the issue.

I guess this is a really minor case because there's not much reason
for having a tuple type within a struct tuple, but it is valid rust syntax...

adamrk: r? @Veykril 

Patch:
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index f781e0987a..9c0f3093e1 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -132,8 +132,5 @@ jobs:
         run: npm --prefix ./editors/code test
         # working-directory: ./editors/code  # does not work: https://github.com/GabrielBB/xvfb-action/issues/8
 
-    - run: npm run pretest
-      working-directory: ./editors/code
-
     - run: npm run package --scripts-prepend-node-path
       working-directory: ./editors/code
diff --git a/Cargo.lock b/Cargo.lock
index ba355216a8..afd1bbe6bc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.17.0"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
+checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
 dependencies = [
  "gimli",
 ]
@@ -37,9 +37,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.45"
+version = "1.0.44"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7"
+checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
 
 [[package]]
 name = "anymap"
@@ -78,9 +78,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 
 [[package]]
 name = "backtrace"
-version = "0.3.63"
+version = "0.3.62"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6"
+checksum = "091bcdf2da9950f96aa522681ce805e6857f6ca8df73833d35736ab2dc78e152"
 dependencies = [
  "addr2line",
  "cc",
@@ -171,9 +171,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chalk-derive"
-version = "0.73.0"
+version = "0.72.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f182e4c40ae0a36afff9904e46389df47d2f943bae70eab3d779c87aa5dd584"
+checksum = "50947a8c71b9a6ee75d6c3b74eb320f58668f872a5ca1347a2b664989fbc8ac8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -183,9 +183,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.73.0"
+version = "0.72.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f998dcab9f6975ce5fe69c28acba246f75f82c1a8faa4455facac82ee61bc14"
+checksum = "39fba0a2f05527fb93c5039803c1f1ffaff5d6cebdff936386e1a5cbe7646283"
 dependencies = [
  "bitflags",
  "chalk-derive",
@@ -194,9 +194,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-recursive"
-version = "0.73.0"
+version = "0.72.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c56b019577ff31fc12748cbe2ddcec47d2b9e647f98cce146bfeb69ad2263fb4"
+checksum = "d01108bc48af1d40e69b3b7f6923323e904c32476d4974750c474c1f94343e5c"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -207,9 +207,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.73.0"
+version = "0.72.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "296c92cae565a4000e3eea00ece09e14ce24e6bdc14a5807d140a4cc7652b8d4"
+checksum = "ff759b94bbb114254ba01b7a7459f8fa78ae98801a814946ce7ed6d5973c8a06"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -432,9 +432,9 @@ checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
 
 [[package]]
 name = "gimli"
-version = "0.26.1"
+version = "0.25.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
+checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
 
 [[package]]
 name = "hashbrown"
@@ -727,9 +727,9 @@ dependencies = [
 
 [[package]]
 name = "inotify"
-version = "0.9.6"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
+checksum = "9e5fc8f41dbaa9c8492a96c8afffda4f76896ee041d6a57606e70581b80c901f"
 dependencies = [
  "bitflags",
  "inotify-sys",
@@ -807,9 +807,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.107"
+version = "0.2.105"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
+checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013"
 
 [[package]]
 name = "libloading"
@@ -866,9 +866,9 @@ dependencies = [
 
 [[package]]
 name = "lsp-types"
-version = "0.91.1"
+version = "0.91.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2368312c59425dd133cb9a327afee65be0a633a8ce471d248e2202a48f8f68ae"
+checksum = "be7801b458592d0998af808d97f6a85a6057af3aaf2a2a5c3c677702bbeb4ed7"
 dependencies = [
  "bitflags",
  "serde",
@@ -1065,9 +1065,9 @@ dependencies = [
 
 [[package]]
 name = "paste"
-version = "1.0.6"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5"
+checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58"
 
 [[package]]
 name = "paths"
@@ -1462,9 +1462,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.69"
+version = "1.0.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8"
+checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
 dependencies = [
  "indexmap",
  "itoa",
@@ -1500,12 +1500,9 @@ checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
 
 [[package]]
 name = "smol_str"
-version = "0.1.21"
+version = "0.1.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61d15c83e300cce35b7c8cd39ff567c1ef42dde6d4a1a38dbdbf9a59902261bd"
-dependencies = [
- "serde",
-]
+checksum = "b203e79e90905594272c1c97c7af701533d42adaab0beb3859018e477d54a3b0"
 
 [[package]]
 name = "snap"
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index 2b091f37a0..84e295e014 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -136,7 +136,6 @@ impl ChangeFixture {
                     file_id,
                     meta.edition,
                     Some(crate_name.clone().into()),
-                    None,
                     meta.cfg.clone(),
                     meta.cfg,
                     meta.env,
@@ -169,7 +168,6 @@ impl ChangeFixture {
                 crate_root,
                 Edition::CURRENT,
                 Some(CrateName::new("test").unwrap().into()),
-                None,
                 default_cfg.clone(),
                 default_cfg,
                 Env::default(),
@@ -204,7 +202,6 @@ impl ChangeFixture {
                 core_file,
                 Edition::Edition2021,
                 Some(CrateDisplayName::from_canonical_name("core".to_string())),
-                None,
                 CfgOptions::default(),
                 CfgOptions::default(),
                 Env::default(),
@@ -238,7 +235,6 @@ impl ChangeFixture {
                 proc_lib_file,
                 Edition::Edition2021,
                 Some(CrateDisplayName::from_canonical_name("proc_macros".to_string())),
-                None,
                 CfgOptions::default(),
                 CfgOptions::default(),
                 Env::default(),
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 98533ca0a7..63b2691154 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -192,7 +192,6 @@ pub struct ProcMacro {
 pub struct CrateData {
     pub root_file_id: FileId,
     pub edition: Edition,
-    pub version: Option<String>,
     /// A name used in the package's project declaration: for Cargo projects,
     /// its `[package].name` can be different for other project types or even
     /// absent (a dummy crate for the code snippet, for example).
@@ -251,7 +250,6 @@ impl CrateGraph {
         file_id: FileId,
         edition: Edition,
         display_name: Option<CrateDisplayName>,
-        version: Option<String>,
         cfg_options: CfgOptions,
         potential_cfg_options: CfgOptions,
         env: Env,
@@ -260,7 +258,6 @@ impl CrateGraph {
         let data = CrateData {
             root_file_id: file_id,
             edition,
-            version,
             display_name,
             cfg_options,
             potential_cfg_options,
@@ -566,7 +563,6 @@ mod tests {
             FileId(1u32),
             Edition2018,
             None,
-            None,
             CfgOptions::default(),
             CfgOptions::default(),
             Env::default(),
@@ -576,7 +572,6 @@ mod tests {
             FileId(2u32),
             Edition2018,
             None,
-            None,
             CfgOptions::default(),
             CfgOptions::default(),
             Env::default(),
@@ -586,7 +581,6 @@ mod tests {
             FileId(3u32),
             Edition2018,
             None,
-            None,
             CfgOptions::default(),
             CfgOptions::default(),
             Env::default(),
@@ -610,7 +604,6 @@ mod tests {
             FileId(1u32),
             Edition2018,
             None,
-            None,
             CfgOptions::default(),
             CfgOptions::default(),
             Env::default(),
@@ -620,7 +613,6 @@ mod tests {
             FileId(2u32),
             Edition2018,
             None,
-            None,
             CfgOptions::default(),
             CfgOptions::default(),
             Env::default(),
@@ -641,7 +633,6 @@ mod tests {
             FileId(1u32),
             Edition2018,
             None,
-            None,
             CfgOptions::default(),
             CfgOptions::default(),
             Env::default(),
@@ -651,7 +642,6 @@ mod tests {
             FileId(2u32),
             Edition2018,
             None,
-            None,
             CfgOptions::default(),
             CfgOptions::default(),
             Env::default(),
@@ -661,7 +651,6 @@ mod tests {
             FileId(3u32),
             Edition2018,
             None,
-            None,
             CfgOptions::default(),
             CfgOptions::default(),
             Env::default(),
@@ -682,7 +671,6 @@ mod tests {
             FileId(1u32),
             Edition2018,
             None,
-            None,
             CfgOptions::default(),
             CfgOptions::default(),
             Env::default(),
@@ -692,7 +680,6 @@ mod tests {
             FileId(2u32),
             Edition2018,
             None,
-            None,
             CfgOptions::default(),
             CfgOptions::default(),
             Env::default(),
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs
index f867a903b0..417ba60919 100644
--- a/crates/cfg/src/lib.rs
+++ b/crates/cfg/src/lib.rs
@@ -66,21 +66,24 @@ impl CfgOptions {
         }
     }
 
-    pub fn get_cfg_keys(&self) -> impl Iterator<Item = &SmolStr> {
-        self.enabled.iter().map(|x| match x {
-            CfgAtom::Flag(key) => key,
-            CfgAtom::KeyValue { key, .. } => key,
-        })
+    pub fn get_cfg_keys(&self) -> Vec<&SmolStr> {
+        self.enabled
+            .iter()
+            .map(|x| match x {
+                CfgAtom::Flag(key) => key,
+                CfgAtom::KeyValue { key, .. } => key,
+            })
+            .collect()
     }
 
-    pub fn get_cfg_values<'a>(
-        &'a self,
-        cfg_key: &'a str,
-    ) -> impl Iterator<Item = &'a SmolStr> + 'a {
-        self.enabled.iter().filter_map(move |x| match x {
-            CfgAtom::KeyValue { key, value } if cfg_key == key => Some(value),
-            _ => None,
-        })
+    pub fn get_cfg_values(&self, cfg_key: &str) -> Vec<&SmolStr> {
+        self.enabled
+            .iter()
+            .filter_map(|x| match x {
+                CfgAtom::KeyValue { key, value } if cfg_key == key => Some(value),
+                _ => None,
+            })
+            .collect()
     }
 }
 
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 2096c485e4..9c6531da20 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -183,10 +183,6 @@ impl Crate {
         db.crate_graph()[self.id].edition
     }
 
-    pub fn version(self, db: &dyn HirDatabase) -> Option<String> {
-        db.crate_graph()[self.id].version.clone()
-    }
-
     pub fn display_name(self, db: &dyn HirDatabase) -> Option<CrateDisplayName> {
         db.crate_graph()[self.id].display_name.clone()
     }
@@ -580,7 +576,7 @@ impl Module {
                                     });
                                 for token in tokens {
                                     if token.kind() == SyntaxKind::IDENT
-                                        && token.text() == &**derive_name
+                                        && token.text() == derive_name.as_str()
                                     {
                                         precise_location = Some(token.text_range());
                                         break 'outer;
@@ -606,12 +602,7 @@ impl Module {
                         }
                     };
                     acc.push(
-                        UnresolvedProcMacro {
-                            node,
-                            precise_location,
-                            macro_name: name.map(Into::into),
-                        }
-                        .into(),
+                        UnresolvedProcMacro { node, precise_location, macro_name: name }.into(),
                     );
                 }
 
@@ -2224,7 +2215,7 @@ impl Impl {
             .attrs()
             .filter_map(|it| {
                 let path = ModPath::from_src(db.upcast(), it.path()?, &hygenic)?;
-                if path.as_ident()?.to_smol_str() == "derive" {
+                if path.as_ident()?.to_string() == "derive" {
                     Some(it)
                 } else {
                     None
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index c753369bfd..ca23d85cb2 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -17,8 +17,8 @@ use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::{smallvec, SmallVec};
 use syntax::{
     algo::skip_trivia_token,
-    ast::{self, HasAttrs, HasGenericParams, HasLoopBody},
-    match_ast, AstNode, Direction, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize,
+    ast::{self, HasGenericParams, HasLoopBody},
+    match_ast, AstNode, Direction, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize,
 };
 
 use crate::{
@@ -121,10 +121,7 @@ pub struct SemanticsImpl<'db> {
     pub db: &'db dyn HirDatabase,
     s2d_cache: RefCell<SourceToDefCache>,
     expansion_info_cache: RefCell<FxHashMap<HirFileId, Option<ExpansionInfo>>>,
-    // Rootnode to HirFileId cache
     cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
-    // MacroCall to its expansion's HirFileId cache
-    macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, HirFileId>>,
 }
 
 impl<DB> fmt::Debug for Semantics<'_, DB> {
@@ -178,12 +175,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.speculative_expand_attr(actual_macro_call, speculative_args, token_to_map)
     }
 
-    /// Descend the token into macrocalls to its first mapped counterpart.
     pub fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken {
-        self.imp.descend_into_macros_single(token)
+        self.imp.descend_into_macros(token).pop().unwrap()
     }
 
-    /// Descend the token into macrocalls to all its mapped counterparts.
     pub fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
         self.imp.descend_into_macros(token)
     }
@@ -213,10 +208,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.original_range_opt(node)
     }
 
-    pub fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
-        self.imp.original_ast_node(node)
-    }
-
     pub fn diagnostics_display_range(&self, diagnostics: InFile<SyntaxNodePtr>) -> FileRange {
         self.imp.diagnostics_display_range(diagnostics)
     }
@@ -329,10 +320,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.resolve_path(path)
     }
 
-    pub fn resolve_path_as_macro(&self, path: &ast::Path) -> Option<MacroDef> {
-        self.imp.resolve_path_as_macro(path)
-    }
-
     pub fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
         self.imp.resolve_extern_crate(extern_crate)
     }
@@ -405,7 +392,6 @@ impl<'db> SemanticsImpl<'db> {
             s2d_cache: Default::default(),
             cache: Default::default(),
             expansion_info_cache: Default::default(),
-            macro_call_cache: Default::default(),
         }
     }
 
@@ -515,102 +501,71 @@ impl<'db> SemanticsImpl<'db> {
         };
 
         if first == last {
-            self.descend_into_macros_impl(
-                first,
-                |InFile { value, .. }| {
-                    if let Some(node) = value.ancestors().find_map(N::cast) {
-                        res.push(node)
-                    }
-                },
-                false,
-            );
+            self.descend_into_macros_impl(first, |InFile { value, .. }| {
+                if let Some(node) = value.ancestors().find_map(N::cast) {
+                    res.push(node)
+                }
+            });
         } else {
             // Descend first and last token, then zip them to look for the node they belong to
             let mut scratch: SmallVec<[_; 1]> = smallvec![];
-            self.descend_into_macros_impl(
-                first,
-                |token| {
-                    scratch.push(token);
-                },
-                false,
-            );
+            self.descend_into_macros_impl(first, |token| {
+                scratch.push(token);
+            });
 
             let mut scratch = scratch.into_iter();
-            self.descend_into_macros_impl(
-                last,
-                |InFile { value: last, file_id: last_fid }| {
-                    if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() {
-                        if first_fid == last_fid {
-                            if let Some(p) = first.parent() {
-                                let range = first.text_range().cover(last.text_range());
-                                let node = find_root(&p)
-                                    .covering_element(range)
-                                    .ancestors()
-                                    .take_while(|it| it.text_range() == range)
-                                    .find_map(N::cast);
-                                if let Some(node) = node {
-                                    res.push(node);
-                                }
+            self.descend_into_macros_impl(last, |InFile { value: last, file_id: last_fid }| {
+                if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() {
+                    if first_fid == last_fid {
+                        if let Some(p) = first.parent() {
+                            let range = first.text_range().cover(last.text_range());
+                            let node = find_root(&p)
+                                .covering_element(range)
+                                .ancestors()
+                                .take_while(|it| it.text_range() == range)
+                                .find_map(N::cast);
+                            if let Some(node) = node {
+                                res.push(node);
                             }
                         }
                     }
-                },
-                false,
-            );
+                }
+            });
         }
         res
     }
 
     fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
         let mut res = smallvec![];
-        self.descend_into_macros_impl(token, |InFile { value, .. }| res.push(value), false);
-        res
-    }
-
-    fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken {
-        let mut res = token.clone();
-        self.descend_into_macros_impl(token, |InFile { value, .. }| res = value, true);
+        self.descend_into_macros_impl(token, |InFile { value, .. }| res.push(value));
         res
     }
 
-    fn descend_into_macros_impl(
-        &self,
-        token: SyntaxToken,
-        mut f: impl FnMut(InFile<SyntaxToken>),
-        single: bool,
-    ) {
+    fn descend_into_macros_impl(&self, token: SyntaxToken, mut f: impl FnMut(InFile<SyntaxToken>)) {
         let _p = profile::span("descend_into_macros");
         let parent = match token.parent() {
             Some(it) => it,
             None => return,
         };
         let sa = self.analyze(&parent);
-        let mut stack: SmallVec<[_; 4]> = smallvec![InFile::new(sa.file_id, token)];
+        let mut stack: SmallVec<[_; 1]> = smallvec![InFile::new(sa.file_id, token)];
         let mut cache = self.expansion_info_cache.borrow_mut();
-        let mut mcache = self.macro_call_cache.borrow_mut();
 
         let mut process_expansion_for_token =
-            |stack: &mut SmallVec<_>, macro_file, item, token: InFile<&_>| {
-                let expansion_info = cache
-                    .entry(macro_file)
-                    .or_insert_with(|| macro_file.expansion_info(self.db.upcast()))
-                    .as_ref()?;
-
-                {
-                    let InFile { file_id, value } = expansion_info.expanded();
-                    self.cache(value, file_id);
-                }
-
-                let mut mapped_tokens =
-                    expansion_info.map_token_down(self.db.upcast(), item, token)?;
+            |stack: &mut SmallVec<_>, file_id, item, token: InFile<&_>| {
+                let mapped_tokens = cache
+                    .entry(file_id)
+                    .or_insert_with(|| file_id.expansion_info(self.db.upcast()))
+                    .as_ref()?
+                    .map_token_down(self.db.upcast(), item, token)?;
 
                 let len = stack.len();
                 // requeue the tokens we got from mapping our current token down
-                if single {
-                    stack.extend(mapped_tokens.next());
-                } else {
-                    stack.extend(mapped_tokens);
-                }
+                stack.extend(mapped_tokens.inspect(|token| {
+                    if let Some(parent) = token.value.parent() {
+                        self.cache(find_root(&parent), token.file_id);
+                    }
+                }));
                 // if the length changed we have found a mapping for the token
                 (stack.len() != len).then(|| ())
             };
@@ -623,13 +578,14 @@ impl<'db> SemanticsImpl<'db> {
             let was_not_remapped = (|| {
                 // are we inside an attribute macro call
                 let containing_attribute_macro_call = self.with_ctx(|ctx| {
-                    token.value.ancestors().filter_map(ast::Item::cast).find_map(|item| {
-                        if item.attrs().next().is_none() {
-                            // Don't force populate the dyn cache for items that don't have an attribute anyways
-                            return None;
-                        }
-                        Some((ctx.item_to_macro_call(token.with_value(item.clone()))?, item))
-                    })
+                    token
+                        .value
+                        .ancestors()
+                        .filter_map(ast::Item::cast)
+                        .filter_map(|item| {
+                            Some((ctx.item_to_macro_call(token.with_value(item.clone()))?, item))
+                        })
+                        .last()
                 });
                 if let Some((call_id, item)) = containing_attribute_macro_call {
                     let file_id = call_id.as_file();
@@ -642,27 +598,21 @@ impl<'db> SemanticsImpl<'db> {
                 }
 
                 // or are we inside a function-like macro call
-                if let Some(tt) =
-                    // FIXME replace map.while_some with take_while once stable
-                    token.value.ancestors().map(ast::TokenTree::cast).while_some().last()
-                {
-                    let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
-                    if tt.left_delimiter_token().map_or(false, |it| it == token.value) {
-                        return None;
-                    }
-                    if tt.right_delimiter_token().map_or(false, |it| it == token.value) {
+                if let Some(macro_call) = token.value.ancestors().find_map(ast::MacroCall::cast) {
+                    let tt = macro_call.token_tree()?;
+                    let l_delim = match tt.left_delimiter_token() {
+                        Some(it) => it.text_range().end(),
+                        None => tt.syntax().text_range().start(),
+                    };
+                    let r_delim = match tt.right_delimiter_token() {
+                        Some(it) => it.text_range().start(),
+                        None => tt.syntax().text_range().end(),
+                    };
+                    if !TextRange::new(l_delim, r_delim).contains_range(token.value.text_range()) {
                         return None;
                     }
 
-                    let mcall = token.with_value(macro_call);
-                    let file_id = match mcache.get(&mcall) {
-                        Some(&it) => it,
-                        None => {
-                            let it = sa.expand(self.db, mcall.as_ref())?;
-                            mcache.insert(mcall, it);
-                            it
-                        }
-                    };
+                    let file_id = sa.expand(self.db, token.with_value(&macro_call))?;
                     return process_expansion_for_token(&mut stack, file_id, None, token.as_ref());
                 }
 
@@ -710,11 +660,6 @@ impl<'db> SemanticsImpl<'db> {
         node.as_ref().original_file_range_opt(self.db.upcast())
     }
 
-    fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
-        let file = self.find_file(node.syntax().clone());
-        file.with_value(node).original_ast_node(self.db.upcast()).map(|it| it.value)
-    }
-
     fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
         let root = self.db.parse_or_expand(src.file_id).unwrap();
         let node = src.value.to_node(&root);
@@ -849,12 +794,6 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(path.syntax()).resolve_path(self.db, path)
     }
 
-    // FIXME: This shouldn't exist, but is currently required to always resolve attribute paths in
-    // the IDE layer due to namespace collisions
-    fn resolve_path_as_macro(&self, path: &ast::Path) -> Option<MacroDef> {
-        self.analyze(path.syntax()).resolve_path_as_macro(self.db, path)
-    }
-
     fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
         let krate = self.scope(extern_crate.syntax()).krate()?;
         krate.dependencies(self.db).into_iter().find_map(|dep| {
@@ -897,13 +836,13 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
-        let SourceAnalyzer { file_id, resolver, .. } = self.analyze(node);
-        SemanticsScope { db: self.db, file_id, resolver }
+        let sa = self.analyze(node);
+        SemanticsScope { db: self.db, file_id: sa.file_id, resolver: sa.resolver }
     }
 
     fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
-        let SourceAnalyzer { file_id, resolver, .. } = self.analyze_with_offset(node, offset);
-        SemanticsScope { db: self.db, file_id, resolver }
+        let sa = self.analyze_with_offset(node, offset);
+        SemanticsScope { db: self.db, file_id: sa.file_id, resolver: sa.resolver }
     }
 
     fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
@@ -924,11 +863,9 @@ impl<'db> SemanticsImpl<'db> {
     fn analyze(&self, node: &SyntaxNode) -> SourceAnalyzer {
         self.analyze_impl(node, None)
     }
-
     fn analyze_with_offset(&self, node: &SyntaxNode, offset: TextSize) -> SourceAnalyzer {
         self.analyze_impl(node, Some(offset))
     }
-
     fn analyze_impl(&self, node: &SyntaxNode, offset: Option<TextSize>) -> SourceAnalyzer {
         let _p = profile::span("Semantics::analyze_impl");
         let node = self.find_file(node.clone());
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index b12461818e..08d0a02d79 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -246,18 +246,6 @@ impl SourceAnalyzer {
         }
     }
 
-    pub(crate) fn resolve_path_as_macro(
-        &self,
-        db: &dyn HirDatabase,
-        path: &ast::Path,
-    ) -> Option<MacroDef> {
-        // This must be a normal source file rather than macro file.
-        let hygiene = Hygiene::new(db.upcast(), self.file_id);
-        let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
-        let hir_path = Path::from_src(path.clone(), &ctx)?;
-        resolve_hir_path_as_macro(db, &self.resolver, &hir_path)
-    }
-
     pub(crate) fn resolve_path(
         &self,
         db: &dyn HirDatabase,
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 4f68c91cc9..3bf7a33030 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -796,7 +796,7 @@ impl<'a> AttrQuery<'a> {
         let key = self.key;
         self.attrs
             .iter()
-            .filter(move |attr| attr.path.as_ident().map_or(false, |s| s.to_smol_str() == key))
+            .filter(move |attr| attr.path.as_ident().map_or(false, |s| s.to_string() == key))
     }
 }
 
diff --git a/crates/hir_def/src/body/scope.rs b/crates/hir_def/src/body/scope.rs
index f40eb2f9d4..82b23f2f46 100644
--- a/crates/hir_def/src/body/scope.rs
+++ b/crates/hir_def/src/body/scope.rs
@@ -282,7 +282,7 @@ mod tests {
         let actual = scopes
             .scope_chain(scope)
             .flat_map(|scope| scopes.entries(scope))
-            .map(|it| it.name().to_smol_str())
+            .map(|it| it.name().to_string())
             .collect::<Vec<_>>()
             .join("\n");
         let expected = expected.join("\n");
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index 0a2a6719ed..ec8c3a87c0 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -136,17 +136,12 @@ impl ItemScope {
 
     /// XXX: this is O(N) rather than O(1), try to not introduce new usages.
     pub(crate) fn name_of(&self, item: ItemInNs) -> Option<(&Name, Visibility)> {
-        let (def, mut iter) = match item {
-            ItemInNs::Macros(def) => {
-                return self
-                    .macros
-                    .iter()
-                    .find_map(|(name, &(other_def, vis))| (other_def == def).then(|| (name, vis)));
+        for (name, per_ns) in self.entries() {
+            if let Some(vis) = item.match_with(per_ns) {
+                return Some((name, vis));
             }
-            ItemInNs::Types(def) => (def, self.types.iter()),
-            ItemInNs::Values(def) => (def, self.values.iter()),
-        };
-        iter.find_map(|(name, &(other_def, vis))| (other_def == def).then(|| (name, vis)))
+        }
+        None
     }
 
     pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
@@ -391,6 +386,20 @@ pub enum ItemInNs {
 }
 
 impl ItemInNs {
+    fn match_with(self, per_ns: PerNs) -> Option<Visibility> {
+        match self {
+            ItemInNs::Types(def) => {
+                per_ns.types.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
+            }
+            ItemInNs::Values(def) => {
+                per_ns.values.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
+            }
+            ItemInNs::Macros(def) => {
+                per_ns.macros.filter(|(other_def, _)| *other_def == def).map(|(_, vis)| vis)
+            }
+        }
+    }
+
     pub fn as_module_def_id(self) -> Option<ModuleDefId> {
         match self {
             ItemInNs::Types(id) | ItemInNs::Values(id) => Some(id),
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 9381ca39f7..a15125c3d4 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -449,7 +449,7 @@ impl<'a> Ctx<'a> {
 
     fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
         let mut name = konst.name().map(|it| it.as_name());
-        if name.as_ref().map_or(false, |n| n.to_smol_str().starts_with("_DERIVE_")) {
+        if name.as_ref().map_or(false, |n| n.to_string().starts_with("_DERIVE_")) {
             // FIXME: this is a hack to treat consts generated by synstructure as unnamed
             // remove this some time in the future
             name = None;
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 5ddef48495..6cc6bf98fb 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -764,7 +764,7 @@ fn derive_macro_as_call_id(
         krate,
         MacroCallKind::Derive {
             ast_id: item_attr.ast_id,
-            derive_name: last_segment.to_string().into_boxed_str(),
+            derive_name: last_segment.to_string(),
             derive_attr_index: derive_attr.ast_index,
         },
     );
@@ -801,7 +801,7 @@ fn attr_macro_as_call_id(
         krate,
         MacroCallKind::Attr {
             ast_id: item_attr.ast_id,
-            attr_name: last_segment.to_string().into_boxed_str(),
+            attr_name: last_segment.to_string(),
             attr_args: arg,
             invoc_attr_index: macro_attr.id.ast_index,
         },
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 1c578dbdc2..0349754fba 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -1759,7 +1759,7 @@ impl ModCollector<'_, '_> {
     fn is_builtin_or_registered_attr(&self, path: &ModPath) -> bool {
         if path.kind == PathKind::Plain {
             if let Some(tool_module) = path.segments().first() {
-                let tool_module = tool_module.to_smol_str();
+                let tool_module = tool_module.to_string();
                 let is_tool = builtin_attr::TOOL_MODULES
                     .iter()
                     .copied()
@@ -1771,7 +1771,7 @@ impl ModCollector<'_, '_> {
             }
 
             if let Some(name) = path.as_ident() {
-                let name = name.to_smol_str();
+                let name = name.to_string();
                 let is_inert = builtin_attr::INERT_ATTRIBUTES
                     .iter()
                     .chain(builtin_attr::EXTRA_ATTRIBUTES)
diff --git a/crates/hir_def/src/nameres/mod_resolution.rs b/crates/hir_def/src/nameres/mod_resolution.rs
index bd2588e592..031ff8b181 100644
--- a/crates/hir_def/src/nameres/mod_resolution.rs
+++ b/crates/hir_def/src/nameres/mod_resolution.rs
@@ -42,7 +42,7 @@ impl ModDir {
         let path = match attr_path.map(|it| it.as_str()) {
             None => {
                 let mut path = self.dir_path.clone();
-                path.push(&name.to_smol_str());
+                path.push(&name.to_string());
                 path
             }
             Some(attr_path) => {
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index d17e6b1834..667092cd20 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -46,7 +46,7 @@ impl Display for ImportAlias {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             ImportAlias::Underscore => f.write_str("_"),
-            ImportAlias::Alias(name) => f.write_str(&name.to_smol_str()),
+            ImportAlias::Alias(name) => f.write_str(&name.to_string()),
         }
     }
 }
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index a0a79b2b4c..f411ef9b3c 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -18,15 +18,15 @@ pub mod eager;
 use base_db::ProcMacroKind;
 use either::Either;
 
-pub use mbe::{ExpandError, ExpandResult, Origin};
+pub use mbe::{ExpandError, ExpandResult};
 
 use std::{hash::Hash, iter, sync::Arc};
 
 use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange};
 use syntax::{
-    algo::{self, skip_trivia_token},
+    algo::skip_trivia_token,
     ast::{self, AstNode, HasAttrs},
-    Direction, SyntaxNode, SyntaxToken,
+    Direction, SyntaxNode, SyntaxToken, TextRange,
 };
 
 use crate::{
@@ -122,7 +122,7 @@ pub enum MacroCallKind {
     },
     Derive {
         ast_id: AstId<ast::Item>,
-        derive_name: Box<str>,
+        derive_name: String,
         /// Syntactical index of the invoking `#[derive]` attribute.
         ///
         /// Outer attributes are counted first, then inner attributes. This does not support
@@ -131,7 +131,7 @@ pub enum MacroCallKind {
     },
     Attr {
         ast_id: AstId<ast::Item>,
-        attr_name: Box<str>,
+        attr_name: String,
         attr_args: (tt::Subtree, mbe::TokenMap),
         /// Syntactical index of the invoking `#[attribute]`.
         ///
@@ -380,11 +380,9 @@ pub struct ExpansionInfo {
     exp_map: Arc<mbe::TokenMap>,
 }
 
-impl ExpansionInfo {
-    pub fn expanded(&self) -> InFile<SyntaxNode> {
-        self.expanded.clone()
-    }
+pub use mbe::Origin;
 
+impl ExpansionInfo {
     pub fn call_node(&self) -> Option<InFile<SyntaxNode>> {
         Some(self.arg.with_value(self.arg.value.parent()?))
     }
@@ -602,15 +600,13 @@ impl<'a> InFile<&'a SyntaxNode> {
 
     /// Attempts to map the syntax node back up its macro calls.
     pub fn original_file_range_opt(self, db: &dyn db::AstDatabase) -> Option<FileRange> {
-        match ascend_node_border_tokens(db, self) {
-            Some(InFile { file_id, value: (first, last) }) => {
-                let original_file = file_id.original_file(db);
-                let range = first.text_range().cover(last.text_range());
-                if file_id != original_file.into() {
+        match original_range_opt(db, self) {
+            Some(range) => {
+                let original_file = range.file_id.original_file(db);
+                if range.file_id != original_file.into() {
                     tracing::error!("Failed mapping up more for {:?}", range);
-                    return None;
                 }
-                Some(FileRange { file_id: original_file, range })
+                Some(FileRange { file_id: original_file, range: range.value })
             }
             _ if !self.file_id.is_macro() => Some(FileRange {
                 file_id: self.file_id.original_file(db),
@@ -621,29 +617,28 @@ impl<'a> InFile<&'a SyntaxNode> {
     }
 }
 
-fn ascend_node_border_tokens(
+fn original_range_opt(
     db: &dyn db::AstDatabase,
-    InFile { file_id, value: node }: InFile<&SyntaxNode>,
-) -> Option<InFile<(SyntaxToken, SyntaxToken)>> {
-    let expansion = file_id.expansion_info(db)?;
+    node: InFile<&SyntaxNode>,
+) -> Option<InFile<TextRange>> {
+    let expansion = node.file_id.expansion_info(db)?;
 
     // the input node has only one token ?
-    let first = skip_trivia_token(node.first_token()?, Direction::Next)?;
-    let last = skip_trivia_token(node.last_token()?, Direction::Prev)?;
-    let is_single_token = first == last;
+    let single = skip_trivia_token(node.value.first_token()?, Direction::Next)?
+        == skip_trivia_token(node.value.last_token()?, Direction::Prev)?;
 
-    node.descendants().find_map(|it| {
+    node.value.descendants().find_map(|it| {
         let first = skip_trivia_token(it.first_token()?, Direction::Next)?;
-        let first = ascend_call_token(db, &expansion, InFile::new(file_id, first))?;
+        let first = ascend_call_token(db, &expansion, node.with_value(first))?;
 
         let last = skip_trivia_token(it.last_token()?, Direction::Prev)?;
-        let last = ascend_call_token(db, &expansion, InFile::new(file_id, last))?;
+        let last = ascend_call_token(db, &expansion, node.with_value(last))?;
 
-        if (!is_single_token && first == last) || (first.file_id != last.file_id) {
+        if (!single && first == last) || (first.file_id != last.file_id) {
             return None;
         }
 
-        Some(InFile::new(first.file_id, (first.value, last.value)))
+        Some(first.with_value(first.value.text_range().cover(last.value.text_range())))
     })
 }
 
@@ -679,23 +674,6 @@ impl<N: AstNode> InFile<N> {
         self.value.syntax().descendants().filter_map(T::cast).map(move |n| self.with_value(n))
     }
 
-    pub fn original_ast_node(self, db: &dyn db::AstDatabase) -> Option<InFile<N>> {
-        match ascend_node_border_tokens(db, self.syntax()) {
-            Some(InFile { file_id, value: (first, last) }) => {
-                let original_file = file_id.original_file(db);
-                if file_id != original_file.into() {
-                    let range = first.text_range().cover(last.text_range());
-                    tracing::error!("Failed mapping up more for {:?}", range);
-                    return None;
-                }
-                let anc = algo::least_common_ancestor(&first.parent()?, &last.parent()?)?;
-                Some(InFile::new(file_id, anc.ancestors().find_map(N::cast)?))
-            }
-            _ if !self.file_id.is_macro() => Some(self),
-            _ => None,
-        }
-    }
-
     pub fn syntax(&self) -> InFile<&SyntaxNode> {
         self.with_value(self.value.syntax())
     }
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index 95d272ba68..0225ab425f 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -84,8 +84,7 @@ impl Name {
     }
 
     /// Returns the textual representation of this name as a [`SmolStr`].
-    /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper in
-    /// the general case.
+    /// Prefer using this over [`ToString::to_string`] if possible as this conversion is cheaper.
     pub fn to_smol_str(&self) -> SmolStr {
         match &self.0 {
             Repr::Text(it) => it.clone(),
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 48820d8c83..d0f22cdae3 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -18,9 +18,9 @@ ena = "0.14.0"
 tracing = "0.1"
 rustc-hash = "1.1.0"
 scoped-tls = "1"
-chalk-solve = { version = "0.73", default-features = false }
-chalk-ir = "0.73"
-chalk-recursive = { version = "0.73", default-features = false }
+chalk-solve = { version = "0.72", default-features = false }
+chalk-ir = "0.72"
+chalk-recursive = { version = "0.72", default-features = false }
 la-arena = { version = "0.3.0", path = "../../lib/arena" }
 once_cell = { version = "1.5.0" }
 
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index 3a787aa47f..98a5849001 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -77,9 +77,6 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
     fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
 
-    #[salsa::invoke(InherentImpls::inherent_impls_in_block_query)]
-    fn inherent_impls_in_block(&self, block: BlockId) -> Option<Arc<InherentImpls>>;
-
     #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
     fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
 
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 8e19928746..8e6ab8af0f 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -13,7 +13,6 @@ use hir_def::{
 };
 use hir_expand::name::Name;
 use rustc_hash::{FxHashMap, FxHashSet};
-use stdx::never;
 
 use crate::{
     autoderef,
@@ -262,45 +261,33 @@ impl InherentImpls {
         let mut impls = Self { map: FxHashMap::default() };
 
         let crate_def_map = db.crate_def_map(krate);
-        impls.collect_def_map(db, &crate_def_map);
+        collect_def_map(db, &crate_def_map, &mut impls);
 
         return Arc::new(impls);
-    }
-
-    pub(crate) fn inherent_impls_in_block_query(
-        db: &dyn HirDatabase,
-        block: BlockId,
-    ) -> Option<Arc<Self>> {
-        let mut impls = Self { map: FxHashMap::default() };
-        if let Some(block_def_map) = db.block_def_map(block) {
-            impls.collect_def_map(db, &block_def_map);
-            return Some(Arc::new(impls));
-        }
-        return None;
-    }
-
-    fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
-        for (_module_id, module_data) in def_map.modules() {
-            for impl_id in module_data.scope.impls() {
-                let data = db.impl_data(impl_id);
-                if data.target_trait.is_some() {
-                    continue;
-                }
 
-                let self_ty = db.impl_self_ty(impl_id);
-                let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders());
-                if let Some(fp) = fp {
-                    self.map.entry(fp).or_default().push(impl_id);
+        fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap, impls: &mut InherentImpls) {
+            for (_module_id, module_data) in def_map.modules() {
+                for impl_id in module_data.scope.impls() {
+                    let data = db.impl_data(impl_id);
+                    if data.target_trait.is_some() {
+                        continue;
+                    }
+
+                    let self_ty = db.impl_self_ty(impl_id);
+                    let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders());
+                    if let Some(fp) = fp {
+                        impls.map.entry(fp).or_default().push(impl_id);
+                    }
+                    // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution)
                 }
-                // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution)
-            }
 
-            // To better support custom derives, collect impls in all unnamed const items.
-            // const _: () = { ... };
-            for konst in module_data.scope.unnamed_consts() {
-                let body = db.body(konst.into());
-                for (_, block_def_map) in body.blocks(db.upcast()) {
-                    self.collect_def_map(db, &block_def_map);
+                // To better support custom derives, collect impls in all unnamed const items.
+                // const _: () = { ... };
+                for konst in module_data.scope.unnamed_consts() {
+                    let body = db.body(konst.into());
+                    for (_, block_def_map) in body.blocks(db.upcast()) {
+                        collect_def_map(db, &block_def_map, impls);
+                    }
                 }
             }
         }
@@ -335,7 +322,7 @@ pub fn def_crates(
             }};
         }
 
-    let mod_to_crate_ids = |module: ModuleId| Some(iter::once(module.krate()).collect());
+    let mod_to_crate_ids = |module: ModuleId| Some(std::iter::once(module.krate()).collect());
 
     let lang_item_targets = match ty.kind(&Interner) {
         TyKind::Adt(AdtId(def_id), _) => {
@@ -534,16 +521,9 @@ fn iterate_method_candidates_with_autoref(
     name: Option<&Name>,
     mut callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
-    let (receiver_ty, rest) = match deref_chain.split_first() {
-        Some((rec, rest)) => (rec.clone(), rest),
-        None => {
-            never!("received empty deref-chain");
-            return ControlFlow::Break(());
-        }
-    };
     iterate_method_candidates_by_receiver(
-        &receiver_ty,
-        &rest,
+        &deref_chain[0],
+        &deref_chain[1..],
         db,
         env.clone(),
         krate,
@@ -554,8 +534,8 @@ fn iterate_method_candidates_with_autoref(
     )?;
 
     let refed = Canonical {
-        binders: receiver_ty.binders.clone(),
-        value: TyKind::Ref(Mutability::Not, static_lifetime(), receiver_ty.value.clone())
+        binders: deref_chain[0].binders.clone(),
+        value: TyKind::Ref(Mutability::Not, static_lifetime(), deref_chain[0].value.clone())
             .intern(&Interner),
     };
 
@@ -572,8 +552,9 @@ fn iterate_method_candidates_with_autoref(
     )?;
 
     let ref_muted = Canonical {
-        binders: receiver_ty.binders,
-        value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value).intern(&Interner),
+        binders: deref_chain[0].binders.clone(),
+        value: TyKind::Ref(Mutability::Mut, static_lifetime(), deref_chain[0].value.clone())
+            .intern(&Interner),
     };
 
     iterate_method_candidates_by_receiver(
@@ -603,7 +584,7 @@ fn iterate_method_candidates_by_receiver(
     // We're looking for methods with *receiver* type receiver_ty. These could
     // be found in any of the derefs of receiver_ty, so we have to go through
     // that.
-    for self_ty in iter::once(receiver_ty).chain(rest_of_deref_chain) {
+    for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
         iterate_inherent_methods(
             self_ty,
             db,
@@ -616,7 +597,7 @@ fn iterate_method_candidates_by_receiver(
         )?
     }
 
-    for self_ty in iter::once(receiver_ty).chain(rest_of_deref_chain) {
+    for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
         iterate_trait_method_candidates(
             self_ty,
             db,
@@ -678,7 +659,8 @@ fn iterate_trait_method_candidates(
         }
         _ => Vec::new(),
     };
-    let traits = inherent_trait.chain(env_traits).chain(traits_in_scope.iter().copied());
+    let traits =
+        inherent_trait.chain(env_traits.into_iter()).chain(traits_in_scope.iter().copied());
 
     'traits: for t in traits {
         let data = db.trait_data(t);
@@ -762,51 +744,13 @@ fn iterate_inherent_methods(
         None => return ControlFlow::Continue(()),
     };
 
-    if let Some(module_id) = visible_from_module {
-        if let Some(block_id) = module_id.containing_block() {
-            if let Some(impls) = db.inherent_impls_in_block(block_id) {
-                impls_for_self_ty(
-                    &impls,
-                    self_ty,
-                    db,
-                    env.clone(),
-                    name,
-                    receiver_ty,
-                    visible_from_module,
-                    callback,
-                )?;
-            }
-        }
-    }
-
     for krate in def_crates {
         let impls = db.inherent_impls_in_crate(krate);
-        impls_for_self_ty(
-            &impls,
-            self_ty,
-            db,
-            env.clone(),
-            name,
-            receiver_ty,
-            visible_from_module,
-            callback,
-        )?;
-    }
-    return ControlFlow::Continue(());
 
-    fn impls_for_self_ty(
-        impls: &InherentImpls,
-        self_ty: &Canonical<Ty>,
-        db: &dyn HirDatabase,
-        env: Arc<TraitEnvironment>,
-        name: Option<&Name>,
-        receiver_ty: Option<&Canonical<Ty>>,
-        visible_from_module: Option<ModuleId>,
-        callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
-    ) -> ControlFlow<()> {
-        let impls_for_self_ty = filter_inherent_impls_for_self_ty(impls, &self_ty.value);
+        let impls_for_self_ty = filter_inherent_impls_for_self_ty(&impls, &self_ty.value);
+
         for &impl_def in impls_for_self_ty {
-            for &item in &db.impl_data(impl_def).items {
+            for &item in db.impl_data(impl_def).items.iter() {
                 if !is_valid_candidate(
                     db,
                     env.clone(),
@@ -832,8 +776,8 @@ fn iterate_inherent_methods(
                 callback(receiver_ty, item)?;
             }
         }
-        ControlFlow::Continue(())
     }
+    ControlFlow::Continue(())
 }
 
 /// Returns the self type for the index trait call.
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index b21998e0d2..01c1259fc5 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -90,7 +90,7 @@ impl NavigationTarget {
     }
 
     pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
-        let name = module.name(db).map(|it| it.to_smol_str()).unwrap_or_default();
+        let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
         if let Some(src) = module.declaration_source(db) {
             let node = src.syntax();
             let full_range = node.original_file_range(db);
@@ -275,7 +275,7 @@ where
 impl ToNav for hir::Module {
     fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
         let src = self.definition_source(db);
-        let name = self.name(db).map(|it| it.to_smol_str()).unwrap_or_default();
+        let name = self.name(db).map(|it| it.to_string().into()).unwrap_or_default();
         let (syntax, focus) = match &src.value {
             ModuleSource::SourceFile(node) => (node.syntax(), None),
             ModuleSource::Module(node) => {
@@ -399,7 +399,7 @@ impl ToNav for hir::Local {
 
         let full_range = src.with_value(&node).original_file_range(db);
         let name = match self.name(db) {
-            Some(it) => it.to_smol_str(),
+            Some(it) => it.to_string().into(),
             None => "".into(),
         };
         let kind = if self.is_self(db) {
@@ -429,7 +429,7 @@ impl ToNav for hir::Label {
         let FileRange { file_id, range } = src.with_value(node).original_file_range(db);
         let focus_range =
             src.value.lifetime().and_then(|lt| lt.lifetime_ident_token()).map(|lt| lt.text_range());
-        let name = self.name(db).to_smol_str();
+        let name = self.name(db).to_string().into();
         NavigationTarget {
             file_id,
             name,
@@ -459,7 +459,7 @@ impl TryToNav for hir::TypeParam {
         .map(|it| it.syntax().text_range());
         Some(NavigationTarget {
             file_id: src.file_id.original_file(db),
-            name: self.name(db).to_smol_str(),
+            name: self.name(db).to_string().into(),
             kind: Some(SymbolKind::TypeParam),
             full_range,
             focus_range,
@@ -476,7 +476,7 @@ impl TryToNav for hir::LifetimeParam {
         let full_range = src.value.syntax().text_range();
         Some(NavigationTarget {
             file_id: src.file_id.original_file(db),
-            name: self.name(db).to_smol_str(),
+            name: self.name(db).to_string().into(),
             kind: Some(SymbolKind::LifetimeParam),
             full_range,
             focus_range: Some(full_range),
@@ -493,7 +493,7 @@ impl TryToNav for hir::ConstParam {
         let full_range = src.value.syntax().text_range();
         Some(NavigationTarget {
             file_id: src.file_id.original_file(db),
-            name: self.name(db).to_smol_str(),
+            name: self.name(db).to_string().into(),
             kind: Some(SymbolKind::ConstParam),
             full_range,
             focus_range: src.value.name().map(|n| n.syntax().text_range()),
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 703449fe40..8c47b809b9 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -32,13 +32,11 @@ use crate::{
 /// Weblink to an item's documentation.
 pub(crate) type DocumentationLink = String;
 
-const MARKDOWN_OPTIONS: Options =
-    Options::ENABLE_FOOTNOTES.union(Options::ENABLE_TABLES).union(Options::ENABLE_TASKLISTS);
-
 /// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs)
 pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Definition) -> String {
     let mut cb = broken_link_clone_cb;
-    let doc = Parser::new_with_broken_link_callback(markdown, MARKDOWN_OPTIONS, Some(&mut cb));
+    let doc =
+        Parser::new_with_broken_link_callback(markdown, Options::ENABLE_TASKLISTS, Some(&mut cb));
 
     let doc = map_links(doc, |target, title| {
         // This check is imperfect, there's some overlap between valid intra-doc links
@@ -77,11 +75,13 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Defin
 pub(crate) fn remove_links(markdown: &str) -> String {
     let mut drop_link = false;
 
+    let opts = Options::ENABLE_TASKLISTS | Options::ENABLE_FOOTNOTES;
+
     let mut cb = |_: BrokenLink| {
         let empty = InlineStr::try_from("").unwrap();
         Some((CowStr::Inlined(empty), CowStr::Inlined(empty)))
     };
-    let doc = Parser::new_with_broken_link_callback(markdown, MARKDOWN_OPTIONS, Some(&mut cb));
+    let doc = Parser::new_with_broken_link_callback(markdown, opts, Some(&mut cb));
     let doc = doc.filter_map(move |evt| match evt {
         Event::Start(Tag::Link(link_type, target, title)) => {
             if link_type == LinkType::Inline && target.contains("://") {
@@ -151,7 +151,7 @@ pub(crate) fn extract_definitions_from_docs(
 ) -> Vec<(TextRange, String, Option<hir::Namespace>)> {
     Parser::new_with_broken_link_callback(
         docs.as_str(),
-        MARKDOWN_OPTIONS,
+        Options::ENABLE_TASKLISTS,
         Some(&mut broken_link_clone_cb),
     )
     .into_offset_iter()
@@ -473,17 +473,12 @@ fn get_doc_base_url(db: &RootDatabase, krate: &Crate) -> Option<Url> {
         }
         _ => {
             krate.get_html_root_url(db).or_else(|| {
-                let version = krate.version(db);
                 // Fallback to docs.rs. This uses `display_name` and can never be
                 // correct, but that's what fallbacks are about.
                 //
                 // FIXME: clicking on the link should just open the file in the editor,
                 // instead of falling back to external urls.
-                Some(format!(
-                    "https://docs.rs/{krate}/{version}/",
-                    krate = display_name,
-                    version = version.as_deref().unwrap_or("*")
-                ))
+                Some(format!("https://docs.rs/{krate}/*/", krate = display_name))
             })?
         }
     };
diff --git a/crates/ide/src/doc_links/intra_doc_links.rs b/crates/ide/src/doc_links/intra_doc_links.rs
index 1df9aaae28..d94999dddd 100644
--- a/crates/ide/src/doc_links/intra_doc_links.rs
+++ b/crates/ide/src/doc_links/intra_doc_links.rs
@@ -21,7 +21,8 @@ pub(super) fn parse_intra_doc_link(s: &str) -> (&str, Option<hir::Namespace>) {
         (hir::Namespace::Values, (VALUES.0.iter(), VALUES.1.iter())),
         (hir::Namespace::Macros, (MACROS.0.iter(), MACROS.1.iter())),
     ]
-    .into_iter()
+    .iter()
+    .cloned()
     .find_map(|(ns, (mut prefixes, mut suffixes))| {
         if let Some(prefix) = prefixes.find(|&&prefix| {
             s.starts_with(prefix)
@@ -41,7 +42,8 @@ pub(super) fn strip_prefixes_suffixes(s: &str) -> &str {
         (VALUES.0.iter(), VALUES.1.iter()),
         (MACROS.0.iter(), MACROS.1.iter()),
     ]
-    .into_iter()
+    .iter()
+    .cloned()
     .find_map(|(mut prefixes, mut suffixes)| {
         if let Some(prefix) = prefixes.find(|&&prefix| {
             s.starts_with(prefix)
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 710d6b7882..db91e68ff3 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -344,7 +344,7 @@ fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir
         enum_data
             .variants(db)
             .into_iter()
-            .map(|variant| variant.name(db).to_smol_str())
+            .map(|variant| variant.name(db).to_string())
             .any(|enum_name| enum_name == pat_text)
     } else {
         false
@@ -363,7 +363,7 @@ fn should_not_display_type_hint(
     }
 
     if let Some(hir::Adt::Struct(s)) = pat_ty.as_adt() {
-        if s.fields(db).is_empty() && s.name(db).to_smol_str() == bind_pat.to_string() {
+        if s.fields(db).is_empty() && s.name(db).to_string() == bind_pat.to_string() {
             return true;
         }
     }
@@ -419,7 +419,7 @@ fn should_hide_param_name_hint(
     }
 
     let fn_name = match callable.kind() {
-        hir::CallableKind::Function(it) => Some(it.name(sema.db).to_smol_str()),
+        hir::CallableKind::Function(it) => Some(it.name(sema.db).to_string()),
         _ => None,
     };
     let fn_name = fn_name.as_deref();
@@ -475,9 +475,7 @@ fn is_enum_name_similar_to_param_name(
     param_name: &str,
 ) -> bool {
     match sema.type_of_expr(argument).and_then(|t| t.original.as_adt()) {
-        Some(hir::Adt::Enum(e)) => {
-            to_lower_snake_case(&e.name(sema.db).to_smol_str()) == param_name
-        }
+        Some(hir::Adt::Enum(e)) => to_lower_snake_case(&e.name(sema.db).to_string()) == param_name,
         _ => false,
     }
 }
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index bc447177af..c2412254ef 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -219,7 +219,6 @@ impl Analysis {
             file_id,
             Edition::CURRENT,
             None,
-            None,
             cfg_options.clone(),
             cfg_options,
             Env::default(),
diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs
index a7ebba82b0..d6f381497b 100644
--- a/crates/ide/src/rename.rs
+++ b/crates/ide/src/rename.rs
@@ -3,7 +3,6 @@
 //! This is mostly front-end for [`ide_db::rename`], but it also includes the
 //! tests. This module also implements a couple of magic tricks, like renaming
 //! `self` and to `self` (to switch between associated function and method).
-
 use hir::{AsAssocItem, InFile, Semantics};
 use ide_db::{
     base_db::FileId,
@@ -11,7 +10,6 @@ use ide_db::{
     rename::{bail, format_err, source_edit_from_references, IdentifierKind},
     RootDatabase,
 };
-use itertools::Itertools;
 use stdx::{always, never};
 use syntax::{ast, AstNode, SyntaxNode};
 
@@ -33,33 +31,14 @@ pub(crate) fn prepare_rename(
     let source_file = sema.parse(position.file_id);
     let syntax = source_file.syntax();
 
-    let res = find_definitions(&sema, syntax, position)?
-        .map(|(name_like, def)| {
-            // ensure all ranges are valid
-
-            if def.range_for_rename(&sema).is_none() {
-                bail!("No references found at position")
-            }
-            let frange = sema.original_range(name_like.syntax());
-
-            always!(
-                frange.range.contains_inclusive(position.offset)
-                    && frange.file_id == position.file_id
-            );
-            Ok(frange.range)
-        })
-        .reduce(|acc, cur| match (acc, cur) {
-            // ensure all ranges are the same
-            (Ok(acc_inner), Ok(cur_inner)) if acc_inner == cur_inner => Ok(acc_inner),
-            (Err(e), _) => Err(e),
-            _ => bail!("inconsistent text range"),
-        });
-
-    match res {
-        // ensure at least one definition was found
-        Some(res) => res.map(|range| RangeInfo::new(range, ())),
-        None => bail!("No references found at position"),
+    let (name_like, def) = find_definition(&sema, syntax, position)?;
+    if def.range_for_rename(&sema).is_none() {
+        bail!("No references found at position")
     }
+
+    let frange = sema.original_range(name_like.syntax());
+    always!(frange.range.contains_inclusive(position.offset) && frange.file_id == position.file_id);
+    Ok(RangeInfo::new(frange.range, ()))
 }
 
 // Feature: Rename
@@ -82,27 +61,20 @@ pub(crate) fn rename(
     let source_file = sema.parse(position.file_id);
     let syntax = source_file.syntax();
 
-    let defs = find_definitions(&sema, syntax, position)?;
+    let (_name_like, def) = find_definition(&sema, syntax, position)?;
 
-    let ops: RenameResult<Vec<SourceChange>> = defs
-        .map(|(_namelike, def)| {
-            if let Definition::Local(local) = def {
-                if let Some(self_param) = local.as_self_param(sema.db) {
-                    cov_mark::hit!(rename_self_to_param);
-                    return rename_self_to_param(&sema, local, self_param, new_name);
-                }
-                if new_name == "self" {
-                    cov_mark::hit!(rename_to_self);
-                    return rename_to_self(&sema, local);
-                }
-            }
-            def.rename(&sema, new_name)
-        })
-        .collect();
+    if let Definition::Local(local) = def {
+        if let Some(self_param) = local.as_self_param(sema.db) {
+            cov_mark::hit!(rename_self_to_param);
+            return rename_self_to_param(&sema, local, self_param, new_name);
+        }
+        if new_name == "self" {
+            cov_mark::hit!(rename_to_self);
+            return rename_to_self(&sema, local);
+        }
+    }
 
-    ops?.into_iter()
-        .reduce(|acc, elem| acc.merge(elem))
-        .ok_or_else(|| format_err!("No references found at position"))
+    def.rename(&sema, new_name)
 }
 
 /// Called by the client when it is about to rename a file.
@@ -119,86 +91,59 @@ pub(crate) fn will_rename_file(
     Some(change)
 }
 
-fn find_definitions(
+fn find_definition(
     sema: &Semantics<RootDatabase>,
     syntax: &SyntaxNode,
     position: FilePosition,
-) -> RenameResult<impl Iterator<Item = (ast::NameLike, Definition)>> {
-    let symbols = sema
-        .find_nodes_at_offset_with_descend::<ast::NameLike>(syntax, position.offset)
-        .map(|name_like| {
-            let res = match &name_like {
-                // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet
-                ast::NameLike::Name(name)
-                    if name
-                        .syntax()
-                        .parent()
-                        .map_or(false, |it| ast::Rename::can_cast(it.kind())) =>
-                {
-                    bail!("Renaming aliases is currently unsupported")
-                }
-                ast::NameLike::Name(name) => NameClass::classify(sema, name)
-                    .map(|class| match class {
-                        NameClass::Definition(it) | NameClass::ConstReference(it) => it,
-                        NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
-                            Definition::Local(local_def)
-                        }
-                    })
-                    .map(|def| (name_like.clone(), def))
-                    .ok_or_else(|| format_err!("No references found at position")),
-                ast::NameLike::NameRef(name_ref) => {
-                    NameRefClass::classify(sema, name_ref)
-                        .map(|class| match class {
-                            NameRefClass::Definition(def) => def,
-                            NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
-                                Definition::Local(local_ref)
-                            }
-                        })
-                        .ok_or_else(|| format_err!("No references found at position"))
-                        .and_then(|def| {
-                            // if the name differs from the definitions name it has to be an alias
-                            if def
-                                .name(sema.db)
-                                .map_or(false, |it| it.to_smol_str() != name_ref.text().as_str())
-                            {
-                                Err(format_err!("Renaming aliases is currently unsupported"))
-                            } else {
-                                Ok((name_like.clone(), def))
-                            }
-                        })
+) -> RenameResult<(ast::NameLike, Definition)> {
+    let name_like = sema
+        .find_node_at_offset_with_descend::<ast::NameLike>(syntax, position.offset)
+        .ok_or_else(|| format_err!("No references found at position"))?;
+
+    let def = match &name_like {
+        // renaming aliases would rename the item being aliased as the HIR doesn't track aliases yet
+        ast::NameLike::Name(name)
+            if name.syntax().parent().map_or(false, |it| ast::Rename::can_cast(it.kind())) =>
+        {
+            bail!("Renaming aliases is currently unsupported")
+        }
+        ast::NameLike::Name(name) => NameClass::classify(sema, name).map(|class| match class {
+            NameClass::Definition(it) | NameClass::ConstReference(it) => it,
+            NameClass::PatFieldShorthand { local_def, field_ref: _ } => {
+                Definition::Local(local_def)
+            }
+        }),
+        ast::NameLike::NameRef(name_ref) => {
+            if let Some(def) = NameRefClass::classify(sema, name_ref).map(|class| match class {
+                NameRefClass::Definition(def) => def,
+                NameRefClass::FieldShorthand { local_ref, field_ref: _ } => {
+                    Definition::Local(local_ref)
                 }
-                ast::NameLike::Lifetime(lifetime) => {
-                    NameRefClass::classify_lifetime(sema, lifetime)
-                        .and_then(|class| match class {
-                            NameRefClass::Definition(def) => Some(def),
-                            _ => None,
-                        })
-                        .or_else(|| {
-                            NameClass::classify_lifetime(sema, lifetime).and_then(|it| match it {
-                                NameClass::Definition(it) => Some(it),
-                                _ => None,
-                            })
-                        })
-                        .map(|def| (name_like, def))
-                        .ok_or_else(|| format_err!("No references found at position"))
+            }) {
+                // if the name differs from the definitions name it has to be an alias
+                if def.name(sema.db).map_or(false, |it| it.to_string() != name_ref.text()) {
+                    bail!("Renaming aliases is currently unsupported");
                 }
-            };
-            res
-        });
-
-    let res: RenameResult<Vec<_>> = symbols.collect();
-    match res {
-        Ok(v) => {
-            if v.is_empty() {
-                // FIXME: some semantic duplication between "empty vec" and "Err()"
-                Err(format_err!("No references found at position"))
+                Some(def)
             } else {
-                // remove duplicates, comparing `Definition`s
-                Ok(v.into_iter().unique_by(|t| t.1))
+                None
             }
         }
-        Err(e) => Err(e),
+        ast::NameLike::Lifetime(lifetime) => NameRefClass::classify_lifetime(sema, lifetime)
+            .and_then(|class| match class {
+                NameRefClass::Definition(def) => Some(def),
+                _ => None,
+            })
+            .or_else(|| {
+                NameClass::classify_lifetime(sema, lifetime).and_then(|it| match it {
+                    NameClass::Definition(it) => Some(it),
+                    _ => None,
+                })
+            }),
     }
+    .ok_or_else(|| format_err!("No references found at position"))?;
+
+    Ok((name_like, def))
 }
 
 fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameResult<SourceChange> {
@@ -570,36 +515,6 @@ fn main() {
         );
     }
 
-    #[test]
-    fn test_rename_macro_multiple_occurrences() {
-        check(
-            "Baaah",
-            r#"macro_rules! foo {
-    ($ident:ident) => {
-        const $ident: () = ();
-        struct $ident {}
-    };
-}
-
-foo!($0Foo);
-const _: () = Foo;
-const _: Foo = Foo {};
-    "#,
-            r#"
-macro_rules! foo {
-    ($ident:ident) => {
-        const $ident: () = ();
-        struct $ident {}
-    };
-}
-
-foo!(Baaah);
-const _: () = Baaah;
-const _: Baaah = Baaah {};
-    "#,
-        )
-    }
-
     #[test]
     fn test_rename_for_macro_args() {
         check(
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index cac736ff85..a5858869c5 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -95,7 +95,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
         NodeOrToken::Token(token) => token.text_range(),
     };
     let group_label = group_label(import_assets.import_candidate());
-    let scope = ImportScope::find_insert_use_container(
+    let scope = ImportScope::find_insert_use_container_with_macros(
         &match syntax_under_caret {
             NodeOrToken::Node(it) => it,
             NodeOrToken::Token(it) => it.parent()?,
@@ -164,60 +164,6 @@ mod tests {
 
     use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
 
-    #[test]
-    fn not_applicable_if_scope_inside_macro() {
-        check_assist_not_applicable(
-            auto_import,
-            r"
-mod bar {
-    pub struct Baz;
-}
-macro_rules! foo {
-    ($it:ident) => {
-        mod __ {
-            fn __(x: $it) {}
-        }
-    };
-}
-foo! {
-    Baz$0
-}
-",
-        );
-    }
-
-    #[test]
-    fn applicable_in_attributes() {
-        check_assist(
-            auto_import,
-            r"
-//- proc_macros: identity
-#[proc_macros::identity]
-mod foo {
-    mod bar {
-        const _: Baz$0 = ();
-    }
-}
-mod baz {
-    pub struct Baz;
-}
-",
-            r"
-#[proc_macros::identity]
-mod foo {
-    mod bar {
-        use crate::baz::Baz;
-
-        const _: Baz = ();
-    }
-}
-mod baz {
-    pub struct Baz;
-}
-",
-        );
-    }
-
     #[test]
     fn applicable_when_found_an_import_partial() {
         check_assist(
diff --git a/crates/ide_assists/src/handlers/expand_glob_import.rs b/crates/ide_assists/src/handlers/expand_glob_import.rs
index 3abf06d588..34eb235ce2 100644
--- a/crates/ide_assists/src/handlers/expand_glob_import.rs
+++ b/crates/ide_assists/src/handlers/expand_glob_import.rs
@@ -226,7 +226,7 @@ fn find_imported_defs(ctx: &AssistContext, star: SyntaxToken) -> Option<Vec<Def>
 
     Some(
         [Direction::Prev, Direction::Next]
-            .into_iter()
+            .iter()
             .flat_map(|dir| {
                 parent_use_item_syntax
                     .siblings(dir.to_owned())
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs
index 3a334efe0a..7ffb5728cc 100644
--- a/crates/ide_assists/src/handlers/extract_function.rs
+++ b/crates/ide_assists/src/handlers/extract_function.rs
@@ -91,7 +91,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
 
     let target_range = body.text_range();
 
-    let scope = ImportScope::find_insert_use_container(&node, &ctx.sema)?;
+    let scope = ImportScope::find_insert_use_container_with_macros(&node, &ctx.sema)?;
 
     acc.add(
         AssistId("extract_function", crate::AssistKind::RefactorExtract),
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index 8e28f0443d..3b812cdf17 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -314,7 +314,7 @@ fn process_references(
                 if let Some(mut mod_path) = mod_path {
                     mod_path.pop_segment();
                     mod_path.push_segment(variant_hir_name.clone());
-                    let scope = ImportScope::find_insert_use_container(&scope_node, &ctx.sema)?;
+                    let scope = ImportScope::find_insert_use_container(&scope_node)?;
                     visited_modules.insert(module);
                     return Some((segment, scope_node, Some((scope, mod_path))));
                 }
diff --git a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
index 8df8c4b726..47600be763 100644
--- a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -70,7 +70,7 @@ pub(crate) fn replace_qualified_name_with_use(
         })
         .flatten();
 
-    let scope = ImportScope::find_insert_use_container(path.syntax(), &ctx.sema)?;
+    let scope = ImportScope::find_insert_use_container_with_macros(path.syntax(), &ctx.sema)?;
     let target = path.syntax().text_range();
     acc.add(
         AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite),
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index e86f38aaa4..2482418ae6 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -104,7 +104,7 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
                 let mut item = CompletionItem::new(
                     CompletionItemKind::Attribute,
                     ctx.source_range(),
-                    name.to_smol_str(),
+                    name.to_string(),
                 );
                 if let Some(docs) = mac.docs(ctx.sema.db) {
                     item.documentation(docs);
diff --git a/crates/ide_completion/src/completions/attribute/cfg.rs b/crates/ide_completion/src/completions/attribute/cfg.rs
index 1a10531a1b..c83e1718ec 100644
--- a/crates/ide_completion/src/completions/attribute/cfg.rs
+++ b/crates/ide_completion/src/completions/attribute/cfg.rs
@@ -31,11 +31,13 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
         Some("target_endian") => ["little", "big"].into_iter().for_each(add_completion),
         Some(name) => {
             if let Some(krate) = ctx.krate {
-                krate.potential_cfg(ctx.db).get_cfg_values(&name).cloned().for_each(|s| {
-                    let insert_text = format!(r#""{}""#, s);
-                    let mut item =
-                        CompletionItem::new(CompletionItemKind::Attribute, ctx.source_range(), s);
-                    item.insert_text(insert_text);
+                krate.potential_cfg(ctx.db).get_cfg_values(&name).iter().for_each(|s| {
+                    let mut item = CompletionItem::new(
+                        CompletionItemKind::Attribute,
+                        ctx.source_range(),
+                        s.as_str(),
+                    );
+                    item.insert_text(format!(r#""{}""#, s));
 
                     acc.add(item.build());
                 })
@@ -43,9 +45,12 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
         }
         None => {
             if let Some(krate) = ctx.krate {
-                krate.potential_cfg(ctx.db).get_cfg_keys().cloned().for_each(|s| {
-                    let item =
-                        CompletionItem::new(CompletionItemKind::Attribute, ctx.source_range(), s);
+                krate.potential_cfg(ctx.db).get_cfg_keys().iter().for_each(|s| {
+                    let item = CompletionItem::new(
+                        CompletionItemKind::Attribute,
+                        ctx.source_range(),
+                        s.as_str(),
+                    );
                     acc.add(item.build());
                 })
             }
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs
index b9032318ec..5c08d12ef2 100644
--- a/crates/ide_completion/src/completions/attribute/derive.rs
+++ b/crates/ide_completion/src/completions/attribute/derive.rs
@@ -3,7 +3,7 @@ use hir::{HasAttrs, MacroDef, MacroKind};
 use ide_db::helpers::{import_assets::ImportAssets, insert_use::ImportScope, FamousDefs};
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
-use syntax::{ast, SmolStr, SyntaxKind};
+use syntax::{ast, SyntaxKind};
 
 use crate::{
     completions::flyimport::compute_fuzzy_completion_order_key,
@@ -30,6 +30,7 @@ pub(super) fn complete_derive(
         }
 
         let name = name.to_smol_str();
+        let label;
         let (label, lookup) = match core.zip(mac.module(ctx.db).map(|it| it.krate())) {
             // show derive dependencies for `core`/`std` derives
             Some((core, mac_krate)) if core == mac_krate => {
@@ -47,13 +48,13 @@ pub(super) fn complete_derive(
                         },
                     ));
                     let lookup = components.join(", ");
-                    let label = Itertools::intersperse(components.into_iter().rev(), ", ");
-                    (SmolStr::from_iter(label), Some(lookup))
+                    label = components.iter().rev().join(", ");
+                    (label.as_str(), Some(lookup))
                 } else {
-                    (name, None)
+                    (&*name, None)
                 }
             }
-            _ => (name, None),
+            _ => (&*name, None),
         };
 
         let mut item =
@@ -67,7 +68,7 @@ pub(super) fn complete_derive(
         item.add_to(acc);
     }
 
-    flyimport_attribute(acc, ctx);
+    flyimport_attribute(ctx, acc);
 }
 
 fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, MacroDef)> {
@@ -82,7 +83,7 @@ fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, MacroDef)> {
     result
 }
 
-fn flyimport_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
+fn flyimport_attribute(ctx: &CompletionContext, acc: &mut Completions) -> Option<()> {
     if ctx.token.kind() != SyntaxKind::IDENT {
         return None;
     };
@@ -97,7 +98,7 @@ fn flyimport_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option
         &ctx.sema,
         parent.clone(),
     )?;
-    let import_scope = ImportScope::find_insert_use_container(&parent, &ctx.sema)?;
+    let import_scope = ImportScope::find_insert_use_container_with_macros(&parent, &ctx.sema)?;
     acc.add_all(
         import_assets
             .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
@@ -114,7 +115,7 @@ fn flyimport_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option
                 let mut item = CompletionItem::new(
                     CompletionItemKind::Attribute,
                     ctx.source_range(),
-                    mac.name(ctx.db)?.to_smol_str(),
+                    mac.name(ctx.db)?.to_string(),
                 );
                 item.add_import(ImportEdit { import, scope: import_scope.clone() });
                 if let Some(docs) = mac.docs(ctx.db) {
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 47036f2e13..a5c134714b 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -129,7 +129,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
 
     let user_input_lowercased = potential_import_name.to_lowercase();
     let import_assets = import_assets(ctx, potential_import_name)?;
-    let import_scope = ImportScope::find_insert_use_container(
+    let import_scope = ImportScope::find_insert_use_container_with_macros(
         &position_for_import(ctx, Some(import_assets.import_candidate()))?,
         &ctx.sema,
     )?;
@@ -209,7 +209,7 @@ pub(crate) fn compute_fuzzy_completion_order_key(
 ) -> usize {
     cov_mark::hit!(certain_fuzzy_order_test);
     let import_name = match proposed_mod_path.segments().last() {
-        Some(name) => name.to_smol_str().to_lowercase(),
+        Some(name) => name.to_string().to_lowercase(),
         None => return usize::MAX,
     };
     match import_name.match_indices(user_input_lowercased).next() {
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs
index 5acda46498..e910c1daaa 100644
--- a/crates/ide_completion/src/completions/fn_param.rs
+++ b/crates/ide_completion/src/completions/fn_param.rs
@@ -30,7 +30,6 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
         }
         func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| {
             if let Some(pat) = param.pat() {
-                // FIXME: We should be able to turn these into SmolStr without having to allocate a String
                 let text = param.syntax().text().to_string();
                 let lookup = pat.syntax().text().to_string();
                 params.entry(text).or_insert(lookup);
@@ -60,7 +59,7 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
 
     let self_completion_items = ["self", "&self", "mut self", "&mut self"];
     if ctx.impl_def.is_some() && me?.param_list()?.params().next().is_none() {
-        self_completion_items.into_iter().for_each(|self_item| {
+        self_completion_items.iter().for_each(|self_item| {
             add_new_item_to_acc(ctx, acc, self_item.to_string(), self_item.to_string())
         });
     }
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index 36d25d5d02..afb8df2911 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -27,7 +27,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
         return;
     }
 
-    let mut add_keyword = |kw, snippet| add_keyword(acc, ctx, kw, snippet);
+    let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet);
 
     let expects_assoc_item = ctx.expects_assoc_item();
     let has_block_expr_parent = ctx.has_block_expr_parent();
@@ -157,7 +157,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
     )
 }
 
-fn add_keyword(acc: &mut Completions, ctx: &CompletionContext, kw: &str, snippet: &str) {
+fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
     let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
 
     match ctx.config.snippet_cap {
diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs
index f530825434..283dc021d6 100644
--- a/crates/ide_completion/src/completions/lifetime.rs
+++ b/crates/ide_completion/src/completions/lifetime.rs
@@ -34,7 +34,7 @@ pub(crate) fn complete_lifetime(acc: &mut Completions, ctx: &CompletionContext)
 
     ctx.scope.process_all_names(&mut |name, res| {
         if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
-            if param_lifetime != Some(&*name.to_smol_str()) {
+            if param_lifetime != Some(&*name.to_string()) {
                 acc.add_resolution(ctx, name, &res);
             }
         }
diff --git a/crates/ide_completion/src/completions/mod_.rs b/crates/ide_completion/src/completions/mod_.rs
index beef834581..28be83f196 100644
--- a/crates/ide_completion/src/completions/mod_.rs
+++ b/crates/ide_completion/src/completions/mod_.rs
@@ -121,7 +121,7 @@ fn directory_to_look_for_submodules(
     module_chain_to_containing_module_file(module, db)
         .into_iter()
         .filter_map(|module| module.name(db))
-        .try_fold(base_directory, |path, name| path.join(&name.to_smol_str()))
+        .try_fold(base_directory, |path, name| path.join(&name.to_string()))
 }
 
 fn module_chain_to_containing_module_file(
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs
index c239401e48..4ee257ab43 100644
--- a/crates/ide_completion/src/completions/postfix.rs
+++ b/crates/ide_completion/src/completions/postfix.rs
@@ -244,7 +244,8 @@ fn add_custom_postfix_completions(
     postfix_snippet: impl Fn(&str, &str, &str) -> Builder,
     receiver_text: &str,
 ) -> Option<()> {
-    let import_scope = ImportScope::find_insert_use_container(&ctx.token.parent()?, &ctx.sema)?;
+    let import_scope =
+        ImportScope::find_insert_use_container_with_macros(&ctx.token.parent()?, &ctx.sema)?;
     ctx.config.postfix_snippets().filter(|(_, snip)| snip.scope == SnippetScope::Expr).for_each(
         |(trigger, snippet)| {
             let imports = match snippet.imports(ctx, &import_scope) {
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index 385bf59cde..e9d39edc43 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -93,7 +93,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
                 if ctx.in_use_tree() {
                     if let hir::ScopeDef::Unknown = def {
                         if let Some(ast::NameLike::NameRef(name_ref)) = ctx.name_syntax.as_ref() {
-                            if name_ref.syntax().text() == name.to_smol_str().as_str() {
+                            if name_ref.syntax().text() == name.to_string().as_str() {
                                 // for `use self::foo$0`, don't suggest `foo` as a completion
                                 cov_mark::hit!(dont_complete_current_use);
                                 continue;
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs
index 12bccfae11..1840e780ed 100644
--- a/crates/ide_completion/src/completions/snippet.rs
+++ b/crates/ide_completion/src/completions/snippet.rs
@@ -102,7 +102,8 @@ fn add_custom_completions(
     cap: SnippetCap,
     scope: SnippetScope,
 ) -> Option<()> {
-    let import_scope = ImportScope::find_insert_use_container(&ctx.token.parent()?, &ctx.sema)?;
+    let import_scope =
+        ImportScope::find_insert_use_container_with_macros(&ctx.token.parent()?, &ctx.sema)?;
     ctx.config.prefix_snippets().filter(|(_, snip)| snip.scope == scope).for_each(
         |(trigger, snip)| {
             let imports = match snip.imports(ctx, &import_scope) {
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs
index 46da7cfa37..fc6ef5839c 100644
--- a/crates/ide_completion/src/completions/trait_impl.rs
+++ b/crates/ide_completion/src/completions/trait_impl.rs
@@ -133,7 +133,7 @@ fn add_function_impl(
     func: hir::Function,
     impl_def: hir::Impl,
 ) {
-    let fn_name = func.name(ctx.db).to_smol_str();
+    let fn_name = func.name(ctx.db).to_string();
 
     let label = if func.assoc_fn_params(ctx.db).is_empty() {
         format!("fn {}()", fn_name)
@@ -205,12 +205,12 @@ fn add_type_alias_impl(
     ctx: &CompletionContext,
     type_alias: hir::TypeAlias,
 ) {
-    let alias_name = type_alias.name(ctx.db).to_smol_str();
+    let alias_name = type_alias.name(ctx.db).to_string();
 
     let snippet = format!("type {} = ", alias_name);
 
     let range = replacement_range(ctx, type_def_node);
-    let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), &snippet);
+    let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), snippet.clone());
     item.text_edit(TextEdit::replace(range, snippet))
         .lookup_by(alias_name)
         .set_documentation(type_alias.docs(ctx.db));
@@ -224,7 +224,7 @@ fn add_const_impl(
     const_: hir::Const,
     impl_def: hir::Impl,
 ) {
-    let const_name = const_.name(ctx.db).map(|n| n.to_smol_str());
+    let const_name = const_.name(ctx.db).map(|n| n.to_string());
 
     if let Some(const_name) = const_name {
         if let Some(source) = const_.source(ctx.db) {
@@ -238,7 +238,8 @@ fn add_const_impl(
                 let snippet = make_const_compl_syntax(&transformed_const);
 
                 let range = replacement_range(ctx, const_def_node);
-                let mut item = CompletionItem::new(SymbolKind::Const, ctx.source_range(), &snippet);
+                let mut item =
+                    CompletionItem::new(SymbolKind::Const, ctx.source_range(), snippet.clone());
                 item.text_edit(TextEdit::replace(range, snippet))
                     .lookup_by(const_name)
                     .set_documentation(const_.docs(ctx.db));
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index a84f0b334b..825fae587b 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -6,7 +6,6 @@ use syntax::{ast, AstNode};
 use crate::{patterns::ImmediateLocation, CompletionContext, Completions};
 
 pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
-    let _p = profile::span("complete_unqualified_path");
     if ctx.is_path_disallowed() || !ctx.is_trivial_path() || ctx.has_impl_or_trait_prev_sibling() {
         return;
     }
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 05ae95769b..0cb484d507 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -58,7 +58,6 @@ pub(crate) struct PathCompletionContext {
 pub(super) struct PatternContext {
     pub(super) refutability: PatternRefutability,
     pub(super) is_param: Option<ParamKind>,
-    pub(super) has_type_ascription: bool,
 }
 
 #[derive(Debug)]
@@ -350,28 +349,28 @@ impl<'a> CompletionContext<'a> {
 impl<'a> CompletionContext<'a> {
     pub(super) fn new(
         db: &'a RootDatabase,
-        position @ FilePosition { file_id, offset }: FilePosition,
+        position: FilePosition,
         config: &'a CompletionConfig,
     ) -> Option<CompletionContext<'a>> {
-        let _p = profile::span("CompletionContext::new");
         let sema = Semantics::new(db);
 
-        let original_file = sema.parse(file_id);
+        let original_file = sema.parse(position.file_id);
 
         // Insert a fake ident to get a valid parse tree. We will use this file
         // to determine context, though the original_file will be used for
         // actual completion.
         let file_with_fake_ident = {
-            let parse = db.parse(file_id);
-            let edit = Indel::insert(offset, "intellijRulezz".to_string());
+            let parse = db.parse(position.file_id);
+            let edit = Indel::insert(position.offset, "intellijRulezz".to_string());
             parse.reparse(&edit).tree()
         };
         let fake_ident_token =
-            file_with_fake_ident.syntax().token_at_offset(offset).right_biased().unwrap();
+            file_with_fake_ident.syntax().token_at_offset(position.offset).right_biased().unwrap();
 
-        let original_token = original_file.syntax().token_at_offset(offset).left_biased()?;
+        let original_token =
+            original_file.syntax().token_at_offset(position.offset).left_biased()?;
         let token = sema.descend_into_macros_single(original_token.clone());
-        let scope = sema.scope_at_offset(&token, offset);
+        let scope = sema.scope_at_offset(&token, position.offset);
         let krate = scope.krate();
         let mut locals = vec![];
         scope.process_all_names(&mut |name, scope| {
@@ -407,7 +406,7 @@ impl<'a> CompletionContext<'a> {
         ctx.expand_and_fill(
             original_file.syntax().clone(),
             file_with_fake_ident.syntax().clone(),
-            offset,
+            position.offset,
             fake_ident_token,
         );
         Some(ctx)
@@ -598,8 +597,7 @@ impl<'a> CompletionContext<'a> {
                             .map(|c| (Some(c.return_type()), None))
                             .unwrap_or((None, None))
                     },
-                    ast::ParamList(__) => (None, None),
-                    ast::Stmt(__) => (None, None),
+                    ast::Stmt(_it) => (None, None),
                     ast::Item(__) => (None, None),
                     _ => {
                         match node.parent() {
@@ -710,15 +708,15 @@ impl<'a> CompletionContext<'a> {
             return None;
         }
         let mut is_param = None;
-        let (refutability, has_type_ascription) = bind_pat
+        let refutability = bind_pat
             .syntax()
             .ancestors()
             .skip_while(|it| ast::Pat::can_cast(it.kind()))
             .next()
-            .map_or((PatternRefutability::Irrefutable, false), |node| {
-                let refutability = match_ast! {
+            .map_or(PatternRefutability::Irrefutable, |node| {
+                match_ast! {
                     match node {
-                        ast::LetStmt(let_) => return (PatternRefutability::Irrefutable, let_.ty().is_some()),
+                        ast::LetStmt(__) => PatternRefutability::Irrefutable,
                         ast::Param(param) => {
                             let is_closure_param = param
                                 .syntax()
@@ -731,17 +729,16 @@ impl<'a> CompletionContext<'a> {
                             } else {
                                 ParamKind::Function
                             });
-                            return (PatternRefutability::Irrefutable, param.ty().is_some())
+                            PatternRefutability::Irrefutable
                         },
                         ast::MatchArm(__) => PatternRefutability::Refutable,
                         ast::Condition(__) => PatternRefutability::Refutable,
                         ast::ForExpr(__) => PatternRefutability::Irrefutable,
                         _ => PatternRefutability::Irrefutable,
                     }
-                };
-                (refutability, false)
+                }
             });
-        Some(PatternContext { refutability, is_param, has_type_ascription })
+        Some(PatternContext { refutability, is_param })
     }
 
     fn classify_name_ref(
@@ -1175,23 +1172,4 @@ fn foo() {
             expect![[r#"ty: Foo, name: ?"#]],
         );
     }
-
-    #[test]
-    fn expected_type_param_pat() {
-        check_expected_type_and_name(
-            r#"
-struct Foo { field: u32 }
-fn foo(a$0: Foo) {}
-"#,
-            expect![[r#"ty: Foo, name: ?"#]],
-        );
-        check_expected_type_and_name(
-            r#"
-struct Foo { field: u32 }
-fn foo($0: Foo) {}
-"#,
-            // FIXME make this work, currently fails due to pattern recovery eating the `:`
-            expect![[r#"ty: ?, name: ?"#]],
-        );
-    }
 }
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index ebe227d260..3f0accfbe1 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -12,8 +12,8 @@ use ide_db::{
     SymbolKind,
 };
 use smallvec::SmallVec;
-use stdx::{impl_from, never};
-use syntax::{algo, SmolStr, TextRange};
+use stdx::{format_to, impl_from, never};
+use syntax::{algo, TextRange};
 use text_edit::TextEdit;
 
 /// `CompletionItem` describes a single completion variant in the editor pop-up.
@@ -22,7 +22,7 @@ use text_edit::TextEdit;
 #[derive(Clone)]
 pub struct CompletionItem {
     /// Label in the completion pop up which identifies completion.
-    label: SmolStr,
+    label: String,
     /// Range of identifier that is being completed.
     ///
     /// It should be used primarily for UI, but we also use this to convert
@@ -46,7 +46,7 @@ pub struct CompletionItem {
     ///
     /// That is, in `foo.bar$0` lookup of `abracadabra` will be accepted (it
     /// contains `bar` sub sequence), and `quux` will rejected.
-    lookup: Option<SmolStr>,
+    lookup: Option<String>,
 
     /// Additional info to show in the UI pop up.
     detail: Option<String>,
@@ -268,7 +268,7 @@ impl CompletionItem {
     pub(crate) fn new(
         kind: impl Into<CompletionItemKind>,
         source_range: TextRange,
-        label: impl Into<SmolStr>,
+        label: impl Into<String>,
     ) -> Builder {
         let label = label.into();
         Builder {
@@ -379,13 +379,13 @@ impl ImportEdit {
 pub(crate) struct Builder {
     source_range: TextRange,
     imports_to_add: SmallVec<[ImportEdit; 1]>,
-    trait_name: Option<SmolStr>,
-    label: SmolStr,
+    trait_name: Option<String>,
+    label: String,
     insert_text: Option<String>,
     is_snippet: bool,
     detail: Option<String>,
     documentation: Option<Documentation>,
-    lookup: Option<SmolStr>,
+    lookup: Option<String>,
     kind: CompletionItemKind,
     text_edit: Option<TextEdit>,
     deprecated: bool,
@@ -400,21 +400,25 @@ impl Builder {
 
         let mut label = self.label;
         let mut lookup = self.lookup;
-        let insert_text = self.insert_text.unwrap_or_else(|| label.to_string());
+        let mut insert_text = self.insert_text;
 
         if let [import_edit] = &*self.imports_to_add {
             // snippets can have multiple imports, but normal completions only have up to one
             if let Some(original_path) = import_edit.import.original_path.as_ref() {
                 lookup = lookup.or_else(|| Some(label.clone()));
-                label = SmolStr::from(format!("{} (use {})", label, original_path));
+                insert_text = insert_text.or_else(|| Some(label.clone()));
+                format_to!(label, " (use {})", original_path)
             }
         } else if let Some(trait_name) = self.trait_name {
-            label = SmolStr::from(format!("{} (as {})", label, trait_name));
+            insert_text = insert_text.or_else(|| Some(label.clone()));
+            format_to!(label, " (as {})", trait_name)
         }
 
         let text_edit = match self.text_edit {
             Some(it) => it,
-            None => TextEdit::replace(self.source_range, insert_text),
+            None => {
+                TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone()))
+            }
         };
 
         CompletionItem {
@@ -433,16 +437,16 @@ impl Builder {
             import_to_add: self.imports_to_add,
         }
     }
-    pub(crate) fn lookup_by(&mut self, lookup: impl Into<SmolStr>) -> &mut Builder {
+    pub(crate) fn lookup_by(&mut self, lookup: impl Into<String>) -> &mut Builder {
         self.lookup = Some(lookup.into());
         self
     }
-    pub(crate) fn label(&mut self, label: impl Into<SmolStr>) -> &mut Builder {
+    pub(crate) fn label(&mut self, label: impl Into<String>) -> &mut Builder {
         self.label = label.into();
         self
     }
-    pub(crate) fn trait_name(&mut self, trait_name: SmolStr) -> &mut Builder {
-        self.trait_name = Some(trait_name);
+    pub(crate) fn trait_name(&mut self, trait_name: impl Into<String>) -> &mut Builder {
+        self.trait_name = Some(trait_name.into());
         self
     }
     pub(crate) fn insert_text(&mut self, insert_text: impl Into<String>) -> &mut Builder {
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index d9618642c4..463744f22a 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -183,7 +183,7 @@ pub fn resolve_completion_edits(
     let _p = profile::span("resolve_completion_edits");
     let ctx = CompletionContext::new(db, position, config)?;
     let position_for_import = &position_for_import(&ctx, None)?;
-    let scope = ImportScope::find_insert_use_container(position_for_import, &ctx.sema)?;
+    let scope = ImportScope::find_insert_use_container_with_macros(position_for_import, &ctx.sema)?;
 
     let current_module = ctx.sema.scope(position_for_import).module()?;
     let current_crate = current_module.krate();
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index a1d4eb998f..4180d704a3 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -16,7 +16,7 @@ use ide_db::{
     helpers::{item_name, SnippetCap},
     RootDatabase, SymbolKind,
 };
-use syntax::{SmolStr, SyntaxKind, TextRange};
+use syntax::{SyntaxKind, TextRange};
 
 use crate::{
     context::{PathCompletionContext, PathKind},
@@ -83,11 +83,11 @@ pub(crate) fn render_field(
     ty: &hir::Type,
 ) -> CompletionItem {
     let is_deprecated = ctx.is_deprecated(field);
-    let name = field.name(ctx.db()).to_smol_str();
+    let name = field.name(ctx.db()).to_string();
     let mut item = CompletionItem::new(
         SymbolKind::Field,
         ctx.source_range(),
-        receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name).into()),
+        receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
     );
     item.set_relevance(CompletionRelevance {
         type_match: compute_type_match(ctx.completion, ty),
@@ -97,7 +97,7 @@ pub(crate) fn render_field(
     item.detail(ty.display(ctx.db()).to_string())
         .set_documentation(field.docs(ctx.db()))
         .set_deprecated(is_deprecated)
-        .lookup_by(name.clone());
+        .lookup_by(name.as_str());
     let is_keyword = SyntaxKind::from_keyword(name.as_str()).is_some();
     if is_keyword && !matches!(name.as_str(), "self" | "crate" | "super" | "Self") {
         item.insert_text(format!("r#{}", name));
@@ -199,7 +199,7 @@ fn render_resolution_(
             let mut item = CompletionItem::new(
                 CompletionItemKind::UnresolvedReference,
                 ctx.source_range(),
-                local_name.to_smol_str(),
+                local_name.to_string(),
             );
             if let Some(import_to_add) = import_to_add {
                 item.add_import(import_to_add);
@@ -208,7 +208,7 @@ fn render_resolution_(
         }
     };
 
-    let local_name = local_name.to_smol_str();
+    let local_name = local_name.to_string();
     let mut item = CompletionItem::new(kind, ctx.source_range(), local_name.clone());
     if let hir::ScopeDef::Local(local) = resolution {
         let ty = local.ty(ctx.db());
@@ -243,7 +243,7 @@ fn render_resolution_(
             if has_non_default_type_params {
                 cov_mark::hit!(inserts_angle_brackets_for_generics);
                 item.lookup_by(local_name.clone())
-                    .label(SmolStr::from_iter([&local_name, "<…>"]))
+                    .label(format!("{}<…>", local_name))
                     .insert_snippet(cap, format!("{}<$0>", local_name));
             }
         }
diff --git a/crates/ide_completion/src/render/const_.rs b/crates/ide_completion/src/render/const_.rs
index c40490ac0b..241e0043c9 100644
--- a/crates/ide_completion/src/render/const_.rs
+++ b/crates/ide_completion/src/render/const_.rs
@@ -2,12 +2,14 @@
 
 use hir::{AsAssocItem, HasSource};
 use ide_db::SymbolKind;
-use syntax::{ast::Const, display::const_label};
+use syntax::{
+    ast::{Const, HasName},
+    display::const_label,
+};
 
 use crate::{item::CompletionItem, render::RenderContext};
 
 pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem> {
-    let _p = profile::span("render_const");
     ConstRender::new(ctx, const_)?.render()
 }
 
@@ -25,7 +27,7 @@ impl<'a> ConstRender<'a> {
     }
 
     fn render(self) -> Option<CompletionItem> {
-        let name = self.const_.name(self.ctx.db())?.to_smol_str();
+        let name = self.name()?;
         let detail = self.detail();
 
         let mut item =
@@ -40,7 +42,7 @@ impl<'a> ConstRender<'a> {
         let db = self.ctx.db();
         if let Some(actm) = self.const_.as_assoc_item(db) {
             if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
-                item.trait_name(trt.name(db).to_smol_str());
+                item.trait_name(trt.name(db).to_string());
                 item.insert_text(name);
             }
         }
@@ -48,6 +50,10 @@ impl<'a> ConstRender<'a> {
         Some(item.build())
     }
 
+    fn name(&self) -> Option<String> {
+        self.ast_node.name().map(|name| name.text().to_string())
+    }
+
     fn detail(&self) -> String {
         const_label(&self.ast_node)
     }
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index f598b414a7..7515bb6d47 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -38,7 +38,7 @@ pub(crate) fn render_method(
 #[derive(Debug)]
 struct FunctionRender<'a> {
     ctx: RenderContext<'a>,
-    name: hir::Name,
+    name: String,
     receiver: Option<hir::Name>,
     func: hir::Function,
     /// NB: having `ast::Fn` here might or might not be a good idea. The problem
@@ -67,7 +67,7 @@ impl<'a> FunctionRender<'a> {
         fn_: hir::Function,
         is_method: bool,
     ) -> Option<FunctionRender<'a>> {
-        let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()));
+        let name = local_name.unwrap_or_else(|| fn_.name(ctx.db())).to_string();
         let ast_node = fn_.source(ctx.db())?.value;
 
         Some(FunctionRender { ctx, name, receiver, func: fn_, ast_node, is_method })
@@ -77,7 +77,7 @@ impl<'a> FunctionRender<'a> {
         let params = self.params();
         let call = match &self.receiver {
             Some(receiver) => format!("{}.{}", receiver, &self.name),
-            None => self.name.to_string(),
+            None => self.name.clone(),
         };
         let mut item = CompletionItem::new(self.kind(), self.ctx.source_range(), call.clone());
         item.set_documentation(self.ctx.docs(self.func))
@@ -91,7 +91,7 @@ impl<'a> FunctionRender<'a> {
             let db = self.ctx.db();
             if let Some(actm) = self.func.as_assoc_item(db) {
                 if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
-                    item.trait_name(trt.name(db).to_smol_str());
+                    item.trait_name(trt.name(db).to_string());
                 }
             }
         }
@@ -99,7 +99,7 @@ impl<'a> FunctionRender<'a> {
         if let Some(import_to_add) = import_to_add {
             item.add_import(import_to_add);
         }
-        item.lookup_by(self.name.to_smol_str());
+        item.lookup_by(self.name);
 
         let ret_type = self.func.ret_type(self.ctx.db());
         item.set_relevance(CompletionRelevance {
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index 090bb5a715..b1ddfab0cb 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -2,7 +2,7 @@
 
 use hir::HasSource;
 use ide_db::SymbolKind;
-use syntax::{display::macro_label, SmolStr};
+use syntax::display::macro_label;
 
 use crate::{
     context::CallKind,
@@ -23,7 +23,7 @@ pub(crate) fn render_macro(
 #[derive(Debug)]
 struct MacroRender<'a> {
     ctx: RenderContext<'a>,
-    name: SmolStr,
+    name: String,
     macro_: hir::MacroDef,
     docs: Option<hir::Documentation>,
     bra: &'static str,
@@ -32,7 +32,7 @@ struct MacroRender<'a> {
 
 impl<'a> MacroRender<'a> {
     fn new(ctx: RenderContext<'a>, name: hir::Name, macro_: hir::MacroDef) -> MacroRender<'a> {
-        let name = name.to_smol_str();
+        let name = name.to_string();
         let docs = ctx.docs(macro_);
         let docs_str = docs.as_ref().map_or("", |s| s.as_str());
         let (bra, ket) = guess_macro_braces(&name, docs_str);
@@ -40,15 +40,17 @@ impl<'a> MacroRender<'a> {
         MacroRender { ctx, name, macro_, docs, bra, ket }
     }
 
-    fn render(self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
+    fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
         let source_range = if self.ctx.completion.is_immediately_after_macro_bang() {
             cov_mark::hit!(completes_macro_call_if_cursor_at_bang_token);
             self.ctx.completion.token.parent().map(|it| it.text_range())
         } else {
             Some(self.ctx.source_range())
         }?;
-        let mut item = CompletionItem::new(SymbolKind::Macro, source_range, self.label());
-        item.set_deprecated(self.ctx.is_deprecated(self.macro_)).set_detail(self.detail());
+        let mut item = CompletionItem::new(SymbolKind::Macro, source_range, &self.label());
+        item.set_documentation(self.docs.clone())
+            .set_deprecated(self.ctx.is_deprecated(self.macro_))
+            .set_detail(self.detail());
 
         if let Some(import_to_add) = import_to_add {
             item.add_import(import_to_add);
@@ -70,11 +72,10 @@ impl<'a> MacroRender<'a> {
             }
             _ => {
                 cov_mark::hit!(dont_insert_macro_call_parens_unncessary);
-                item.insert_text(&*self.name);
+                item.insert_text(&self.name);
             }
         };
 
-        item.set_documentation(self.docs);
         Some(item.build())
     }
 
@@ -83,18 +84,18 @@ impl<'a> MacroRender<'a> {
             && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac))
     }
 
-    fn label(&self) -> SmolStr {
+    fn label(&self) -> String {
         if self.needs_bang() && self.ctx.snippet_cap().is_some() {
-            SmolStr::from_iter([&*self.name, "!", self.bra, "…", self.ket])
+            format!("{}!{}…{}", self.name, self.bra, self.ket)
         } else if self.macro_.kind() == hir::MacroKind::Derive {
-            self.name.clone()
+            self.name.to_string()
         } else {
             self.banged_name()
         }
     }
 
-    fn banged_name(&self) -> SmolStr {
-        SmolStr::from_iter([&*self.name, "!"])
+    fn banged_name(&self) -> String {
+        format!("{}!", self.name)
     }
 
     fn detail(&self) -> Option<String> {
diff --git a/crates/ide_completion/src/render/pattern.rs b/crates/ide_completion/src/render/pattern.rs
index 888a5b4b0a..b703280620 100644
--- a/crates/ide_completion/src/render/pattern.rs
+++ b/crates/ide_completion/src/render/pattern.rs
@@ -3,7 +3,6 @@
 use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind};
 use ide_db::helpers::SnippetCap;
 use itertools::Itertools;
-use syntax::SmolStr;
 
 use crate::{
     context::{ParamKind, PatternContext},
@@ -26,7 +25,7 @@ pub(crate) fn render_struct_pat(
         return None;
     }
 
-    let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_smol_str();
+    let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_string();
     let pat = render_pat(&ctx, &name, strukt.kind(ctx.db()), &visible_fields, fields_omitted)?;
 
     Some(build_completion(ctx, name, pat, strukt))
@@ -44,8 +43,8 @@ pub(crate) fn render_variant_pat(
     let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, variant)?;
 
     let name = match &path {
-        Some(path) => path.to_string().into(),
-        None => local_name.unwrap_or_else(|| variant.name(ctx.db())).to_smol_str(),
+        Some(path) => path.to_string(),
+        None => local_name.unwrap_or_else(|| variant.name(ctx.db())).to_string(),
     };
     let pat = render_pat(&ctx, &name, variant.kind(ctx.db()), &visible_fields, fields_omitted)?;
 
@@ -54,7 +53,7 @@ pub(crate) fn render_variant_pat(
 
 fn build_completion(
     ctx: RenderContext<'_>,
-    name: SmolStr,
+    name: String,
     pat: String,
     def: impl HasAttrs + Copy,
 ) -> CompletionItem {
@@ -86,11 +85,7 @@ fn render_pat(
 
     if matches!(
         ctx.completion.pattern_ctx,
-        Some(PatternContext {
-            is_param: Some(ParamKind::Function),
-            has_type_ascription: false,
-            ..
-        })
+        Some(PatternContext { is_param: Some(ParamKind::Function), .. })
     ) {
         pat.push(':');
         pat.push(' ');
diff --git a/crates/ide_completion/src/render/struct_literal.rs b/crates/ide_completion/src/render/struct_literal.rs
index a70015dcaf..4eb4f6b9f1 100644
--- a/crates/ide_completion/src/render/struct_literal.rs
+++ b/crates/ide_completion/src/render/struct_literal.rs
@@ -3,7 +3,6 @@
 use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind};
 use ide_db::helpers::SnippetCap;
 use itertools::Itertools;
-use syntax::SmolStr;
 
 use crate::{render::RenderContext, CompletionItem, CompletionItemKind};
 
@@ -22,7 +21,7 @@ pub(crate) fn render_struct_literal(
         return None;
     }
 
-    let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_smol_str();
+    let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_string();
     let literal = render_literal(&ctx, &name, strukt.kind(ctx.db()), &visible_fields)?;
 
     Some(build_completion(ctx, name, literal, strukt))
@@ -30,15 +29,12 @@ pub(crate) fn render_struct_literal(
 
 fn build_completion(
     ctx: RenderContext<'_>,
-    name: SmolStr,
+    name: String,
     literal: String,
     def: impl HasAttrs + Copy,
 ) -> CompletionItem {
-    let mut item = CompletionItem::new(
-        CompletionItemKind::Snippet,
-        ctx.source_range(),
-        SmolStr::from_iter([&name, " {…}"]),
-    );
+    let mut item =
+        CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), name + " {…}");
     item.set_documentation(ctx.docs(def)).set_deprecated(ctx.is_deprecated(def)).detail(&literal);
     match ctx.snippet_cap() {
         Some(snippet_cap) => item.insert_snippet(snippet_cap, literal),
diff --git a/crates/ide_completion/src/render/type_alias.rs b/crates/ide_completion/src/render/type_alias.rs
index 259fe25a6c..7b6d2fa5c3 100644
--- a/crates/ide_completion/src/render/type_alias.rs
+++ b/crates/ide_completion/src/render/type_alias.rs
@@ -13,7 +13,6 @@ pub(crate) fn render_type_alias(
     ctx: RenderContext<'_>,
     type_alias: hir::TypeAlias,
 ) -> Option<CompletionItem> {
-    let _p = profile::span("render_type_alias");
     TypeAliasRender::new(ctx, type_alias)?.render(false)
 }
 
@@ -21,7 +20,6 @@ pub(crate) fn render_type_alias_with_eq(
     ctx: RenderContext<'_>,
     type_alias: hir::TypeAlias,
 ) -> Option<CompletionItem> {
-    let _p = profile::span("render_type_alias_with_eq");
     TypeAliasRender::new(ctx, type_alias)?.render(true)
 }
 
@@ -60,7 +58,7 @@ impl<'a> TypeAliasRender<'a> {
         let db = self.ctx.db();
         if let Some(actm) = self.type_alias.as_assoc_item(db) {
             if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
-                item.trait_name(trt.name(db).to_smol_str());
+                item.trait_name(trt.name(db).to_string());
                 item.insert_text(name);
             }
         }
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index e4874c7c48..5bc8e8764f 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -404,7 +404,7 @@ impl NameRefClass {
                             hir::AssocItem::TypeAlias(it) => Some(*it),
                             _ => None,
                         })
-                        .find(|alias| alias.name(sema.db).to_smol_str() == name_ref.text().as_str())
+                        .find(|alias| alias.name(sema.db).to_string() == name_ref.text())
                     {
                         return Some(NameRefClass::Definition(Definition::ModuleDef(
                             ModuleDef::TypeAlias(ty),
@@ -433,20 +433,20 @@ impl NameRefClass {
                 .find_map(ast::Attr::cast)
                 .map(|attr| attr.path().as_ref() == Some(&top_path));
             return match is_attribute_path {
-                Some(true) if path == top_path => sema
-                    .resolve_path_as_macro(&path)
-                    .filter(|mac| mac.kind() == hir::MacroKind::Attr)
-                    .map(Definition::Macro)
-                    .map(NameRefClass::Definition),
-                // in case of the path being a qualifier, don't resolve to anything but a module
-                Some(true) => match sema.resolve_path(&path)? {
-                    PathResolution::Def(module @ ModuleDef::Module(_)) => {
-                        cov_mark::hit!(name_ref_classify_attr_path_qualifier);
-                        Some(NameRefClass::Definition(Definition::ModuleDef(module)))
+                Some(true) => sema.resolve_path(&path).and_then(|resolved| {
+                    match resolved {
+                        // Don't wanna collide with builtin attributes here like `test` hence guard
+                        // so only resolve to modules that aren't the last segment
+                        PathResolution::Def(module @ ModuleDef::Module(_)) if path != top_path => {
+                            cov_mark::hit!(name_ref_classify_attr_path_qualifier);
+                            Some(NameRefClass::Definition(Definition::ModuleDef(module)))
+                        }
+                        PathResolution::Macro(mac) if mac.kind() == hir::MacroKind::Attr => {
+                            Some(NameRefClass::Definition(Definition::Macro(mac)))
+                        }
+                        _ => None,
                     }
-                    _ => None,
-                },
-                // inside attribute, but our path isn't part of the attribute's path(might be in its expression only)
+                }),
                 Some(false) => None,
                 None => sema.resolve_path(&path).map(Into::into).map(NameRefClass::Definition),
             };
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs
index 5c5dbdfb5f..f6a1a55218 100644
--- a/crates/ide_db/src/helpers.rs
+++ b/crates/ide_db/src/helpers.rs
@@ -113,7 +113,7 @@ pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
     segments.extend(
         path.segments()
             .iter()
-            .map(|segment| make::path_segment(make::name_ref(&segment.to_smol_str()))),
+            .map(|segment| make::path_segment(make::name_ref(&segment.to_string()))),
     );
     make::path_from_segments(segments, is_abs)
 }
diff --git a/crates/ide_db/src/helpers/famous_defs.rs b/crates/ide_db/src/helpers/famous_defs.rs
index fd92c64f17..e8993d327f 100644
--- a/crates/ide_db/src/helpers/famous_defs.rs
+++ b/crates/ide_db/src/helpers/famous_defs.rs
@@ -139,7 +139,7 @@ impl FamousDefs<'_, '_> {
         let krate = self.1?;
         let db = self.0.db;
         let res =
-            krate.dependencies(db).into_iter().find(|dep| dep.name.to_smol_str() == name)?.krate;
+            krate.dependencies(db).into_iter().find(|dep| dep.name.to_string() == name)?.krate;
         Some(res)
     }
 
@@ -153,7 +153,7 @@ impl FamousDefs<'_, '_> {
         for segment in path {
             module = module.children(db).find_map(|child| {
                 let name = child.name(db)?;
-                if name.to_smol_str() == segment {
+                if name.to_string() == segment {
                     Some(child)
                 } else {
                     None
@@ -161,7 +161,7 @@ impl FamousDefs<'_, '_> {
             })?;
         }
         let def =
-            module.scope(db, None).into_iter().find(|(name, _def)| name.to_smol_str() == trait_)?.1;
+            module.scope(db, None).into_iter().find(|(name, _def)| name.to_string() == trait_)?.1;
         Some(def)
     }
 }
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index 9a8adf167c..0b3ecd095b 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -410,7 +410,7 @@ fn find_import_for_segment(
     unresolved_first_segment: &str,
 ) -> Option<ItemInNs> {
     let segment_is_name = item_name(db, original_item)
-        .map(|name| name.to_smol_str() == unresolved_first_segment)
+        .map(|name| name.to_string() == unresolved_first_segment)
         .unwrap_or(false);
 
     Some(if segment_is_name {
@@ -434,7 +434,7 @@ fn module_with_segment_name(
     };
     while let Some(module) = current_module {
         if let Some(module_name) = module.name(db) {
-            if module_name.to_smol_str() == segment_name {
+            if module_name.to_string() == segment_name {
                 return Some(module);
             }
         }
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index 1f3e3c55bf..9889dd772e 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -8,7 +8,7 @@ use hir::Semantics;
 use syntax::{
     algo,
     ast::{self, make, AstNode, HasAttrs, HasModuleItem, HasVisibility, PathSegmentKind},
-    ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken,
+    match_ast, ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken,
 };
 
 use crate::{
@@ -50,10 +50,7 @@ pub enum ImportScope {
 }
 
 impl ImportScope {
-    // FIXME: Remove this?
-    #[cfg(test)]
     fn from(syntax: SyntaxNode) -> Option<Self> {
-        use syntax::match_ast;
         fn contains_cfg_attr(attrs: &dyn HasAttrs) -> bool {
             attrs
                 .attrs()
@@ -79,60 +76,16 @@ impl ImportScope {
     }
 
     /// Determines the containing syntax node in which to insert a `use` statement affecting `position`.
-    /// Returns the original source node inside attributes.
-    pub fn find_insert_use_container(
+    pub fn find_insert_use_container_with_macros(
         position: &SyntaxNode,
         sema: &Semantics<'_, RootDatabase>,
     ) -> Option<Self> {
-        fn contains_cfg_attr(attrs: &dyn HasAttrs) -> bool {
-            attrs
-                .attrs()
-                .any(|attr| attr.as_simple_call().map_or(false, |(ident, _)| ident == "cfg"))
-        }
+        sema.ancestors_with_macros(position.clone()).find_map(Self::from)
+    }
 
-        // Walk up the ancestor tree searching for a suitable node to do insertions on
-        // with special handling on cfg-gated items, in which case we want to insert imports locally
-        // or FIXME: annotate inserted imports with the same cfg
-        for syntax in sema.ancestors_with_macros(position.clone()) {
-            if let Some(file) = ast::SourceFile::cast(syntax.clone()) {
-                return Some(ImportScope::File(file));
-            } else if let Some(item) = ast::Item::cast(syntax) {
-                return match item {
-                    ast::Item::Const(konst) if contains_cfg_attr(&konst) => {
-                        // FIXME: Instead of bailing out with None, we should note down that
-                        // this import needs an attribute added
-                        match sema.original_ast_node(konst)?.body()? {
-                            ast::Expr::BlockExpr(block) => block,
-                            _ => return None,
-                        }
-                        .stmt_list()
-                        .map(ImportScope::Block)
-                    }
-                    ast::Item::Fn(func) if contains_cfg_attr(&func) => {
-                        // FIXME: Instead of bailing out with None, we should note down that
-                        // this import needs an attribute added
-                        sema.original_ast_node(func)?.body()?.stmt_list().map(ImportScope::Block)
-                    }
-                    ast::Item::Static(statik) if contains_cfg_attr(&statik) => {
-                        // FIXME: Instead of bailing out with None, we should note down that
-                        // this import needs an attribute added
-                        match sema.original_ast_node(statik)?.body()? {
-                            ast::Expr::BlockExpr(block) => block,
-                            _ => return None,
-                        }
-                        .stmt_list()
-                        .map(ImportScope::Block)
-                    }
-                    ast::Item::Module(module) => {
-                        // early return is important here, if we can't find the original module
-                        // in the input there is no way for us to insert an import anywhere.
-                        sema.original_ast_node(module)?.item_list().map(ImportScope::Module)
-                    }
-                    _ => continue,
-                };
-            }
-        }
-        None
+    /// Determines the containing syntax node in which to insert a `use` statement affecting `position`.
+    pub fn find_insert_use_container(position: &SyntaxNode) -> Option<Self> {
+        std::iter::successors(Some(position.clone()), SyntaxNode::parent).find_map(Self::from)
     }
 
     pub fn as_syntax_node(&self) -> &SyntaxNode {
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index 65deaf4d7d..7073232729 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -385,7 +385,7 @@ impl<'a> FindUsages<'a> {
             })
         });
         let name = match name {
-            Some(name) => name.to_smol_str(),
+            Some(name) => name.to_string(),
             None => return,
         };
         let name = name.as_str();
diff --git a/crates/ide_db/src/source_change.rs b/crates/ide_db/src/source_change.rs
index aa910eb325..4c2133e65b 100644
--- a/crates/ide_db/src/source_change.rs
+++ b/crates/ide_db/src/source_change.rs
@@ -54,13 +54,6 @@ impl SourceChange {
     pub fn get_source_edit(&self, file_id: FileId) -> Option<&TextEdit> {
         self.source_file_edits.get(&file_id)
     }
-
-    pub fn merge(mut self, other: SourceChange) -> SourceChange {
-        self.extend(other.source_file_edits);
-        self.extend(other.file_system_edits);
-        self.is_snippet |= other.is_snippet;
-        self
-    }
 }
 
 impl Extend<(FileId, TextEdit)> for SourceChange {
@@ -69,12 +62,6 @@ impl Extend<(FileId, TextEdit)> for SourceChange {
     }
 }
 
-impl Extend<FileSystemEdit> for SourceChange {
-    fn extend<T: IntoIterator<Item = FileSystemEdit>>(&mut self, iter: T) {
-        iter.into_iter().for_each(|edit| self.push_file_system_edit(edit));
-    }
-}
-
 impl From<FxHashMap<FileId, TextEdit>> for SourceChange {
     fn from(source_file_edits: FxHashMap<FileId, TextEdit>) -> SourceChange {
         SourceChange { source_file_edits, file_system_edits: Vec::new(), is_snippet: false }
diff --git a/crates/ide_db/src/ty_filter.rs b/crates/ide_db/src/ty_filter.rs
index 2c6b00b134..28c01d3173 100644
--- a/crates/ide_db/src/ty_filter.rs
+++ b/crates/ide_db/src/ty_filter.rs
@@ -26,7 +26,7 @@ impl TryEnum {
             _ => return None,
         };
         TryEnum::ALL.iter().find_map(|&var| {
-            if enum_.name(sema.db).to_smol_str() == var.type_name() {
+            if enum_.name(sema.db).to_string() == var.type_name() {
                 return Some(var);
             }
             None
diff --git a/crates/ide_diagnostics/src/handlers/missing_fields.rs b/crates/ide_diagnostics/src/handlers/missing_fields.rs
index 8d17a7e714..3d416591fe 100644
--- a/crates/ide_diagnostics/src/handlers/missing_fields.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_fields.rs
@@ -76,7 +76,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
             Some(make::ext::expr_todo())
         };
         let field =
-            make::record_expr_field(make::name_ref(&f.name(ctx.sema.db).to_smol_str()), field_expr)
+            make::record_expr_field(make::name_ref(&f.name(ctx.sema.db).to_string()), field_expr)
                 .clone_for_update();
         new_field_list.add_field(field);
     }
diff --git a/crates/ide_ssr/src/resolving.rs b/crates/ide_ssr/src/resolving.rs
index 84e5f82604..9cdd270b80 100644
--- a/crates/ide_ssr/src/resolving.rs
+++ b/crates/ide_ssr/src/resolving.rs
@@ -226,7 +226,7 @@ impl<'db> ResolutionScope<'db> {
                 None,
                 |_ty, assoc_item| {
                     let item_name = assoc_item.name(self.scope.db)?;
-                    if item_name.to_smol_str().as_str() == name.text() {
+                    if item_name.to_string().as_str() == name.text() {
                         Some(hir::PathResolution::AssocItem(assoc_item))
                     } else {
                         None
diff --git a/crates/ide_ssr/src/search.rs b/crates/ide_ssr/src/search.rs
index ffecffc46d..42ce85eebe 100644
--- a/crates/ide_ssr/src/search.rs
+++ b/crates/ide_ssr/src/search.rs
@@ -58,7 +58,7 @@ impl<'db> MatchFinder<'db> {
         if let Some(resolved_path) = pick_path_for_usages(pattern) {
             let definition: Definition = resolved_path.resolution.clone().into();
             for file_range in self.find_usages(usage_cache, definition).file_ranges() {
-                for node_to_match in self.find_nodes_to_match(resolved_path, file_range) {
+                if let Some(node_to_match) = self.find_node_to_match(resolved_path, file_range) {
                     if !is_search_permitted_ancestors(&node_to_match) {
                         cov_mark::hit!(use_declaration_with_braces);
                         continue;
@@ -69,45 +69,36 @@ impl<'db> MatchFinder<'db> {
         }
     }
 
-    fn find_nodes_to_match(
+    fn find_node_to_match(
         &self,
         resolved_path: &ResolvedPath,
         file_range: FileRange,
-    ) -> Vec<SyntaxNode> {
+    ) -> Option<SyntaxNode> {
         let file = self.sema.parse(file_range.file_id);
         let depth = resolved_path.depth as usize;
         let offset = file_range.range.start();
-
-        let mut paths = self
-            .sema
-            .find_nodes_at_offset_with_descend::<ast::Path>(file.syntax(), offset)
-            .peekable();
-
-        if paths.peek().is_some() {
-            paths
-                .filter_map(|path| {
-                    self.sema.ancestors_with_macros(path.syntax().clone()).nth(depth)
-                })
-                .collect::<Vec<_>>()
-        } else {
+        if let Some(path) =
+            self.sema.find_node_at_offset_with_descend::<ast::Path>(file.syntax(), offset)
+        {
+            self.sema.ancestors_with_macros(path.syntax().clone()).nth(depth)
+        } else if let Some(path) =
+            self.sema.find_node_at_offset_with_descend::<ast::MethodCallExpr>(file.syntax(), offset)
+        {
+            // If the pattern contained a path and we found a reference to that path that wasn't
+            // itself a path, but was a method call, then we need to adjust how far up to try
+            // matching by how deep the path was within a CallExpr. The structure would have been
+            // CallExpr, PathExpr, Path - i.e. a depth offset of 2. We don't need to check if the
+            // path was part of a CallExpr because if it wasn't then all that will happen is we'll
+            // fail to match, which is the desired behavior.
+            const PATH_DEPTH_IN_CALL_EXPR: usize = 2;
+            if depth < PATH_DEPTH_IN_CALL_EXPR {
+                return None;
+            }
             self.sema
-                .find_nodes_at_offset_with_descend::<ast::MethodCallExpr>(file.syntax(), offset)
-                .filter_map(|path| {
-                    // If the pattern contained a path and we found a reference to that path that wasn't
-                    // itself a path, but was a method call, then we need to adjust how far up to try
-                    // matching by how deep the path was within a CallExpr. The structure would have been
-                    // CallExpr, PathExpr, Path - i.e. a depth offset of 2. We don't need to check if the
-                    // path was part of a CallExpr because if it wasn't then all that will happen is we'll
-                    // fail to match, which is the desired behavior.
-                    const PATH_DEPTH_IN_CALL_EXPR: usize = 2;
-                    if depth < PATH_DEPTH_IN_CALL_EXPR {
-                        return None;
-                    }
-                    self.sema
-                        .ancestors_with_macros(path.syntax().clone())
-                        .nth(depth - PATH_DEPTH_IN_CALL_EXPR)
-                })
-                .collect::<Vec<_>>()
+                .ancestors_with_macros(path.syntax().clone())
+                .nth(depth - PATH_DEPTH_IN_CALL_EXPR)
+        } else {
+            None
         }
     }
 
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index 991955fca6..25178ddd77 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -75,7 +75,7 @@ pub(crate) mod entry_points {
     }
 
     pub(crate) fn visibility(p: &mut Parser) {
-        let _ = opt_visibility(p);
+        let _ = opt_visibility(p, false);
     }
 
     // Parse a meta item , which excluded [], e.g : #[ MetaItem ]
@@ -149,7 +149,7 @@ impl BlockLike {
     }
 }
 
-fn opt_visibility(p: &mut Parser) -> bool {
+fn opt_visibility(p: &mut Parser, in_tuple_field: bool) -> bool {
     match p.current() {
         T![pub] => {
             let m = p.start();
@@ -165,9 +165,17 @@ fn opt_visibility(p: &mut Parser) -> bool {
                     // struct B(pub (super::A));
                     // struct B(pub (crate::A,));
                     T![crate] | T![self] | T![super] | T![ident] if p.nth(2) != T![:] => {
-                        p.bump(T!['(']);
-                        paths::use_path(p);
-                        p.expect(T![')']);
+                        // If we are in a tuple struct, then the parens following `pub`
+                        // might be an tuple field, not part of the visibility. So in that
+                        // case we don't want to consume an identifier.
+
+                        // test pub_tuple_field
+                        // struct MyStruct(pub (u32, u32));
+                        if !(in_tuple_field && matches!(p.nth(1), T![ident])) {
+                            p.bump(T!['(']);
+                            paths::use_path(p);
+                            p.expect(T![')']);
+                        }
                     }
                     // test crate_visibility_in
                     // pub(in super::A) struct S;
diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs
index 9de9afde5d..39be0e1a19 100644
--- a/crates/parser/src/grammar/items.rs
+++ b/crates/parser/src/grammar/items.rs
@@ -87,7 +87,7 @@ pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool) {
 pub(super) fn opt_item(p: &mut Parser, m: Marker) -> Result<(), Marker> {
     // test_err pub_expr
     // fn foo() { pub 92; }
-    let has_visibility = opt_visibility(p);
+    let has_visibility = opt_visibility(p, false);
 
     let m = match opt_item_without_modifiers(p, m) {
         Ok(()) => return Ok(()),
diff --git a/crates/parser/src/grammar/items/adt.rs b/crates/parser/src/grammar/items/adt.rs
index 42ebecc6d6..c5bd5b14ba 100644
--- a/crates/parser/src/grammar/items/adt.rs
+++ b/crates/parser/src/grammar/items/adt.rs
@@ -128,7 +128,7 @@ pub(crate) fn record_field_list(p: &mut Parser) {
         // test record_field_attrs
         // struct S { #[attr] f: f32 }
         attributes::outer_attrs(p);
-        opt_visibility(p);
+        opt_visibility(p, false);
         if p.at(IDENT) {
             name(p);
             p.expect(T![:]);
@@ -150,7 +150,7 @@ fn tuple_field_list(p: &mut Parser) {
         // test tuple_field_attrs
         // struct S (#[attr] f32);
         attributes::outer_attrs(p);
-        opt_visibility(p);
+        opt_visibility(p, true);
         if !p.at_ts(types::TYPE_FIRST) {
             p.error("expected a type");
             m.complete(p, ERROR);
diff --git a/crates/proc_macro_srv/src/abis/abi_1_55/rustc_server.rs b/crates/proc_macro_srv/src/abis/abi_1_55/rustc_server.rs
index 6105238d0b..f8626c5f62 100644
--- a/crates/proc_macro_srv/src/abis/abi_1_55/rustc_server.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_55/rustc_server.rs
@@ -488,8 +488,8 @@ impl server::Literal for Rustc {
         // They must still be present to be ABI-compatible and work with upstream proc_macro.
         "".to_owned()
     }
-    fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
-        Ok(Literal { text: s.into(), id: tt::TokenId::unspecified() })
+    fn from_str(&mut self, _s: &str) -> Result<Self::Literal, ()> {
+        unimplemented!()
     }
     fn symbol(&mut self, literal: &Self::Literal) -> String {
         literal.text.to_string()
diff --git a/crates/proc_macro_srv/src/abis/abi_1_56/rustc_server.rs b/crates/proc_macro_srv/src/abis/abi_1_56/rustc_server.rs
index 1cebc289f8..fb8a4c8cbe 100644
--- a/crates/proc_macro_srv/src/abis/abi_1_56/rustc_server.rs
+++ b/crates/proc_macro_srv/src/abis/abi_1_56/rustc_server.rs
@@ -489,8 +489,8 @@ impl server::Literal for Rustc {
         // They must still be present to be ABI-compatible and work with upstream proc_macro.
         "".to_owned()
     }
-    fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
-        Ok(Literal { text: s.into(), id: tt::TokenId::unspecified() })
+    fn from_str(&mut self, _s: &str) -> Result<Self::Literal, ()> {
+        unimplemented!()
     }
     fn symbol(&mut self, literal: &Self::Literal) -> String {
         literal.text.to_string()
diff --git a/crates/project_model/src/project_json.rs b/crates/project_model/src/project_json.rs
index d8d0d07aff..75ad66a5cc 100644
--- a/crates/project_model/src/project_json.rs
+++ b/crates/project_model/src/project_json.rs
@@ -29,7 +29,6 @@ pub struct Crate {
     pub(crate) display_name: Option<CrateDisplayName>,
     pub(crate) root_module: AbsPathBuf,
     pub(crate) edition: Edition,
-    pub(crate) version: Option<String>,
     pub(crate) deps: Vec<Dependency>,
     pub(crate) cfg: Vec<CfgFlag>,
     pub(crate) target: Option<String>,
@@ -81,7 +80,6 @@ impl ProjectJson {
                             .map(CrateDisplayName::from_canonical_name),
                         root_module,
                         edition: crate_data.edition.into(),
-                        version: crate_data.version.as_ref().map(ToString::to_string),
                         deps: crate_data
                             .deps
                             .into_iter()
@@ -129,8 +127,6 @@ struct CrateData {
     display_name: Option<String>,
     root_module: PathBuf,
     edition: EditionData,
-    #[serde(default)]
-    version: Option<semver::Version>,
     deps: Vec<DepData>,
     #[serde(default)]
     cfg: Vec<CfgFlag>,
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs
index 52750f4896..415bc4c9b7 100644
--- a/crates/project_model/src/sysroot.rs
+++ b/crates/project_model/src/sysroot.rs
@@ -43,7 +43,8 @@ impl Sysroot {
         // core is added as a dependency before std in order to
         // mimic rustcs dependency order
         ["core", "alloc", "std"]
-            .into_iter()
+            .iter()
+            .copied()
             .zip(iter::repeat(true))
             .chain(iter::once(("test", false)))
             .filter_map(move |(name, prelude)| Some((name, self.by_name(name)?, prelude)))
@@ -77,7 +78,7 @@ impl Sysroot {
         for path in SYSROOT_CRATES.trim().lines() {
             let name = path.split('/').last().unwrap();
             let root = [format!("{}/src/lib.rs", path), format!("lib{}/lib.rs", path)]
-                .into_iter()
+                .iter()
                 .map(|it| sysroot.root.join(it))
                 .filter_map(|it| ManifestPath::try_from(it).ok())
                 .find(|it| fs::metadata(it).is_ok());
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 2fc88bf505..54e3bae17b 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -468,7 +468,6 @@ fn project_json_to_crate_graph(
                     file_id,
                     krate.edition,
                     krate.display_name.clone(),
-                    krate.version.clone(),
                     cfg_options.clone(),
                     cfg_options,
                     env,
@@ -676,7 +675,6 @@ fn detached_files_to_crate_graph(
             file_id,
             Edition::CURRENT,
             display_name,
-            None,
             cfg_options.clone(),
             cfg_options.clone(),
             Env::default(),
@@ -826,7 +824,6 @@ fn add_target_crate_root(
         file_id,
         edition,
         Some(display_name),
-        Some(pkg.version.to_string()),
         cfg_options,
         potential_cfg_options,
         env,
@@ -869,7 +866,6 @@ fn sysroot_to_crate_graph(
                 file_id,
                 Edition::CURRENT,
                 Some(display_name),
-                None,
                 cfg_options.clone(),
                 cfg_options.clone(),
                 env,
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index bef943464a..8e947b5540 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -8,7 +8,7 @@ use std::{sync::Arc, time::Instant};
 use crossbeam_channel::{unbounded, Receiver, Sender};
 use flycheck::FlycheckHandle;
 use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId};
-use ide_db::base_db::{CrateId, FileLoader, SourceDatabase};
+use ide_db::base_db::CrateId;
 use lsp_types::{SemanticTokens, Url};
 use parking_lot::{Mutex, RwLock};
 use proc_macro_api::ProcMacroServer;
@@ -58,7 +58,6 @@ pub(crate) struct GlobalState {
     pub(crate) mem_docs: MemDocs,
     pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
     pub(crate) shutdown_requested: bool,
-    pub(crate) proc_macro_changed: bool,
     pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
     pub(crate) source_root_config: SourceRootConfig,
     pub(crate) proc_macro_client: Option<ProcMacroServer>,
@@ -148,7 +147,6 @@ impl GlobalState {
             mem_docs: MemDocs::default(),
             semantic_tokens_cache: Arc::new(Default::default()),
             shutdown_requested: false,
-            proc_macro_changed: false,
             last_reported_status: None,
             source_root_config: SourceRootConfig::default(),
             proc_macro_client: None,
@@ -189,15 +187,6 @@ impl GlobalState {
             }
 
             for file in changed_files {
-                if !file.is_created_or_deleted() {
-                    let crates = self.analysis_host.raw_database().relevant_crates(file.file_id);
-                    let crate_graph = self.analysis_host.raw_database().crate_graph();
-
-                    if crates.iter().any(|&krate| !crate_graph[krate].proc_macro.is_empty()) {
-                        self.proc_macro_changed = true;
-                    }
-                }
-
                 if let Some(path) = vfs.file_path(file.file_id).as_path() {
                     let path = path.to_path_buf();
                     if reload::should_refresh_for_change(&path, file.change_kind) {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 8f00c6f6df..9f08ad5ebf 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -406,19 +406,7 @@ impl GlobalState {
                             // When we're running multiple flychecks, we have to include a disambiguator in
                             // the title, or the editor complains. Note that this is a user-facing string.
                             let title = if self.flycheck.len() == 1 {
-                                match self.config.flycheck() {
-                                    Some(flycheck::FlycheckConfig::CargoCommand {
-                                        command,
-                                        ..
-                                    }) => {
-                                        format!("cargo {}", command)
-                                    }
-                                    Some(flycheck::FlycheckConfig::CustomCommand {
-                                        command,
-                                        ..
-                                    }) => command,
-                                    None => "cargo check".to_string(),
-                                }
+                                "cargo check".to_string()
                             } else {
                                 format!("cargo check (#{})", id + 1)
                             };
@@ -573,7 +561,7 @@ impl GlobalState {
                 s.shutdown_requested = true;
                 Ok(())
             })?
-            .on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage)?
+            .on_sync_mut::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))?
             .on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)?
             .on_sync::<lsp_ext::OnEnter>(handlers::handle_on_enter)?
             .on_sync::<lsp_types::request::SelectionRangeRequest>(handlers::handle_selection_range)?
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 7ba5697176..6a6df9c1dd 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -66,11 +66,6 @@ impl GlobalState {
             message: None,
         };
 
-        if self.proc_macro_changed {
-            status.health = lsp_ext::Health::Warning;
-            status.message =
-                Some("Reload required due to source changes of a procedural macro.".into())
-        }
         if let Some(error) = self.fetch_build_data_error() {
             status.health = lsp_ext::Health::Warning;
             status.message = Some(error)
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index c3d08acb27..080697b96f 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -18,7 +18,7 @@ rustc_lexer = { version = "725.0.0", package = "rustc-ap-rustc_lexer" }
 rustc-hash = "1.1.0"
 once_cell = "1.3.1"
 indexmap = "1.4.0"
-smol_str = "0.1.21"
+smol_str = "0.1.15"
 
 stdx = { path = "../stdx", version = "0.0.0" }
 text_edit = { path = "../text_edit", version = "0.0.0" }
diff --git a/crates/text_edit/src/lib.rs b/crates/text_edit/src/lib.rs
index 21c622d3d6..e9700c560a 100644
--- a/crates/text_edit/src/lib.rs
+++ b/crates/text_edit/src/lib.rs
@@ -3,13 +3,12 @@
 //! `rust-analyzer` never mutates text itself and only sends diffs to clients,
 //! so `TextEdit` is the ultimate representation of the work done by
 //! rust-analyzer.
-
 pub use text_size::{TextRange, TextSize};
 
 /// `InsertDelete` -- a single "atomic" change to text
 ///
 /// Must not overlap with other `InDel`s
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone)]
 pub struct Indel {
     pub insert: String,
     /// Refers to offsets in the original text
@@ -117,14 +116,11 @@ impl TextEdit {
     pub fn union(&mut self, other: TextEdit) -> Result<(), TextEdit> {
         // FIXME: can be done without allocating intermediate vector
         let mut all = self.iter().chain(other.iter()).collect::<Vec<_>>();
-        if !check_disjoint_and_sort(&mut all) {
+        if !check_disjoint(&mut all) {
             return Err(other);
         }
-
         self.indels.extend(other.indels);
-        check_disjoint_and_sort(&mut self.indels);
-        // Only dedup deletions and replacements, keep all insertions
-        self.indels.dedup_by(|a, b| a == b && !a.delete.is_empty());
+        assert_disjoint(&mut self.indels);
         Ok(())
     }
 
@@ -177,7 +173,7 @@ impl TextEditBuilder {
     }
     pub fn finish(self) -> TextEdit {
         let mut indels = self.indels;
-        assert_disjoint_or_equal(&mut indels);
+        assert_disjoint(&mut indels);
         TextEdit { indels }
     }
     pub fn invalidates_offset(&self, offset: TextSize) -> bool {
@@ -186,20 +182,18 @@ impl TextEditBuilder {
     fn indel(&mut self, indel: Indel) {
         self.indels.push(indel);
         if self.indels.len() <= 16 {
-            assert_disjoint_or_equal(&mut self.indels);
+            assert_disjoint(&mut self.indels);
         }
     }
 }
 
-fn assert_disjoint_or_equal(indels: &mut [Indel]) {
-    assert!(check_disjoint_and_sort(indels));
+fn assert_disjoint(indels: &mut [impl std::borrow::Borrow<Indel>]) {
+    assert!(check_disjoint(indels));
 }
-// FIXME: Remove the impl Bound here, it shouldn't be needed
-fn check_disjoint_and_sort(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool {
+fn check_disjoint(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool {
     indels.sort_by_key(|indel| (indel.borrow().delete.start(), indel.borrow().delete.end()));
-    indels.iter().zip(indels.iter().skip(1)).all(|(l, r)| {
-        let l = l.borrow();
-        let r = r.borrow();
-        l.delete.end() <= r.delete.start() || l == r
-    })
+    indels
+        .iter()
+        .zip(indels.iter().skip(1))
+        .all(|(l, r)| l.borrow().delete.end() <= r.borrow().delete.start())
 }
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index ef2e9ce749..3bb9c8d8be 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -150,15 +150,12 @@ On Linux to install the `rust-analyzer` binary into `~/.local/bin`, these comman
 
 [source,bash]
 ----
-$ mkdir -p ~/.local/bin
 $ curl -L https://github.com/rust-analyzer/rust-analyzer/releases/latest/download/rust-analyzer-x86_64-unknown-linux-gnu.gz | gunzip -c - > ~/.local/bin/rust-analyzer
 $ chmod +x ~/.local/bin/rust-analyzer
 ----
 
 Make sure that `~/.local/bin` is listed in the `$PATH` variable and use the appropriate URL if you're not on a `x86-64` system.
 
-You don't have to use `~/.local/bin`, any other path like `~/.cargo/bin` or `/usr/local/bin` will work just as well.
-
 Alternatively, you can install it from source using the command below.
 You'll need the latest stable version of the Rust toolchain.
 
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index e3372574b3..0b226a985d 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -28,7 +28,7 @@
                 "glob": "^7.1.6",
                 "mocha": "^9.0.2",
                 "tslib": "^2.3.0",
-                "typescript": "^4.4.4",
+                "typescript": "^4.3.5",
                 "typescript-formatter": "^7.2.2",
                 "vsce": "^1.95.1",
                 "vscode-test": "^1.5.1"
@@ -3541,9 +3541,9 @@
             }
         },
         "node_modules/typescript": {
-            "version": "4.4.4",
-            "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
-            "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
+            "version": "4.3.5",
+            "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
+            "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
             "dev": true,
             "bin": {
                 "tsc": "bin/tsc",
@@ -6647,9 +6647,9 @@
             }
         },
         "typescript": {
-            "version": "4.4.4",
-            "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
-            "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
+            "version": "4.3.5",
+            "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
+            "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
             "dev": true
         },
         "typescript-formatter": {
diff --git a/editors/code/package.json b/editors/code/package.json
index 4c718f0b79..336081e88c 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -32,7 +32,7 @@
         "watch": "npm run build-base -- --sourcemap --watch",
         "lint": "tsfmt --verify && eslint -c .eslintrc.js --ext ts ./src ./tests",
         "fix": " tsfmt -r       && eslint -c .eslintrc.js --ext ts ./src ./tests --fix",
-        "pretest": "tsc --noEmit && npm run build",
+        "pretest": "tsc && npm run build",
         "test": "node ./out/tests/runTests.js"
     },
     "dependencies": {
diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json
index 7c4fbd21eb..c9f348241a 100644
--- a/editors/code/tsconfig.json
+++ b/editors/code/tsconfig.json
@@ -9,7 +9,6 @@
         "sourceMap": true,
         "rootDir": ".",
         "strict": true,
-        "useUnknownInCatchVariables": false,
         "noUnusedLocals": true,
         "noUnusedParameters": true,
         "noImplicitReturns": true,
diff --git a/xtask/src/install.rs b/xtask/src/install.rs
index 58f386be85..6bae5123a6 100644
--- a/xtask/src/install.rs
+++ b/xtask/src/install.rs
@@ -50,8 +50,8 @@ fn fix_path_for_mac() -> Result<()> {
         };
 
         [ROOT_DIR, &home_dir]
-            .into_iter()
-            .map(|dir| dir.to_string() + COMMON_APP_PATH)
+            .iter()
+            .map(|dir| String::from(*dir) + COMMON_APP_PATH)
             .map(PathBuf::from)
             .filter(|path| path.exists())
             .collect()


Test patch:
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index 9b1f682b61..26078a4b2f 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -1386,24 +1386,3 @@ fn f<S: Sized, T, U: ?Sized>() {
         "#]],
     );
 }
-
-#[test]
-fn local_impl() {
-    check_types(
-        r#"
-fn main() {
-    struct SomeStruct(i32);
-
-    impl SomeStruct {
-        fn is_even(&self) -> bool {
-            self.0 % 2 == 0
-        }
-    }
-
-    let o = SomeStruct(3);
-    let is_even = o.is_even();
-     // ^^^^^^^ bool
-}
-    "#,
-    );
-}
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index ab810aceca..1a10a78d24 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -43,7 +43,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="brace">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="brace">}</span><span class="semicolon">;</span>
 <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
 
-<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="module attribute">proc_macros</span><span class="operator attribute">::</span><span class="macro attribute">identity</span><span class="attribute attribute">]</span>
+<span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="module attribute">proc_macros</span><span class="operator attribute">::</span><span class="builtin_attr attribute">identity</span><span class="attribute attribute">]</span>
 <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration public">ops</span> <span class="brace">{</span>
     <span class="attribute attribute">#</span><span class="attribute attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_once"</span><span class="attribute attribute">]</span>
     <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">FnOnce</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index 5a79979533..7f3c93d740 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -2,7 +2,7 @@ mod sourcegen;
 mod generated;
 
 use expect_test::expect;
-use hir::{db::DefDatabase, Semantics};
+use hir::Semantics;
 use ide_db::{
     base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt},
     helpers::{
@@ -117,8 +117,7 @@ enum ExpectedResult<'a> {
 
 #[track_caller]
 fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label: Option<&str>) {
-    let (mut db, file_with_caret_id, range_or_offset) = RootDatabase::with_range_or_offset(before);
-    db.set_enable_proc_attr_macros(true);
+    let (db, file_with_caret_id, range_or_offset) = RootDatabase::with_range_or_offset(before);
     let text_without_caret = db.file_text(file_with_caret_id).to_string();
 
     let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() };
diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs
index 6dd1b66998..3e10575b19 100644
--- a/crates/ide_completion/src/tests/pattern.rs
+++ b/crates/ide_completion/src/tests/pattern.rs
@@ -163,21 +163,6 @@ fn foo(a$0) {
             ma makro!(…) #[macro_export] macro_rules! makro
         "##]],
     );
-    check(
-        r#"
-fn foo(a$0: Tuple) {
-}
-"#,
-        expect![[r##"
-            kw mut
-            bn Record    Record { field$1 }$0
-            st Record
-            bn Tuple     Tuple($1)$0
-            st Tuple
-            st Unit
-            ma makro!(…) #[macro_export] macro_rules! makro
-        "##]],
-    );
 }
 
 #[test]
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs
index 34a6900e26..f3b9c7130f 100644
--- a/crates/ide_db/src/helpers/insert_use/tests.rs
+++ b/crates/ide_db/src/helpers/insert_use/tests.rs
@@ -1,7 +1,5 @@
-use base_db::fixture::WithFixture;
 use hir::PrefixKind;
-use stdx::trim_indent;
-use test_utils::{assert_eq_text, CURSOR_MARKER};
+use test_utils::{assert_eq_text, extract_range_or_offset, CURSOR_MARKER};
 
 use super::*;
 
@@ -867,20 +865,17 @@ fn check_with_config(
     ra_fixture_after: &str,
     config: &InsertUseConfig,
 ) {
-    let (db, file_id, pos) = if ra_fixture_before.contains(CURSOR_MARKER) {
-        let (db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture_before);
-        (db, file_id, Some(range_or_offset))
+    let (text, pos) = if ra_fixture_before.contains(CURSOR_MARKER) {
+        let (range_or_offset, text) = extract_range_or_offset(ra_fixture_before);
+        (text, Some(range_or_offset))
     } else {
-        let (db, file_id) = RootDatabase::with_single_file(ra_fixture_before);
-        (db, file_id, None)
+        (ra_fixture_before.to_owned(), None)
     };
-    let sema = &Semantics::new(&db);
-    let source_file = sema.parse(file_id);
-    let syntax = source_file.syntax().clone_for_update();
+    let syntax = ast::SourceFile::parse(&text).tree().syntax().clone_for_update();
     let file = pos
         .and_then(|pos| syntax.token_at_offset(pos.expect_offset()).next()?.parent())
-        .and_then(|it| ImportScope::find_insert_use_container(&it, sema))
-        .or_else(|| ImportScope::from(syntax))
+        .and_then(|it| super::ImportScope::find_insert_use_container(&it))
+        .or_else(|| super::ImportScope::from(syntax))
         .unwrap();
     let path = ast::SourceFile::parse(&format!("use {};", path))
         .tree()
@@ -891,7 +886,7 @@ fn check_with_config(
 
     insert_use(&file, path, config);
     let result = file.as_syntax_node().ancestors().last().unwrap().to_string();
-    assert_eq_text!(&trim_indent(ra_fixture_after), &result);
+    assert_eq_text!(ra_fixture_after, &result);
 }
 
 fn check(
@@ -947,6 +942,6 @@ fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior
 
 fn check_guess(ra_fixture: &str, expected: ImportGranularityGuess) {
     let syntax = ast::SourceFile::parse(ra_fixture).tree().syntax().clone();
-    let file = ImportScope::from(syntax).unwrap();
+    let file = super::ImportScope::from(syntax).unwrap();
     assert_eq!(super::guess_granularity_from_scope(&file), expected);
 }
diff --git a/crates/ide_db/src/tests/sourcegen_lints.rs b/crates/ide_db/src/tests/sourcegen_lints.rs
index 3a44fab0f8..3c37aa6cb9 100644
--- a/crates/ide_db/src/tests/sourcegen_lints.rs
+++ b/crates/ide_db/src/tests/sourcegen_lints.rs
@@ -105,7 +105,7 @@ fn generate_lint_descriptor(buf: &mut String) {
 
 fn generate_feature_descriptor(buf: &mut String, src_dir: &Path) {
     let mut features = ["language-features", "library-features"]
-        .into_iter()
+        .iter()
         .flat_map(|it| sourcegen::list_files(&src_dir.join(it)))
         .filter(|path| {
             // Get all `.md ` files
diff --git a/crates/project_model/src/tests.rs b/crates/project_model/src/tests.rs
index 252acde14d..647d30605d 100644
--- a/crates/project_model/src/tests.rs
+++ b/crates/project_model/src/tests.rs
@@ -121,9 +121,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                             1,
                         ),
                         edition: Edition2018,
-                        version: Some(
-                            "0.1.0",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -181,9 +178,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                             6,
                         ),
                         edition: Edition2015,
-                        version: Some(
-                            "0.2.98",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -250,9 +244,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                             3,
                         ),
                         edition: Edition2018,
-                        version: Some(
-                            "0.1.0",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -319,9 +310,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                             5,
                         ),
                         edition: Edition2015,
-                        version: Some(
-                            "0.2.98",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -378,9 +366,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                             2,
                         ),
                         edition: Edition2018,
-                        version: Some(
-                            "0.1.0",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -447,9 +432,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                             7,
                         ),
                         edition: Edition2015,
-                        version: Some(
-                            "0.2.98",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -506,9 +488,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
                             4,
                         ),
                         edition: Edition2018,
-                        version: Some(
-                            "0.1.0",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -597,9 +576,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                             1,
                         ),
                         edition: Edition2018,
-                        version: Some(
-                            "0.1.0",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -659,9 +635,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                             6,
                         ),
                         edition: Edition2015,
-                        version: Some(
-                            "0.2.98",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -728,9 +701,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                             3,
                         ),
                         edition: Edition2018,
-                        version: Some(
-                            "0.1.0",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -799,9 +769,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                             5,
                         ),
                         edition: Edition2015,
-                        version: Some(
-                            "0.2.98",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -858,9 +825,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                             2,
                         ),
                         edition: Edition2018,
-                        version: Some(
-                            "0.1.0",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -929,9 +893,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                             7,
                         ),
                         edition: Edition2015,
-                        version: Some(
-                            "0.2.98",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -988,9 +949,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
                             4,
                         ),
                         edition: Edition2018,
-                        version: Some(
-                            "0.1.0",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1072,9 +1030,6 @@ fn cargo_hello_world_project_model() {
                             1,
                         ),
                         edition: Edition2018,
-                        version: Some(
-                            "0.1.0",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1134,9 +1089,6 @@ fn cargo_hello_world_project_model() {
                             6,
                         ),
                         edition: Edition2015,
-                        version: Some(
-                            "0.2.98",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1205,9 +1157,6 @@ fn cargo_hello_world_project_model() {
                             3,
                         ),
                         edition: Edition2018,
-                        version: Some(
-                            "0.1.0",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1276,9 +1225,6 @@ fn cargo_hello_world_project_model() {
                             5,
                         ),
                         edition: Edition2015,
-                        version: Some(
-                            "0.2.98",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1337,9 +1283,6 @@ fn cargo_hello_world_project_model() {
                             2,
                         ),
                         edition: Edition2018,
-                        version: Some(
-                            "0.1.0",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1408,9 +1351,6 @@ fn cargo_hello_world_project_model() {
                             7,
                         ),
                         edition: Edition2015,
-                        version: Some(
-                            "0.2.98",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1469,9 +1409,6 @@ fn cargo_hello_world_project_model() {
                             4,
                         ),
                         edition: Edition2018,
-                        version: Some(
-                            "0.1.0",
-                        ),
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1553,7 +1490,6 @@ fn rust_project_hello_world_project_model() {
                             1,
                         ),
                         edition: Edition2018,
-                        version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1591,7 +1527,6 @@ fn rust_project_hello_world_project_model() {
                             11,
                         ),
                         edition: Edition2018,
-                        version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1619,7 +1554,6 @@ fn rust_project_hello_world_project_model() {
                             8,
                         ),
                         edition: Edition2018,
-                        version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1647,7 +1581,6 @@ fn rust_project_hello_world_project_model() {
                             5,
                         ),
                         edition: Edition2018,
-                        version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1685,7 +1618,6 @@ fn rust_project_hello_world_project_model() {
                             2,
                         ),
                         edition: Edition2018,
-                        version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1713,7 +1645,6 @@ fn rust_project_hello_world_project_model() {
                             12,
                         ),
                         edition: Edition2018,
-                        version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1778,7 +1709,6 @@ fn rust_project_hello_world_project_model() {
                             9,
                         ),
                         edition: Edition2018,
-                        version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1806,7 +1736,6 @@ fn rust_project_hello_world_project_model() {
                             6,
                         ),
                         edition: Edition2018,
-                        version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1834,7 +1763,6 @@ fn rust_project_hello_world_project_model() {
                             3,
                         ),
                         edition: Edition2018,
-                        version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1862,7 +1790,6 @@ fn rust_project_hello_world_project_model() {
                             10,
                         ),
                         edition: Edition2018,
-                        version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -1890,7 +1817,6 @@ fn rust_project_hello_world_project_model() {
                             7,
                         ),
                         edition: Edition2018,
-                        version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
@@ -2000,7 +1926,6 @@ fn rust_project_hello_world_project_model() {
                             4,
                         ),
                         edition: Edition2018,
-                        version: None,
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt b/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt
index fd04163de9..a9c0edcf9f 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt
@@ -23,7 +23,9 @@
                 },
             },
             severity: Some(
-                Warning,
+                DiagnosticSeverity(
+                    2,
+                ),
             ),
             code: Some(
                 String(
@@ -140,7 +142,9 @@
                 },
             },
             severity: Some(
-                Hint,
+                DiagnosticSeverity(
+                    4,
+                ),
             ),
             code: Some(
                 String(
@@ -231,7 +235,9 @@
                 },
             },
             severity: Some(
-                Hint,
+                DiagnosticSeverity(
+                    4,
+                ),
             ),
             code: Some(
                 String(
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt b/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt
index a7f936a703..fd69097d05 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt
@@ -23,7 +23,9 @@
                 },
             },
             severity: Some(
-                Error,
+                DiagnosticSeverity(
+                    1,
+                ),
             ),
             code: Some(
                 String(
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt
index 8bee4cfe10..1c25a3ed69 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt
@@ -23,7 +23,9 @@
                 },
             },
             severity: Some(
-                Hint,
+                DiagnosticSeverity(
+                    4,
+                ),
             ),
             code: None,
             code_description: None,
@@ -90,7 +92,9 @@
                 },
             },
             severity: Some(
-                Hint,
+                DiagnosticSeverity(
+                    4,
+                ),
             ),
             code: None,
             code_description: None,
@@ -157,7 +161,9 @@
                 },
             },
             severity: Some(
-                Error,
+                DiagnosticSeverity(
+                    1,
+                ),
             ),
             code: None,
             code_description: None,
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt
index afc562a0e2..653fb0130d 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt
@@ -23,7 +23,9 @@
                 },
             },
             severity: Some(
-                Error,
+                DiagnosticSeverity(
+                    1,
+                ),
             ),
             code: Some(
                 String(
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt
index 05074a914b..f37e416b7b 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt
@@ -23,7 +23,9 @@
                 },
             },
             severity: Some(
-                Error,
+                DiagnosticSeverity(
+                    1,
+                ),
             ),
             code: Some(
                 String(
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt
index 3ded70411d..df73efe5f8 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt
@@ -23,7 +23,9 @@
                 },
             },
             severity: Some(
-                Warning,
+                DiagnosticSeverity(
+                    2,
+                ),
             ),
             code: Some(
                 String(
@@ -67,7 +69,9 @@
             ),
             tags: Some(
                 [
-                    Unnecessary,
+                    DiagnosticTag(
+                        1,
+                    ),
                 ],
             ),
             data: None,
@@ -98,7 +102,9 @@
                 },
             },
             severity: Some(
-                Hint,
+                DiagnosticSeverity(
+                    4,
+                ),
             ),
             code: Some(
                 String(
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt
index 0993aa1af1..ad22a34d67 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt
@@ -23,7 +23,9 @@
                 },
             },
             severity: Some(
-                Hint,
+                DiagnosticSeverity(
+                    4,
+                ),
             ),
             code: Some(
                 String(
@@ -67,7 +69,9 @@
             ),
             tags: Some(
                 [
-                    Unnecessary,
+                    DiagnosticTag(
+                        1,
+                    ),
                 ],
             ),
             data: None,
@@ -98,7 +102,9 @@
                 },
             },
             severity: Some(
-                Hint,
+                DiagnosticSeverity(
+                    4,
+                ),
             ),
             code: Some(
                 String(
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt
index d7a974ae57..1072d8a177 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt
@@ -23,7 +23,9 @@
                 },
             },
             severity: Some(
-                Information,
+                DiagnosticSeverity(
+                    3,
+                ),
             ),
             code: Some(
                 String(
@@ -67,7 +69,9 @@
             ),
             tags: Some(
                 [
-                    Unnecessary,
+                    DiagnosticTag(
+                        1,
+                    ),
                 ],
             ),
             data: None,
@@ -98,7 +102,9 @@
                 },
             },
             severity: Some(
-                Hint,
+                DiagnosticSeverity(
+                    4,
+                ),
             ),
             code: Some(
                 String(
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt
index 5ea27a1527..3e043666aa 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt
@@ -23,7 +23,9 @@
                 },
             },
             severity: Some(
-                Error,
+                DiagnosticSeverity(
+                    1,
+                ),
             ),
             code: Some(
                 String(
@@ -114,7 +116,9 @@
                 },
             },
             severity: Some(
-                Hint,
+                DiagnosticSeverity(
+                    4,
+                ),
             ),
             code: Some(
                 String(
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt
index f77abde515..67e442d73d 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt
@@ -23,7 +23,9 @@
                 },
             },
             severity: Some(
-                Warning,
+                DiagnosticSeverity(
+                    2,
+                ),
             ),
             code: Some(
                 String(
@@ -140,7 +142,9 @@
                 },
             },
             severity: Some(
-                Hint,
+                DiagnosticSeverity(
+                    4,
+                ),
             ),
             code: Some(
                 String(
@@ -231,7 +235,9 @@
                 },
             },
             severity: Some(
-                Hint,
+                DiagnosticSeverity(
+                    4,
+                ),
             ),
             code: Some(
                 String(
diff --git a/crates/rust-analyzer/tests/slow-tests/support.rs b/crates/rust-analyzer/tests/slow-tests/support.rs
index a8c2a5bb61..99ae418f7c 100644
--- a/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -212,8 +212,8 @@ impl Server {
                     if req.method == "client/registerCapability" {
                         let params = req.params.to_string();
                         if ["workspace/didChangeWatchedFiles", "textDocument/didSave"]
-                            .into_iter()
-                            .any(|it| params.contains(it))
+                            .iter()
+                            .any(|&it| params.contains(it))
                         {
                             continue;
                         }
diff --git a/crates/syntax/test_data/parser/inline/ok/0196_pub_tuple_field.rast b/crates/syntax/test_data/parser/inline/ok/0196_pub_tuple_field.rast
new file mode 100644
index 0000000000..8a1f5903d2
--- /dev/null
+++ b/crates/syntax/test_data/parser/inline/ok/0196_pub_tuple_field.rast
@@ -0,0 +1,30 @@
+SOURCE_FILE@0..33
+  STRUCT@0..32
+    STRUCT_KW@0..6 "struct"
+    WHITESPACE@6..7 " "
+    NAME@7..15
+      IDENT@7..15 "MyStruct"
+    TUPLE_FIELD_LIST@15..31
+      L_PAREN@15..16 "("
+      TUPLE_FIELD@16..30
+        VISIBILITY@16..19
+          PUB_KW@16..19 "pub"
+        WHITESPACE@19..20 " "
+        TUPLE_TYPE@20..30
+          L_PAREN@20..21 "("
+          PATH_TYPE@21..24
+            PATH@21..24
+              PATH_SEGMENT@21..24
+                NAME_REF@21..24
+                  IDENT@21..24 "u32"
+          COMMA@24..25 ","
+          WHITESPACE@25..26 " "
+          PATH_TYPE@26..29
+            PATH@26..29
+              PATH_SEGMENT@26..29
+                NAME_REF@26..29
+                  IDENT@26..29 "u32"
+          R_PAREN@29..30 ")"
+      R_PAREN@30..31 ")"
+    SEMICOLON@31..32 ";"
+  WHITESPACE@32..33 "\n"
diff --git a/crates/syntax/test_data/parser/inline/ok/0196_pub_tuple_field.rs b/crates/syntax/test_data/parser/inline/ok/0196_pub_tuple_field.rs
new file mode 100644
index 0000000000..00d8feba96
--- /dev/null
+++ b/crates/syntax/test_data/parser/inline/ok/0196_pub_tuple_field.rs
@@ -0,0 +1,1 @@
+struct MyStruct(pub (u32, u32));
diff --git a/editors/code/tests/unit/launch_config.test.ts b/editors/code/tests/unit/launch_config.test.ts
index e53ae5ce9e..68794d53ed 100644
--- a/editors/code/tests/unit/launch_config.test.ts
+++ b/editors/code/tests/unit/launch_config.test.ts
@@ -7,22 +7,22 @@ suite('Launch configuration', () => {
         test('A binary', async () => {
             const args = Cargo.artifactSpec(["build", "--package", "pkg_name", "--bin", "pkg_name"]);
 
-            assert.deepStrictEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "pkg_name", "--message-format=json"]);
-            assert.deepStrictEqual(args.filter, undefined);
+            assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "pkg_name", "--message-format=json"]);
+            assert.deepEqual(args.filter, undefined);
         });
 
         test('One of Multiple Binaries', async () => {
             const args = Cargo.artifactSpec(["build", "--package", "pkg_name", "--bin", "bin1"]);
 
-            assert.deepStrictEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "bin1", "--message-format=json"]);
-            assert.deepStrictEqual(args.filter, undefined);
+            assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "bin1", "--message-format=json"]);
+            assert.deepEqual(args.filter, undefined);
         });
 
         test('A test', async () => {
             const args = Cargo.artifactSpec(["test", "--package", "pkg_name", "--lib", "--no-run"]);
 
-            assert.deepStrictEqual(args.cargoArgs, ["test", "--package", "pkg_name", "--lib", "--no-run", "--message-format=json"]);
-            assert.notDeepStrictEqual(args.filter, undefined);
+            assert.deepEqual(args.cargoArgs, ["test", "--package", "pkg_name", "--lib", "--no-run", "--message-format=json"]);
+            assert.notDeepEqual(args.filter, undefined);
         });
     });
 
@@ -30,23 +30,23 @@ suite('Launch configuration', () => {
         test('A binary', async () => {
             const args = Cargo.artifactSpec(["run", "--package", "pkg_name", "--bin", "pkg_name"]);
 
-            assert.deepStrictEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "pkg_name", "--message-format=json"]);
-            assert.deepStrictEqual(args.filter, undefined);
+            assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "pkg_name", "--message-format=json"]);
+            assert.deepEqual(args.filter, undefined);
         });
 
 
         test('One of Multiple Binaries', async () => {
             const args = Cargo.artifactSpec(["run", "--package", "pkg_name", "--bin", "bin2"]);
 
-            assert.deepStrictEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "bin2", "--message-format=json"]);
-            assert.deepStrictEqual(args.filter, undefined);
+            assert.deepEqual(args.cargoArgs, ["build", "--package", "pkg_name", "--bin", "bin2", "--message-format=json"]);
+            assert.deepEqual(args.filter, undefined);
         });
 
         test('A test', async () => {
             const args = Cargo.artifactSpec(["test", "--package", "pkg_name", "--lib"]);
 
-            assert.deepStrictEqual(args.cargoArgs, ["test", "--package", "pkg_name", "--lib", "--message-format=json", "--no-run"]);
-            assert.notDeepStrictEqual(args.filter, undefined);
+            assert.deepEqual(args.cargoArgs, ["test", "--package", "pkg_name", "--lib", "--message-format=json", "--no-run"]);
+            assert.notDeepEqual(args.filter, undefined);
         });
     });
 });
diff --git a/editors/code/tests/unit/runnable_env.test.ts b/editors/code/tests/unit/runnable_env.test.ts
index d5f522dd11..c5600cf64f 100644
--- a/editors/code/tests/unit/runnable_env.test.ts
+++ b/editors/code/tests/unit/runnable_env.test.ts
@@ -23,10 +23,10 @@ function fakePrepareEnv(runnableName: string, config: RunnableEnvCfg): Record<st
 suite('Runnable env', () => {
     test('Global config works', () => {
         const binEnv = fakePrepareEnv("run project_name", { "GLOBAL": "g" });
-        assert.strictEqual(binEnv["GLOBAL"], "g");
+        assert.equal(binEnv["GLOBAL"], "g");
 
         const testEnv = fakePrepareEnv("test some::mod::test_name", { "GLOBAL": "g" });
-        assert.strictEqual(testEnv["GLOBAL"], "g");
+        assert.equal(testEnv["GLOBAL"], "g");
     });
 
     test('null mask works', () => {
@@ -36,10 +36,10 @@ suite('Runnable env', () => {
             }
         ];
         const binEnv = fakePrepareEnv("run project_name", config);
-        assert.strictEqual(binEnv["DATA"], "data");
+        assert.equal(binEnv["DATA"], "data");
 
         const testEnv = fakePrepareEnv("test some::mod::test_name", config);
-        assert.strictEqual(testEnv["DATA"], "data");
+        assert.equal(testEnv["DATA"], "data");
     });
 
     test('order works', () => {
@@ -52,10 +52,10 @@ suite('Runnable env', () => {
             }
         ];
         const binEnv = fakePrepareEnv("run project_name", config);
-        assert.strictEqual(binEnv["DATA"], "newdata");
+        assert.equal(binEnv["DATA"], "newdata");
 
         const testEnv = fakePrepareEnv("test some::mod::test_name", config);
-        assert.strictEqual(testEnv["DATA"], "newdata");
+        assert.equal(testEnv["DATA"], "newdata");
     });
 
     test('mask works', () => {
@@ -73,13 +73,13 @@ suite('Runnable env', () => {
             }
         ];
         const binEnv = fakePrepareEnv("run project_name", config);
-        assert.strictEqual(binEnv["DATA"], "rundata");
+        assert.equal(binEnv["DATA"], "rundata");
 
         const testEnv = fakePrepareEnv("test some::mod::test_name", config);
-        assert.strictEqual(testEnv["DATA"], "data");
+        assert.equal(testEnv["DATA"], "data");
 
         const specialTestEnv = fakePrepareEnv("test some::mod::special_test", config);
-        assert.strictEqual(specialTestEnv["DATA"], "special_test");
+        assert.equal(specialTestEnv["DATA"], "special_test");
     });
 
     test('exact test name works', () => {
@@ -93,10 +93,10 @@ suite('Runnable env', () => {
             }
         ];
         const testEnv = fakePrepareEnv("test some::mod::test_name", config);
-        assert.strictEqual(testEnv["DATA"], "test special");
+        assert.equal(testEnv["DATA"], "test special");
 
         const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config);
-        assert.strictEqual(specialTestEnv["DATA"], "data");
+        assert.equal(specialTestEnv["DATA"], "data");
     });
 
     test('test mod name works', () => {
@@ -110,10 +110,10 @@ suite('Runnable env', () => {
             }
         ];
         const testEnv = fakePrepareEnv("test some::mod::test_name", config);
-        assert.strictEqual(testEnv["DATA"], "mod special");
+        assert.equal(testEnv["DATA"], "mod special");
 
         const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config);
-        assert.strictEqual(specialTestEnv["DATA"], "mod special");
+        assert.equal(specialTestEnv["DATA"], "mod special");
     });
 
 });