Repository: rust-lang/rust-analyzer
Pull request #13058 (2022-08-18 22:16:11)

Add a new configuration settings to set env vars when running cargo, rustc, etc. commands: cargo.extraEnv and checkOnSave.extraEnv
It can be extremely useful to be able to set environment variables when rust-analyzer is running various cargo or rustc commands (such as `cargo check`, `cargo --print cfg` or `cargo metadata`): users may want to set custom `RUSTFLAGS`, change `PATH` to use a custom toolchain or set a different `CARGO_HOME`.

There is the existing `server.extraEnv` setting that allows env vars to be set when the rust-analyzer server is launched, but using this as the recommended mechanism to also configure cargo/rust has some drawbacks:
- It convolutes configuring the rust-analyzer server with configuring cargo/rustc (one may want to change the `PATH` for cargo/rustc without affecting the rust-analyzer server).
- The name `server.extraEnv` doesn't indicate that cargo/rustc will be affected but renaming it to `cargo.extraEnv` doesn't indicate that the rust-analyzer server would be affected.
- To make the setting useful, it needs to be dynamically reloaded without requiring that the entire extension is reloaded. It might be possible to do this, but it would require the client communicating to the server what the overwritten env vars were at first launch, which isn't easy to do.

This change adds two new configuration settings: `cargo.extraEnv` and `checkOnSave.extraEnv` that can be used to change the environment for the rust-analyzer server after launch (thus affecting any process that rust-analyzer invokes) and the `cargo check` command respectively. `cargo.extraEnv` supports dynamic changes by keeping track of the pre-change values of environment variables, thus it can undo changes made previously before applying the new configuration (and then requesting a workspace reload).


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 9f10d92c4e..8c6d25f7e8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -394,6 +394,7 @@ dependencies = [
  "crossbeam-channel",
  "jod-thread",
  "paths",
+ "rustc-hash",
  "serde",
  "serde_json",
  "stdx",
diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml
index d3d180ece5..688e790c53 100644
--- a/crates/flycheck/Cargo.toml
+++ b/crates/flycheck/Cargo.toml
@@ -13,6 +13,7 @@ doctest = false
 crossbeam-channel = "0.5.5"
 tracing = "0.1.35"
 cargo_metadata = "0.15.0"
+rustc-hash = "1.1.0"
 serde = { version = "1.0.137", features = ["derive"] }
 serde_json = "1.0.81"
 jod-thread = "0.1.2"
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index d9f4ef5b7f..fdc03f4053 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -12,6 +12,7 @@ use std::{
 
 use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
 use paths::AbsPathBuf;
+use rustc_hash::FxHashMap;
 use serde::Deserialize;
 use stdx::{process::streaming_output, JodChild};
 
@@ -30,10 +31,12 @@ pub enum FlycheckConfig {
         all_features: bool,
         features: Vec<String>,
         extra_args: Vec<String>,
+        extra_env: FxHashMap<String, String>,
     },
     CustomCommand {
         command: String,
         args: Vec<String>,
+        extra_env: FxHashMap<String, String>,
     },
 }
 
@@ -41,7 +44,7 @@ impl fmt::Display for FlycheckConfig {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             FlycheckConfig::CargoCommand { command, .. } => write!(f, "cargo {}", command),
-            FlycheckConfig::CustomCommand { command, args } => {
+            FlycheckConfig::CustomCommand { command, args, .. } => {
                 write!(f, "{} {}", command, args.join(" "))
             }
         }
@@ -256,6 +259,7 @@ impl FlycheckActor {
                 all_features,
                 extra_args,
                 features,
+                extra_env,
             } => {
                 let mut cmd = Command::new(toolchain::cargo());
                 cmd.arg(command);
@@ -281,11 +285,13 @@ impl FlycheckActor {
                     }
                 }
                 cmd.args(extra_args);
+                cmd.envs(extra_env);
                 cmd
             }
-            FlycheckConfig::CustomCommand { command, args } => {
+            FlycheckConfig::CustomCommand { command, args, extra_env } => {
                 let mut cmd = Command::new(command);
                 cmd.args(args);
+                cmd.envs(extra_env);
                 cmd
             }
         };
diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs
index b94b500040..f46054e8cc 100644
--- a/crates/hir-def/src/find_path.rs
+++ b/crates/hir-def/src/find_path.rs
@@ -1,6 +1,6 @@
 //! An algorithm to find a path to refer to a certain item.
 
-use std::{cmp::Ordering, iter};
+use std::iter;
 
 use hir_expand::name::{known, AsName, Name};
 use rustc_hash::FxHashSet;
@@ -20,10 +20,10 @@ pub fn find_path(
     db: &dyn DefDatabase,
     item: ItemInNs,
     from: ModuleId,
-    prefer_no_std: bool,
+    prefer_core: bool,
 ) -> Option<ModPath> {
     let _p = profile::span("find_path");
-    find_path_inner(db, item, from, None, prefer_no_std)
+    find_path_inner(db, item, from, None, prefer_core)
 }
 
 pub fn find_path_prefixed(
@@ -31,14 +31,48 @@ pub fn find_path_prefixed(
     item: ItemInNs,
     from: ModuleId,
     prefix_kind: PrefixKind,
-    prefer_no_std: bool,
+    prefer_core: bool,
 ) -> Option<ModPath> {
     let _p = profile::span("find_path_prefixed");
-    find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std)
+    find_path_inner(db, item, from, Some(prefix_kind), prefer_core)
 }
 
 const MAX_PATH_LEN: usize = 15;
 
+trait ModPathExt {
+    fn starts_with_std(&self) -> bool;
+    fn can_start_with_std(&self) -> bool;
+}
+
+impl ModPathExt for ModPath {
+    fn starts_with_std(&self) -> bool {
+        self.segments().first() == Some(&known::std)
+    }
+
+    // Can we replace the first segment with `std::` and still get a valid, identical path?
+    fn can_start_with_std(&self) -> bool {
+        let first_segment = self.segments().first();
+        first_segment == Some(&known::alloc) || first_segment == Some(&known::core)
+    }
+}
+
+fn check_self_super(def_map: &DefMap, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
+    if item == ItemInNs::Types(from.into()) {
+        // - if the item is the module we're in, use `self`
+        Some(ModPath::from_segments(PathKind::Super(0), None))
+    } else if let Some(parent_id) = def_map[from.local_id].parent {
+        // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
+        let parent_id = def_map.module_id(parent_id);
+        if item == ItemInNs::Types(ModuleDefId::ModuleId(parent_id)) {
+            Some(ModPath::from_segments(PathKind::Super(1), None))
+        } else {
+            None
+        }
+    } else {
+        None
+    }
+}
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum PrefixKind {
     /// Causes paths to always start with either `self`, `super`, `crate` or a crate-name.
@@ -66,247 +100,149 @@ impl PrefixKind {
         self == &PrefixKind::ByCrate
     }
 }
-
 /// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
 fn find_path_inner(
     db: &dyn DefDatabase,
     item: ItemInNs,
     from: ModuleId,
     prefixed: Option<PrefixKind>,
-    prefer_no_std: bool,
+    prefer_core: bool,
 ) -> Option<ModPath> {
-    // - if the item is a builtin, it's in scope
-    if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
-        return Some(ModPath::from_segments(PathKind::Plain, Some(builtin.as_name())));
-    }
-
-    let def_map = from.def_map(db);
-    let crate_root = def_map.crate_root(db);
-    // - if the item is a module, jump straight to module search
-    if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
-        let mut visited_modules = FxHashSet::default();
-        return find_path_for_module(
-            db,
-            &def_map,
-            &mut visited_modules,
-            crate_root,
-            from,
-            module_id,
-            MAX_PATH_LEN,
-            prefixed,
-            prefer_no_std || db.crate_supports_no_std(crate_root.krate),
-        );
-    }
-
-    // - if the item is already in scope, return the name under which it is
-    let scope_name = find_in_scope(db, &def_map, from, item);
-    if prefixed.is_none() {
-        if let Some(scope_name) = scope_name {
-            return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name)));
-        }
-    }
-
-    // - if the item is in the prelude, return the name from there
-    if let Some(value) = find_in_prelude(db, &crate_root.def_map(db), item, from) {
-        return value;
-    }
-
-    if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
-        // - if the item is an enum variant, refer to it via the enum
-        if let Some(mut path) = find_path_inner(
-            db,
-            ItemInNs::Types(variant.parent.into()),
-            from,
-            prefixed,
-            prefer_no_std,
-        ) {
-            let data = db.enum_data(variant.parent);
-            path.push_segment(data.variants[variant.local_id].name.clone());
-            return Some(path);
-        }
-        // If this doesn't work, it seems we have no way of referring to the
-        // enum; that's very weird, but there might still be a reexport of the
-        // variant somewhere
-    }
+    // FIXME: Do fast path for std/core libs?
 
     let mut visited_modules = FxHashSet::default();
-
-    calculate_best_path(
+    let def_map = from.def_map(db);
+    find_path_inner_(
         db,
         &def_map,
-        &mut visited_modules,
-        crate_root,
-        MAX_PATH_LEN,
-        item,
         from,
+        item,
+        MAX_PATH_LEN,
         prefixed,
-        prefer_no_std || db.crate_supports_no_std(crate_root.krate),
-        scope_name,
+        &mut visited_modules,
+        prefer_core,
     )
 }
 
-fn find_path_for_module(
+fn find_path_inner_(
     db: &dyn DefDatabase,
     def_map: &DefMap,
-    visited_modules: &mut FxHashSet<ModuleId>,
-    crate_root: ModuleId,
     from: ModuleId,
-    module_id: ModuleId,
+    item: ItemInNs,
     max_len: usize,
-    prefixed: Option<PrefixKind>,
-    prefer_no_std: bool,
+    mut prefixed: Option<PrefixKind>,
+    visited_modules: &mut FxHashSet<ModuleId>,
+    prefer_core: bool,
 ) -> Option<ModPath> {
     if max_len == 0 {
         return None;
     }
 
     // Base cases:
+
     // - if the item is already in scope, return the name under which it is
-    let scope_name = find_in_scope(db, def_map, from, ItemInNs::Types(module_id.into()));
+    let scope_name = def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
+        def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone())
+    });
     if prefixed.is_none() {
         if let Some(scope_name) = scope_name {
             return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name)));
         }
     }
 
+    // - if the item is a builtin, it's in scope
+    if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
+        return Some(ModPath::from_segments(PathKind::Plain, Some(builtin.as_name())));
+    }
+
     // - if the item is the crate root, return `crate`
-    if module_id == crate_root {
+    let crate_root = def_map.crate_root(db);
+    if item == ItemInNs::Types(ModuleDefId::ModuleId(crate_root)) {
         return Some(ModPath::from_segments(PathKind::Crate, None));
     }
 
-    // - if relative paths are fine, check if we are searching for a parent
     if prefixed.filter(PrefixKind::is_absolute).is_none() {
-        if let modpath @ Some(_) = find_self_super(&def_map, module_id, from) {
+        if let modpath @ Some(_) = check_self_super(&def_map, item, from) {
             return modpath;
         }
     }
 
     // - if the item is the crate root of a dependency crate, return the name from the extern prelude
     let root_def_map = crate_root.def_map(db);
-    for (name, &def_id) in root_def_map.extern_prelude() {
-        if module_id == def_id {
-            let name = scope_name.unwrap_or_else(|| name.clone());
-
-            let name_already_occupied_in_type_ns = def_map
-                .with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
-                    def_map[local_id]
-                        .scope
-                        .type_(&name)
-                        .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id))
-                })
-                .is_some();
-            let kind = if name_already_occupied_in_type_ns {
-                cov_mark::hit!(ambiguous_crate_start);
-                PathKind::Abs
-            } else {
-                PathKind::Plain
-            };
-            return Some(ModPath::from_segments(kind, Some(name)));
+    if let ItemInNs::Types(ModuleDefId::ModuleId(item)) = item {
+        for (name, &def_id) in root_def_map.extern_prelude() {
+            if item == def_id {
+                let name = scope_name.unwrap_or_else(|| name.clone());
+
+                let name_already_occupied_in_type_ns = def_map
+                    .with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
+                        def_map[local_id]
+                            .scope
+                            .type_(&name)
+                            .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id))
+                    })
+                    .is_some();
+                let kind = if name_already_occupied_in_type_ns {
+                    cov_mark::hit!(ambiguous_crate_start);
+                    PathKind::Abs
+                } else {
+                    PathKind::Plain
+                };
+                return Some(ModPath::from_segments(kind, Some(name)));
+            }
         }
     }
 
-    if let Some(value) = find_in_prelude(db, &root_def_map, ItemInNs::Types(module_id.into()), from)
-    {
-        return value;
-    }
-    calculate_best_path(
-        db,
-        def_map,
-        visited_modules,
-        crate_root,
-        max_len,
-        ItemInNs::Types(module_id.into()),
-        from,
-        prefixed,
-        prefer_no_std,
-        scope_name,
-    )
-}
-
-fn find_in_scope(
-    db: &dyn DefDatabase,
-    def_map: &DefMap,
-    from: ModuleId,
-    item: ItemInNs,
-) -> Option<Name> {
-    def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
-        def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone())
-    })
-}
-
-fn find_in_prelude(
-    db: &dyn DefDatabase,
-    root_def_map: &DefMap,
-    item: ItemInNs,
-    from: ModuleId,
-) -> Option<Option<ModPath>> {
+    // - if the item is in the prelude, return the name from there
     if let Some(prelude_module) = root_def_map.prelude() {
         // Preludes in block DefMaps are ignored, only the crate DefMap is searched
         let prelude_def_map = prelude_module.def_map(db);
         let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
         if let Some((name, vis)) = prelude_scope.name_of(item) {
             if vis.is_visible_from(db, from) {
-                return Some(Some(ModPath::from_segments(PathKind::Plain, Some(name.clone()))));
+                return Some(ModPath::from_segments(PathKind::Plain, Some(name.clone())));
             }
         }
     }
-    None
-}
 
-fn find_self_super(def_map: &DefMap, item: ModuleId, from: ModuleId) -> Option<ModPath> {
-    if item == from {
-        // - if the item is the module we're in, use `self`
-        Some(ModPath::from_segments(PathKind::Super(0), None))
-    } else if let Some(parent_id) = def_map[from.local_id].parent {
-        // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
-        let parent_id = def_map.module_id(parent_id);
-        if item == parent_id {
-            Some(ModPath::from_segments(PathKind::Super(1), None))
-        } else {
-            None
+    // Recursive case:
+    // - if the item is an enum variant, refer to it via the enum
+    if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
+        if let Some(mut path) =
+            find_path(db, ItemInNs::Types(variant.parent.into()), from, prefer_core)
+        {
+            let data = db.enum_data(variant.parent);
+            path.push_segment(data.variants[variant.local_id].name.clone());
+            return Some(path);
         }
-    } else {
-        None
+        // If this doesn't work, it seems we have no way of referring to the
+        // enum; that's very weird, but there might still be a reexport of the
+        // variant somewhere
     }
-}
 
-fn calculate_best_path(
-    db: &dyn DefDatabase,
-    def_map: &DefMap,
-    visited_modules: &mut FxHashSet<ModuleId>,
-    crate_root: ModuleId,
-    max_len: usize,
-    item: ItemInNs,
-    from: ModuleId,
-    mut prefixed: Option<PrefixKind>,
-    prefer_no_std: bool,
-    scope_name: Option<Name>,
-) -> Option<ModPath> {
-    if max_len <= 1 {
-        return None;
-    }
-    let mut best_path = None;
-    // Recursive case:
     // - otherwise, look for modules containing (reexporting) it and import it from one of those
+    let prefer_no_std = prefer_core || db.crate_supports_no_std(crate_root.krate);
+    let mut best_path = None;
+    let mut best_path_len = max_len;
+
     if item.krate(db) == Some(from.krate) {
-        let mut best_path_len = max_len;
         // Item was defined in the same crate that wants to import it. It cannot be found in any
         // dependency in this case.
+        // FIXME: this should have a fast path that doesn't look through the prelude again?
         for (module_id, name) in find_local_import_locations(db, item, from) {
             if !visited_modules.insert(module_id) {
                 cov_mark::hit!(recursive_imports);
                 continue;
             }
-            if let Some(mut path) = find_path_for_module(
+            if let Some(mut path) = find_path_inner_(
                 db,
                 def_map,
-                visited_modules,
-                crate_root,
                 from,
-                module_id,
+                ItemInNs::Types(ModuleDefId::ModuleId(module_id)),
                 best_path_len - 1,
                 prefixed,
-                prefer_no_std,
+                visited_modules,
+                prefer_core,
             ) {
                 path.push_segment(name);
 
@@ -329,16 +265,15 @@ fn calculate_best_path(
             import_map.import_info_for(item).and_then(|info| {
                 // Determine best path for containing module and append last segment from `info`.
                 // FIXME: we should guide this to look up the path locally, or from the same crate again?
-                let mut path = find_path_for_module(
+                let mut path = find_path_inner_(
                     db,
                     def_map,
-                    visited_modules,
                     from,
-                    crate_root,
-                    info.container,
-                    max_len - 1,
+                    ItemInNs::Types(ModuleDefId::ModuleId(info.container)),
+                    best_path_len - 1,
                     prefixed,
-                    prefer_no_std,
+                    visited_modules,
+                    prefer_core,
                 )?;
                 cov_mark::hit!(partially_imported);
                 path.push_segment(info.path.segments.last()?.clone());
@@ -354,12 +289,16 @@ fn calculate_best_path(
             best_path = Some(new_path);
         }
     }
-    if let Some(module) = item.module(db) {
-        if module.def_map(db).block_id().is_some() && prefixed.is_some() {
+
+    // If the item is declared inside a block expression, don't use a prefix, as we don't handle
+    // that correctly (FIXME).
+    if let Some(item_module) = item.as_module_def_id().and_then(|did| did.module(db)) {
+        if item_module.def_map(db).block_id().is_some() && prefixed.is_some() {
             cov_mark::hit!(prefixed_in_block_expression);
             prefixed = Some(PrefixKind::Plain);
         }
     }
+
     match prefixed.map(PrefixKind::prefix) {
         Some(prefix) => best_path.or_else(|| {
             scope_name.map(|scope_name| ModPath::from_segments(prefix, Some(scope_name)))
@@ -369,48 +308,29 @@ fn calculate_best_path(
 }
 
 fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath {
-    const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc];
-    match (old_path.segments().first(), new_path.segments().first()) {
-        (Some(old), Some(new)) if STD_CRATES.contains(old) && STD_CRATES.contains(new) => {
-            let rank = match prefer_no_std {
-                false => |name: &Name| match name {
-                    name if name == &known::core => 0,
-                    name if name == &known::alloc => 0,
-                    name if name == &known::std => 1,
-                    _ => unreachable!(),
-                },
-                true => |name: &Name| match name {
-                    name if name == &known::core => 2,
-                    name if name == &known::alloc => 1,
-                    name if name == &known::std => 0,
-                    _ => unreachable!(),
-                },
-            };
-            let nrank = rank(new);
-            let orank = rank(old);
-            match nrank.cmp(&orank) {
-                Ordering::Less => old_path,
-                Ordering::Equal => {
-                    if new_path.len() < old_path.len() {
-                        new_path
-                    } else {
-                        old_path
-                    }
-                }
-                Ordering::Greater => new_path,
-            }
+    if old_path.starts_with_std() && new_path.can_start_with_std() {
+        if prefer_no_std {
+            cov_mark::hit!(prefer_no_std_paths);
+            new_path
+        } else {
+            cov_mark::hit!(prefer_std_paths);
+            old_path
         }
-        _ => {
-            if new_path.len() < old_path.len() {
-                new_path
-            } else {
-                old_path
-            }
+    } else if new_path.starts_with_std() && old_path.can_start_with_std() {
+        if prefer_no_std {
+            cov_mark::hit!(prefer_no_std_paths);
+            old_path
+        } else {
+            cov_mark::hit!(prefer_std_paths);
+            new_path
         }
+    } else if new_path.len() < old_path.len() {
+        new_path
+    } else {
+        old_path
     }
 }
 
-// FIXME: Remove allocations
 /// Finds locations in `from.krate` from which `item` can be imported by `from`.
 fn find_local_import_locations(
     db: &dyn DefDatabase,
@@ -570,8 +490,8 @@ $0
         "#,
             "E::A",
             "E::A",
-            "crate::E::A",
-            "self::E::A",
+            "E::A",
+            "E::A",
         );
     }
 
@@ -890,6 +810,7 @@ pub use super::foo;
 
     #[test]
     fn prefer_std_paths_over_alloc() {
+        cov_mark::check!(prefer_std_paths);
         check_found_path(
             r#"
 //- /main.rs crate:main deps:alloc,std
@@ -914,6 +835,7 @@ pub mod sync {
 
     #[test]
     fn prefer_core_paths_over_std() {
+        cov_mark::check!(prefer_no_std_paths);
         check_found_path(
             r#"
 //- /main.rs crate:main deps:core,std
diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs
index a40656fd6a..a11a92204c 100644
--- a/crates/hir-def/src/item_scope.rs
+++ b/crates/hir-def/src/item_scope.rs
@@ -457,15 +457,8 @@ impl ItemInNs {
     /// Returns the crate defining this item (or `None` if `self` is built-in).
     pub fn krate(&self, db: &dyn DefDatabase) -> Option<CrateId> {
         match self {
-            ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db).map(|m| m.krate),
+            ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate),
             ItemInNs::Macros(id) => Some(id.module(db).krate),
         }
     }
-
-    pub fn module(&self, db: &dyn DefDatabase) -> Option<ModuleId> {
-        match self {
-            ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db),
-            ItemInNs::Macros(id) => Some(id.module(db)),
-        }
-    }
 }
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 69283e55a4..dd5639f00d 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -156,7 +156,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
         &self,
         projection: crate::ProjectionTy,
         env: Arc<crate::TraitEnvironment>,
-    ) -> Ty;
+    ) -> Option<crate::Ty>;
 
     #[salsa::invoke(trait_solve_wait)]
     #[salsa::transparent]
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index 372c3a3cca..aaff894b34 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -69,10 +69,10 @@ pub(crate) fn normalize_projection_query(
     db: &dyn HirDatabase,
     projection: ProjectionTy,
     env: Arc<TraitEnvironment>,
-) -> Ty {
-    let mut table = InferenceTable::new(db, env);
+) -> Option<Ty> {
+    let mut table = InferenceTable::new(db, env.clone());
     let ty = table.normalize_projection_ty(projection);
-    table.resolve_completely(ty)
+    Some(table.resolve_completely(ty))
 }
 
 /// Solve a trait goal using Chalk.
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index d2717c5665..7dd891c86e 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -585,9 +585,9 @@ impl Module {
         self,
         db: &dyn DefDatabase,
         item: impl Into<ItemInNs>,
-        prefer_no_std: bool,
+        prefer_core: bool,
     ) -> Option<ModPath> {
-        hir_def::find_path::find_path(db, item.into().into(), self.into(), prefer_no_std)
+        hir_def::find_path::find_path(db, item.into().into(), self.into(), prefer_core)
     }
 
     /// Finds a path that can be used to refer to the given item from within
@@ -597,14 +597,14 @@ impl Module {
         db: &dyn DefDatabase,
         item: impl Into<ItemInNs>,
         prefix_kind: PrefixKind,
-        prefer_no_std: bool,
+        prefer_core: bool,
     ) -> Option<ModPath> {
         hir_def::find_path::find_path_prefixed(
             db,
             item.into().into(),
             self.into(),
             prefix_kind,
-            prefer_no_std,
+            prefer_core,
         )
     }
 }
@@ -2892,12 +2892,7 @@ impl Type {
             })
             .build();
 
-        let ty = db.normalize_projection(projection, self.env.clone());
-        if ty.is_unknown() {
-            None
-        } else {
-            Some(self.derived(ty))
-        }
+        db.normalize_projection(projection, self.env.clone()).map(|ty| self.derived(ty))
     }
 
     pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
diff --git a/crates/ide-assists/src/assist_config.rs b/crates/ide-assists/src/assist_config.rs
index 60d1588a44..fe2dfca6d5 100644
--- a/crates/ide-assists/src/assist_config.rs
+++ b/crates/ide-assists/src/assist_config.rs
@@ -13,5 +13,5 @@ pub struct AssistConfig {
     pub snippet_cap: Option<SnippetCap>,
     pub allowed: Option<Vec<AssistKind>>,
     pub insert_use: InsertUseConfig,
-    pub prefer_no_std: bool,
+    pub prefer_core: bool,
 }
diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index 73f4db4e5f..d4e21b778c 100644
--- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -87,7 +87,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
             .into_iter()
             .filter_map(|variant| {
                 Some((
-                    build_pat(ctx.db(), module, variant, ctx.config.prefer_no_std)?,
+                    build_pat(ctx.db(), module, variant, ctx.config.prefer_core)?,
                     variant.should_be_hidden(ctx.db(), module.krate()),
                 ))
             })
@@ -133,7 +133,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
                     .iter()
                     .any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
                 let patterns = variants.into_iter().filter_map(|variant| {
-                    build_pat(ctx.db(), module, variant, ctx.config.prefer_no_std)
+                    build_pat(ctx.db(), module, variant, ctx.config.prefer_core)
                 });
 
                 (ast::Pat::from(make::tuple_pat(patterns)), is_hidden)
@@ -354,12 +354,12 @@ fn build_pat(
     db: &RootDatabase,
     module: hir::Module,
     var: ExtendedVariant,
-    prefer_no_std: bool,
+    prefer_core: bool,
 ) -> Option<ast::Pat> {
     match var {
         ExtendedVariant::Variant(var) => {
             let path =
-                mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var), prefer_no_std)?);
+                mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var), prefer_core)?);
 
             // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though
             let pat: ast::Pat = match var.source(db)?.value.kind() {
diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs
index e257218ba9..88a6b8558c 100644
--- a/crates/ide-assists/src/handlers/auto_import.rs
+++ b/crates/ide-assists/src/handlers/auto_import.rs
@@ -92,7 +92,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
     let mut proposed_imports = import_assets.search_for_imports(
         &ctx.sema,
         ctx.config.insert_use.prefix_kind,
-        ctx.config.prefer_no_std,
+        ctx.config.prefer_core,
     );
     if proposed_imports.is_empty() {
         return None;
diff --git a/crates/ide-assists/src/handlers/convert_into_to_from.rs b/crates/ide-assists/src/handlers/convert_into_to_from.rs
index 95d11abe8b..e0c0e9a484 100644
--- a/crates/ide-assists/src/handlers/convert_into_to_from.rs
+++ b/crates/ide-assists/src/handlers/convert_into_to_from.rs
@@ -50,7 +50,7 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -
             _ => return None,
         };
 
-        mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def, ctx.config.prefer_no_std)?)
+        mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def, ctx.config.prefer_core)?)
     };
 
     let dest_type = match &ast_trait {
diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs
index d6c8ea785f..749d94d5a9 100644
--- a/crates/ide-assists/src/handlers/extract_function.rs
+++ b/crates/ide-assists/src/handlers/extract_function.rs
@@ -152,7 +152,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
                         ctx.sema.db,
                         ModuleDef::from(control_flow_enum),
                         ctx.config.insert_use.prefix_kind,
-                        ctx.config.prefer_no_std,
+                        ctx.config.prefer_core,
                     );
 
                     if let Some(mod_path) = mod_path {
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 8d5cab283d..431f7b3c0f 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
@@ -409,7 +409,7 @@ fn process_references(
                     ctx.sema.db,
                     *enum_module_def,
                     ctx.config.insert_use.prefix_kind,
-                    ctx.config.prefer_no_std,
+                    ctx.config.prefer_core,
                 );
                 if let Some(mut mod_path) = mod_path {
                     mod_path.pop_segment();
diff --git a/crates/ide-assists/src/handlers/generate_deref.rs b/crates/ide-assists/src/handlers/generate_deref.rs
index 8f4405a8c8..cf4ed84281 100644
--- a/crates/ide-assists/src/handlers/generate_deref.rs
+++ b/crates/ide-assists/src/handlers/generate_deref.rs
@@ -59,7 +59,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
     let module = ctx.sema.to_def(&strukt)?.module(ctx.db());
     let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?;
     let trait_path =
-        module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_no_std)?;
+        module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_core)?;
 
     let field_type = field.ty()?;
     let field_name = field.name()?;
@@ -100,7 +100,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
     let module = ctx.sema.to_def(&strukt)?.module(ctx.db());
     let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?;
     let trait_path =
-        module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_no_std)?;
+        module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_core)?;
 
     let field_type = field.ty()?;
     let target = field.syntax().text_range();
diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs
index 9cda74d9e0..ceb7dac0fe 100644
--- a/crates/ide-assists/src/handlers/generate_new.rs
+++ b/crates/ide-assists/src/handlers/generate_new.rs
@@ -63,7 +63,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
                 let type_path = current_module.find_use_path(
                     ctx.sema.db,
                     item_for_path_search(ctx.sema.db, item_in_ns)?,
-                    ctx.config.prefer_no_std,
+                    ctx.config.prefer_core,
                 )?;
 
                 let expr = use_trivial_constructor(
diff --git a/crates/ide-assists/src/handlers/qualify_method_call.rs b/crates/ide-assists/src/handlers/qualify_method_call.rs
index e57d1d065d..cb81ebd228 100644
--- a/crates/ide-assists/src/handlers/qualify_method_call.rs
+++ b/crates/ide-assists/src/handlers/qualify_method_call.rs
@@ -47,7 +47,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     let receiver_path = current_module.find_use_path(
         ctx.sema.db,
         item_for_path_search(ctx.sema.db, item_in_ns)?,
-        ctx.config.prefer_no_std,
+        ctx.config.prefer_core,
     )?;
 
     let qualify_candidate = QualifyCandidate::ImplMethod(ctx.sema.db, call, resolved_call);
diff --git a/crates/ide-assists/src/handlers/qualify_path.rs b/crates/ide-assists/src/handlers/qualify_path.rs
index 4b2af550bc..232cd39e8b 100644
--- a/crates/ide-assists/src/handlers/qualify_path.rs
+++ b/crates/ide-assists/src/handlers/qualify_path.rs
@@ -38,7 +38,7 @@ use crate::{
 pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
     let mut proposed_imports =
-        import_assets.search_for_relative_paths(&ctx.sema, ctx.config.prefer_no_std);
+        import_assets.search_for_relative_paths(&ctx.sema, ctx.config.prefer_core);
     if proposed_imports.is_empty() {
         return None;
     }
diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index 9fd5e1886d..04a1366327 100644
--- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -85,7 +85,7 @@ pub(crate) fn replace_derive_with_manual_impl(
     })
     .flat_map(|trait_| {
         current_module
-            .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.prefer_no_std)
+            .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.prefer_core)
             .as_ref()
             .map(mod_path_to_ast)
             .zip(Some(trait_))
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 dbbc56958f..533e1670a0 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
@@ -67,7 +67,7 @@ pub(crate) fn replace_qualified_name_with_use(
                 ctx.sema.db,
                 module,
                 ctx.config.insert_use.prefix_kind,
-                ctx.config.prefer_no_std,
+                ctx.config.prefer_core,
             )
         })
         .flatten();
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index 97b90c62dd..89a971e544 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -551,11 +551,9 @@ fn enum_variants_with_paths(
     }
 
     for variant in variants {
-        if let Some(path) = ctx.module.find_use_path(
-            ctx.db,
-            hir::ModuleDef::from(variant),
-            ctx.config.prefer_no_std,
-        ) {
+        if let Some(path) =
+            ctx.module.find_use_path(ctx.db, hir::ModuleDef::from(variant), ctx.config.prefer_core)
+        {
             // Variants with trivial paths are already added by the existing completion logic,
             // so we should avoid adding these twice
             if path.segments().len() > 1 {
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index 3192b21cfb..1ccf33a96b 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -168,7 +168,7 @@ pub(crate) fn complete_expr_path(
                             .find_use_path(
                                 ctx.db,
                                 hir::ModuleDef::from(strukt),
-                                ctx.config.prefer_no_std,
+                                ctx.config.prefer_core,
                             )
                             .filter(|it| it.len() > 1);
 
@@ -187,11 +187,7 @@ pub(crate) fn complete_expr_path(
                     hir::Adt::Union(un) => {
                         let path = ctx
                             .module
-                            .find_use_path(
-                                ctx.db,
-                                hir::ModuleDef::from(un),
-                                ctx.config.prefer_no_std,
-                            )
+                            .find_use_path(ctx.db, hir::ModuleDef::from(un), ctx.config.prefer_core)
                             .filter(|it| it.len() > 1);
 
                         acc.add_union_literal(ctx, un, path, None);
diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs
index 364969af9c..528959943b 100644
--- a/crates/ide-completion/src/completions/flyimport.rs
+++ b/crates/ide-completion/src/completions/flyimport.rs
@@ -265,7 +265,7 @@ fn import_on_the_fly(
             .search_for_imports(
                 &ctx.sema,
                 ctx.config.insert_use.prefix_kind,
-                ctx.config.prefer_no_std,
+                ctx.config.prefer_core,
             )
             .into_iter()
             .filter(ns_filter)
@@ -313,7 +313,7 @@ fn import_on_the_fly_pat_(
             .search_for_imports(
                 &ctx.sema,
                 ctx.config.insert_use.prefix_kind,
-                ctx.config.prefer_no_std,
+                ctx.config.prefer_core,
             )
             .into_iter()
             .filter(ns_filter)
@@ -352,7 +352,7 @@ fn import_on_the_fly_method(
     let user_input_lowercased = potential_import_name.to_lowercase();
 
     import_assets
-        .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std)
+        .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_core)
         .into_iter()
         .filter(|import| {
             !ctx.is_item_hidden(&import.item_to_import)
diff --git a/crates/ide-completion/src/config.rs b/crates/ide-completion/src/config.rs
index a0f5e81b4f..54ebce1eb7 100644
--- a/crates/ide-completion/src/config.rs
+++ b/crates/ide-completion/src/config.rs
@@ -17,7 +17,7 @@ pub struct CompletionConfig {
     pub callable: Option<CallableSnippets>,
     pub snippet_cap: Option<SnippetCap>,
     pub insert_use: InsertUseConfig,
-    pub prefer_no_std: bool,
+    pub prefer_core: bool,
     pub snippets: Vec<Snippet>,
 }
 
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index 8d21f4fce0..7cefb6bb4a 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -238,7 +238,7 @@ pub fn resolve_completion_edits(
                     db,
                     candidate,
                     config.insert_use.prefix_kind,
-                    config.prefer_no_std,
+                    config.prefer_core,
                 )
             })
             .find(|mod_path| mod_path.to_string() == full_import_path);
diff --git a/crates/ide-completion/src/snippet.rs b/crates/ide-completion/src/snippet.rs
index f3b8eae4fe..2dc62bbdc6 100644
--- a/crates/ide-completion/src/snippet.rs
+++ b/crates/ide-completion/src/snippet.rs
@@ -178,7 +178,7 @@ fn import_edits(ctx: &CompletionContext<'_>, requires: &[GreenNode]) -> Option<V
             ctx.db,
             item,
             ctx.config.insert_use.prefix_kind,
-            ctx.config.prefer_no_std,
+            ctx.config.prefer_core,
         )?;
         Some((path.len() > 1).then(|| LocatedImport::new(path.clone(), item, item, None)))
     };
diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs
index 40a6a3e897..53bc516109 100644
--- a/crates/ide-db/src/imports/import_assets.rs
+++ b/crates/ide-db/src/imports/import_assets.rs
@@ -212,20 +212,20 @@ impl ImportAssets {
         &self,
         sema: &Semantics<'_, RootDatabase>,
         prefix_kind: PrefixKind,
-        prefer_no_std: bool,
+        prefer_core: bool,
     ) -> Vec<LocatedImport> {
         let _p = profile::span("import_assets::search_for_imports");
-        self.search_for(sema, Some(prefix_kind), prefer_no_std)
+        self.search_for(sema, Some(prefix_kind), prefer_core)
     }
 
     /// This may return non-absolute paths if a part of the returned path is already imported into scope.
     pub fn search_for_relative_paths(
         &self,
         sema: &Semantics<'_, RootDatabase>,
-        prefer_no_std: bool,
+        prefer_core: bool,
     ) -> Vec<LocatedImport> {
         let _p = profile::span("import_assets::search_for_relative_paths");
-        self.search_for(sema, None, prefer_no_std)
+        self.search_for(sema, None, prefer_core)
     }
 
     pub fn path_fuzzy_name_to_exact(&mut self, case_sensitive: bool) {
@@ -244,7 +244,7 @@ impl ImportAssets {
         &self,
         sema: &Semantics<'_, RootDatabase>,
         prefixed: Option<PrefixKind>,
-        prefer_no_std: bool,
+        prefer_core: bool,
     ) -> Vec<LocatedImport> {
         let _p = profile::span("import_assets::search_for");
 
@@ -255,7 +255,7 @@ impl ImportAssets {
                 item_for_path_search(sema.db, item)?,
                 &self.module_with_candidate,
                 prefixed,
-                prefer_no_std,
+                prefer_core,
             )
         };
 
@@ -568,12 +568,12 @@ fn get_mod_path(
     item_to_search: ItemInNs,
     module_with_candidate: &Module,
     prefixed: Option<PrefixKind>,
-    prefer_no_std: bool,
+    prefer_core: bool,
 ) -> Option<ModPath> {
     if let Some(prefix_kind) = prefixed {
-        module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind, prefer_no_std)
+        module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind, prefer_core)
     } else {
-        module_with_candidate.find_use_path(db, item_to_search, prefer_no_std)
+        module_with_candidate.find_use_path(db, item_to_search, prefer_core)
     }
 }
 
diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs
index 6f885fba78..7deffe8e0f 100644
--- a/crates/ide-db/src/search.rs
+++ b/crates/ide-db/src/search.rs
@@ -9,7 +9,6 @@ use std::{mem, sync::Arc};
 use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
 use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility};
 use once_cell::unsync::Lazy;
-use parser::SyntaxKind;
 use stdx::hash::NoHashHashMap;
 use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
 
@@ -68,7 +67,6 @@ pub enum ReferenceCategory {
     // Create
     Write,
     Read,
-    Import,
     // FIXME: Some day should be able to search in doc comments. Would probably
     // need to switch from enum to bitflags then?
     // DocComment
@@ -579,7 +577,7 @@ impl<'a> FindUsages<'a> {
                 let reference = FileReference {
                     range,
                     name: ast::NameLike::NameRef(name_ref.clone()),
-                    category: is_name_ref_in_import(name_ref).then(|| ReferenceCategory::Import),
+                    category: None,
                 };
                 sink(file_id, reference)
             }
@@ -758,7 +756,7 @@ impl ReferenceCategory {
     fn new(def: &Definition, r: &ast::NameRef) -> Option<ReferenceCategory> {
         // Only Locals and Fields have accesses for now.
         if !matches!(def, Definition::Local(_) | Definition::Field(_)) {
-            return is_name_ref_in_import(r).then(|| ReferenceCategory::Import);
+            return None;
         }
 
         let mode = r.syntax().ancestors().find_map(|node| {
@@ -785,12 +783,3 @@ impl ReferenceCategory {
         mode.or(Some(ReferenceCategory::Read))
     }
 }
-
-fn is_name_ref_in_import(name_ref: &ast::NameRef) -> bool {
-    name_ref
-        .syntax()
-        .parent()
-        .and_then(ast::PathSegment::cast)
-        .and_then(|it| it.parent_path().top_path().syntax().parent())
-        .map_or(false, |it| it.kind() == SyntaxKind::USE_TREE)
-}
diff --git a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index 3034295196..06073ca1b2 100644
--- a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -137,7 +137,7 @@ pub(crate) fn json_in_items(
                                         sema.db,
                                         it,
                                         config.insert_use.prefix_kind,
-                                        config.prefer_no_std,
+                                        config.prefer_core,
                                     ) {
                                         insert_use(
                                             &scope,
@@ -153,7 +153,7 @@ pub(crate) fn json_in_items(
                                         sema.db,
                                         it,
                                         config.insert_use.prefix_kind,
-                                        config.prefer_no_std,
+                                        config.prefer_core,
                                     ) {
                                         insert_use(
                                             &scope,
diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs
index 7f140eb6a7..5a81a55d82 100644
--- a/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -124,7 +124,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
                         let type_path = current_module?.find_use_path(
                             ctx.sema.db,
                             item_for_path_search(ctx.sema.db, item_in_ns)?,
-                            ctx.config.prefer_no_std,
+                            ctx.config.prefer_core,
                         )?;
 
                         use_trivial_constructor(
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index ae299f0584..22e644bb59 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -150,7 +150,7 @@ pub struct DiagnosticsConfig {
     pub expr_fill_default: ExprFillDefaultMode,
     // FIXME: We may want to include a whole `AssistConfig` here
     pub insert_use: InsertUseConfig,
-    pub prefer_no_std: bool,
+    pub prefer_core: bool,
 }
 
 impl DiagnosticsConfig {
@@ -171,7 +171,7 @@ impl DiagnosticsConfig {
                 group: false,
                 skip_glob_imports: false,
             },
-            prefer_no_std: false,
+            prefer_core: false,
         }
     }
 }
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs
index bfbe0db6e4..ba4c330bf3 100644
--- a/crates/ide/src/annotations.rs
+++ b/crates/ide/src/annotations.rs
@@ -41,12 +41,6 @@ pub struct AnnotationConfig {
     pub annotate_references: bool,
     pub annotate_method_references: bool,
     pub annotate_enum_variant_references: bool,
-    pub location: AnnotationLocation,
-}
-
-pub enum AnnotationLocation {
-    AboveName,
-    AboveWholeItem,
 }
 
 pub(crate) fn annotations(
@@ -71,10 +65,10 @@ pub(crate) fn annotations(
     visit_file_defs(&Semantics::new(db), file_id, &mut |def| {
         let range = match def {
             Definition::Const(konst) if config.annotate_references => {
-                konst.source(db).and_then(|node| name_range(db, config, node, file_id))
+                konst.source(db).and_then(|node| name_range(db, node, file_id))
             }
             Definition::Trait(trait_) if config.annotate_references || config.annotate_impls => {
-                trait_.source(db).and_then(|node| name_range(db, config, node, file_id))
+                trait_.source(db).and_then(|node| name_range(db, node, file_id))
             }
             Definition::Adt(adt) => match adt {
                 hir::Adt::Enum(enum_) => {
@@ -83,9 +77,7 @@ pub(crate) fn annotations(
                             .variants(db)
                             .into_iter()
                             .map(|variant| {
-                                variant
-                                    .source(db)
-                                    .and_then(|node| name_range(db, config, node, file_id))
+                                variant.source(db).and_then(|node| name_range(db, node, file_id))
                             })
                             .flatten()
                             .for_each(|range| {
@@ -96,14 +88,14 @@ pub(crate) fn annotations(
                             })
                     }
                     if config.annotate_references || config.annotate_impls {
-                        enum_.source(db).and_then(|node| name_range(db, config, node, file_id))
+                        enum_.source(db).and_then(|node| name_range(db, node, file_id))
                     } else {
                         None
                     }
                 }
                 _ => {
                     if config.annotate_references || config.annotate_impls {
-                        adt.source(db).and_then(|node| name_range(db, config, node, file_id))
+                        adt.source(db).and_then(|node| name_range(db, node, file_id))
                     } else {
                         None
                     }
@@ -121,7 +113,6 @@ pub(crate) fn annotations(
             annotations
                 .push(Annotation { range, kind: AnnotationKind::HasImpls { file_id, data: None } });
         }
-
         if config.annotate_references {
             annotations.push(Annotation {
                 range,
@@ -131,18 +122,12 @@ pub(crate) fn annotations(
 
         fn name_range<T: HasName>(
             db: &RootDatabase,
-            config: &AnnotationConfig,
             node: InFile<T>,
             source_file_id: FileId,
         ) -> Option<TextRange> {
             if let Some(InFile { file_id, value }) = node.original_ast_node(db) {
                 if file_id == source_file_id.into() {
-                    return match config.location {
-                        AnnotationLocation::AboveName => {
-                            value.name().map(|name| name.syntax().text_range())
-                        }
-                        AnnotationLocation::AboveWholeItem => Some(value.syntax().text_range()),
-                    };
+                    return value.name().map(|it| it.syntax().text_range());
                 }
             }
             None
@@ -173,6 +158,7 @@ pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation)
                 &Semantics::new(db),
                 FilePosition { file_id, offset: annotation.range.start() },
                 None,
+                false,
             )
             .map(|result| {
                 result
@@ -203,23 +189,21 @@ mod tests {
 
     use crate::{fixture, Annotation, AnnotationConfig};
 
-    use super::AnnotationLocation;
-
-    const DEFAULT_CONFIG: AnnotationConfig = AnnotationConfig {
-        binary_target: true,
-        annotate_runnables: true,
-        annotate_impls: true,
-        annotate_references: true,
-        annotate_method_references: true,
-        annotate_enum_variant_references: true,
-        location: AnnotationLocation::AboveName,
-    };
-
-    fn check_with_config(ra_fixture: &str, expect: Expect, config: &AnnotationConfig) {
+    fn check(ra_fixture: &str, expect: Expect) {
         let (analysis, file_id) = fixture::file(ra_fixture);
 
         let annotations: Vec<Annotation> = analysis
-            .annotations(config, file_id)
+            .annotations(
+                &AnnotationConfig {
+                    binary_target: true,
+                    annotate_runnables: true,
+                    annotate_impls: true,
+                    annotate_references: true,
+                    annotate_method_references: true,
+                    annotate_enum_variant_references: true,
+                },
+                file_id,
+            )
             .unwrap()
             .into_iter()
             .map(|annotation| analysis.resolve_annotation(annotation).unwrap())
@@ -228,10 +212,6 @@ mod tests {
         expect.assert_debug_eq(&annotations);
     }
 
-    fn check(ra_fixture: &str, expect: Expect) {
-        check_with_config(ra_fixture, expect, &DEFAULT_CONFIG);
-    }
-
     #[test]
     fn const_annotations() {
         check(
@@ -807,40 +787,4 @@ m!();
             "#]],
         );
     }
-
-    #[test]
-    fn test_annotations_appear_above_whole_item_when_configured_to_do_so() {
-        check_with_config(
-            r#"
-/// This is a struct named Foo, obviously.
-#[derive(Clone)]
-struct Foo;
-"#,
-            expect![[r#"
-                [
-                    Annotation {
-                        range: 0..71,
-                        kind: HasImpls {
-                            file_id: FileId(
-                                0,
-                            ),
-                            data: Some(
-                                [],
-                            ),
-                        },
-                    },
-                    Annotation {
-                        range: 0..71,
-                        kind: HasReferences {
-                            file_id: FileId(
-                                0,
-                            ),
-                            data: None,
-                        },
-                    },
-                ]
-            "#]],
-            &AnnotationConfig { location: AnnotationLocation::AboveWholeItem, ..DEFAULT_CONFIG },
-        );
-    }
 }
diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs
index 1bdd626f1e..f190da326e 100644
--- a/crates/ide/src/highlight_related.rs
+++ b/crates/ide/src/highlight_related.rs
@@ -377,7 +377,6 @@ mod tests {
                         match it {
                             ReferenceCategory::Read => "read",
                             ReferenceCategory::Write => "write",
-                            ReferenceCategory::Import => "import",
                         }
                         .to_string()
                     }),
@@ -424,12 +423,12 @@ struct Foo;
         check(
             r#"
 use crate$0;
-  //^^^^^ import
+  //^^^^^
 use self;
-  //^^^^ import
+  //^^^^
 mod __ {
     use super;
-      //^^^^^ import
+      //^^^^^
 }
 "#,
         );
@@ -437,7 +436,7 @@ mod __ {
             r#"
 //- /main.rs crate:main deps:lib
 use lib$0;
-  //^^^ import
+  //^^^
 //- /lib.rs crate:lib
 "#,
         );
@@ -451,7 +450,7 @@ use lib$0;
 mod foo;
 //- /foo.rs
 use self$0;
- // ^^^^ import
+ // ^^^^
 "#,
         );
     }
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index c1ef25b592..065b48378b 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -74,7 +74,7 @@ use syntax::SourceFile;
 use crate::navigation_target::{ToNav, TryToNav};
 
 pub use crate::{
-    annotations::{Annotation, AnnotationConfig, AnnotationKind, AnnotationLocation},
+    annotations::{Annotation, AnnotationConfig, AnnotationKind},
     call_hierarchy::CallItem,
     expand_macro::ExpandedMacro,
     file_structure::{StructureNode, StructureNodeKind},
@@ -425,8 +425,11 @@ impl Analysis {
         &self,
         position: FilePosition,
         search_scope: Option<SearchScope>,
+        exclude_imports: bool,
     ) -> Cancellable<Option<Vec<ReferenceSearchResult>>> {
-        self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, search_scope))
+        self.with_db(|db| {
+            references::find_all_refs(&Semantics::new(db), position, search_scope, exclude_imports)
+        })
     }
 
     /// Finds all methods and free functions for the file. Does not return tests!
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index e942413c11..5b410c454d 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -54,6 +54,7 @@ pub(crate) fn find_all_refs(
     sema: &Semantics<'_, RootDatabase>,
     position: FilePosition,
     search_scope: Option<SearchScope>,
+    exclude_imports: bool,
 ) -> Option<Vec<ReferenceSearchResult>> {
     let _p = profile::span("find_all_refs");
     let syntax = sema.parse(position.file_id).syntax().clone();
@@ -79,6 +80,10 @@ pub(crate) fn find_all_refs(
                 retain_adt_literal_usages(&mut usages, def, sema);
             }
 
+            if exclude_imports {
+                filter_import_references(&mut usages);
+            }
+
             let references = usages
                 .into_iter()
                 .map(|(file_id, refs)| {
@@ -112,6 +117,17 @@ pub(crate) fn find_all_refs(
     }
 }
 
+fn filter_import_references(usages: &mut UsageSearchResult) {
+    for (_file_id, refs) in &mut usages.references {
+        refs.retain(|it| match it.name.as_name_ref() {
+            Some(name_ref) => {
+                !name_ref.syntax().ancestors().any(|it_ref| matches!(it_ref.kind(), USE))
+            }
+            None => true,
+        });
+    }
+}
+
 pub(crate) fn find_defs<'a>(
     sema: &'a Semantics<'_, RootDatabase>,
     syntax: &SyntaxNode,
@@ -742,7 +758,7 @@ pub struct Foo {
             expect![[r#"
                 foo Module FileId(0) 0..8 4..7
 
-                FileId(0) 14..17 Import
+                FileId(0) 14..17
             "#]],
         );
     }
@@ -760,7 +776,7 @@ use self$0;
             expect![[r#"
                 foo Module FileId(0) 0..8 4..7
 
-                FileId(1) 4..8 Import
+                FileId(1) 4..8
             "#]],
         );
     }
@@ -775,7 +791,7 @@ use self$0;
             expect![[r#"
                 Module FileId(0) 0..10
 
-                FileId(0) 4..8 Import
+                FileId(0) 4..8
             "#]],
         );
     }
@@ -803,7 +819,7 @@ pub(super) struct Foo$0 {
             expect![[r#"
                 Foo Struct FileId(2) 0..41 18..21
 
-                FileId(1) 20..23 Import
+                FileId(1) 20..23
                 FileId(1) 47..50
             "#]],
         );
@@ -966,7 +982,7 @@ fn g() { f(); }
             expect![[r#"
                 f Function FileId(0) 22..31 25..26
 
-                FileId(1) 11..12 Import
+                FileId(1) 11..12
                 FileId(1) 24..25
             "#]],
         );
@@ -1094,7 +1110,7 @@ impl Foo {
 
     fn check_with_scope(ra_fixture: &str, search_scope: Option<SearchScope>, expect: Expect) {
         let (analysis, pos) = fixture::position(ra_fixture);
-        let refs = analysis.find_all_refs(pos, search_scope).unwrap().unwrap();
+        let refs = analysis.find_all_refs(pos, search_scope, false).unwrap().unwrap();
 
         let mut actual = String::new();
         for refs in refs {
@@ -1424,9 +1440,9 @@ pub use level1::Foo;
             expect![[r#"
                 Foo Struct FileId(0) 0..15 11..14
 
-                FileId(1) 16..19 Import
-                FileId(2) 16..19 Import
-                FileId(3) 16..19 Import
+                FileId(1) 16..19
+                FileId(2) 16..19
+                FileId(3) 16..19
             "#]],
         );
     }
@@ -1454,7 +1470,7 @@ lib::foo!();
             expect![[r#"
                 foo Macro FileId(1) 0..61 29..32
 
-                FileId(0) 46..49 Import
+                FileId(0) 46..49
                 FileId(2) 0..3
                 FileId(3) 5..8
             "#]],
@@ -1617,7 +1633,7 @@ struct Foo;
             expect![[r#"
                 derive_identity Derive FileId(2) 1..107 45..60
 
-                FileId(0) 17..31 Import
+                FileId(0) 17..31
                 FileId(0) 56..70
             "#]],
         );
diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs
index 84e772d168..837ea01619 100644
--- a/crates/project-model/src/build_scripts.rs
+++ b/crates/project-model/src/build_scripts.rs
@@ -43,10 +43,12 @@ impl WorkspaceBuildScripts {
         if let Some([program, args @ ..]) = config.run_build_script_command.as_deref() {
             let mut cmd = Command::new(program);
             cmd.args(args);
+            cmd.envs(&config.extra_env);
             return cmd;
         }
 
         let mut cmd = Command::new(toolchain::cargo());
+        cmd.envs(&config.extra_env);
 
         cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]);
 
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index eed955b42d..736d80041b 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -2,6 +2,7 @@
 
 use std::iter;
 use std::path::PathBuf;
+use std::str::from_utf8;
 use std::{ops, process::Command};
 
 use anyhow::{Context, Result};
@@ -98,6 +99,8 @@ pub struct CargoConfig {
     pub wrap_rustc_in_build_scripts: bool,
 
     pub run_build_script_command: Option<Vec<String>>,
+
+    pub extra_env: FxHashMap<String, String>,
 }
 
 impl CargoConfig {
@@ -263,8 +266,8 @@ impl CargoWorkspace {
         let target = config
             .target
             .clone()
-            .or_else(|| cargo_config_build_target(cargo_toml))
-            .or_else(|| rustc_discover_host_triple(cargo_toml));
+            .or_else(|| cargo_config_build_target(cargo_toml, config))
+            .or_else(|| rustc_discover_host_triple(cargo_toml, config));
 
         let mut meta = MetadataCommand::new();
         meta.cargo_path(toolchain::cargo());
@@ -292,8 +295,27 @@ impl CargoWorkspace {
         // unclear whether cargo itself supports it.
         progress("metadata".to_string());
 
-        let meta =
-            meta.exec().with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))?;
+        fn exec_with_env(
+            command: &cargo_metadata::MetadataCommand,
+            extra_env: &FxHashMap<String, String>,
+        ) -> Result<cargo_metadata::Metadata, cargo_metadata::Error> {
+            let mut command = command.cargo_command();
+            command.envs(extra_env);
+            let output = command.output()?;
+            if !output.status.success() {
+                return Err(cargo_metadata::Error::CargoMetadata {
+                    stderr: String::from_utf8(output.stderr)?,
+                });
+            }
+            let stdout = from_utf8(&output.stdout)?
+                .lines()
+                .find(|line| line.starts_with('{'))
+                .ok_or(cargo_metadata::Error::NoJson)?;
+            cargo_metadata::MetadataCommand::parse(stdout)
+        }
+
+        let meta = exec_with_env(&meta, &config.extra_env)
+            .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))?;
 
         Ok(meta)
     }
@@ -463,8 +485,9 @@ impl CargoWorkspace {
     }
 }
 
-fn rustc_discover_host_triple(cargo_toml: &ManifestPath) -> Option<String> {
+fn rustc_discover_host_triple(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option<String> {
     let mut rustc = Command::new(toolchain::rustc());
+    rustc.envs(&config.extra_env);
     rustc.current_dir(cargo_toml.parent()).arg("-vV");
     tracing::debug!("Discovering host platform by {:?}", rustc);
     match utf8_stdout(rustc) {
@@ -486,8 +509,9 @@ fn rustc_discover_host_triple(cargo_toml: &ManifestPath) -> Option<String> {
     }
 }
 
-fn cargo_config_build_target(cargo_toml: &ManifestPath) -> Option<String> {
+fn cargo_config_build_target(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option<String> {
     let mut cargo_config = Command::new(toolchain::cargo());
+    cargo_config.envs(&config.extra_env);
     cargo_config
         .current_dir(cargo_toml.parent())
         .args(&["-Z", "unstable-options", "config", "get", "build.target"])
diff --git a/crates/project-model/src/rustc_cfg.rs b/crates/project-model/src/rustc_cfg.rs
index 17e244d064..486cb143b8 100644
--- a/crates/project-model/src/rustc_cfg.rs
+++ b/crates/project-model/src/rustc_cfg.rs
@@ -4,9 +4,13 @@ use std::process::Command;
 
 use anyhow::Result;
 
-use crate::{cfg_flag::CfgFlag, utf8_stdout, ManifestPath};
+use crate::{cfg_flag::CfgFlag, utf8_stdout, CargoConfig, ManifestPath};
 
-pub(crate) fn get(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Vec<CfgFlag> {
+pub(crate) fn get(
+    cargo_toml: Option<&ManifestPath>,
+    target: Option<&str>,
+    config: &CargoConfig,
+) -> Vec<CfgFlag> {
     let _p = profile::span("rustc_cfg::get");
     let mut res = Vec::with_capacity(6 * 2 + 1);
 
@@ -18,7 +22,7 @@ pub(crate) fn get(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Ve
         }
     }
 
-    match get_rust_cfgs(cargo_toml, target) {
+    match get_rust_cfgs(cargo_toml, target, config) {
         Ok(rustc_cfgs) => {
             tracing::debug!(
                 "rustc cfgs found: {:?}",
@@ -35,9 +39,14 @@ pub(crate) fn get(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Ve
     res
 }
 
-fn get_rust_cfgs(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Result<String> {
+fn get_rust_cfgs(
+    cargo_toml: Option<&ManifestPath>,
+    target: Option<&str>,
+    config: &CargoConfig,
+) -> Result<String> {
     if let Some(cargo_toml) = cargo_toml {
         let mut cargo_config = Command::new(toolchain::cargo());
+        cargo_config.envs(&config.extra_env);
         cargo_config
             .current_dir(cargo_toml.parent())
             .args(&["-Z", "unstable-options", "rustc", "--print", "cfg"])
@@ -52,6 +61,7 @@ fn get_rust_cfgs(cargo_toml: Option<&ManifestPath>, target: Option<&str>) -> Res
     }
     // using unstable cargo features failed, fall back to using plain rustc
     let mut cmd = Command::new(toolchain::rustc());
+    cmd.envs(&config.extra_env);
     cmd.args(&["--print", "cfg", "-O"]);
     if let Some(target) = target {
         cmd.args(&["--target", target]);
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs
index 362bb0f5e7..3282719fef 100644
--- a/crates/project-model/src/sysroot.rs
+++ b/crates/project-model/src/sysroot.rs
@@ -10,7 +10,7 @@ use anyhow::{format_err, Result};
 use la_arena::{Arena, Idx};
 use paths::{AbsPath, AbsPathBuf};
 
-use crate::{utf8_stdout, ManifestPath};
+use crate::{utf8_stdout, CargoConfig, ManifestPath};
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Sysroot {
@@ -67,18 +67,20 @@ impl Sysroot {
         self.crates.iter().map(|(id, _data)| id)
     }
 
-    pub fn discover(dir: &AbsPath) -> Result<Sysroot> {
+    pub fn discover(dir: &AbsPath, config: &CargoConfig) -> Result<Sysroot> {
         tracing::debug!("Discovering sysroot for {}", dir.display());
-        let sysroot_dir = discover_sysroot_dir(dir)?;
-        let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, dir)?;
+        let sysroot_dir = discover_sysroot_dir(dir, config)?;
+        let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, dir, config)?;
         let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
         Ok(res)
     }
 
-    pub fn discover_rustc(cargo_toml: &ManifestPath) -> Option<ManifestPath> {
+    pub fn discover_rustc(cargo_toml: &ManifestPath, config: &CargoConfig) -> Option<ManifestPath> {
         tracing::debug!("Discovering rustc source for {}", cargo_toml.display());
         let current_dir = cargo_toml.parent();
-        discover_sysroot_dir(current_dir).ok().and_then(|sysroot_dir| get_rustc_src(&sysroot_dir))
+        discover_sysroot_dir(current_dir, config)
+            .ok()
+            .and_then(|sysroot_dir| get_rustc_src(&sysroot_dir))
     }
 
     pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Result<Sysroot> {
@@ -144,8 +146,9 @@ impl Sysroot {
     }
 }
 
-fn discover_sysroot_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> {
+fn discover_sysroot_dir(current_dir: &AbsPath, config: &CargoConfig) -> Result<AbsPathBuf> {
     let mut rustc = Command::new(toolchain::rustc());
+    rustc.envs(&config.extra_env);
     rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
     tracing::debug!("Discovering sysroot by {:?}", rustc);
     let stdout = utf8_stdout(rustc)?;
@@ -155,6 +158,7 @@ fn discover_sysroot_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> {
 fn discover_sysroot_src_dir(
     sysroot_path: &AbsPathBuf,
     current_dir: &AbsPath,
+    config: &CargoConfig,
 ) -> Result<AbsPathBuf> {
     if let Ok(path) = env::var("RUST_SRC_PATH") {
         let path = AbsPathBuf::try_from(path.as_str())
@@ -170,6 +174,7 @@ fn discover_sysroot_src_dir(
     get_rust_src(sysroot_path)
         .or_else(|| {
             let mut rustup = Command::new(toolchain::rustup());
+            rustup.envs(&config.extra_env);
             rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]);
             utf8_stdout(rustup).ok()?;
             get_rust_src(sysroot_path)
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 818bbed6af..bc4ab45dae 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -156,11 +156,12 @@ impl ProjectWorkspace {
                 })?;
                 let project_location = project_json.parent().to_path_buf();
                 let project_json = ProjectJson::new(&project_location, data);
-                ProjectWorkspace::load_inline(project_json, config.target.as_deref())?
+                ProjectWorkspace::load_inline(project_json, config.target.as_deref(), config)?
             }
             ProjectManifest::CargoToml(cargo_toml) => {
                 let cargo_version = utf8_stdout({
                     let mut cmd = Command::new(toolchain::cargo());
+                    cmd.envs(&config.extra_env);
                     cmd.arg("--version");
                     cmd
                 })?;
@@ -186,7 +187,7 @@ impl ProjectWorkspace {
                 let sysroot = if config.no_sysroot {
                     None
                 } else {
-                    Some(Sysroot::discover(cargo_toml.parent()).with_context(|| {
+                    Some(Sysroot::discover(cargo_toml.parent(), config).with_context(|| {
                         format!(
                             "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
                             cargo_toml.display()
@@ -196,7 +197,7 @@ impl ProjectWorkspace {
 
                 let rustc_dir = match &config.rustc_source {
                     Some(RustcSource::Path(path)) => ManifestPath::try_from(path.clone()).ok(),
-                    Some(RustcSource::Discover) => Sysroot::discover_rustc(&cargo_toml),
+                    Some(RustcSource::Discover) => Sysroot::discover_rustc(&cargo_toml, config),
                     None => None,
                 };
 
@@ -216,7 +217,7 @@ impl ProjectWorkspace {
                     None => None,
                 };
 
-                let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref());
+                let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref(), config);
 
                 let cfg_overrides = config.cfg_overrides();
                 ProjectWorkspace::Cargo {
@@ -237,6 +238,7 @@ impl ProjectWorkspace {
     pub fn load_inline(
         project_json: ProjectJson,
         target: Option<&str>,
+        config: &CargoConfig,
     ) -> Result<ProjectWorkspace> {
         let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
             (Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)?),
@@ -258,7 +260,7 @@ impl ProjectWorkspace {
             (None, None) => None,
         };
 
-        let rustc_cfg = rustc_cfg::get(None, target);
+        let rustc_cfg = rustc_cfg::get(None, target, config);
         Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
     }
 
@@ -268,8 +270,9 @@ impl ProjectWorkspace {
                 .first()
                 .and_then(|it| it.parent())
                 .ok_or_else(|| format_err!("No detached files to load"))?,
+            &CargoConfig::default(),
         )?;
-        let rustc_cfg = rustc_cfg::get(None, None);
+        let rustc_cfg = rustc_cfg::get(None, None, &CargoConfig::default());
         Ok(ProjectWorkspace::DetachedFiles { files: detached_files, sysroot, rustc_cfg })
     }
 
@@ -416,6 +419,7 @@ impl ProjectWorkspace {
         &self,
         load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
         load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
+        config: &CargoConfig,
     ) -> CrateGraph {
         let _p = profile::span("ProjectWorkspace::to_crate_graph");
 
@@ -426,6 +430,7 @@ impl ProjectWorkspace {
                 load,
                 project,
                 sysroot,
+                config,
             ),
             ProjectWorkspace::Cargo {
                 cargo,
@@ -464,6 +469,7 @@ fn project_json_to_crate_graph(
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
     project: &ProjectJson,
     sysroot: &Option<Sysroot>,
+    config: &CargoConfig,
 ) -> CrateGraph {
     let mut crate_graph = CrateGraph::default();
     let sysroot_deps = sysroot
@@ -489,9 +495,9 @@ fn project_json_to_crate_graph(
             };
 
             let target_cfgs = match krate.target.as_deref() {
-                Some(target) => {
-                    cfg_cache.entry(target).or_insert_with(|| rustc_cfg::get(None, Some(target)))
-                }
+                Some(target) => cfg_cache
+                    .entry(target)
+                    .or_insert_with(|| rustc_cfg::get(None, Some(target), config)),
                 None => &rustc_cfg,
             };
 
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index f52e1e7512..80128e43fd 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -80,7 +80,8 @@ impl flags::AnalysisStats {
             Some(build_scripts_sw.elapsed())
         };
 
-        let (host, vfs, _proc_macro) = load_workspace(workspace, &load_cargo_config)?;
+        let (host, vfs, _proc_macro) =
+            load_workspace(workspace, &cargo_config, &load_cargo_config)?;
         let db = host.raw_database();
         eprint!("{:<20} {}", "Database loaded:", db_load_sw.elapsed());
         eprint!(" (metadata {}", metadata_time);
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index 5d1c013c32..88953096e2 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -38,7 +38,7 @@ pub fn load_workspace_at(
         workspace.set_build_scripts(build_scripts)
     }
 
-    load_workspace(workspace, load_config)
+    load_workspace(workspace, cargo_config, load_config)
 }
 
 // Note: Since this function is used by external tools that use rust-analyzer as a library
@@ -48,6 +48,7 @@ pub fn load_workspace_at(
 // these tools need access to `ProjectWorkspace`, too, which `load_workspace_at` hides.
 pub fn load_workspace(
     ws: ProjectWorkspace,
+    cargo_config: &CargoConfig,
     load_config: &LoadCargoConfig,
 ) -> Result<(AnalysisHost, vfs::Vfs, Option<ProcMacroServer>)> {
     let (sender, receiver) = unbounded();
@@ -75,6 +76,7 @@ pub fn load_workspace(
             vfs.set_file_contents(path.clone(), contents);
             vfs.file_id(&path)
         },
+        cargo_config,
     );
 
     let project_folders = ProjectFolders::new(&[ws], &[]);
diff --git a/crates/rust-analyzer/src/cli/lsif.rs b/crates/rust-analyzer/src/cli/lsif.rs
index 491c55a04f..79577bf78c 100644
--- a/crates/rust-analyzer/src/cli/lsif.rs
+++ b/crates/rust-analyzer/src/cli/lsif.rs
@@ -299,7 +299,8 @@ impl flags::Lsif {
 
         let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?;
 
-        let (host, vfs, _proc_macro) = load_workspace(workspace, &load_cargo_config)?;
+        let (host, vfs, _proc_macro) =
+            load_workspace(workspace, &cargo_config, &load_cargo_config)?;
         let db = host.raw_database();
         let analysis = host.analysis();
 
diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs
index 65cc993c45..05c16bb39e 100644
--- a/crates/rust-analyzer/src/cli/scip.rs
+++ b/crates/rust-analyzer/src/cli/scip.rs
@@ -40,7 +40,7 @@ impl flags::Scip {
 
         let workspace = ProjectWorkspace::load(manifest, &cargo_config, no_progress)?;
 
-        let (host, vfs, _) = load_workspace(workspace, &load_cargo_config)?;
+        let (host, vfs, _) = load_workspace(workspace, &cargo_config, &load_cargo_config)?;
         let db = host.raw_database();
         let analysis = host.analysis();
 
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 3cafbc7433..2cf7a3c85b 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -84,6 +84,9 @@ config_data! {
         /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
         /// avoid checking unnecessary things.
         cargo_buildScripts_useRustcWrapper: bool = "true",
+        /// Extra environment variables that will be set when running cargo, rustc
+        /// or other commands within the workspace. Useful for setting RUSTFLAGS.
+        cargo_extraEnv: FxHashMap<String, String> = "{}",
         /// List of features to activate.
         ///
         /// Set this to `"all"` to pass `--all-features` to cargo.
@@ -105,6 +108,8 @@ config_data! {
         checkOnSave_enable: bool                         = "true",
         /// Extra arguments for `cargo check`.
         checkOnSave_extraArgs: Vec<String>               = "[]",
+        /// Extra environment variables that will be set when running `cargo check`.
+        checkOnSave_extraEnv: FxHashMap<String, String> = "{}",
         /// List of features to activate. Defaults to
         /// `#rust-analyzer.cargo.features#`.
         ///
@@ -262,8 +267,8 @@ config_data! {
         imports_group_enable: bool                           = "true",
         /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
         imports_merge_glob: bool           = "true",
-        /// Prefer to unconditionally use imports of the core and alloc crate, over the std crate.
-        imports_prefer_no_std: bool                     = "false",
+        /// Prefer to use imports of the core crate over the std crate.
+        imports_prefer_core: bool                     = "false",
         /// The path structure for newly inserted paths to use.
         imports_prefix: ImportPrefixDef               = "\"plain\"",
 
@@ -308,7 +313,6 @@ config_data! {
         /// Join lines unwraps trivial blocks.
         joinLines_unwrapTrivialBlock: bool = "true",
 
-
         /// Whether to show `Debug` lens. Only applies when
         /// `#rust-analyzer.lens.enable#` is set.
         lens_debug_enable: bool            = "true",
@@ -320,8 +324,6 @@ config_data! {
         /// Whether to show `Implementations` lens. Only applies when
         /// `#rust-analyzer.lens.enable#` is set.
         lens_implementations_enable: bool  = "true",
-        /// Where to render annotations.
-        lens_location: AnnotationLocation = "\"above_name\"",
         /// Whether to show `References` lens for Struct, Enum, and Union.
         /// Only applies when `#rust-analyzer.lens.enable#` is set.
         lens_references_adt_enable: bool = "false",
@@ -501,25 +503,6 @@ pub struct LensConfig {
     pub refs_adt: bool,   // for Struct, Enum, Union and Trait
     pub refs_trait: bool, // for Struct, Enum, Union and Trait
     pub enum_variant_refs: bool,
-
-    // annotations
-    pub location: AnnotationLocation,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
-#[serde(rename_all = "snake_case")]
-pub enum AnnotationLocation {
-    AboveName,
-    AboveWholeItem,
-}
-
-impl From<AnnotationLocation> for ide::AnnotationLocation {
-    fn from(location: AnnotationLocation) -> Self {
-        match location {
-            AnnotationLocation::AboveName => ide::AnnotationLocation::AboveName,
-            AnnotationLocation::AboveWholeItem => ide::AnnotationLocation::AboveWholeItem,
-        }
-    }
 }
 
 impl LensConfig {
@@ -944,7 +927,7 @@ impl Config {
                 ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
             },
             insert_use: self.insert_use_config(),
-            prefer_no_std: self.data.imports_prefer_no_std,
+            prefer_core: self.data.imports_prefer_core,
         }
     }
 
@@ -956,6 +939,16 @@ impl Config {
         }
     }
 
+    pub fn extra_env(&self) -> &FxHashMap<String, String> {
+        &self.data.cargo_extraEnv
+    }
+
+    pub fn check_on_save_extra_env(&self) -> FxHashMap<String, String> {
+        let mut extra_env = self.data.cargo_extraEnv.clone();
+        extra_env.extend(self.data.checkOnSave_extraEnv.clone());
+        extra_env
+    }
+
     pub fn lru_capacity(&self) -> Option<usize> {
         self.data.lru_capacity
     }
@@ -1025,6 +1018,7 @@ impl Config {
             unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()),
             wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper,
             run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(),
+            extra_env: self.data.cargo_extraEnv.clone(),
         }
     }
 
@@ -1050,7 +1044,11 @@ impl Config {
             Some(args) if !args.is_empty() => {
                 let mut args = args.clone();
                 let command = args.remove(0);
-                FlycheckConfig::CustomCommand { command, args }
+                FlycheckConfig::CustomCommand {
+                    command,
+                    args,
+                    extra_env: self.check_on_save_extra_env(),
+                }
             }
             Some(_) | None => FlycheckConfig::CargoCommand {
                 command: self.data.checkOnSave_command.clone(),
@@ -1078,6 +1076,7 @@ impl Config {
                     CargoFeatures::Listed(it) => it,
                 },
                 extra_args: self.data.checkOnSave_extraArgs.clone(),
+                extra_env: self.check_on_save_extra_env(),
             },
         };
         Some(flycheck_config)
@@ -1160,7 +1159,7 @@ impl Config {
                 CallableCompletionDef::None => None,
             },
             insert_use: self.insert_use_config(),
-            prefer_no_std: self.data.imports_prefer_no_std,
+            prefer_core: self.data.imports_prefer_core,
             snippet_cap: SnippetCap::new(try_or_def!(
                 self.caps
                     .text_document
@@ -1188,7 +1187,7 @@ impl Config {
             snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")),
             allowed: None,
             insert_use: self.insert_use_config(),
-            prefer_no_std: self.data.imports_prefer_no_std,
+            prefer_core: self.data.imports_prefer_core,
         }
     }
 
@@ -1218,7 +1217,6 @@ impl Config {
             refs_trait: self.data.lens_enable && self.data.lens_references_trait_enable,
             enum_variant_refs: self.data.lens_enable
                 && self.data.lens_references_enumVariant_enable,
-            location: self.data.lens_location,
         }
     }
 
@@ -1955,14 +1953,6 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
                 "Use server-side file watching",
             ],
         },
-        "AnnotationLocation" => set! {
-            "type": "string",
-            "enum": ["above_name", "above_whole_item"],
-            "enumDescriptions": [
-                "Render annotations above the name of the item.",
-                "Render annotations above the whole item, including documentation comments and attributes."
-            ],
-        },
         _ => panic!("missing entry for {}: {}", ty, default),
     }
 
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 7dfa32cf37..d511ba347a 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -10,8 +10,8 @@ use std::{
 use anyhow::Context;
 use ide::{
     AnnotationConfig, AssistKind, AssistResolveStrategy, FileId, FilePosition, FileRange,
-    HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind,
-    SingleResolve, SourceChange, TextEdit,
+    HoverAction, HoverGotoTypeData, Query, RangeInfo, Runnable, RunnableKind, SingleResolve,
+    SourceChange, TextEdit,
 };
 use ide_db::SymbolKind;
 use lsp_server::ErrorCode;
@@ -1014,7 +1014,7 @@ pub(crate) fn handle_references(
 
     let exclude_imports = snap.config.find_all_refs_exclude_imports();
 
-    let refs = match snap.analysis.find_all_refs(position, None)? {
+    let refs = match snap.analysis.find_all_refs(position, None, exclude_imports)? {
         None => return Ok(None),
         Some(refs) => refs,
     };
@@ -1034,11 +1034,7 @@ pub(crate) fn handle_references(
             refs.references
                 .into_iter()
                 .flat_map(|(file_id, refs)| {
-                    refs.into_iter()
-                        .filter(|&(_, category)| {
-                            !exclude_imports || category != Some(ReferenceCategory::Import)
-                        })
-                        .map(move |(range, _)| FileRange { file_id, range })
+                    refs.into_iter().map(move |(range, _)| FileRange { file_id, range })
                 })
                 .chain(decl)
         })
@@ -1240,7 +1236,6 @@ pub(crate) fn handle_code_lens(
             annotate_references: lens_config.refs_adt,
             annotate_method_references: lens_config.method_refs,
             annotate_enum_variant_references: lens_config.enum_variant_refs,
-            location: lens_config.location.into(),
         },
         file_id,
     )?;
@@ -1290,7 +1285,7 @@ pub(crate) fn handle_document_highlight(
         .into_iter()
         .map(|ide::HighlightedRange { range, category }| lsp_types::DocumentHighlight {
             range: to_proto::range(&line_index, range),
-            kind: category.and_then(to_proto::document_highlight_kind),
+            kind: category.map(to_proto::document_highlight_kind),
         })
         .collect();
     Ok(Some(res))
@@ -1659,7 +1654,9 @@ fn show_ref_command_link(
     position: &FilePosition,
 ) -> Option<lsp_ext::CommandLinkGroup> {
     if snap.config.hover_actions().references && snap.config.client_commands().show_reference {
-        if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) {
+        if let Some(ref_search_res) =
+            snap.analysis.find_all_refs(*position, None, false).unwrap_or(None)
+        {
             let uri = to_proto::url(snap, position.file_id);
             let line_index = snap.file_line_index(position.file_id).ok()?;
             let position = to_proto::position(&line_index, position.offset);
@@ -1789,6 +1786,7 @@ fn run_rustfmt(
     let mut command = match snap.config.rustfmt() {
         RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => {
             let mut cmd = process::Command::new(toolchain::rustfmt());
+            cmd.envs(snap.config.extra_env());
             cmd.args(extra_args);
             // try to chdir to the file so we can respect `rustfmt.toml`
             // FIXME: use `rustfmt --config-path` once
@@ -1846,6 +1844,7 @@ fn run_rustfmt(
         }
         RustfmtConfig::CustomCommand { command, args } => {
             let mut cmd = process::Command::new(command);
+            cmd.envs(snap.config.extra_env());
             cmd.args(args);
             cmd
         }
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index 96b1cb6b12..5dbb64d7df 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -145,7 +145,7 @@ fn integrated_completion_benchmark() {
                 skip_glob_imports: true,
             },
             snippets: Vec::new(),
-            prefer_no_std: false,
+            prefer_core: false,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -183,7 +183,7 @@ fn integrated_completion_benchmark() {
                 skip_glob_imports: true,
             },
             snippets: Vec::new(),
-            prefer_no_std: false,
+            prefer_core: false,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index e47f70fff3..4cf5de46c4 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -143,6 +143,7 @@ impl GlobalState {
                             project_model::ProjectWorkspace::load_inline(
                                 it.clone(),
                                 cargo_config.target.as_deref(),
+                                &cargo_config,
                             )
                         }
                     })
@@ -398,7 +399,11 @@ impl GlobalState {
                         dummy_replacements.get(crate_name).map(|v| &**v).unwrap_or_default(),
                     )
                 };
-                crate_graph.extend(ws.to_crate_graph(&mut load_proc_macro, &mut load));
+                crate_graph.extend(ws.to_crate_graph(
+                    &mut load_proc_macro,
+                    &mut load,
+                    &self.config.cargo(),
+                ));
             }
             crate_graph
         };
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 1de801e23e..e083b9d0e3 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -83,11 +83,10 @@ pub(crate) fn structure_node_kind(kind: StructureNodeKind) -> lsp_types::SymbolK
 
 pub(crate) fn document_highlight_kind(
     category: ReferenceCategory,
-) -> Option<lsp_types::DocumentHighlightKind> {
+) -> lsp_types::DocumentHighlightKind {
     match category {
-        ReferenceCategory::Read => Some(lsp_types::DocumentHighlightKind::READ),
-        ReferenceCategory::Write => Some(lsp_types::DocumentHighlightKind::WRITE),
-        ReferenceCategory::Import => None,
+        ReferenceCategory::Read => lsp_types::DocumentHighlightKind::READ,
+        ReferenceCategory::Write => lsp_types::DocumentHighlightKind::WRITE,
     }
 }
 
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 62671459d7..ffae3c105c 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -46,6 +46,12 @@ cargo check --quiet --workspace --message-format=json --all-targets
 Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
 avoid checking unnecessary things.
 --
+[[rust-analyzer.cargo.extraEnv]]rust-analyzer.cargo.extraEnv (default: `{}`)::
++
+--
+Extra environment variables that will be set when running cargo, rustc
+or other commands within the workspace. Useful for setting RUSTFLAGS.
+--
 [[rust-analyzer.cargo.features]]rust-analyzer.cargo.features (default: `[]`)::
 +
 --
@@ -93,6 +99,11 @@ Run specified `cargo check` command for diagnostics on save.
 --
 Extra arguments for `cargo check`.
 --
+[[rust-analyzer.checkOnSave.extraEnv]]rust-analyzer.checkOnSave.extraEnv (default: `{}`)::
++
+--
+Extra environment variables that will be set when running `cargo check`.
+--
 [[rust-analyzer.checkOnSave.features]]rust-analyzer.checkOnSave.features (default: `null`)::
 +
 --
@@ -353,10 +364,10 @@ Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-i
 --
 Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
 --
-[[rust-analyzer.imports.prefer.no.std]]rust-analyzer.imports.prefer.no.std (default: `false`)::
+[[rust-analyzer.imports.prefer.core]]rust-analyzer.imports.prefer.core (default: `false`)::
 +
 --
-Prefer to unconditionally use imports of the core and alloc crate, over the std crate.
+Prefer to use imports of the core crate over the std crate.
 --
 [[rust-analyzer.imports.prefix]]rust-analyzer.imports.prefix (default: `"plain"`)::
 +
@@ -479,11 +490,6 @@ client doesn't set the corresponding capability.
 Whether to show `Implementations` lens. Only applies when
 `#rust-analyzer.lens.enable#` is set.
 --
-[[rust-analyzer.lens.location]]rust-analyzer.lens.location (default: `"above_name"`)::
-+
---
-Where to render annotations.
---
 [[rust-analyzer.lens.references.adt.enable]]rust-analyzer.lens.references.adt.enable (default: `false`)::
 +
 --
diff --git a/editors/code/package.json b/editors/code/package.json
index e2cc2c16c9..394222e73a 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -437,6 +437,11 @@
                     "default": true,
                     "type": "boolean"
                 },
+                "rust-analyzer.cargo.extraEnv": {
+                    "markdownDescription": "Extra environment variables that will be set when running cargo, rustc\nor other commands within the workspace. Useful for setting RUSTFLAGS.",
+                    "default": {},
+                    "type": "object"
+                },
                 "rust-analyzer.cargo.features": {
                     "markdownDescription": "List of features to activate.\n\nSet this to `\"all\"` to pass `--all-features` to cargo.",
                     "default": [],
@@ -509,6 +514,11 @@
                         "type": "string"
                     }
                 },
+                "rust-analyzer.checkOnSave.extraEnv": {
+                    "markdownDescription": "Extra environment variables that will be set when running `cargo check`.",
+                    "default": {},
+                    "type": "object"
+                },
                 "rust-analyzer.checkOnSave.features": {
                     "markdownDescription": "List of features to activate. Defaults to\n`#rust-analyzer.cargo.features#`.\n\nSet to `\"all\"` to pass `--all-features` to Cargo.",
                     "default": null,
@@ -798,8 +808,8 @@
                     "default": true,
                     "type": "boolean"
                 },
-                "rust-analyzer.imports.prefer.no.std": {
-                    "markdownDescription": "Prefer to unconditionally use imports of the core and alloc crate, over the std crate.",
+                "rust-analyzer.imports.prefer.core": {
+                    "markdownDescription": "Prefer to use imports of the core crate over the std crate.",
                     "default": false,
                     "type": "boolean"
                 },
@@ -963,19 +973,6 @@
                     "default": true,
                     "type": "boolean"
                 },
-                "rust-analyzer.lens.location": {
-                    "markdownDescription": "Where to render annotations.",
-                    "default": "above_name",
-                    "type": "string",
-                    "enum": [
-                        "above_name",
-                        "above_whole_item"
-                    ],
-                    "enumDescriptions": [
-                        "Render annotations above the name of the item.",
-                        "Render annotations above the whole item, including documentation comments and attributes."
-                    ]
-                },
                 "rust-analyzer.lens.references.adt.enable": {
                     "markdownDescription": "Whether to show `References` lens for Struct, Enum, and Union.\nOnly applies when `#rust-analyzer.lens.enable#` is set.",
                     "default": false,


Test patch:
diff --git a/crates/ide-assists/src/tests.rs b/crates/ide-assists/src/tests.rs
index 258144bae3..4e589dc86a 100644
--- a/crates/ide-assists/src/tests.rs
+++ b/crates/ide-assists/src/tests.rs
@@ -29,7 +29,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
         group: true,
         skip_glob_imports: true,
     },
-    prefer_no_std: false,
+    prefer_core: false,
 };
 
 pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs
index 9e2beb9ee3..d24c914856 100644
--- a/crates/ide-completion/src/tests.rs
+++ b/crates/ide-completion/src/tests.rs
@@ -66,7 +66,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
     enable_private_editable: false,
     callable: Some(CallableSnippets::FillArguments),
     snippet_cap: SnippetCap::new(true),
-    prefer_no_std: false,
+    prefer_core: false,
     insert_use: InsertUseConfig {
         granularity: ImportGranularity::Crate,
         prefix_kind: PrefixKind::Plain,
diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs
index 9ccb6e9101..bea624bd54 100644
--- a/crates/project-model/src/tests.rs
+++ b/crates/project-model/src/tests.rs
@@ -10,8 +10,8 @@ use paths::{AbsPath, AbsPathBuf};
 use serde::de::DeserializeOwned;
 
 use crate::{
-    CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot,
-    WorkspaceBuildScripts,
+    CargoConfig, CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace,
+    Sysroot, WorkspaceBuildScripts,
 };
 
 fn load_cargo(file: &str) -> CrateGraph {
@@ -92,13 +92,17 @@ fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
 }
 
 fn to_crate_graph(project_workspace: ProjectWorkspace) -> CrateGraph {
-    project_workspace.to_crate_graph(&mut |_, _| Ok(Vec::new()), &mut {
-        let mut counter = 0;
-        move |_path| {
-            counter += 1;
-            Some(FileId(counter))
-        }
-    })
+    project_workspace.to_crate_graph(
+        &mut |_, _| Ok(Vec::new()),
+        &mut {
+            let mut counter = 0;
+            move |_path| {
+                counter += 1;
+                Some(FileId(counter))
+            }
+        },
+        &CargoConfig::default(),
+    )
 }
 
 fn check_crate_graph(crate_graph: CrateGraph, expect: Expect) {