Repository: rust-lang/rust-analyzer
Pull request #17251 (2024-05-17 15:33:15)

fix: resolve extern prelude for local mods in block modules
fix https://github.com/rust-lang/rust-analyzer/issues/17057, https://github.com/rust-lang/rust-analyzer/issues/17032.

We should use `ModuleOrigin` to check if the current module is a pseudo-module introduced by blocks (where names might be shadowed), rather than checking `block_def_map`.


Patch:
diff --git a/.github/workflows/metrics.yaml b/.github/workflows/metrics.yaml
index a4146d6021..aa776c035e 100644
--- a/.github/workflows/metrics.yaml
+++ b/.github/workflows/metrics.yaml
@@ -25,24 +25,20 @@ jobs:
       - name: Checkout repository
         uses: actions/checkout@v4
 
-      - name: Cache cargo
-        uses: actions/cache@v4
+      - name: Restore cargo cache
+        uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609
         with:
-          path: |
-            ~/.cargo/bin/
-            ~/.cargo/registry/index/
-            ~/.cargo/registry/cache/
-            ~/.cargo/git/db/
-          key: ${{ runner.os }}-cargo-${{ github.sha }}
+          shared-key: ${{ runner.os }}-cargo-metrics-${{ github.sha }}
+          cache-targets: "false"
 
       - name: Collect build metrics
         run: cargo xtask metrics build
 
       - name: Cache target
-        uses: actions/cache@v4
+        uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609
         with:
-          path: target/
-          key: ${{ runner.os }}-target-${{ github.sha }}
+          shared-key: ${{ runner.os }}-cargo-metrics-${{ github.sha }}
+          cache-targets: "true"
 
       - name: Upload build metrics
         uses: actions/upload-artifact@v4
@@ -68,11 +64,11 @@ jobs:
       - name: Checkout repository
         uses: actions/checkout@v4
 
-      - name: Restore target cache
-        uses: actions/cache@v4
+      - name: Restore cargo cache
+        uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609
         with:
-          path: target/
-          key: ${{ runner.os }}-target-${{ github.sha }}
+          shared-key: ${{ runner.os }}-cargo-metrics-${{ github.sha }}
+          cache-targets: "true"
 
       - name: Collect metrics
         run: cargo xtask metrics "${{ matrix.names }}"
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 262bc538b9..587997c473 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -395,6 +395,8 @@ impl DefCollector<'_> {
             .cfg()
             .map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false));
         if is_cfg_enabled {
+            self.inject_prelude();
+
             ModCollector {
                 def_collector: self,
                 macro_depth: 0,
diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs
index ee29b89f3d..d621f3a360 100644
--- a/crates/hir-def/src/nameres/path_resolution.rs
+++ b/crates/hir-def/src/nameres/path_resolution.rs
@@ -221,7 +221,7 @@ impl DefMap {
                     None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                 };
                 tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
-                self.resolve_name_in_crate_root_or_extern_prelude(db, segment)
+                self.resolve_name_in_crate_root_or_extern_prelude(db, original_module, segment)
             }
             PathKind::Plain => {
                 let (_, segment) = match segments.next() {
@@ -470,9 +470,9 @@ impl DefMap {
         };
 
         let extern_prelude = || {
-            if self.block.is_some() {
-                // Don't resolve extern prelude in block `DefMap`s, defer it to the crate def map so
-                // that blocks can properly shadow them
+            if self.block.is_some() && module == DefMap::ROOT {
+                // Don't resolve extern prelude in pseudo-modules of blocks, because
+                // they might been shadowed by local names.
                 return PerNs::none();
             }
             self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
@@ -505,6 +505,7 @@ impl DefMap {
     fn resolve_name_in_crate_root_or_extern_prelude(
         &self,
         db: &dyn DefDatabase,
+        module: LocalModuleId,
         name: &Name,
     ) -> PerNs {
         let from_crate_root = match self.block {
@@ -515,8 +516,8 @@ impl DefMap {
             None => self[Self::ROOT].scope.get(name),
         };
         let from_extern_prelude = || {
-            if self.block.is_some() {
-                // Don't resolve extern prelude in block `DefMap`s.
+            if self.block.is_some() && module == DefMap::ROOT {
+                // Don't resolve extern prelude in pseudo-module of a block.
                 return PerNs::none();
             }
             self.data.extern_prelude.get(name).copied().map_or(
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 85f33a10fc..9fef3e0575 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2563,15 +2563,6 @@ impl HasVisibility for TypeAlias {
     }
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct StaticLifetime;
-
-impl StaticLifetime {
-    pub fn name(self) -> Name {
-        known::STATIC_LIFETIME
-    }
-}
-
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct BuiltinType {
     pub(crate) inner: hir_def::builtin_type::BuiltinType,
diff --git a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
index 43ff115886..76f021ed91 100644
--- a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
+++ b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
@@ -85,7 +85,7 @@ fn edit_struct_def(
     strukt: &Either<ast::Struct, ast::Variant>,
     record_fields: ast::RecordFieldList,
 ) {
-    // Note that we don't need to consider macro files in this function because this is
+    // Note that we don't need to consider macro files in this function because this this is
     // currently not triggered for struct definitions inside macro calls.
     let tuple_fields = record_fields
         .fields()
diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs
index 634277e869..c0f0faba35 100644
--- a/crates/ide-db/src/defs.rs
+++ b/crates/ide-db/src/defs.rs
@@ -11,8 +11,8 @@ use hir::{
     Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType,
     Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field,
     Function, GenericParam, HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module,
-    ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait,
-    TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility,
+    ModuleDef, Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TupleField,
+    TypeAlias, Variant, VariantDef, Visibility,
 };
 use stdx::{format_to, impl_from};
 use syntax::{
@@ -39,13 +39,12 @@ pub enum Definition {
     Trait(Trait),
     TraitAlias(TraitAlias),
     TypeAlias(TypeAlias),
+    BuiltinType(BuiltinType),
     SelfType(Impl),
     GenericParam(GenericParam),
     Local(Local),
     Label(Label),
     DeriveHelper(DeriveHelper),
-    BuiltinType(BuiltinType),
-    BuiltinLifetime(StaticLifetime),
     BuiltinAttr(BuiltinAttr),
     ToolModule(ToolModule),
     ExternCrateDecl(ExternCrateDecl),
@@ -84,7 +83,6 @@ impl Definition {
             Definition::DeriveHelper(it) => it.derive().module(db),
             Definition::BuiltinAttr(_)
             | Definition::BuiltinType(_)
-            | Definition::BuiltinLifetime(_)
             | Definition::TupleField(_)
             | Definition::ToolModule(_) => return None,
         };
@@ -114,7 +112,6 @@ impl Definition {
             Definition::BuiltinType(_) | Definition::TupleField(_) => Visibility::Public,
             Definition::Macro(_) => return None,
             Definition::BuiltinAttr(_)
-            | Definition::BuiltinLifetime(_)
             | Definition::ToolModule(_)
             | Definition::SelfType(_)
             | Definition::Local(_)
@@ -144,7 +141,6 @@ impl Definition {
             Definition::Local(it) => it.name(db),
             Definition::GenericParam(it) => it.name(db),
             Definition::Label(it) => it.name(db),
-            Definition::BuiltinLifetime(StaticLifetime) => hir::known::STATIC_LIFETIME,
             Definition::BuiltinAttr(_) => return None, // FIXME
             Definition::ToolModule(_) => return None,  // FIXME
             Definition::DeriveHelper(it) => it.name(db),
@@ -178,7 +174,6 @@ impl Definition {
                     doc_owner.docs(fd.0.db)
                 })
             }
-            Definition::BuiltinLifetime(StaticLifetime) => None,
             Definition::Local(_) => None,
             Definition::SelfType(impl_def) => {
                 impl_def.self_ty(db).as_adt().map(|adt| adt.docs(db))?
@@ -233,7 +228,6 @@ impl Definition {
             Definition::TraitAlias(it) => it.display(db).to_string(),
             Definition::TypeAlias(it) => it.display(db).to_string(),
             Definition::BuiltinType(it) => it.name().display(db).to_string(),
-            Definition::BuiltinLifetime(it) => it.name().display(db).to_string(),
             Definition::Local(it) => {
                 let ty = it.ty(db);
                 let ty_display = ty.display_truncated(db, None);
@@ -699,9 +693,6 @@ impl NameRefClass {
     ) -> Option<NameRefClass> {
         let _p = tracing::span!(tracing::Level::INFO, "NameRefClass::classify_lifetime", ?lifetime)
             .entered();
-        if lifetime.text() == "'static" {
-            return Some(NameRefClass::Definition(Definition::BuiltinLifetime(StaticLifetime)));
-        }
         let parent = lifetime.syntax().parent()?;
         match parent.kind() {
             SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => {
diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs
index 288d56b534..6a7042988a 100644
--- a/crates/ide-db/src/rename.rs
+++ b/crates/ide-db/src/rename.rs
@@ -196,12 +196,11 @@ impl Definition {
                         .and_then(syn_ctx_is_root)
                 }
             }
-            Definition::BuiltinType(_)
-            | Definition::BuiltinLifetime(_)
-            | Definition::BuiltinAttr(_)
-            | Definition::SelfType(_)
-            | Definition::ToolModule(_)
-            | Definition::TupleField(_) => return None,
+            Definition::BuiltinType(_) => return None,
+            Definition::SelfType(_) => return None,
+            Definition::BuiltinAttr(_) => return None,
+            Definition::ToolModule(_) => return None,
+            Definition::TupleField(_) => return None,
             // FIXME: This should be doable in theory
             Definition::DeriveHelper(_) => return None,
         };
diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs
index 8f633065f3..cb103313c9 100644
--- a/crates/ide-db/src/search.rs
+++ b/crates/ide-db/src/search.rs
@@ -1,7 +1,7 @@
 //! Implementation of find-usages functionality.
 //!
 //! It is based on the standard ide trick: first, we run a fast text search to
-//! get a super-set of matches. Then, we confirm each match using precise
+//! get a super-set of matches. Then, we we confirm each match using precise
 //! name resolution.
 
 use std::mem;
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 8d765dfc91..64b4ccc5bd 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -214,9 +214,8 @@ pub(crate) fn resolve_doc_path_for_def(
         Definition::SelfType(it) => it.resolve_doc_path(db, link, ns),
         Definition::ExternCrateDecl(it) => it.resolve_doc_path(db, link, ns),
         Definition::BuiltinAttr(_)
-        | Definition::BuiltinType(_)
-        | Definition::BuiltinLifetime(_)
         | Definition::ToolModule(_)
+        | Definition::BuiltinType(_)
         | Definition::TupleField(_)
         | Definition::Local(_)
         | Definition::GenericParam(_)
@@ -649,7 +648,6 @@ fn filename_and_frag_for_def(
         | Definition::TupleField(_)
         | Definition::Label(_)
         | Definition::BuiltinAttr(_)
-        | Definition::BuiltinLifetime(_)
         | Definition::ToolModule(_)
         | Definition::DeriveHelper(_) => return None,
     };
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 3bc17f95e7..a166bab37c 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -756,7 +756,15 @@ fn closure_ty(
 }
 
 fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
-    if matches!(def, Definition::GenericParam(_) | Definition::Local(_) | Definition::Label(_)) {
+    if matches!(
+        def,
+        Definition::GenericParam(_)
+            | Definition::BuiltinType(_)
+            | Definition::Local(_)
+            | Definition::Label(_)
+            | Definition::BuiltinAttr(_)
+            | Definition::ToolModule(_)
+    ) {
         return None;
     }
     def.module(db).map(|module| path(db, module, definition_owner_name(db, def)))
diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs
index 68854c33ce..08760c0d88 100644
--- a/crates/ide/src/moniker.rs
+++ b/crates/ide/src/moniker.rs
@@ -211,7 +211,6 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati
             }
         }
         Definition::BuiltinType(..) => Type,
-        Definition::BuiltinLifetime(_) => TypeParameter,
         Definition::SelfType(..) => TypeAlias,
         Definition::GenericParam(..) => TypeParameter,
         Definition::Local(it) => {
@@ -317,7 +316,6 @@ pub(crate) fn def_to_moniker(
         Definition::GenericParam(_)
         | Definition::Label(_)
         | Definition::DeriveHelper(_)
-        | Definition::BuiltinLifetime(_)
         | Definition::BuiltinAttr(_)
         | Definition::ToolModule(_) => return None,
 
diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs
index fc836d5540..2123c98605 100644
--- a/crates/ide/src/navigation_target.rs
+++ b/crates/ide/src/navigation_target.rs
@@ -235,11 +235,9 @@ impl TryToNav for Definition {
             Definition::TraitAlias(it) => it.try_to_nav(db),
             Definition::TypeAlias(it) => it.try_to_nav(db),
             Definition::ExternCrateDecl(it) => Some(it.try_to_nav(db)?),
-            Definition::BuiltinLifetime(_)
-            | Definition::BuiltinType(_)
-            | Definition::TupleField(_)
-            | Definition::ToolModule(_)
-            | Definition::BuiltinAttr(_) => None,
+            Definition::BuiltinType(_) | Definition::TupleField(_) => None,
+            Definition::ToolModule(_) => None,
+            Definition::BuiltinAttr(_) => None,
             // FIXME: The focus range should be set to the helper declaration
             Definition::DeriveHelper(it) => it.derive().try_to_nav(db),
         }
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 3b784ebec3..a72f505eb8 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -484,7 +484,6 @@ pub(super) fn highlight_def(
             h
         }
         Definition::BuiltinType(_) => Highlight::new(HlTag::BuiltinType),
-        Definition::BuiltinLifetime(_) => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)),
         Definition::Static(s) => {
             let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static));
 
@@ -543,14 +542,13 @@ pub(super) fn highlight_def(
     let def_crate = def.krate(db);
     let is_from_other_crate = def_crate != Some(krate);
     let is_from_builtin_crate = def_crate.map_or(false, |def_crate| def_crate.is_builtin(db));
-    let is_builtin = matches!(
-        def,
-        Definition::BuiltinType(_) | Definition::BuiltinLifetime(_) | Definition::BuiltinAttr(_)
-    );
-    match is_from_other_crate {
-        true if !is_builtin => h |= HlMod::Library,
-        false if def.visibility(db) == Some(hir::Visibility::Public) => h |= HlMod::Public,
-        _ => (),
+    let is_builtin_type = matches!(def, Definition::BuiltinType(_));
+    let is_public = def.visibility(db) == Some(hir::Visibility::Public);
+
+    match (is_from_other_crate, is_builtin_type, is_public) {
+        (true, false, _) => h |= HlMod::Library,
+        (false, _, true) => h |= HlMod::Public,
+        _ => {}
     }
 
     if is_from_builtin_crate {
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index f9b8a22a3c..10d867fe2b 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -299,7 +299,6 @@ fn module_def_to_hl_tag(def: Definition) -> HlTag {
         Definition::Trait(_) => SymbolKind::Trait,
         Definition::TraitAlias(_) => SymbolKind::TraitAlias,
         Definition::TypeAlias(_) => SymbolKind::TypeAlias,
-        Definition::BuiltinLifetime(_) => SymbolKind::LifetimeParam,
         Definition::BuiltinType(_) => return HlTag::BuiltinType,
         Definition::Macro(_) => SymbolKind::Macro,
         Definition::Field(_) | Definition::TupleField(_) => SymbolKind::Field,
diff --git a/crates/profile/src/lib.rs b/crates/profile/src/lib.rs
index 2ccb1cd06a..a3fdb72a6d 100644
--- a/crates/profile/src/lib.rs
+++ b/crates/profile/src/lib.rs
@@ -26,7 +26,7 @@ thread_local!(static IN_SCOPE: RefCell<bool> = const { RefCell::new(false) });
 /// A wrapper around google_cpu_profiler.
 ///
 /// Usage:
-/// 1. Install gperf_tools (<https://github.com/gperftools/gperftools>), probably packaged with your Linux distro.
+/// 1. Install gpref_tools (<https://github.com/gperftools/gperftools>), probably packaged with your Linux distro.
 /// 2. Build with `cpu_profiler` feature.
 /// 3. Run the code, the *raw* output would be in the `./out.profile` file.
 /// 4. Install pprof for visualization (<https://github.com/google/pprof>).
diff --git a/crates/rust-analyzer/src/task_pool.rs b/crates/rust-analyzer/src/task_pool.rs
index 2bcd8505e8..f7de5fb2ff 100644
--- a/crates/rust-analyzer/src/task_pool.rs
+++ b/crates/rust-analyzer/src/task_pool.rs
@@ -45,7 +45,7 @@ impl<T> TaskPool<T> {
 
 /// `TaskQueue`, like its name suggests, queues tasks.
 ///
-/// This should only be used if a task must run after [`GlobalState::process_changes`]
+/// This should only be used used if a task must run after [`GlobalState::process_changes`]
 /// has been called.
 pub(crate) struct TaskQueue {
     pub(crate) sender: crossbeam_channel::Sender<QueuedTask>,
diff --git a/crates/salsa/src/lib.rs b/crates/salsa/src/lib.rs
index 5dde0d560f..f86683ee77 100644
--- a/crates/salsa/src/lib.rs
+++ b/crates/salsa/src/lib.rs
@@ -443,7 +443,7 @@ pub trait QueryDb<'d>: Sized {
 /// Trait implements by all of the "special types" associated with
 /// each of your queries.
 pub trait Query: Debug + Default + Sized + for<'d> QueryDb<'d> {
-    /// Type that you give as a parameter -- for queries with zero
+    /// Type that you you give as a parameter -- for queries with zero
     /// or more than one input, this will be a tuple.
     type Key: Clone + Debug + Hash + Eq;
 


Test patch:
diff --git a/crates/hir-def/src/body/tests/block.rs b/crates/hir-def/src/body/tests/block.rs
index 985c6387ba..f483efa851 100644
--- a/crates/hir-def/src/body/tests/block.rs
+++ b/crates/hir-def/src/body/tests/block.rs
@@ -528,3 +528,65 @@ fn f() {$0
         "#]],
     )
 }
+
+#[test]
+fn resolve_extern_prelude_in_block() {
+    check_at(
+        r#"
+//- /main.rs crate:main deps:core
+fn main() {
+    mod f {
+        use core::S;
+        $0
+    }
+}
+
+//- /core.rs crate:core
+pub struct S;
+        "#,
+        expect![[r#"
+            block scope
+            f: t
+
+            block scope::f
+            S: ti vi
+
+            crate
+            main: v
+        "#]],
+    )
+}
+
+#[test]
+fn shadow_extern_prelude_in_block() {
+    check_at(
+        r#"
+//- /main.rs crate:main deps:core
+fn main() {
+    mod core { pub struct S; }
+    {
+        fn inner() {} // forces a block def map
+        use core::S; // should resolve to the local one
+        $0
+    }
+}
+
+//- /core.rs crate:core
+pub const S;
+        "#,
+        expect![[r#"
+            block scope
+            S: ti vi
+            inner: v
+
+            block scope
+            core: t
+
+            block scope::core
+            S: t v
+
+            crate
+            main: v
+        "#]],
+    )
+}
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 20d07bf991..76d86f8ede 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -4441,7 +4441,7 @@ fn foo() {
             ```rust
             'label
             ```
-        "#]],
+            "#]],
     );
 }
 
@@ -4455,17 +4455,7 @@ fn hover_lifetime() {
             ```rust
             'lifetime
             ```
-        "#]],
-    );
-    check(
-        r#"fn foo(_: &'static$0 ()) {}"#,
-        expect![[r#"
-            *'static*
-
-            ```rust
-            'static
-            ```
-        "#]],
+            "#]],
     );
 }
 
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html b/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
index cad5a8b593..de902b5137 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
@@ -45,7 +45,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
-<pre><code><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">allow</span><span class="parenthesis attribute">(</span><span class="none attribute">dead_code</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<pre><code><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">allow</span><span class="parenthesis attribute">(</span><span class="none attribute">dead_code</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute library">rustfmt</span><span class="operator attribute">::</span><span class="tool_module attribute library">skip</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="module attribute crate_root library">proc_macros</span><span class="operator attribute">::</span><span class="attribute attribute library">identity</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="derive attribute default_library library">Default</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 35650bbe87..b2ca6e1ca4 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -79,7 +79,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="comment documentation">/// # Examples</span>
     <span class="comment documentation">///</span>
     <span class="comment documentation">/// ```</span>
-    <span class="comment documentation">///</span><span class="comment documentation"> #</span><span class="none injected"> </span><span class="attribute_bracket attribute injected">#</span><span class="attribute_bracket attribute injected">!</span><span class="attribute_bracket attribute injected">[</span><span class="builtin_attr attribute injected">allow</span><span class="parenthesis attribute injected">(</span><span class="none attribute injected">unused_mut</span><span class="parenthesis attribute injected">)</span><span class="attribute_bracket attribute injected">]</span>
+    <span class="comment documentation">///</span><span class="comment documentation"> #</span><span class="none injected"> </span><span class="attribute_bracket attribute injected">#</span><span class="attribute_bracket attribute injected">!</span><span class="attribute_bracket attribute injected">[</span><span class="builtin_attr attribute injected library">allow</span><span class="parenthesis attribute injected">(</span><span class="none attribute injected">unused_mut</span><span class="parenthesis attribute injected">)</span><span class="attribute_bracket attribute injected">]</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="keyword injected">mut</span><span class="none injected"> </span><span class="variable declaration injected mutable">foo</span><span class="colon injected">:</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
     <span class="comment documentation">/// ```</span>
     <span class="keyword">pub</span> <span class="keyword const">const</span> <span class="keyword">fn</span> <span class="function associated const declaration public static">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="struct">Foo</span> <span class="brace">{</span>
@@ -162,12 +162,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="comment documentation">///</span>
 <span class="comment documentation">/// ```</span>
 <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">not</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"false"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">not</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"false"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="attribute_bracket attribute">]</span>
 <span class="comment documentation">/// ```</span>
 <span class="comment documentation">///</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"alloc"</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"```rust"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">not</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"alloc"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"```ignore"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"alloc"</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"```rust"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">not</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"alloc"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"```ignore"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="module injected">alloc</span><span class="operator injected">::</span><span class="macro injected">vec</span><span class="macro_bang injected">!</span><span class="bracket injected macro">[</span><span class="numeric_literal injected macro">1</span><span class="comma injected macro">,</span><span class="none injected"> </span><span class="numeric_literal injected macro">2</span><span class="comma injected macro">,</span><span class="none injected"> </span><span class="numeric_literal injected macro">3</span><span class="bracket injected macro">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
 <span class="comment documentation">/// ```</span>
 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration public">mix_and_match</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
index 413edb6d65..5234d362c2 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
@@ -49,13 +49,13 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
 
 <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration public">ops</span> <span class="brace">{</span>
-    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_once"</span><span class="attribute_bracket attribute">]</span>
+    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_once"</span><span class="attribute_bracket attribute">]</span>
     <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">FnOnce</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
 
-    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_mut"</span><span class="attribute_bracket attribute">]</span>
+    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_mut"</span><span class="attribute_bracket attribute">]</span>
     <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">FnMut</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span><span class="colon">:</span> <span class="trait public">FnOnce</span><span class="angle">&lt;</span><span class="type_param">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
 
-    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn"</span><span class="attribute_bracket attribute">]</span>
+    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn"</span><span class="attribute_bracket attribute">]</span>
     <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">Fn</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span><span class="colon">:</span> <span class="trait public">FnMut</span><span class="angle">&lt;</span><span class="type_param">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index be6176894b..15d6be6334 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -69,7 +69,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="method associated declaration reference unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">repr</span><span class="parenthesis attribute">(</span><span class="none attribute">packed</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">repr</span><span class="parenthesis attribute">(</span><span class="none attribute">packed</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="brace">{</span>
     <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span>
 <span class="brace">}</span>