Repository: rust-lang/rust-analyzer
Pull request #13832 (2022-12-23 10:37:47)

Enum variant discriminants hints

![image](https://user-images.githubusercontent.com/3757771/209320042-eced617a-9a47-4808-ac23-916f469dc90c.png)



Patch:
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index 20bf8497cb..7aff9b1ae8 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -128,7 +128,7 @@ impl fmt::Display for CrateName {
 impl ops::Deref for CrateName {
     type Target = str;
     fn deref(&self) -> &str {
-        &self.0
+        &*self.0
     }
 }
 
@@ -211,7 +211,7 @@ impl fmt::Display for CrateDisplayName {
 impl ops::Deref for CrateDisplayName {
     type Target = str;
     fn deref(&self) -> &str {
-        &self.crate_name
+        &*self.crate_name
     }
 }
 
diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs
index f725064cda..da11e4ae7b 100644
--- a/crates/base-db/src/lib.rs
+++ b/crates/base-db/src/lib.rs
@@ -77,7 +77,7 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug {
 fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
     let _p = profile::span("parse_query").detail(|| format!("{:?}", file_id));
     let text = db.file_text(file_id);
-    SourceFile::parse(&text)
+    SourceFile::parse(&*text)
 }
 
 /// We don't want to give HIR knowledge of source roots, hence we extract these
diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs
index 78fbaa9d7d..759f3b8c04 100644
--- a/crates/hir-def/src/body.rs
+++ b/crates/hir-def/src/body.rs
@@ -372,7 +372,7 @@ impl Body {
     /// Retrieves all ident patterns this pattern shares the ident with.
     pub fn ident_patterns_for<'slf>(&'slf self, pat: &'slf PatId) -> &'slf [PatId] {
         match self.or_pats.get(pat) {
-            Some(pats) => pats,
+            Some(pats) => &**pats,
             None => std::slice::from_ref(pat),
         }
     }
diff --git a/crates/hir-def/src/body/scope.rs b/crates/hir-def/src/body/scope.rs
index 2617d4288a..45f64ebb06 100644
--- a/crates/hir-def/src/body/scope.rs
+++ b/crates/hir-def/src/body/scope.rs
@@ -47,7 +47,7 @@ pub struct ScopeData {
 impl ExprScopes {
     pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
         let body = db.body(def);
-        let mut scopes = ExprScopes::new(&body);
+        let mut scopes = ExprScopes::new(&*body);
         scopes.shrink_to_fit();
         Arc::new(scopes)
     }
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 1cd42500c0..f21d674f20 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -1345,7 +1345,7 @@ impl DefCollector<'_> {
                     // Missing proc macros are non-fatal, so they are handled specially.
                     DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone(), loc.def.krate)
                 }
-                _ => DefDiagnostic::macro_error(module_id, loc.kind, err.to_string()),
+                _ => DefDiagnostic::macro_error(module_id, loc.kind.clone(), err.to_string()),
             };
 
             self.def_map.diagnostics.push(diag);
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 48581d4e0a..2a41cafba9 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -577,9 +577,10 @@ pub fn callable_sig_from_fnonce(
     let fn_once =
         TyBuilder::trait_ref(db, fn_once_trait).push(self_ty.clone()).push(args.clone()).build();
     let projection =
-        TyBuilder::assoc_type_projection(db, output_assoc_type, Some(fn_once.substitution)).build();
+        TyBuilder::assoc_type_projection(db, output_assoc_type, Some(fn_once.substitution.clone()))
+            .build();
 
     let ret_ty = db.normalize_projection(projection, env);
 
-    Some(CallableSig::from_params_and_return(params, ret_ty, false, Safety::Safe))
+    Some(CallableSig::from_params_and_return(params, ret_ty.clone(), false, Safety::Safe))
 }
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 752a3caceb..e8466a7eda 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -1983,7 +1983,7 @@ fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Intern
             if bound.index_if_innermost().map_or(true, is_allowed) {
                 bound.shifted_in_from(binders).to_const(Interner, ty)
             } else {
-                unknown_const(ty)
+                unknown_const(ty.clone())
             }
         },
     )
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 55950da9d5..569c2bfb9e 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -847,7 +847,7 @@ impl<'db> SemanticsImpl<'db> {
                         }
                     };
                     process_expansion_for_token(&mut stack, file_id, None, token.as_ref())
-                } else if let Some(meta) = ast::Meta::cast(parent) {
+                } else if let Some(meta) = ast::Meta::cast(parent.clone()) {
                     // attribute we failed expansion for earlier, this might be a derive invocation
                     // or derive helper attribute
                     let attr = meta.parent_attr()?;
@@ -1246,7 +1246,7 @@ impl<'db> SemanticsImpl<'db> {
 
     fn with_ctx<F: FnOnce(&mut SourceToDefCtx<'_, '_>) -> T, T>(&self, f: F) -> T {
         let mut cache = self.s2d_cache.borrow_mut();
-        let mut ctx = SourceToDefCtx { db: self.db, cache: &mut cache };
+        let mut ctx = SourceToDefCtx { db: self.db, cache: &mut *cache };
         f(&mut ctx)
     }
 
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index e2fa1d5cab..5e444db4a1 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -118,7 +118,7 @@ impl SourceAnalyzer {
     fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
         let src = match expr {
             ast::Expr::MacroExpr(expr) => {
-                self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?
+                self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?.clone()))?
             }
             _ => InFile::new(self.file_id, expr.clone()),
         };
diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs
index 5ac18727c1..0c546ce5d4 100644
--- a/crates/ide-assists/src/handlers/inline_call.rs
+++ b/crates/ide-assists/src/handlers/inline_call.rs
@@ -394,7 +394,7 @@ fn inline(
     // Inline parameter expressions or generate `let` statements depending on whether inlining works or not.
     for ((pat, param_ty, _), usages, expr) in izip!(params, param_use_nodes, arguments).rev() {
         // izip confuses RA due to our lack of hygiene info currently losing us type info causing incorrect errors
-        let usages: &[ast::PathExpr] = &usages;
+        let usages: &[ast::PathExpr] = &*usages;
         let expr: &ast::Expr = expr;
 
         let insert_let_stmt = || {
diff --git a/crates/ide-assists/src/handlers/replace_or_with_or_else.rs b/crates/ide-assists/src/handlers/replace_or_with_or_else.rs
index f0ed3c4fe6..77382056c1 100644
--- a/crates/ide-assists/src/handlers/replace_or_with_or_else.rs
+++ b/crates/ide-assists/src/handlers/replace_or_with_or_else.rs
@@ -75,7 +75,7 @@ fn into_closure(param: &Expr) -> Expr {
     (|| {
         if let ast::Expr::CallExpr(call) = param {
             if call.arg_list()?.args().count() == 0 {
-                Some(call.expr()?)
+                Some(call.expr()?.clone())
             } else {
                 None
             }
@@ -151,7 +151,7 @@ fn into_call(param: &Expr) -> Expr {
     (|| {
         if let ast::Expr::ClosureExpr(closure) = param {
             if closure.param_list()?.params().count() == 0 {
-                Some(closure.body()?)
+                Some(closure.body()?.clone())
             } else {
                 None
             }
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index ba5afde19b..296dfc1425 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -494,7 +494,7 @@ impl Completions {
             pattern_ctx,
             path_ctx,
             variant,
-            local_name,
+            local_name.clone(),
             None,
         ));
     }
diff --git a/crates/ide-completion/src/completions/postfix.rs b/crates/ide-completion/src/completions/postfix.rs
index 31ec9d9f63..3669f462a9 100644
--- a/crates/ide-completion/src/completions/postfix.rs
+++ b/crates/ide-completion/src/completions/postfix.rs
@@ -224,7 +224,7 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) {
 
     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;
+            resulting_element = expr.clone();
         }
 
         while let Some(parent_ref_element) =
@@ -571,7 +571,7 @@ fn main() { ControlFlow::Break('\\\\') }
         );
 
         check_edit_with_config(
-            config,
+            config.clone(),
             "break",
             r#"
 //- minicore: try
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index c412fd575c..c142a7305f 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -286,7 +286,7 @@ fn analyze(
         ast::NameLike::NameRef(name_ref) => {
             let parent = name_ref.syntax().parent()?;
             let (nameref_ctx, qualifier_ctx) =
-                classify_name_ref(sema, &original_file, name_ref, parent)?;
+                classify_name_ref(sema, &original_file, name_ref, parent.clone())?;
             qual_ctx = qualifier_ctx;
             CompletionAnalysis::NameRef(nameref_ctx)
         }
@@ -585,7 +585,11 @@ fn classify_name_ref(
                 original_file,
                 &record_field.parent_record_pat(),
             ),
-            ..pattern_context_for(sema, original_file, record_field.parent_record_pat().into())
+            ..pattern_context_for(
+                sema,
+                original_file,
+                record_field.parent_record_pat().clone().into(),
+            )
         });
         return Some(make_res(kind));
     }
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index c3ffc6d507..86302cb067 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -131,7 +131,7 @@ pub(crate) fn render_field(
     item.detail(ty.display(ctx.db()).to_string())
         .set_documentation(field.docs(ctx.db()))
         .set_deprecated(is_deprecated)
-        .lookup_by(name);
+        .lookup_by(name.clone());
     item.insert_text(field_with_receiver(receiver.as_ref(), &escaped_name));
     if let Some(receiver) = &dot_access.receiver {
         if let Some(original) = ctx.completion.sema.original_ast_node(receiver.clone()) {
diff --git a/crates/ide-completion/src/render/const_.rs b/crates/ide-completion/src/render/const_.rs
index 70b19988ca..93ea825e00 100644
--- a/crates/ide-completion/src/render/const_.rs
+++ b/crates/ide-completion/src/render/const_.rs
@@ -16,7 +16,7 @@ fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem>
     let (name, escaped_name) = (name.unescaped().to_smol_str(), name.to_smol_str());
     let detail = const_.display(db).to_string();
 
-    let mut item = CompletionItem::new(SymbolKind::Const, ctx.source_range(), name);
+    let mut item = CompletionItem::new(SymbolKind::Const, ctx.source_range(), name.clone());
     item.set_documentation(ctx.docs(const_))
         .set_deprecated(ctx.is_deprecated(const_) || ctx.is_deprecated_assoc_item(const_))
         .detail(detail)
diff --git a/crates/ide-completion/src/render/literal.rs b/crates/ide-completion/src/render/literal.rs
index 64dab02f7c..3aeb69258e 100644
--- a/crates/ide-completion/src/render/literal.rs
+++ b/crates/ide-completion/src/render/literal.rs
@@ -84,7 +84,7 @@ fn render(
         }
         _ => RenderedLiteral {
             literal: escaped_qualified_name.clone(),
-            detail: escaped_qualified_name,
+            detail: escaped_qualified_name.clone(),
         },
     };
 
diff --git a/crates/ide-completion/src/render/type_alias.rs b/crates/ide-completion/src/render/type_alias.rs
index fbe120d2ac..de919429f2 100644
--- a/crates/ide-completion/src/render/type_alias.rs
+++ b/crates/ide-completion/src/render/type_alias.rs
@@ -40,7 +40,7 @@ fn render(
     };
     let detail = type_alias.display(db).to_string();
 
-    let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), name);
+    let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), name.clone());
     item.set_documentation(ctx.docs(type_alias))
         .set_deprecated(ctx.is_deprecated(type_alias) || ctx.is_deprecated_assoc_item(type_alias))
         .detail(detail)
diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs
index 156bbb634e..e0bc0f89f0 100644
--- a/crates/ide-db/src/lib.rs
+++ b/crates/ide-db/src/lib.rs
@@ -165,7 +165,7 @@ pub trait LineIndexDatabase: base_db::SourceDatabase {
 
 fn line_index(db: &dyn LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> {
     let text = db.file_text(file_id);
-    Arc::new(LineIndex::new(&text))
+    Arc::new(LineIndex::new(&*text))
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
diff --git a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index e8df6dcf28..3034295196 100644
--- a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -125,7 +125,7 @@ pub(crate) fn json_in_items(
                         .severity(Severity::WeakWarning)
                         .with_fixes(Some(vec![{
                             let mut scb = SourceChangeBuilder::new(file_id);
-                            let scope = match import_scope {
+                            let scope = match import_scope.clone() {
                                 ImportScope::File(it) => ImportScope::File(scb.make_mut(it)),
                                 ImportScope::Module(it) => ImportScope::Module(scb.make_mut(it)),
                                 ImportScope::Block(it) => ImportScope::Block(scb.make_mut(it)),
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 6b3c15fba7..073252e17b 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -24,12 +24,14 @@ mod chaining;
 mod param_name;
 mod binding_mode;
 mod bind_pat;
+mod discrimant;
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct InlayHintsConfig {
     pub location_links: bool,
     pub render_colons: bool,
     pub type_hints: bool,
+    pub discriminant_hints: DiscriminantHints,
     pub parameter_hints: bool,
     pub chaining_hints: bool,
     pub adjustment_hints: AdjustmentHints,
@@ -51,6 +53,13 @@ pub enum ClosureReturnTypeHints {
     Never,
 }
 
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum DiscriminantHints {
+    Always,
+    Never,
+    Fieldless,
+}
+
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub enum LifetimeElisionHints {
     Always,
@@ -76,6 +85,7 @@ pub enum InlayKind {
     LifetimeHint,
     ParameterHint,
     TypeHint,
+    DiscriminantHint,
     OpeningParenthesis,
     ClosingParenthesis,
 }
@@ -365,6 +375,9 @@ fn hints(
                 ast::Item::Const(it) => implicit_static::hints(hints, config, Either::Right(it)),
                 _ => None,
             },
+            ast::Variant(v) => {
+                discrimant::hints(hints, famous_defs, config, file_id, &v)
+            },
             // FIXME: fn-ptr type, dyn fn type, and trait object type elisions
             ast::Type(_) => None,
             _ => None,
@@ -418,12 +431,14 @@ mod tests {
     use test_utils::extract_annotations;
 
     use crate::inlay_hints::AdjustmentHints;
+    use crate::DiscriminantHints;
     use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
 
     use super::ClosureReturnTypeHints;
 
     pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig {
         location_links: false,
+        discriminant_hints: DiscriminantHints::Never,
         render_colons: false,
         type_hints: false,
         parameter_hints: false,
@@ -459,7 +474,7 @@ mod tests {
     #[track_caller]
     pub(super) fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
         let (analysis, file_id) = fixture::file(ra_fixture);
-        let mut expected = extract_annotations(&analysis.file_text(file_id).unwrap());
+        let mut expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
         let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
         let actual = inlay_hints
             .into_iter()
diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs
index 4e63740098..e22b16a3f8 100644
--- a/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/crates/ide/src/inlay_hints/bind_pat.rs
@@ -81,7 +81,7 @@ fn should_not_display_type_hint(
 
     if config.hide_closure_initialization_hints {
         if let Some(parent) = bind_pat.syntax().parent() {
-            if let Some(it) = ast::LetStmt::cast(parent) {
+            if let Some(it) = ast::LetStmt::cast(parent.clone()) {
                 if let Some(ast::Expr::ClosureExpr(closure)) = it.initializer() {
                     if closure_has_block_body(&closure) {
                         return true;
@@ -463,7 +463,7 @@ fn main() {
         }
         "#;
         let (analysis, file_id) = fixture::file(fixture);
-        let expected = extract_annotations(&analysis.file_text(file_id).unwrap());
+        let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
         let inlay_hints = analysis
             .inlay_hints(
                 &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
diff --git a/crates/ide/src/inlay_hints/binding_mode.rs b/crates/ide/src/inlay_hints/binding_mode.rs
index b10dbba6ee..846f0a4e0c 100644
--- a/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/crates/ide/src/inlay_hints/binding_mode.rs
@@ -31,8 +31,7 @@ pub(super) fn hints(
         .last();
     let range =
         outer_paren_pat.as_ref().map_or_else(|| pat.syntax(), |it| it.syntax()).text_range();
-    let pattern_adjustments = sema.pattern_adjustments(&pat);
-    pattern_adjustments.iter().for_each(|ty| {
+    sema.pattern_adjustments(&pat).iter().for_each(|ty| {
         let reference = ty.is_reference();
         let mut_reference = ty.is_mutable_reference();
         let r = match (reference, mut_reference) {
@@ -62,7 +61,7 @@ pub(super) fn hints(
                 tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
             });
         }
-        ast::Pat::OrPat(pat) if !pattern_adjustments.is_empty() && outer_paren_pat.is_none() => {
+        ast::Pat::OrPat(pat) if outer_paren_pat.is_none() => {
             acc.push(InlayHint {
                 range: pat.syntax().text_range(),
                 kind: InlayKind::OpeningParenthesis,
diff --git a/crates/ide/src/inlay_hints/closure_ret.rs b/crates/ide/src/inlay_hints/closure_ret.rs
index d9929beaac..e711a4af23 100644
--- a/crates/ide/src/inlay_hints/closure_ret.rs
+++ b/crates/ide/src/inlay_hints/closure_ret.rs
@@ -32,7 +32,7 @@ pub(super) fn hints(
 
     let param_list = closure.param_list()?;
 
-    let closure = sema.descend_node_into_attributes(closure).pop()?;
+    let closure = sema.descend_node_into_attributes(closure.clone()).pop()?;
     let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure))?.adjusted();
     let callable = ty.as_callable(sema.db)?;
     let ty = callable.return_type();
diff --git a/crates/ide/src/inlay_hints/discrimant.rs b/crates/ide/src/inlay_hints/discrimant.rs
new file mode 100644
index 0000000000..f32c4bdf28
--- /dev/null
+++ b/crates/ide/src/inlay_hints/discrimant.rs
@@ -0,0 +1,142 @@
+//! Implementation of "enum variant discriminant" inlay hints:
+//! ```no_run
+//! enum Foo {
+//!    Bar/* = 0*/,
+//! }
+//! ```
+use ide_db::{base_db::FileId, famous_defs::FamousDefs};
+use syntax::ast::{self, AstNode, HasName};
+
+use crate::{DiscriminantHints, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip};
+
+pub(super) fn hints(
+    acc: &mut Vec<InlayHint>,
+    FamousDefs(sema, _): &FamousDefs<'_, '_>,
+    config: &InlayHintsConfig,
+    _: FileId,
+    variant: &ast::Variant,
+) -> Option<()> {
+    let field_list = match config.discriminant_hints {
+        DiscriminantHints::Always => variant.field_list(),
+        DiscriminantHints::Fieldless => match variant.field_list() {
+            Some(_) => return None,
+            None => None,
+        },
+        DiscriminantHints::Never => return None,
+    };
+
+    if variant.eq_token().is_some() {
+        return None;
+    }
+
+    let name = variant.name()?;
+
+    let descended = sema.descend_node_into_attributes(variant.clone()).pop();
+    let desc_pat = descended.as_ref().unwrap_or(variant);
+    let v = sema.to_def(desc_pat)?;
+    let d = v.eval(sema.db);
+
+    acc.push(InlayHint {
+        range: match field_list {
+            Some(field_list) => name.syntax().text_range().cover(field_list.syntax().text_range()),
+            None => name.syntax().text_range(),
+        },
+        kind: InlayKind::DiscriminantHint,
+        label: match &d {
+            Ok(v) => format!("{}", v).into(),
+            Err(_) => "?".into(),
+        },
+        tooltip: Some(InlayTooltip::String(match &d {
+            Ok(_) => "enum variant discriminant".into(),
+            Err(e) => format!("{e:?}").into(),
+        })),
+    });
+
+    Some(())
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::inlay_hints::{
+        tests::{check_with_config, DISABLED_CONFIG},
+        DiscriminantHints, InlayHintsConfig,
+    };
+
+    #[track_caller]
+    fn check_discriminants(ra_fixture: &str) {
+        check_with_config(
+            InlayHintsConfig { discriminant_hints: DiscriminantHints::Always, ..DISABLED_CONFIG },
+            ra_fixture,
+        );
+    }
+
+    #[track_caller]
+    fn check_discriminants_fieldless(ra_fixture: &str) {
+        check_with_config(
+            InlayHintsConfig {
+                discriminant_hints: DiscriminantHints::Fieldless,
+                ..DISABLED_CONFIG
+            },
+            ra_fixture,
+        );
+    }
+
+    #[test]
+    fn fieldless() {
+        check_discriminants(
+            r#"
+enum Enum {
+    Variant,
+  //^^^^^^^0
+    Variant1,
+  //^^^^^^^^1
+    Variant2,
+  //^^^^^^^^2
+    Variant5 = 5,
+    Variant6,
+  //^^^^^^^^6
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn datacarrying_mixed() {
+        check_discriminants(
+            r#"
+enum Enum {
+    Variant(),
+  //^^^^^^^^^0
+    Variant1,
+  //^^^^^^^^1
+    Variant2 {},
+  //^^^^^^^^^^^2
+    Variant3,
+  //^^^^^^^^3
+    Variant5 = 5,
+    Variant6,
+  //^^^^^^^^6
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn datacarrying_mixed_fieldless_set() {
+        check_discriminants_fieldless(
+            r#"
+enum Enum {
+    Variant(),
+    Variant1,
+  //^^^^^^^^1
+    Variant2 {},
+    Variant3,
+  //^^^^^^^^3
+    Variant5 = 5,
+    Variant6,
+  //^^^^^^^^6
+}
+"#,
+        );
+    }
+}
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 6698bf766a..200958a433 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,
+        AdjustmentHints, ClosureReturnTypeHints, DiscriminantHints, InlayHint, InlayHintLabel,
+        InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index a8ffc38708..331ff82265 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -108,6 +108,7 @@ impl StaticIndex<'_> {
                 &InlayHintsConfig {
                     location_links: true,
                     render_colons: true,
+                    discriminant_hints: crate::DiscriminantHints::Fieldless,
                     type_hints: true,
                     parameter_hints: true,
                     chaining_hints: true,
diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs
index b48921f191..f4b9988eac 100644
--- a/crates/parser/src/lexed_str.rs
+++ b/crates/parser/src/lexed_str.rs
@@ -57,7 +57,7 @@ impl<'a> LexedStr<'a> {
         let mut conv = Converter::new(text);
         conv.extend_token(&token.kind, text);
         match &*conv.res.kind {
-            [kind] => Some((*kind, conv.res.error.pop().map(|it| it.msg))),
+            [kind] => Some((*kind, conv.res.error.pop().map(|it| it.msg.clone()))),
             _ => None,
         }
     }
diff --git a/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/client.rs b/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/client.rs
index e78842f5c3..ed0e91da36 100644
--- a/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/client.rs
+++ b/crates/proc-macro-srv/src/abis/abi_1_58/proc_macro/bridge/client.rs
@@ -286,7 +286,7 @@ impl BridgeState<'_> {
         BRIDGE_STATE.with(|state| {
             state.replace(BridgeState::InUse, |mut state| {
                 // FIXME(#52812) pass `f` directly to `replace` when `RefMutL` is gone
-                f(&mut state)
+                f(&mut *state)
             })
         })
     }
diff --git a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/client.rs b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/client.rs
index b346c2c189..102027d14a 100644
--- a/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/client.rs
+++ b/crates/proc-macro-srv/src/abis/abi_1_63/proc_macro/bridge/client.rs
@@ -301,7 +301,7 @@ impl BridgeState<'_> {
         BRIDGE_STATE.with(|state| {
             state.replace(BridgeState::InUse, |mut state| {
                 // FIXME(#52812) pass `f` directly to `replace` when `RefMutL` is gone
-                f(&mut state)
+                f(&mut *state)
             })
         })
     }
diff --git a/crates/proc-macro-srv/src/abis/mod.rs b/crates/proc-macro-srv/src/abis/mod.rs
index 5b8aca4d81..0ce099ae0b 100644
--- a/crates/proc-macro-srv/src/abis/mod.rs
+++ b/crates/proc-macro-srv/src/abis/mod.rs
@@ -117,7 +117,7 @@ impl Abi {
                 let inner = unsafe { Abi_1_63::from_lib(lib, symbol_name) }?;
                 Ok(Abi::Abi1_63(inner))
             }
-            _ => Err(LoadProcMacroDylibError::UnsupportedABI(info.version_string)),
+            _ => Err(LoadProcMacroDylibError::UnsupportedABI(info.version_string.clone())),
         }
     }
 
diff --git a/crates/profile/src/hprof.rs b/crates/profile/src/hprof.rs
index deea0b0dd8..b562c193e7 100644
--- a/crates/profile/src/hprof.rs
+++ b/crates/profile/src/hprof.rs
@@ -133,7 +133,7 @@ static FILTER: Lazy<RwLock<Filter>> = Lazy::new(Default::default);
 
 fn with_profile_stack<T>(f: impl FnOnce(&mut ProfileStack) -> T) -> T {
     thread_local!(static STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new()));
-    STACK.with(|it| f(&mut it.borrow_mut()))
+    STACK.with(|it| f(&mut *it.borrow_mut()))
 }
 
 #[derive(Default, Clone, Debug)]
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index 93f44d1ef5..02ec7a4f6f 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -427,7 +427,7 @@ impl CargoWorkspace {
     }
 
     pub fn package_flag(&self, package: &PackageData) -> String {
-        if self.is_unique(&package.name) {
+        if self.is_unique(&*package.name) {
             package.name.clone()
         } else {
             format!("{}:{}", package.name, package.version)
diff --git a/crates/project-model/src/manifest_path.rs b/crates/project-model/src/manifest_path.rs
index 980d92d3df..4910fd3d11 100644
--- a/crates/project-model/src/manifest_path.rs
+++ b/crates/project-model/src/manifest_path.rs
@@ -40,7 +40,7 @@ impl ops::Deref for ManifestPath {
     type Target = AbsPath;
 
     fn deref(&self) -> &Self::Target {
-        &self.file
+        &*self.file
     }
 }
 
diff --git a/crates/rust-analyzer/src/cli/lsif.rs b/crates/rust-analyzer/src/cli/lsif.rs
index 4316177841..c74ddabb17 100644
--- a/crates/rust-analyzer/src/cli/lsif.rs
+++ b/crates/rust-analyzer/src/cli/lsif.rs
@@ -253,7 +253,7 @@ impl LsifManager<'_> {
         };
         let result = folds
             .into_iter()
-            .map(|it| to_proto::folding_range(&text, &line_index, false, it))
+            .map(|it| to_proto::folding_range(&*text, &line_index, false, it))
             .collect();
         let folding_id = self.add_vertex(lsif::Vertex::FoldingRangeResult { result });
         self.add_edge(lsif::Edge::FoldingRange(lsif::EdgeData {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 76ff2d5859..0fe4c2bb99 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -327,6 +327,8 @@ 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 enum variant discriminant hints.
+        inlayHints_discriminantHints_enable: DiscriminantHintsDef            = "\"never\"",
         /// Whether to show inlay hints for type adjustments.
         inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = "\"never\"",
         /// Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
@@ -1218,6 +1220,11 @@ impl Config {
             type_hints: self.data.inlayHints_typeHints_enable,
             parameter_hints: self.data.inlayHints_parameterHints_enable,
             chaining_hints: self.data.inlayHints_chainingHints_enable,
+            discriminant_hints: match self.data.inlayHints_discriminantHints_enable {
+                DiscriminantHintsDef::Always => ide::DiscriminantHints::Always,
+                DiscriminantHintsDef::Never => ide::DiscriminantHints::Never,
+                DiscriminantHintsDef::Fieldless => ide::DiscriminantHints::Fieldless,
+            },
             closure_return_type_hints: match self.data.inlayHints_closureReturnTypeHints_enable {
                 ClosureReturnTypeHintsDef::Always => ide::ClosureReturnTypeHints::Always,
                 ClosureReturnTypeHintsDef::Never => ide::ClosureReturnTypeHints::Never,
@@ -1579,6 +1586,7 @@ mod de_unit_v {
     named_unit_variant!(skip_trivial);
     named_unit_variant!(mutable);
     named_unit_variant!(reborrow);
+    named_unit_variant!(fieldless);
     named_unit_variant!(with_block);
 }
 
@@ -1742,6 +1750,17 @@ enum AdjustmentHintsDef {
     Reborrow,
 }
 
+#[derive(Deserialize, Debug, Clone)]
+#[serde(untagged)]
+enum DiscriminantHintsDef {
+    #[serde(deserialize_with = "true_or_always")]
+    Always,
+    #[serde(deserialize_with = "false_or_never")]
+    Never,
+    #[serde(deserialize_with = "de_unit_v::fieldless")]
+    Fieldless,
+}
+
 #[derive(Deserialize, Debug, Clone)]
 #[serde(rename_all = "snake_case")]
 enum FilesWatcherDef {
@@ -2064,6 +2083,19 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
                 "Only show auto borrow and dereference adjustment hints."
             ]
         },
+        "DiscriminantHintsDef" => set! {
+            "type": "string",
+            "enum": [
+                "always",
+                "never",
+                "fieldless"
+            ],
+            "enumDescriptions": [
+                "Always show all discriminant hints.",
+                "Never show discriminant hints.",
+                "Only show discriminant hints on fieldless enum variants."
+            ]
+        },
         "CargoFeaturesDef" => set! {
             "anyOf": [
                 {
@@ -2178,7 +2210,7 @@ fn manual(fields: &[(&'static str, &'static str, &[&str], &str)]) -> String {
         .iter()
         .map(|(field, _ty, doc, default)| {
             let name = format!("rust-analyzer.{}", field.replace('_', "."));
-            let doc = doc_comment_to_string(doc);
+            let doc = doc_comment_to_string(*doc);
             if default.contains('\n') {
                 format!(
                     r#"[[{}]]{}::
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 7a4d372a28..2850bc2c3d 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -899,7 +899,7 @@ pub(crate) fn handle_folding_range(
     let line_folding_only = snap.config.line_folding_only();
     let res = folds
         .into_iter()
-        .map(|it| to_proto::folding_range(&text, &line_index, line_folding_only, it))
+        .map(|it| to_proto::folding_range(&*text, &line_index, line_folding_only, it))
         .collect();
     Ok(Some(res))
 }
@@ -979,7 +979,7 @@ pub(crate) fn handle_rename(
     let position = from_proto::file_position(&snap, params.text_document_position)?;
 
     let mut change =
-        snap.analysis.rename(position, &params.new_name)?.map_err(to_proto::rename_error)?;
+        snap.analysis.rename(position, &*params.new_name)?.map_err(to_proto::rename_error)?;
 
     // this is kind of a hack to prevent double edits from happening when moving files
     // When a module gets renamed by renaming the mod declaration this causes the file to move
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 2d443231b4..47776f734b 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -561,7 +561,10 @@ impl GlobalState {
                     flycheck::Progress::DidCheckCrate(target) => (Progress::Report, Some(target)),
                     flycheck::Progress::DidCancel => (Progress::End, None),
                     flycheck::Progress::DidFailToRestart(err) => {
-                        self.show_and_log_error("cargo check failed".to_string(), Some(err));
+                        self.show_and_log_error(
+                            "cargo check failed".to_string(),
+                            Some(err.to_string()),
+                        );
                         return;
                     }
                     flycheck::Progress::DidFinish(result) => {
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 9bbce70ec0..faf7a2c213 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -461,7 +461,7 @@ impl GlobalState {
             flycheck::InvocationStrategy::Once => vec![FlycheckHandle::spawn(
                 0,
                 Box::new(move |msg| sender.send(msg).unwrap()),
-                config,
+                config.clone(),
                 self.config.root_path().clone(),
             )],
             flycheck::InvocationStrategy::PerWorkspace => {
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index a7106acc78..0a11aaf3af 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -434,6 +434,7 @@ pub(crate) fn inlay_hint(
         InlayKind::ParameterHint if render_colons => inlay_hint.label.append_str(":"),
         InlayKind::TypeHint if render_colons => inlay_hint.label.prepend_str(": "),
         InlayKind::ClosureReturnTypeHint => inlay_hint.label.prepend_str(" -> "),
+        InlayKind::DiscriminantHint => inlay_hint.label.prepend_str(" = "),
         _ => {}
     }
 
@@ -447,6 +448,7 @@ pub(crate) fn inlay_hint(
             // after annotated thing
             InlayKind::ClosureReturnTypeHint
             | InlayKind::TypeHint
+            | InlayKind::DiscriminantHint
             | InlayKind::ChainingHint
             | InlayKind::GenericParamListHint
             | InlayKind::ClosingParenthesis
@@ -457,6 +459,7 @@ pub(crate) fn inlay_hint(
             InlayKind::TypeHint => !render_colons,
             InlayKind::ChainingHint | InlayKind::ClosingBraceHint => true,
             InlayKind::ClosingParenthesis
+            | InlayKind::DiscriminantHint
             | InlayKind::OpeningParenthesis
             | InlayKind::BindingModeHint
             | InlayKind::ClosureReturnTypeHint
@@ -473,6 +476,7 @@ pub(crate) fn inlay_hint(
             | InlayKind::GenericParamListHint
             | InlayKind::AdjustmentHint
             | InlayKind::TypeHint
+            | InlayKind::DiscriminantHint
             | InlayKind::ClosingBraceHint => false,
             InlayKind::BindingModeHint => inlay_hint.label.as_simple_str() != Some("&"),
             InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
@@ -483,6 +487,7 @@ pub(crate) fn inlay_hint(
                 Some(lsp_types::InlayHintKind::TYPE)
             }
             InlayKind::ClosingParenthesis
+            | InlayKind::DiscriminantHint
             | InlayKind::OpeningParenthesis
             | InlayKind::BindingModeHint
             | InlayKind::GenericParamListHint
diff --git a/crates/stdx/src/panic_context.rs b/crates/stdx/src/panic_context.rs
index a64f9a6f3f..f8fafc5a67 100644
--- a/crates/stdx/src/panic_context.rs
+++ b/crates/stdx/src/panic_context.rs
@@ -45,5 +45,5 @@ fn with_ctx(f: impl FnOnce(&mut Vec<String>)) {
     thread_local! {
         static CTX: RefCell<Vec<String>> = RefCell::new(Vec::new());
     }
-    CTX.with(|ctx| f(&mut ctx.borrow_mut()));
+    CTX.with(|ctx| f(&mut *ctx.borrow_mut()));
 }
diff --git a/crates/tt/src/buffer.rs b/crates/tt/src/buffer.rs
index d27a7aa0d4..69226bd4c4 100644
--- a/crates/tt/src/buffer.rs
+++ b/crates/tt/src/buffer.rs
@@ -190,7 +190,7 @@ impl<'a> Cursor<'a> {
     pub fn token_tree(self) -> Option<TokenTreeRef<'a>> {
         match self.entry() {
             Some(Entry::Leaf(tt)) => match tt {
-                TokenTree::Leaf(leaf) => Some(TokenTreeRef::Leaf(leaf, tt)),
+                TokenTree::Leaf(leaf) => Some(TokenTreeRef::Leaf(leaf, *tt)),
                 TokenTree::Subtree(subtree) => Some(TokenTreeRef::Subtree(subtree, Some(tt))),
             },
             Some(Entry::Subtree(tt, subtree, _)) => Some(TokenTreeRef::Subtree(subtree, *tt)),
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 867fd5620f..91f8e98449 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -454,6 +454,11 @@ to always show them).
 --
 Whether to show inlay type hints for return types of closures.
 --
+[[rust-analyzer.inlayHints.discriminantHints.enable]]rust-analyzer.inlayHints.discriminantHints.enable (default: `"never"`)::
++
+--
+Whether to show enum variant discriminant hints.
+--
 [[rust-analyzer.inlayHints.expressionAdjustmentHints.enable]]rust-analyzer.inlayHints.expressionAdjustmentHints.enable (default: `"never"`)::
 +
 --
diff --git a/editors/code/package.json b/editors/code/package.json
index fad67ce803..b45058a6cf 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -960,6 +960,21 @@
                         "Only show type hints for return types of closures with blocks."
                     ]
                 },
+                "rust-analyzer.inlayHints.discriminantHints.enable": {
+                    "markdownDescription": "Whether to show enum variant discriminant hints.",
+                    "default": "never",
+                    "type": "string",
+                    "enum": [
+                        "always",
+                        "never",
+                        "fieldless"
+                    ],
+                    "enumDescriptions": [
+                        "Always show all discriminant hints.",
+                        "Never show discriminant hints.",
+                        "Only show discriminant hints on fieldless enum variants."
+                    ]
+                },
                 "rust-analyzer.inlayHints.expressionAdjustmentHints.enable": {
                     "markdownDescription": "Whether to show inlay hints for type adjustments.",
                     "default": "never",


Test patch:
diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs
index 5e9011f9e8..9e2beb9ee3 100644
--- a/crates/ide-completion/src/tests.rs
+++ b/crates/ide-completion/src/tests.rs
@@ -86,7 +86,7 @@ pub(crate) fn completion_list_no_kw(ra_fixture: &str) -> String {
 }
 
 pub(crate) fn completion_list_no_kw_with_private_editable(ra_fixture: &str) -> String {
-    let mut config = TEST_CONFIG;
+    let mut config = TEST_CONFIG.clone();
     config.enable_private_editable = true;
     completion_list_with_config(config, ra_fixture, false, None)
 }
diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs
index 8296788317..729619cfde 100644
--- a/crates/ide-diagnostics/src/tests.rs
+++ b/crates/ide-diagnostics/src/tests.rs
@@ -102,7 +102,7 @@ pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixtur
     for file_id in files {
         let diagnostics = super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_id);
 
-        let expected = extract_annotations(&db.file_text(file_id));
+        let expected = extract_annotations(&*db.file_text(file_id));
         let mut actual = diagnostics
             .into_iter()
             .map(|d| {