Repository: rust-lang/rust-analyzer (rust)

Issue:
"Remove all unused imports" code action incorrectly removes `as` aliased imports.
**rust-analyzer version**: 0.3.2112-standalone

**rustc version**: rustc 1.80.1 (3f5fd8dd4 2024-08-06)

**editor or extension**: VScode - latest version (seems to be `v0.3.2112`)

**relevant settings**: None

**repository link (if public, optional)**: Irrelevant

**code snippet to reproduce**: 
```rust
// Any aliased import would really work.

use std::io::Error as IoError; // Here (read after code snippet)

fn main() -> Result<(), IoError> { // Any usage of the alias (it's now clearly used).
    Ok(())
}
```

Place your cursor at the marked spot in the code, click <kbd>ctrl + .</kbd> (or your keybind for code actions) and select "Remove all the unused imports".

Pull request:
fix: Temporary fix for `remove_unused_imports` not handling import aliases correctly
Fixes #18129

Patch:
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index e09ef4f205..96db3db8f0 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -221,7 +221,7 @@ struct DefCollector<'a> {
     deps: FxHashMap<Name, Dependency>,
     glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, UseId)>>,
     unresolved_imports: Vec<ImportDirective>,
-    indeterminate_imports: Vec<(ImportDirective, PerNs)>,
+    indeterminate_imports: Vec<ImportDirective>,
     unresolved_macros: Vec<MacroDirective>,
     mod_dirs: FxHashMap<LocalModuleId, ModDir>,
     cfg_options: &'a CfgOptions,
@@ -415,6 +415,16 @@ impl DefCollector<'_> {
 
         self.resolution_loop();
 
+        // Resolve all indeterminate resolved imports again
+        // As some of the macros will expand newly import shadowing partial resolved imports
+        // FIXME: We maybe could skip this, if we handle the indeterminate imports in `resolve_imports`
+        // correctly
+        let partial_resolved = self.indeterminate_imports.drain(..).map(|directive| {
+            ImportDirective { status: PartialResolvedImport::Unresolved, ..directive }
+        });
+        self.unresolved_imports.extend(partial_resolved);
+        self.resolve_imports();
+
         let unresolved_imports = mem::take(&mut self.unresolved_imports);
         // show unresolved imports in completion, etc
         for directive in &unresolved_imports {
@@ -739,9 +749,9 @@ impl DefCollector<'_> {
             .filter_map(|mut directive| {
                 directive.status = self.resolve_import(directive.module_id, &directive.import);
                 match directive.status {
-                    PartialResolvedImport::Indeterminate(resolved) => {
+                    PartialResolvedImport::Indeterminate(_) => {
                         self.record_resolved_import(&directive);
-                        self.indeterminate_imports.push((directive, resolved));
+                        self.indeterminate_imports.push(directive);
                         res = ReachedFixedPoint::No;
                         None
                     }
@@ -754,33 +764,6 @@ impl DefCollector<'_> {
                 }
             })
             .collect();
-
-        // Resolve all indeterminate resolved imports again
-        // As some of the macros will expand newly import shadowing partial resolved imports
-        // FIXME: We maybe could skip this, if we handle the indeterminate imports in `resolve_imports`
-        // correctly
-        let mut indeterminate_imports = std::mem::take(&mut self.indeterminate_imports);
-        indeterminate_imports.retain_mut(|(directive, partially_resolved)| {
-            let partially_resolved = partially_resolved.availability();
-            directive.status = self.resolve_import(directive.module_id, &directive.import);
-            match directive.status {
-                PartialResolvedImport::Indeterminate(import)
-                    if partially_resolved != import.availability() =>
-                {
-                    self.record_resolved_import(directive);
-                    res = ReachedFixedPoint::No;
-                    false
-                }
-                PartialResolvedImport::Resolved(_) => {
-                    self.record_resolved_import(directive);
-                    res = ReachedFixedPoint::No;
-                    false
-                }
-                _ => true,
-            }
-        });
-        self.indeterminate_imports = indeterminate_imports;
-
         res
     }
 
diff --git a/crates/hir-def/src/per_ns.rs b/crates/hir-def/src/per_ns.rs
index 3f3b98c6b5..19485c476f 100644
--- a/crates/hir-def/src/per_ns.rs
+++ b/crates/hir-def/src/per_ns.rs
@@ -3,8 +3,6 @@
 //!
 //! `PerNs` (per namespace) captures this.
 
-use bitflags::bitflags;
-
 use crate::{
     item_scope::{ImportId, ImportOrExternCrate, ItemInNs},
     visibility::Visibility,
@@ -18,16 +16,6 @@ pub enum Namespace {
     Macros,
 }
 
-bitflags! {
-    /// Describes only the presence/absence of each namespace, without its value.
-    #[derive(Debug, PartialEq, Eq)]
-    pub(crate) struct NsAvailability : u32 {
-        const TYPES = 1 << 0;
-        const VALUES = 1 << 1;
-        const MACROS = 1 << 2;
-    }
-}
-
 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
 pub struct PerNs {
     pub types: Option<(ModuleDefId, Visibility, Option<ImportOrExternCrate>)>,
@@ -36,14 +24,6 @@ pub struct PerNs {
 }
 
 impl PerNs {
-    pub(crate) fn availability(&self) -> NsAvailability {
-        let mut result = NsAvailability::empty();
-        result.set(NsAvailability::TYPES, self.types.is_some());
-        result.set(NsAvailability::VALUES, self.values.is_some());
-        result.set(NsAvailability::MACROS, self.macros.is_some());
-        result
-    }
-
     pub fn none() -> PerNs {
         PerNs { types: None, values: None, macros: None }
     }
diff --git a/crates/hir-ty/src/object_safety.rs b/crates/hir-ty/src/object_safety.rs
index a4c6626855..89bf3619a0 100644
--- a/crates/hir-ty/src/object_safety.rs
+++ b/crates/hir-ty/src/object_safety.rs
@@ -349,7 +349,7 @@ where
                 ControlFlow::Continue(())
             } else {
                 let generic_params = db.generic_params(item.into());
-                if !generic_params.is_empty() {
+                if generic_params.len_type_or_consts() > 0 {
                     cb(ObjectSafetyViolation::GAT(it))
                 } else {
                     ControlFlow::Continue(())
diff --git a/crates/ide-assists/src/handlers/remove_unused_imports.rs b/crates/ide-assists/src/handlers/remove_unused_imports.rs
index d4fdc072fb..c6f99d6874 100644
--- a/crates/ide-assists/src/handlers/remove_unused_imports.rs
+++ b/crates/ide-assists/src/handlers/remove_unused_imports.rs
@@ -6,7 +6,10 @@ use ide_db::{
     search::{FileReference, ReferenceCategory, SearchScope},
     FxHashMap, RootDatabase,
 };
-use syntax::{ast, AstNode};
+use syntax::{
+    ast::{self, Rename},
+    AstNode,
+};
 use text_edit::TextRange;
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -100,19 +103,19 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
                         hir::ScopeDef::ModuleDef(d) => Some(Definition::from(*d)),
                         _ => None,
                     })
-                    .any(|d| used_once_in_scope(ctx, d, scope))
+                    .any(|d| used_once_in_scope(ctx, d, u.rename(), scope))
                 {
                     return Some(u);
                 }
             } else if let Definition::Trait(ref t) = def {
                 // If the trait or any item is used.
-                if !std::iter::once(def)
-                    .chain(t.items(ctx.db()).into_iter().map(Definition::from))
-                    .any(|d| used_once_in_scope(ctx, d, scope))
+                if !std::iter::once((def, u.rename()))
+                    .chain(t.items(ctx.db()).into_iter().map(|item| (item.into(), None)))
+                    .any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope))
                 {
                     return Some(u);
                 }
-            } else if !used_once_in_scope(ctx, def, scope) {
+            } else if !used_once_in_scope(ctx, def, u.rename(), scope) {
                 return Some(u);
             }
 
@@ -138,7 +141,12 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
     }
 }
 
-fn used_once_in_scope(ctx: &AssistContext<'_>, def: Definition, scopes: &Vec<SearchScope>) -> bool {
+fn used_once_in_scope(
+    ctx: &AssistContext<'_>,
+    def: Definition,
+    rename: Option<Rename>,
+    scopes: &Vec<SearchScope>,
+) -> bool {
     let mut found = false;
 
     for scope in scopes {
@@ -151,7 +159,10 @@ fn used_once_in_scope(ctx: &AssistContext<'_>, def: Definition, scopes: &Vec<Sea
                 false
             }
         };
-        def.usages(&ctx.sema).in_scope(scope).search(&mut search_non_import);
+        def.usages(&ctx.sema)
+            .in_scope(scope)
+            .with_rename(rename.as_ref())
+            .search(&mut search_non_import);
         if found {
             break;
         }
@@ -330,7 +341,7 @@ fn w() {
     }
 
     #[test]
-    fn ranamed_trait_item_use_is_use() {
+    fn renamed_trait_item_use_is_use() {
         check_assist_not_applicable(
             remove_unused_imports,
             r#"
@@ -356,7 +367,7 @@ fn w() {
     }
 
     #[test]
-    fn ranamed_underscore_trait_item_use_is_use() {
+    fn renamed_underscore_trait_item_use_is_use() {
         check_assist_not_applicable(
             remove_unused_imports,
             r#"
@@ -942,6 +953,62 @@ pub struct X();
 mod z {
     mod foo;
 }
+"#,
+        );
+    }
+
+    #[test]
+    fn use_as_alias() {
+        check_assist_not_applicable(
+            remove_unused_imports,
+            r#"
+mod foo {
+    pub struct Foo {}
+}
+
+use foo::Foo as Bar$0;
+
+fn test(_: Bar) {}
+"#,
+        );
+
+        check_assist(
+            remove_unused_imports,
+            r#"
+mod foo {
+    pub struct Foo {}
+    pub struct Bar {}
+    pub struct Qux {}
+    pub trait Quux {
+        fn quxx(&self) {}
+    }
+    impl<T> Quxx for T {}
+}
+
+use foo::{Foo as Bar, Bar as Baz, Qux as _, Quxx as _}$0;
+
+fn test(_: Bar) {
+    let a = ();
+    a.quxx();
+}
+"#,
+            r#"
+mod foo {
+    pub struct Foo {}
+    pub struct Bar {}
+    pub struct Qux {}
+    pub trait Quux {
+        fn quxx(&self) {}
+    }
+    impl<T> Quxx for T {}
+}
+
+use foo::{Foo as Bar, Quxx as _};
+
+fn test(_: Bar) {
+    let a = ();
+    a.quxx();
+}
 "#,
         );
     }
diff --git a/crates/ide-completion/src/completions/attribute.rs b/crates/ide-completion/src/completions/attribute.rs
index d0b489c4e8..9821fb4a2f 100644
--- a/crates/ide-completion/src/completions/attribute.rs
+++ b/crates/ide-completion/src/completions/attribute.rs
@@ -56,7 +56,7 @@ pub(crate) fn complete_known_attribute_input(
             &parse_tt_as_comma_sep_paths(tt, ctx.edition)?,
             FEATURES,
         ),
-        "allow" | "expect" | "deny" | "forbid" | "warn" => {
+        "allow" | "warn" | "deny" | "forbid" => {
             let existing_lints = parse_tt_as_comma_sep_paths(tt, ctx.edition)?;
 
             let lints: Vec<Lint> = CLIPPY_LINT_GROUPS
@@ -222,7 +222,7 @@ macro_rules! attrs {
     [@ {} {$($tt:tt)*}] => { &[$($tt)*] as _ };
     // starting matcher
     [$($tt:tt),*] => {
-        attrs!(@ { $($tt)* } { "allow", "cfg", "cfg_attr", "deny", "expect", "forbid", "warn" })
+        attrs!(@ { $($tt)* } { "allow", "cfg", "cfg_attr", "deny", "forbid", "warn" })
     };
 }
 
@@ -303,7 +303,6 @@ const ATTRIBUTES: &[AttrCompletion] = &[
     attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
     attr(r#"doc(alias = "…")"#, Some("docalias"), Some(r#"doc(alias = "${0:docs}")"#)),
     attr(r#"doc(hidden)"#, Some("dochidden"), Some(r#"doc(hidden)"#)),
-    attr("expect(…)", Some("expect"), Some("expect(${0:lint})")),
     attr(
         r#"export_name = "…""#,
         Some("export_name"),
diff --git a/crates/ide-completion/src/completions/postfix.rs b/crates/ide-completion/src/completions/postfix.rs
index d3579fd8cc..a632f14893 100644
--- a/crates/ide-completion/src/completions/postfix.rs
+++ b/crates/ide-completion/src/completions/postfix.rs
@@ -294,18 +294,6 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) {
 
     let mut new_element_opt = initial_element.clone();
 
-    while let Some(parent_deref_element) =
-        resulting_element.syntax().parent().and_then(ast::PrefixExpr::cast)
-    {
-        if parent_deref_element.op_kind() != Some(ast::UnaryOp::Deref) {
-            break;
-        }
-
-        resulting_element = ast::Expr::from(parent_deref_element);
-
-        new_element_opt = make::expr_prefix(syntax::T![*], new_element_opt);
-    }
-
     if let Some(first_ref_expr) = resulting_element.syntax().parent().and_then(ast::RefExpr::cast) {
         if let Some(expr) = first_ref_expr.expr() {
             resulting_element = expr;
@@ -314,10 +302,9 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) {
         while let Some(parent_ref_element) =
             resulting_element.syntax().parent().and_then(ast::RefExpr::cast)
         {
-            let exclusive = parent_ref_element.mut_token().is_some();
             resulting_element = ast::Expr::from(parent_ref_element);
 
-            new_element_opt = make::expr_ref(new_element_opt, exclusive);
+            new_element_opt = make::expr_ref(new_element_opt, false);
         }
     } else {
         // If we do not find any ref expressions, restore
@@ -868,42 +855,4 @@ fn test() {
             expect![[r#""#]],
         );
     }
-
-    #[test]
-    fn mut_ref_consuming() {
-        check_edit(
-            "call",
-            r#"
-fn main() {
-    let mut x = &mut 2;
-    &mut x.$0;
-}
-"#,
-            r#"
-fn main() {
-    let mut x = &mut 2;
-    ${1}(&mut x);
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn deref_consuming() {
-        check_edit(
-            "call",
-            r#"
-fn main() {
-    let mut x = &mut 2;
-    &mut *x.$0;
-}
-"#,
-            r#"
-fn main() {
-    let mut x = &mut 2;
-    ${1}(&mut *x);
-}
-"#,
-        );
-    }
 }
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 192f1b43fa..72a5791516 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -26,7 +26,7 @@ use crate::{
     CompletionConfig,
 };
 
-const COMPLETION_MARKER: &str = "raCompletionMarker";
+const COMPLETION_MARKER: &str = "intellijRulezz";
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub(crate) enum PatternRefutability {
diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs
index ad30c624c4..4166b08339 100644
--- a/crates/ide-db/src/search.rs
+++ b/crates/ide-db/src/search.rs
@@ -19,7 +19,7 @@ use parser::SyntaxKind;
 use rustc_hash::{FxHashMap, FxHashSet};
 use span::EditionedFileId;
 use syntax::{
-    ast::{self, HasName},
+    ast::{self, HasName, Rename},
     match_ast, AstNode, AstToken, SmolStr, SyntaxElement, SyntaxNode, TextRange, TextSize,
     ToSmolStr,
 };
@@ -405,6 +405,7 @@ impl Definition {
     pub fn usages<'a>(self, sema: &'a Semantics<'_, RootDatabase>) -> FindUsages<'a> {
         FindUsages {
             def: self,
+            rename: None,
             assoc_item_container: self.as_assoc_item(sema.db).map(|a| a.container(sema.db)),
             sema,
             scope: None,
@@ -417,6 +418,7 @@ impl Definition {
 #[derive(Clone)]
 pub struct FindUsages<'a> {
     def: Definition,
+    rename: Option<&'a Rename>,
     sema: &'a Semantics<'a, RootDatabase>,
     scope: Option<&'a SearchScope>,
     /// The container of our definition should it be an assoc item
@@ -447,6 +449,14 @@ impl<'a> FindUsages<'a> {
         self
     }
 
+    // FIXME: This is just a temporary fix for not handling import aliases like
+    // `use Foo as Bar`. We need to support them in a proper way.
+    // See issue #14079
+    pub fn with_rename(mut self, rename: Option<&'a Rename>) -> Self {
+        self.rename = rename;
+        self
+    }
+
     pub fn at_least_one(&self) -> bool {
         let mut found = false;
         self.search(&mut |_, _| {
@@ -884,9 +894,16 @@ impl<'a> FindUsages<'a> {
             }
         };
 
-        let name = match self.def {
+        let name = match (self.rename, self.def) {
+            (Some(rename), _) => {
+                if rename.underscore_token().is_some() {
+                    None
+                } else {
+                    rename.name().map(|n| n.to_smolstr())
+                }
+            }
             // special case crate modules as these do not have a proper name
-            Definition::Module(module) if module.is_crate_root() => {
+            (_, Definition::Module(module)) if module.is_crate_root() => {
                 // FIXME: This assumes the crate name is always equal to its display name when it
                 // really isn't
                 // we should instead look at the dependency edge name and recursively search our way
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index 79fdf75b7f..f55082de67 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -149,14 +149,14 @@ fn expand_macro_recur(
         expanded.text_range().len(),
         &expansion_span_map,
     );
-    Some(expand(sema, expanded, result_span_map, u32::from(offset_in_original_node) as i32))
+    Some(expand(sema, expanded, result_span_map, offset_in_original_node))
 }
 
 fn expand(
     sema: &Semantics<'_, RootDatabase>,
     expanded: SyntaxNode,
     result_span_map: &mut SpanMap<SyntaxContextId>,
-    mut offset_in_original_node: i32,
+    offset_in_original_node: TextSize,
 ) -> SyntaxNode {
     let children = expanded.descendants().filter_map(ast::Item::cast);
     let mut replacements = Vec::new();
@@ -166,14 +166,8 @@ fn expand(
             sema,
             &child,
             result_span_map,
-            TextSize::new(
-                (offset_in_original_node + (u32::from(child.syntax().text_range().start()) as i32))
-                    as u32,
-            ),
+            offset_in_original_node + child.syntax().text_range().start(),
         ) {
-            offset_in_original_node = offset_in_original_node
-                + (u32::from(new_node.text_range().len()) as i32)
-                - (u32::from(child.syntax().text_range().len()) as i32);
             // check if the whole original syntax is replaced
             if expanded == *child.syntax() {
                 return new_node;
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 8836166d96..971cd3ef58 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -2750,36 +2750,4 @@ fn foo() {
         "#,
         );
     }
-
-    #[test]
-    fn issue_18138() {
-        check(
-            r#"
-mod foo {
-    macro_rules! x {
-        () => {
-            pub struct Foo;
-                    // ^^^
-        };
-    }
-    pub(crate) use x as m;
-}
-
-mod bar {
-    use crate::m;
-
-    m!();
- // ^^^^^
-
-    fn qux() {
-        Foo$0;
-    }
-}
-
-mod m {}
-
-use foo::m;
-"#,
-        );
-    }
 }
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 83adf6548a..b02e9b0f07 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -329,7 +329,7 @@ pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option<Hove
     }
     let (is_clippy, lints) = match &*path {
         "feature" => (false, FEATURES),
-        "allow" | "deny" | "expect" | "forbid" | "warn" => {
+        "allow" | "deny" | "forbid" | "warn" => {
             let is_clippy = algo::non_trivia_sibling(token.clone().into(), Direction::Prev)
                 .filter(|t| t.kind() == T![:])
                 .and_then(|t| algo::non_trivia_sibling(t, Direction::Prev))
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 2134b033f3..44e56645ba 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -77,11 +77,7 @@ impl flags::AnalysisStats {
         let metadata_time = db_load_sw.elapsed();
         let load_cargo_config = LoadCargoConfig {
             load_out_dirs_from_check: !self.disable_build_scripts,
-            with_proc_macro_server: if self.disable_proc_macros {
-                ProcMacroServerChoice::None
-            } else {
-                ProcMacroServerChoice::Sysroot
-            },
+            with_proc_macro_server: ProcMacroServerChoice::Sysroot,
             prefill_caches: false,
         };
 
diff --git a/crates/rust-analyzer/src/handlers/notification.rs b/crates/rust-analyzer/src/handlers/notification.rs
index 49b1ba32a7..e8d1a7e4df 100644
--- a/crates/rust-analyzer/src/handlers/notification.rs
+++ b/crates/rust-analyzer/src/handlers/notification.rs
@@ -357,7 +357,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
                             .targets
                             .iter()
                             .any(|&it| crate_root_paths.contains(&cargo[it].root.as_path()));
-                        has_target_with_root.then(|| cargo.package_flag(&cargo[pkg]))
+                        has_target_with_root.then(|| cargo[pkg].name.clone())
                     }),
                     project_model::ProjectWorkspaceKind::Json(project) => {
                         if !project.crates().any(|(_, krate)| {
diff --git a/crates/span/src/map.rs b/crates/span/src/map.rs
index f80de05ec6..2680e5036c 100644
--- a/crates/span/src/map.rs
+++ b/crates/span/src/map.rs
@@ -13,7 +13,6 @@ use crate::{
 /// Maps absolute text ranges for the corresponding file to the relevant span data.
 #[derive(Debug, PartialEq, Eq, Clone, Hash)]
 pub struct SpanMap<S> {
-    /// The offset stored here is the *end* of the node.
     spans: Vec<(TextSize, SpanData<S>)>,
     /// Index of the matched macro arm on successful expansion for declarative macros.
     // FIXME: Does it make sense to have this here?
@@ -110,32 +109,11 @@ where
     ///
     /// The length of the replacement node needs to be `other_size`.
     pub fn merge(&mut self, other_range: TextRange, other_size: TextSize, other: &SpanMap<S>) {
-        // I find the following diagram helpful to illustrate the bounds and why we use `<` or `<=`:
-        // --------------------------------------------------------------------
-        //   1   3   5   6   7   10    11          <-- offsets we store
-        // 0-1 1-3 3-5 5-6 6-7 7-10 10-11          <-- ranges these offsets refer to
-        //       3   ..      7                     <-- other_range
-        //         3-5 5-6 6-7                     <-- ranges we replace (len = 7-3 = 4)
-        //         ^^^^^^^^^^^ ^^^^^^^^^^
-        //           remove       shift
-        //   2   3   5   9                         <-- offsets we insert
-        // 0-2 2-3 3-5 5-9                         <-- ranges we insert (other_size = 9-0 = 9)
-        // ------------------------------------
-        //   1   3
-        // 0-1 1-3                                 <-- these remain intact
-        //           5   6   8   12
-        //         3-5 5-6 6-8 8-12                <-- we shift these by other_range.start() and insert them
-        //                             15    16
-        //                          12-15 15-16    <-- we shift these by other_size-other_range.len() = 9-4 = 5
-        // ------------------------------------
-        //   1   3   5   6   8   12    15    16    <-- final offsets we store
-        // 0-1 1-3 3-5 5-6 6-8 8-12 12-15 15-16    <-- final ranges
-
         self.spans.retain_mut(|(offset, _)| {
-            if other_range.start() < *offset && *offset <= other_range.end() {
+            if other_range.contains(*offset) {
                 false
             } else {
-                if *offset > other_range.end() {
+                if *offset >= other_range.end() {
                     *offset += other_size;
                     *offset -= other_range.len();
                 }


Test patch:
diff --git a/crates/hir-ty/src/object_safety/tests.rs b/crates/hir-ty/src/object_safety/tests.rs
index c2a9117c5b..3dc08c4619 100644
--- a/crates/hir-ty/src/object_safety/tests.rs
+++ b/crates/hir-ty/src/object_safety/tests.rs
@@ -378,16 +378,3 @@ pub trait Error: core::fmt::Debug + core::fmt::Display {
         [("Error", vec![])],
     );
 }
-
-#[test]
-fn lifetime_gat_is_object_unsafe() {
-    check_object_safety(
-        r#"
-//- minicore: dispatch_from_dyn
-trait Foo {
-    type Bar<'a>;
-}
-"#,
-        [("Foo", vec![ObjectSafetyViolationKind::GAT])],
-    );
-}
diff --git a/crates/ide-completion/src/tests/attribute.rs b/crates/ide-completion/src/tests/attribute.rs
index 1bbe097cc6..351abe9850 100644
--- a/crates/ide-completion/src/tests/attribute.rs
+++ b/crates/ide-completion/src/tests/attribute.rs
@@ -26,7 +26,6 @@ struct Foo;
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at must_use
             at no_mangle
@@ -76,7 +75,6 @@ fn with_existing_attr() {
             at cfg(…)
             at cfg_attr(…)
             at deny(…)
-            at expect(…)
             at forbid(…)
             at warn(…)
             kw crate::
@@ -99,7 +97,6 @@ fn attr_on_source_file() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at feature(…)
             at forbid(…)
             at must_use
@@ -130,7 +127,6 @@ fn attr_on_module() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at macro_use
             at must_use
@@ -153,7 +149,6 @@ fn attr_on_module() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at must_use
             at no_implicit_prelude
@@ -179,7 +174,6 @@ fn attr_on_macro_rules() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at macro_export
             at macro_use
@@ -205,7 +199,6 @@ fn attr_on_macro_def() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at must_use
             at no_mangle
@@ -229,7 +222,6 @@ fn attr_on_extern_crate() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at macro_use
             at must_use
@@ -254,7 +246,6 @@ fn attr_on_use() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at must_use
             at no_mangle
@@ -278,7 +269,6 @@ fn attr_on_type_alias() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at must_use
             at no_mangle
@@ -309,7 +299,6 @@ struct Foo;
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at must_use
             at no_mangle
@@ -337,7 +326,6 @@ fn attr_on_enum() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at must_use
             at no_mangle
@@ -363,7 +351,6 @@ fn attr_on_const() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at must_use
             at no_mangle
@@ -387,7 +374,6 @@ fn attr_on_static() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at export_name = "…"
             at forbid(…)
             at global_allocator
@@ -416,7 +402,6 @@ fn attr_on_trait() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at must_use
             at must_use
@@ -442,7 +427,6 @@ fn attr_on_impl() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at must_use
             at no_mangle
@@ -462,7 +446,6 @@ fn attr_on_impl() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at must_use
             at no_mangle
@@ -486,7 +469,6 @@ fn attr_on_extern_block() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at link
             at must_use
@@ -507,7 +489,6 @@ fn attr_on_extern_block() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at forbid(…)
             at link
             at must_use
@@ -528,7 +509,6 @@ fn attr_on_variant() {
             at cfg(…)
             at cfg_attr(…)
             at deny(…)
-            at expect(…)
             at forbid(…)
             at non_exhaustive
             at warn(…)
@@ -552,7 +532,6 @@ fn attr_on_fn() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at export_name = "…"
             at forbid(…)
             at ignore = "…"
@@ -593,7 +572,6 @@ fn attr_in_source_file_end() {
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
-            at expect(…)
             at export_name = "…"
             at forbid(…)
             at global_allocator
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index cca62d2181..8805ead818 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -6336,19 +6336,7 @@ fn hover_lint() {
 
                 arithmetic operation overflows
             "#]],
-    );
-    check(
-        r#"#![expect(arithmetic_overflow$0)]"#,
-        expect![[r#"
-                *arithmetic_overflow*
-                ```
-                arithmetic_overflow
-                ```
-                ___
-
-                arithmetic operation overflows
-            "#]],
-    );
+    )
 }
 
 #[test]
@@ -6364,19 +6352,7 @@ fn hover_clippy_lint() {
 
                 Checks for `foo = bar; bar = foo` sequences.
             "#]],
-    );
-    check(
-        r#"#![expect(clippy::almost_swapped$0)]"#,
-        expect![[r#"
-                *almost_swapped*
-                ```
-                clippy::almost_swapped
-                ```
-                ___
-
-                Checks for `foo = bar; bar = foo` sequences.
-            "#]],
-    );
+    )
 }
 
 #[test]