Repository: rust-lang/rust-analyzer
Pull request #13581 (2022-11-08 07:38:00)

fix: Fix item completions not working properly after unit structs and outline modules

Fixes https://github.com/rust-lang/rust-analyzer/issues/13578


Patch:
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index ad33053ad0..b68c764bdc 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -53,7 +53,7 @@ pub use builder::{ParamKind, TyBuilder};
 pub use chalk_ext::*;
 pub use infer::{
     could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic,
-    InferenceResult, OverloadedDeref, PointerCast,
+    InferenceResult,
 };
 pub use interner::Interner;
 pub use lower::{
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 9d77f343bc..cbd9bf32a5 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -117,7 +117,7 @@ pub use {
         name::{known, Name},
         ExpandResult, HirFileId, InFile, MacroFile, Origin,
     },
-    hir_ty::{display::HirDisplay, PointerCast, Safety},
+    hir_ty::display::HirDisplay,
 };
 
 // These are negative re-exports: pub using these names is forbidden, they
@@ -3651,28 +3651,6 @@ impl From<ItemInNs> for ScopeDef {
     }
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub enum Adjust {
-    /// Go from ! to any type.
-    NeverToAny,
-    /// Dereference once, producing a place.
-    Deref(Option<OverloadedDeref>),
-    /// Take the address and produce either a `&` or `*` pointer.
-    Borrow(AutoBorrow),
-    Pointer(PointerCast),
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub enum AutoBorrow {
-    /// Converts from T to &T.
-    Ref(Mutability),
-    /// Converts from T to *T.
-    RawPtr(Mutability),
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub struct OverloadedDeref(pub Mutability);
-
 pub trait HasVisibility {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility;
     fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool {
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 2e1f88ba09..119ec3210e 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -29,10 +29,9 @@ use crate::{
     db::HirDatabase,
     semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
     source_analyzer::{resolve_hir_path, SourceAnalyzer},
-    Access, Adjust, AutoBorrow, BindingMode, BuiltinAttr, Callable, ConstParam, Crate,
-    DeriveHelper, Field, Function, HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local,
-    Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, ToolModule, Trait, Type,
-    TypeAlias, TypeParam, VariantDef,
+    Access, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, DeriveHelper, Field, Function,
+    HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef,
+    Name, Path, ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -334,8 +333,9 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.resolve_trait(trait_)
     }
 
-    pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjust>> {
-        self.imp.expr_adjustments(expr)
+    // FIXME: Figure out a nice interface to inspect adjustments
+    pub fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
+        self.imp.is_implicit_reborrow(expr)
     }
 
     pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
@@ -1067,29 +1067,8 @@ impl<'db> SemanticsImpl<'db> {
         }
     }
 
-    fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjust>> {
-        let mutability = |m| match m {
-            hir_ty::Mutability::Not => Mutability::Shared,
-            hir_ty::Mutability::Mut => Mutability::Mut,
-        };
-        self.analyze(expr.syntax())?.expr_adjustments(self.db, expr).map(|it| {
-            it.iter()
-                .map(|adjust| match adjust.kind {
-                    hir_ty::Adjust::NeverToAny => Adjust::NeverToAny,
-                    hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => {
-                        Adjust::Deref(Some(OverloadedDeref(mutability(m))))
-                    }
-                    hir_ty::Adjust::Deref(None) => Adjust::Deref(None),
-                    hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::RawPtr(m)) => {
-                        Adjust::Borrow(AutoBorrow::RawPtr(mutability(m)))
-                    }
-                    hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::Ref(m)) => {
-                        Adjust::Borrow(AutoBorrow::Ref(mutability(m)))
-                    }
-                    hir_ty::Adjust::Pointer(pc) => Adjust::Pointer(pc),
-                })
-                .collect()
-        })
+    fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
+        self.analyze(expr.syntax())?.is_implicit_reborrow(self.db, expr)
     }
 
     fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 91ea1c24d1..f86c571005 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -38,7 +38,8 @@ use hir_ty::{
         UnsafeExpr,
     },
     method_resolution::{self, lang_names_for_bin_op},
-    Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext,
+    Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind,
+    TyLoweringContext,
 };
 use itertools::Itertools;
 use smallvec::SmallVec;
@@ -155,14 +156,21 @@ impl SourceAnalyzer {
         Some(res)
     }
 
-    pub(crate) fn expr_adjustments(
+    pub(crate) fn is_implicit_reborrow(
         &self,
         db: &dyn HirDatabase,
         expr: &ast::Expr,
-    ) -> Option<&[Adjustment]> {
+    ) -> Option<Mutability> {
         let expr_id = self.expr_id(db, expr)?;
         let infer = self.infer.as_ref()?;
-        infer.expr_adjustments.get(&expr_id).map(|v| &**v)
+        let adjustments = infer.expr_adjustments.get(&expr_id)?;
+        adjustments.windows(2).find_map(|slice| match slice {
+            &[Adjustment {kind: Adjust::Deref(None), ..}, Adjustment {kind: Adjust::Borrow(AutoBorrow::Ref(m)), ..}] => Some(match m {
+                hir_ty::Mutability::Mut => Mutability::Mut,
+                hir_ty::Mutability::Not => Mutability::Shared,
+            }),
+            _ => None,
+        })
     }
 
     pub(crate) fn type_of_expr(
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 04111ec7ef..c142a7305f 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -681,9 +681,13 @@ fn classify_name_ref(
                     ast::Item::ExternBlock(it) => it.extern_item_list().is_none(),
                     ast::Item::Fn(it) => it.body().is_none(),
                     ast::Item::Impl(it) => it.assoc_item_list().is_none(),
-                    ast::Item::Module(it) => it.item_list().is_none(),
+                    ast::Item::Module(it) => {
+                        it.item_list().is_none() && it.semicolon_token().is_none()
+                    }
                     ast::Item::Static(it) => it.body().is_none(),
-                    ast::Item::Struct(it) => it.field_list().is_none(),
+                    ast::Item::Struct(it) => {
+                        it.field_list().is_none() && it.semicolon_token().is_none()
+                    }
                     ast::Item::Trait(it) => it.assoc_item_list().is_none(),
                     ast::Item::TypeAlias(it) => it.ty().is_none(),
                     ast::Item::Union(it) => it.record_field_list().is_none(),
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 37384c4e7e..8ef122528b 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1,10 +1,7 @@
 use std::fmt;
 
 use either::Either;
-use hir::{
-    known, Adjust, AutoBorrow, Callable, HasVisibility, HirDisplay, Mutability, OverloadedDeref,
-    PointerCast, Safety, Semantics, TypeInfo,
-};
+use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo};
 use ide_db::{
     base_db::FileRange, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap,
     RootDatabase,
@@ -25,7 +22,7 @@ pub struct InlayHintsConfig {
     pub type_hints: bool,
     pub parameter_hints: bool,
     pub chaining_hints: bool,
-    pub adjustment_hints: AdjustmentHints,
+    pub reborrow_hints: ReborrowHints,
     pub closure_return_type_hints: ClosureReturnTypeHints,
     pub binding_mode_hints: bool,
     pub lifetime_elision_hints: LifetimeElisionHints,
@@ -51,9 +48,9 @@ pub enum LifetimeElisionHints {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub enum AdjustmentHints {
+pub enum ReborrowHints {
     Always,
-    ReborrowOnly,
+    MutableOnly,
     Never,
 }
 
@@ -64,8 +61,7 @@ pub enum InlayKind {
     ClosingBraceHint,
     ClosureReturnTypeHint,
     GenericParamListHint,
-    AdjustmentHint,
-    AdjustmentHintClosingParenthesis,
+    ImplicitReborrowHint,
     LifetimeHint,
     ParameterHint,
     TypeHint,
@@ -119,12 +115,6 @@ impl From<String> for InlayHintLabel {
     }
 }
 
-impl From<&str> for InlayHintLabel {
-    fn from(s: &str) -> Self {
-        Self { parts: vec![InlayHintLabelPart { text: s.into(), linked_location: None }] }
-    }
-}
-
 impl fmt::Display for InlayHintLabel {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{}", self.parts.iter().map(|part| &part.text).format(""))
@@ -231,7 +221,6 @@ fn hints(
         match node {
             ast::Expr(expr) => {
                 chaining_hints(hints, sema, &famous_defs, config, file_id, &expr);
-                adjustment_hints(hints, sema, config, &expr);
                 match expr {
                     ast::Expr::CallExpr(it) => param_name_hints(hints, sema, config, ast::Expr::from(it)),
                     ast::Expr::MethodCallExpr(it) => {
@@ -240,7 +229,7 @@ fn hints(
                     ast::Expr::ClosureExpr(it) => closure_ret_hints(hints, sema, &famous_defs, config, file_id, it),
                     // We could show reborrows for all expressions, but usually that is just noise to the user
                     // and the main point here is to show why "moving" a mutable reference doesn't necessarily move it
-                    // ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
+                    ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
                     _ => None,
                 }
             },
@@ -628,95 +617,30 @@ fn closure_ret_hints(
     Some(())
 }
 
-fn adjustment_hints(
+fn reborrow_hints(
     acc: &mut Vec<InlayHint>,
     sema: &Semantics<'_, RootDatabase>,
     config: &InlayHintsConfig,
     expr: &ast::Expr,
 ) -> Option<()> {
-    if config.adjustment_hints == AdjustmentHints::Never {
-        return None;
-    }
-
-    if let ast::Expr::ParenExpr(_) = expr {
-        // These inherit from the inner expression which would result in duplicate hints
+    if config.reborrow_hints == ReborrowHints::Never {
         return None;
     }
 
-    let parent = expr.syntax().parent().and_then(ast::Expr::cast);
     let descended = sema.descend_node_into_attributes(expr.clone()).pop();
     let desc_expr = descended.as_ref().unwrap_or(expr);
-    let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?;
-    let needs_parens = match parent {
-        Some(parent) => {
-            match parent {
-                ast::Expr::AwaitExpr(_)
-                | ast::Expr::CallExpr(_)
-                | ast::Expr::CastExpr(_)
-                | ast::Expr::FieldExpr(_)
-                | ast::Expr::MethodCallExpr(_)
-                | ast::Expr::TryExpr(_) => true,
-                // FIXME: shorthands need special casing, though not sure if adjustments are even valid there
-                ast::Expr::RecordExpr(_) => false,
-                ast::Expr::IndexExpr(index) => index.base().as_ref() == Some(expr),
-                _ => false,
-            }
-        }
-        None => false,
+    let mutability = sema.is_implicit_reborrow(desc_expr)?;
+    let label = match mutability {
+        hir::Mutability::Shared if config.reborrow_hints != ReborrowHints::MutableOnly => "&*",
+        hir::Mutability::Mut => "&mut *",
+        _ => return None,
     };
-    if needs_parens {
-        acc.push(InlayHint {
-            range: expr.syntax().text_range(),
-            kind: InlayKind::AdjustmentHint,
-            label: "(".into(),
-            tooltip: None,
-        });
-    }
-    for adjustment in adjustments.into_iter().rev() {
-        // FIXME: Add some nicer tooltips to each of these
-        let text = match adjustment {
-            Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
-                "<never-to-any>"
-            }
-            Adjust::Deref(None) => "*",
-            Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => "*",
-            Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => "*",
-            Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => "&",
-            Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => "&mut ",
-            Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => "&raw const ",
-            Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => "&raw mut ",
-            // some of these could be represented via `as` casts, but that's not too nice and
-            // handling everything as a prefix expr makes the `(` and `)` insertion easier
-            Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
-                match cast {
-                    PointerCast::ReifyFnPointer => "<fn-item-to-fn-pointer>",
-                    PointerCast::UnsafeFnPointer => "<safe-fn-pointer-to-unsafe-fn-pointer>",
-                    PointerCast::ClosureFnPointer(Safety::Unsafe) => {
-                        "<closure-to-unsafe-fn-pointer>"
-                    }
-                    PointerCast::ClosureFnPointer(Safety::Safe) => "<closure-to-fn-pointer>",
-                    PointerCast::MutToConstPointer => "<mut-ptr-to-const-ptr>",
-                    PointerCast::ArrayToPointer => "<array-ptr-to-element-ptr>",
-                    PointerCast::Unsize => "<unsize>",
-                }
-            }
-            _ => continue,
-        };
-        acc.push(InlayHint {
-            range: expr.syntax().text_range(),
-            kind: InlayKind::AdjustmentHint,
-            label: text.into(),
-            tooltip: None,
-        });
-    }
-    if needs_parens {
-        acc.push(InlayHint {
-            range: expr.syntax().text_range(),
-            kind: InlayKind::AdjustmentHintClosingParenthesis,
-            label: ")".into(),
-            tooltip: None,
-        });
-    }
+    acc.push(InlayHint {
+        range: expr.syntax().text_range(),
+        kind: InlayKind::ImplicitReborrowHint,
+        label: label.to_string().into(),
+        tooltip: Some(InlayTooltip::String("Compiler inserted reborrow".into())),
+    });
     Some(())
 }
 
@@ -1293,7 +1217,7 @@ mod tests {
     use syntax::{TextRange, TextSize};
     use test_utils::extract_annotations;
 
-    use crate::inlay_hints::AdjustmentHints;
+    use crate::inlay_hints::ReborrowHints;
     use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
 
     use super::ClosureReturnTypeHints;
@@ -1305,7 +1229,7 @@ mod tests {
         chaining_hints: false,
         lifetime_elision_hints: LifetimeElisionHints::Never,
         closure_return_type_hints: ClosureReturnTypeHints::Never,
-        adjustment_hints: AdjustmentHints::Never,
+        reborrow_hints: ReborrowHints::Always,
         binding_mode_hints: false,
         hide_named_constructor_hints: false,
         hide_closure_initialization_hints: false,
@@ -1317,6 +1241,7 @@ mod tests {
         type_hints: true,
         parameter_hints: true,
         chaining_hints: true,
+        reborrow_hints: ReborrowHints::Always,
         closure_return_type_hints: ClosureReturnTypeHints::WithBlock,
         binding_mode_hints: true,
         lifetime_elision_hints: LifetimeElisionHints::Always,
@@ -2916,6 +2841,48 @@ impl () {
         );
     }
 
+    #[test]
+    fn hints_implicit_reborrow() {
+        check_with_config(
+            InlayHintsConfig {
+                reborrow_hints: ReborrowHints::Always,
+                parameter_hints: true,
+                ..DISABLED_CONFIG
+            },
+            r#"
+fn __() {
+    let unique = &mut ();
+    let r_mov = unique;
+    let foo: &mut _ = unique;
+                    //^^^^^^ &mut *
+    ref_mut_id(unique);
+             //^^^^^^ mut_ref
+             //^^^^^^ &mut *
+    let shared = ref_id(unique);
+                      //^^^^^^ shared_ref
+                      //^^^^^^ &*
+    let mov = shared;
+    let r_mov: &_ = shared;
+    ref_id(shared);
+         //^^^^^^ shared_ref
+
+    identity(unique);
+    identity(shared);
+}
+fn identity<T>(t: T) -> T {
+    t
+}
+fn ref_mut_id(mut_ref: &mut ()) -> &mut () {
+    mut_ref
+  //^^^^^^^ &mut *
+}
+fn ref_id(shared_ref: &()) -> &() {
+    shared_ref
+}
+"#,
+        );
+    }
+
     #[test]
     fn hints_binding_modes() {
         check_with_config(
@@ -3023,76 +2990,4 @@ fn f() {
 "#,
         );
     }
-
-    #[test]
-    fn adjustment_hints() {
-        check_with_config(
-            InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
-            r#"
-//- minicore: coerce_unsized
-fn main() {
-    let _: u32         = loop {};
-                       //^^^^^^^<never-to-any>
-    let _: &u32        = &mut 0;
-                       //^^^^^^&
-                       //^^^^^^*
-    let _: &mut u32    = &mut 0;
-                       //^^^^^^&mut $
-                       //^^^^^^*
-    let _: *const u32  = &mut 0;
-                       //^^^^^^&raw const $
-                       //^^^^^^*
-    let _: *mut u32    = &mut 0;
-                       //^^^^^^&raw mut $
-                       //^^^^^^*
-    let _: fn()        = main;
-                       //^^^^<fn-item-to-fn-pointer>
-    let _: unsafe fn() = main;
-                       //^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
-                       //^^^^<fn-item-to-fn-pointer>
-    let _: unsafe fn() = main as fn();
-                       //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
-    let _: fn()        = || {};
-                       //^^^^^<closure-to-fn-pointer>
-    let _: unsafe fn() = || {};
-                       //^^^^^<closure-to-unsafe-fn-pointer>
-    let _: *const u32  = &mut 0u32 as *mut u32;
-                       //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>
-    let _: &mut [_]    = &mut [0; 0];
-                       //^^^^^^^^^^^<unsize>
-                       //^^^^^^^^^^^&mut $
-                       //^^^^^^^^^^^*
-
-    Struct.consume();
-    Struct.by_ref();
-  //^^^^^^(
-  //^^^^^^&
-  //^^^^^^)
-    Struct.by_ref_mut();
-  //^^^^^^(
-  //^^^^^^&mut $
-  //^^^^^^)
-
-    (&Struct).consume();
-   //^^^^^^^*
-    (&Struct).by_ref();
-
-    (&mut Struct).consume();
-   //^^^^^^^^^^^*
-    (&mut Struct).by_ref();
-   //^^^^^^^^^^^&
-   //^^^^^^^^^^^*
-    (&mut Struct).by_ref_mut();
-}
-
-#[derive(Copy, Clone)]
-struct Struct;
-impl Struct {
-    fn consume(self) {}
-    fn by_ref(&self) {}
-    fn by_ref_mut(&mut self) {}
-}
-"#,
-        )
-    }
 }
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 7402e86f36..841a5832c5 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -81,8 +81,8 @@ pub use crate::{
     highlight_related::{HighlightRelatedConfig, HighlightedRange},
     hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
     inlay_hints::{
-        AdjustmentHints, ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig,
-        InlayKind, InlayTooltip, LifetimeElisionHints,
+        ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
+        InlayTooltip, LifetimeElisionHints, ReborrowHints,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs
index fcbf6d8e58..07d117aff1 100644
--- a/crates/ide/src/moniker.rs
+++ b/crates/ide/src/moniker.rs
@@ -1,9 +1,9 @@
 //! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports)
 //! for LSIF and LSP.
 
-use hir::{AsAssocItem, AssocItemContainer, Crate, Name, Semantics};
+use hir::{db::DefDatabase, AsAssocItem, AssocItemContainer, Crate, Name, Semantics};
 use ide_db::{
-    base_db::{CrateOrigin, FilePosition, LangCrateOrigin},
+    base_db::{CrateOrigin, FileId, FileLoader, FilePosition, LangCrateOrigin},
     defs::{Definition, IdentClass},
     helpers::pick_best_token,
     RootDatabase,
@@ -11,7 +11,7 @@ use ide_db::{
 use itertools::Itertools;
 use syntax::{AstNode, SyntaxKind::*, T};
 
-use crate::{doc_links::token_as_doc_comment, parent_module::crates_for, RangeInfo};
+use crate::{doc_links::token_as_doc_comment, RangeInfo};
 
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub enum MonikerDescriptorKind {
@@ -77,13 +77,25 @@ pub struct PackageInformation {
     pub version: Option<String>,
 }
 
+pub(crate) fn crate_for_file(db: &RootDatabase, file_id: FileId) -> Option<Crate> {
+    for &krate in db.relevant_crates(file_id).iter() {
+        let crate_def_map = db.crate_def_map(krate);
+        for (_, data) in crate_def_map.modules() {
+            if data.origin.file_id() == Some(file_id) {
+                return Some(krate.into());
+            }
+        }
+    }
+    None
+}
+
 pub(crate) fn moniker(
     db: &RootDatabase,
     FilePosition { file_id, offset }: FilePosition,
 ) -> Option<RangeInfo<Vec<MonikerResult>>> {
     let sema = &Semantics::new(db);
     let file = sema.parse(file_id).syntax().clone();
-    let current_crate: hir::Crate = crates_for(db, file_id).pop()?.into();
+    let current_crate = crate_for_file(db, file_id)?;
     let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
         IDENT
         | INT_NUMBER
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 2380cf7381..27ad1a948d 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -13,8 +13,7 @@ use syntax::{AstNode, SyntaxKind::*, SyntaxToken, TextRange, T};
 
 use crate::{
     hover::hover_for_definition,
-    moniker::{def_to_moniker, MonikerResult},
-    parent_module::crates_for,
+    moniker::{crate_for_file, def_to_moniker, MonikerResult},
     Analysis, Fold, HoverConfig, HoverDocFormat, HoverResult, InlayHint, InlayHintsConfig,
     TryToNav,
 };
@@ -100,7 +99,7 @@ fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
 
 impl StaticIndex<'_> {
     fn add_file(&mut self, file_id: FileId) {
-        let current_crate = crates_for(self.db, file_id).pop().map(Into::into);
+        let current_crate = crate_for_file(self.db, file_id);
         let folds = self.analysis.folding_ranges(file_id).unwrap();
         let inlay_hints = self
             .analysis
@@ -112,7 +111,7 @@ impl StaticIndex<'_> {
                     chaining_hints: true,
                     closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock,
                     lifetime_elision_hints: crate::LifetimeElisionHints::Never,
-                    adjustment_hints: crate::AdjustmentHints::Never,
+                    reborrow_hints: crate::ReborrowHints::Never,
                     hide_named_constructor_hints: false,
                     hide_closure_initialization_hints: false,
                     param_names_for_lifetime_elision_hints: false,
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index d642cd9b92..c278ba2d7c 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -261,7 +261,6 @@ config_data! {
         files_excludeDirs: Vec<PathBuf> = "[]",
         /// Controls file watching implementation.
         files_watcher: FilesWatcherDef = "\"client\"",
-
         /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
         highlightRelated_breakPoints_enable: bool = "true",
         /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).
@@ -321,8 +320,6 @@ config_data! {
         inlayHints_closingBraceHints_minLines: usize               = "25",
         /// Whether to show inlay type hints for return types of closures.
         inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef  = "\"never\"",
-        /// Whether to show inlay hints for type adjustments.
-        inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = "\"never\"",
         /// Whether to show inlay type hints for elided lifetimes in function signatures.
         inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = "\"never\"",
         /// Whether to prefer using parameter names as the name for elided lifetime hints if possible.
@@ -332,8 +329,7 @@ config_data! {
         /// Whether to show function parameter name inlay hints at the call
         /// site.
         inlayHints_parameterHints_enable: bool                     = "true",
-        /// Whether to show inlay hints for compiler inserted reborrows.
-        /// This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.
+        /// Whether to show inlay type hints for compiler inserted reborrows.
         inlayHints_reborrowHints_enable: ReborrowHintsDef          = "\"never\"",
         /// Whether to render leading colons for type hints, and trailing colons for parameter hints.
         inlayHints_renderColons: bool                              = "true",
@@ -1204,15 +1200,10 @@ impl Config {
             hide_closure_initialization_hints: self
                 .data
                 .inlayHints_typeHints_hideClosureInitialization,
-            adjustment_hints: match self.data.inlayHints_expressionAdjustmentHints_enable {
-                AdjustmentHintsDef::Always => ide::AdjustmentHints::Always,
-                AdjustmentHintsDef::Never => match self.data.inlayHints_reborrowHints_enable {
-                    ReborrowHintsDef::Always | ReborrowHintsDef::Mutable => {
-                        ide::AdjustmentHints::ReborrowOnly
-                    }
-                    ReborrowHintsDef::Never => ide::AdjustmentHints::Never,
-                },
-                AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly,
+            reborrow_hints: match self.data.inlayHints_reborrowHints_enable {
+                ReborrowHintsDef::Always => ide::ReborrowHints::Always,
+                ReborrowHintsDef::Never => ide::ReborrowHints::Never,
+                ReborrowHintsDef::Mutable => ide::ReborrowHints::MutableOnly,
             },
             binding_mode_hints: self.data.inlayHints_bindingModeHints_enable,
             param_names_for_lifetime_elision_hints: self
@@ -1547,7 +1538,6 @@ mod de_unit_v {
     named_unit_variant!(all);
     named_unit_variant!(skip_trivial);
     named_unit_variant!(mutable);
-    named_unit_variant!(reborrow);
     named_unit_variant!(with_block);
 }
 
@@ -1697,17 +1687,6 @@ enum ReborrowHintsDef {
     Mutable,
 }
 
-#[derive(Deserialize, Debug, Clone)]
-#[serde(untagged)]
-enum AdjustmentHintsDef {
-    #[serde(deserialize_with = "true_or_always")]
-    Always,
-    #[serde(deserialize_with = "false_or_never")]
-    Never,
-    #[serde(deserialize_with = "de_unit_v::reborrow")]
-    Reborrow,
-}
-
 #[derive(Deserialize, Debug, Clone)]
 #[serde(rename_all = "snake_case")]
 enum FilesWatcherDef {
@@ -2017,19 +1996,6 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
                 "Only show mutable reborrow hints."
             ]
         },
-        "AdjustmentHintsDef" => set! {
-            "type": "string",
-            "enum": [
-                "always",
-                "never",
-                "reborrow"
-            ],
-            "enumDescriptions": [
-                "Always show all adjustment hints.",
-                "Never show adjustment hints.",
-                "Only show auto borrow and dereference adjustment hints."
-            ]
-        },
         "CargoFeaturesDef" => set! {
             "anyOf": [
                 {
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 81cc1952ba..830b071b94 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -440,35 +440,32 @@ pub(crate) fn inlay_hint(
     Ok(lsp_types::InlayHint {
         position: match inlay_hint.kind {
             // before annotated thing
-            InlayKind::ParameterHint | InlayKind::AdjustmentHint | InlayKind::BindingModeHint => {
-                position(line_index, inlay_hint.range.start())
-            }
+            InlayKind::ParameterHint
+            | InlayKind::ImplicitReborrowHint
+            | InlayKind::BindingModeHint => position(line_index, inlay_hint.range.start()),
             // after annotated thing
             InlayKind::ClosureReturnTypeHint
             | InlayKind::TypeHint
             | InlayKind::ChainingHint
             | InlayKind::GenericParamListHint
-            | InlayKind::AdjustmentHintClosingParenthesis
             | InlayKind::LifetimeHint
             | InlayKind::ClosingBraceHint => position(line_index, inlay_hint.range.end()),
         },
         padding_left: Some(match inlay_hint.kind {
             InlayKind::TypeHint => !render_colons,
             InlayKind::ChainingHint | InlayKind::ClosingBraceHint => true,
-            InlayKind::AdjustmentHintClosingParenthesis
-            | InlayKind::BindingModeHint
+            InlayKind::BindingModeHint
             | InlayKind::ClosureReturnTypeHint
             | InlayKind::GenericParamListHint
-            | InlayKind::AdjustmentHint
+            | InlayKind::ImplicitReborrowHint
             | InlayKind::LifetimeHint
             | InlayKind::ParameterHint => false,
         }),
         padding_right: Some(match inlay_hint.kind {
-            InlayKind::AdjustmentHintClosingParenthesis
-            | InlayKind::ChainingHint
+            InlayKind::ChainingHint
             | InlayKind::ClosureReturnTypeHint
             | InlayKind::GenericParamListHint
-            | InlayKind::AdjustmentHint
+            | InlayKind::ImplicitReborrowHint
             | InlayKind::TypeHint
             | InlayKind::ClosingBraceHint => false,
             InlayKind::BindingModeHint => inlay_hint.label.as_simple_str() != Some("&"),
@@ -479,11 +476,10 @@ pub(crate) fn inlay_hint(
             InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => {
                 Some(lsp_types::InlayHintKind::TYPE)
             }
-            InlayKind::AdjustmentHintClosingParenthesis
-            | InlayKind::BindingModeHint
+            InlayKind::BindingModeHint
             | InlayKind::GenericParamListHint
             | InlayKind::LifetimeHint
-            | InlayKind::AdjustmentHint
+            | InlayKind::ImplicitReborrowHint
             | InlayKind::ClosingBraceHint => None,
         },
         text_edits: None,
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index 8990f7a7d4..ba72e64425 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -209,19 +209,17 @@ impl ast::String {
         let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
 
         let mut buf = String::new();
-        let mut prev_end = 0;
+        let mut text_iter = text.chars();
         let mut has_error = false;
         unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match (
             unescaped_char,
             buf.capacity() == 0,
         ) {
             (Ok(c), false) => buf.push(c),
-            (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
-                prev_end = char_range.end
-            }
+            (Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (),
             (Ok(c), true) => {
                 buf.reserve_exact(text.len());
-                buf.push_str(&text[..prev_end]);
+                buf.push_str(&text[..char_range.start]);
                 buf.push(c);
             }
             (Err(_), _) => has_error = true,
@@ -254,19 +252,17 @@ impl ast::ByteString {
         let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
 
         let mut buf: Vec<u8> = Vec::new();
-        let mut prev_end = 0;
+        let mut text_iter = text.chars();
         let mut has_error = false;
         unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match (
             unescaped_char,
             buf.capacity() == 0,
         ) {
             (Ok(c), false) => buf.push(c as u8),
-            (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
-                prev_end = char_range.end
-            }
+            (Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (),
             (Ok(c), true) => {
                 buf.reserve_exact(text.len());
-                buf.extend_from_slice(text[..prev_end].as_bytes());
+                buf.extend_from_slice(text[..char_range.start].as_bytes());
                 buf.push(c as u8);
             }
             (Err(_), _) => has_error = true,
@@ -449,36 +445,6 @@ mod tests {
         check_string_value(r"\foobar", None);
         check_string_value(r"\nfoobar", "\nfoobar");
         check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\");
-        check_string_value(r"\x61bcde", "abcde");
-        check_string_value(
-            r"a\
-bcde", "abcde",
-        );
-    }
-
-    fn check_byte_string_value<'a, const N: usize>(
-        lit: &str,
-        expected: impl Into<Option<&'a [u8; N]>>,
-    ) {
-        assert_eq!(
-            ast::ByteString { syntax: make::tokens::literal(&format!("b\"{}\"", lit)) }
-                .value()
-                .as_deref(),
-            expected.into().map(|value| &value[..])
-        );
-    }
-
-    #[test]
-    fn test_byte_string_escape() {
-        check_byte_string_value(r"foobar", b"foobar");
-        check_byte_string_value(r"\foobar", None::<&[u8; 0]>);
-        check_byte_string_value(r"\nfoobar", b"\nfoobar");
-        check_byte_string_value(r"C:\\Windows\\System32\\", b"C:\\Windows\\System32\\");
-        check_byte_string_value(r"\x61bcde", b"abcde");
-        check_byte_string_value(
-            r"a\
-bcde", b"abcde",
-        );
     }
 
     #[test]
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index da8e629807..f171eb41bf 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -450,11 +450,6 @@ to always show them).
 --
 Whether to show inlay type hints for return types of closures.
 --
-[[rust-analyzer.inlayHints.expressionAdjustmentHints.enable]]rust-analyzer.inlayHints.expressionAdjustmentHints.enable (default: `"never"`)::
-+
---
-Whether to show inlay hints for type adjustments.
---
 [[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`)::
 +
 --
@@ -479,8 +474,7 @@ site.
 [[rust-analyzer.inlayHints.reborrowHints.enable]]rust-analyzer.inlayHints.reborrowHints.enable (default: `"never"`)::
 +
 --
-Whether to show inlay hints for compiler inserted reborrows.
-This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.
+Whether to show inlay type hints for compiler inserted reborrows.
 --
 [[rust-analyzer.inlayHints.renderColons]]rust-analyzer.inlayHints.renderColons (default: `true`)::
 +
diff --git a/editors/code/package.json b/editors/code/package.json
index 75e94af6fd..4357dc7306 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -935,21 +935,6 @@
                         "Only show type hints for return types of closures with blocks."
                     ]
                 },
-                "rust-analyzer.inlayHints.expressionAdjustmentHints.enable": {
-                    "markdownDescription": "Whether to show inlay hints for type adjustments.",
-                    "default": "never",
-                    "type": "string",
-                    "enum": [
-                        "always",
-                        "never",
-                        "reborrow"
-                    ],
-                    "enumDescriptions": [
-                        "Always show all adjustment hints.",
-                        "Never show adjustment hints.",
-                        "Only show auto borrow and dereference adjustment hints."
-                    ]
-                },
                 "rust-analyzer.inlayHints.lifetimeElisionHints.enable": {
                     "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.",
                     "default": "never",
@@ -985,7 +970,7 @@
                     "type": "boolean"
                 },
                 "rust-analyzer.inlayHints.reborrowHints.enable": {
-                    "markdownDescription": "Whether to show inlay hints for compiler inserted reborrows.\nThis setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.",
+                    "markdownDescription": "Whether to show inlay type hints for compiler inserted reborrows.",
                     "default": "never",
                     "type": "string",
                     "enum": [


Test patch:
diff --git a/crates/ide-completion/src/tests/item_list.rs b/crates/ide-completion/src/tests/item_list.rs
index 5076c6e86c..8ed6cb3cf8 100644
--- a/crates/ide-completion/src/tests/item_list.rs
+++ b/crates/ide-completion/src/tests/item_list.rs
@@ -245,3 +245,35 @@ impl Test for () {
         "#]],
     );
 }
+
+#[test]
+fn after_unit_struct() {
+    check(
+        r#"struct S; f$0"#,
+        expect![[r#"
+            ma makro!(…)           macro_rules! makro
+            md module
+            kw const
+            kw crate::
+            kw enum
+            kw extern
+            kw fn
+            kw impl
+            kw mod
+            kw pub
+            kw pub(crate)
+            kw pub(super)
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            sn macro_rules
+            sn tfn (Test function)
+            sn tmod (Test module)
+        "#]],
+    );
+}