about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMaybe Waffle <waffle.lapkin@gmail.com>2022-12-21 18:18:12 +0000
committerMaybe Waffle <waffle.lapkin@gmail.com>2022-12-21 19:20:42 +0000
commit3bfe7040e8321e8fbe3c5bdc8660dae1488838d1 (patch)
tree1df98eeaa4bb7aeb411b73a4eccb3fc37f642573
parent474835704568c4d494206282082d79f57068b060 (diff)
downloadrust-3bfe7040e8321e8fbe3c5bdc8660dae1488838d1.tar.gz
rust-3bfe7040e8321e8fbe3c5bdc8660dae1488838d1.zip
Add an option to hide adjustment hints outside of unsafe blocks
-rw-r--r--crates/hir/src/lib.rs7
-rw-r--r--crates/ide/src/inlay_hints.rs2
-rw-r--r--crates/ide/src/inlay_hints/adjustment.rs160
-rw-r--r--crates/ide/src/static_index.rs1
-rw-r--r--crates/rust-analyzer/src/config.rs5
-rw-r--r--docs/user/generated_config.adoc5
-rw-r--r--editors/code/package.json5
7 files changed, 181 insertions, 4 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 2933d488a18..7c2829c855c 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -50,8 +50,8 @@ use hir_def::{
     per_ns::PerNs,
     resolver::{HasResolver, Resolver},
     src::HasSource as _,
-    AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
-    EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
+    AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, EnumId, EnumVariantId,
+    FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
     LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId,
     TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
 };
@@ -107,13 +107,16 @@ pub use {
     hir_def::{
         adt::StructKind,
         attr::{Attr, Attrs, AttrsWithOwner, Documentation},
+        body::{Body, BodySourceMap},
         builtin_attr::AttributeTemplate,
+        expr::Expr,
         find_path::PrefixKind,
         import_map,
         nameres::ModuleSource,
         path::{ModPath, PathKind},
         type_ref::{Mutability, TypeRef},
         visibility::Visibility,
+        DefWithBodyId,
     },
     hir_expand::{
         name::{known, Name},
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 152f31b3a57..eca76d05fde 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -28,6 +28,7 @@ pub struct InlayHintsConfig {
     pub parameter_hints: bool,
     pub chaining_hints: bool,
     pub adjustment_hints: AdjustmentHints,
+    pub adjustment_hints_hide_outside_unsafe: bool,
     pub closure_return_type_hints: ClosureReturnTypeHints,
     pub binding_mode_hints: bool,
     pub lifetime_elision_hints: LifetimeElisionHints,
@@ -343,6 +344,7 @@ mod tests {
         lifetime_elision_hints: LifetimeElisionHints::Never,
         closure_return_type_hints: ClosureReturnTypeHints::Never,
         adjustment_hints: AdjustmentHints::Never,
+        adjustment_hints_hide_outside_unsafe: false,
         binding_mode_hints: false,
         hide_named_constructor_hints: false,
         hide_closure_initialization_hints: false,
diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs
index b2bec10d05d..c853b924b2f 100644
--- a/crates/ide/src/inlay_hints/adjustment.rs
+++ b/crates/ide/src/inlay_hints/adjustment.rs
@@ -3,10 +3,17 @@
 //! let _: u32  = /* <never-to-any> */ loop {};
 //! let _: &u32 = /* &* */ &mut 0;
 //! ```
-use hir::{Adjust, AutoBorrow, Mutability, OverloadedDeref, PointerCast, Safety, Semantics};
+use either::Either;
+use hir::{
+    db::DefDatabase, Adjust, AutoBorrow, InFile, Mutability, OverloadedDeref, PointerCast, Safety,
+    Semantics,
+};
 use ide_db::RootDatabase;
 
-use syntax::ast::{self, AstNode};
+use syntax::{
+    ast::{self, AstNode},
+    SyntaxNode,
+};
 
 use crate::{AdjustmentHints, InlayHint, InlayHintsConfig, InlayKind};
 
@@ -16,6 +23,10 @@ pub(super) fn hints(
     config: &InlayHintsConfig,
     expr: &ast::Expr,
 ) -> Option<()> {
+    if config.adjustment_hints_hide_outside_unsafe && !is_inside_unsafe(sema, expr.syntax()) {
+        return None;
+    }
+
     if config.adjustment_hints == AdjustmentHints::Never {
         return None;
     }
@@ -110,6 +121,59 @@ pub(super) fn hints(
     Some(())
 }
 
+fn is_inside_unsafe(sema: &Semantics<'_, RootDatabase>, node: &SyntaxNode) -> bool {
+    let item_or_variant = |ancestor: SyntaxNode| {
+        if ast::Item::can_cast(ancestor.kind()) {
+            ast::Item::cast(ancestor).map(Either::Left)
+        } else {
+            ast::Variant::cast(ancestor).map(Either::Right)
+        }
+    };
+    let Some(enclosing_item) = node.ancestors().find_map(item_or_variant) else { return false };
+
+    let def = match &enclosing_item {
+        Either::Left(ast::Item::Fn(it)) => {
+            sema.to_def(it).map(<_>::into).map(hir::DefWithBodyId::FunctionId)
+        }
+        Either::Left(ast::Item::Const(it)) => {
+            sema.to_def(it).map(<_>::into).map(hir::DefWithBodyId::ConstId)
+        }
+        Either::Left(ast::Item::Static(it)) => {
+            sema.to_def(it).map(<_>::into).map(hir::DefWithBodyId::StaticId)
+        }
+        Either::Left(_) => None,
+        Either::Right(it) => sema.to_def(it).map(<_>::into).map(hir::DefWithBodyId::VariantId),
+    };
+    let Some(def) = def else { return false };
+    let enclosing_node = enclosing_item.as_ref().either(|i| i.syntax(), |v| v.syntax());
+
+    if ast::Fn::cast(enclosing_node.clone()).and_then(|f| f.unsafe_token()).is_some() {
+        return true;
+    }
+
+    let (body, source_map) = sema.db.body_with_source_map(def);
+
+    let file_id = sema.hir_file_for(node);
+
+    let Some(mut parent) = node.parent() else { return false };
+    loop {
+        if &parent == enclosing_node {
+            break false;
+        }
+
+        if let Some(parent) = ast::Expr::cast(parent.clone()) {
+            if let Some(expr_id) = source_map.node_expr(InFile { file_id, value: &parent }) {
+                if let hir::Expr::Unsafe { .. } = body[expr_id] {
+                    break true;
+                }
+            }
+        }
+
+        let Some(parent_) = parent.parent() else { break false };
+        parent = parent_;
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use crate::{
@@ -233,4 +297,96 @@ fn or_else() {
             "#,
         )
     }
+
+    #[test]
+    fn adjustment_hints_unsafe_only() {
+        check_with_config(
+            InlayHintsConfig {
+                adjustment_hints: AdjustmentHints::Always,
+                adjustment_hints_hide_outside_unsafe: true,
+                ..DISABLED_CONFIG
+            },
+            r#"
+unsafe fn enabled() {
+    f(&&());
+    //^^^^&
+    //^^^^*
+    //^^^^*
+}
+
+fn disabled() {
+    f(&&());
+}
+
+fn mixed() {
+    f(&&());
+
+    unsafe {
+        f(&&());
+        //^^^^&
+        //^^^^*
+        //^^^^*
+    }
+}
+
+const _: () = {
+    f(&&());
+
+    unsafe {
+        f(&&());
+        //^^^^&
+        //^^^^*
+        //^^^^*
+    }
+};
+
+static STATIC: () = {
+    f(&&());
+
+    unsafe {
+        f(&&());
+        //^^^^&
+        //^^^^*
+        //^^^^*
+    }
+};
+
+enum E {
+    Disable = { f(&&()); 0 },
+    Enable = unsafe { f(&&()); 1 },
+                      //^^^^&
+                      //^^^^*
+                      //^^^^*
+}
+
+const fn f(_: &()) {}
+            "#,
+        )
+    }
+
+    #[test]
+    fn adjustment_hints_unsafe_only_with_item() {
+        check_with_config(
+            InlayHintsConfig {
+                adjustment_hints: AdjustmentHints::Always,
+                adjustment_hints_hide_outside_unsafe: true,
+                ..DISABLED_CONFIG
+            },
+            r#"
+fn a() {
+    struct Struct;
+    impl Struct {
+        fn by_ref(&self) {}
+    }
+
+    _ = Struct.by_ref();
+
+    _ = unsafe { Struct.by_ref() };
+               //^^^^^^(
+               //^^^^^^&
+               //^^^^^^)
+}
+            "#,
+        );
+    }
 }
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 2380cf7381c..4f1946ed487 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -113,6 +113,7 @@ impl StaticIndex<'_> {
                     closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock,
                     lifetime_elision_hints: crate::LifetimeElisionHints::Never,
                     adjustment_hints: crate::AdjustmentHints::Never,
+                    adjustment_hints_hide_outside_unsafe: false,
                     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 835b37c98e2..35d0d8f9772 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -329,6 +329,8 @@ config_data! {
         inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef  = "\"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.
+        inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = "false",
         /// 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.
@@ -1224,6 +1226,9 @@ impl Config {
                 },
                 AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly,
             },
+            adjustment_hints_hide_outside_unsafe: self
+                .data
+                .inlayHints_expressionAdjustmentHints_hideOutsideUnsafe,
             binding_mode_hints: self.data.inlayHints_bindingModeHints_enable,
             param_names_for_lifetime_elision_hints: self
                 .data
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index db41c7bf109..7cff2cbb6a4 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -459,6 +459,11 @@ Whether to show inlay type hints for return types of closures.
 --
 Whether to show inlay hints for type adjustments.
 --
+[[rust-analyzer.inlayHints.expressionAdjustmentHints.hideOutsideUnsafe]]rust-analyzer.inlayHints.expressionAdjustmentHints.hideOutsideUnsafe (default: `false`)::
++
+--
+Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
+--
 [[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`)::
 +
 --
diff --git a/editors/code/package.json b/editors/code/package.json
index f9b0e28dadb..21d65321d2f 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -975,6 +975,11 @@
                         "Only show auto borrow and dereference adjustment hints."
                     ]
                 },
+                "rust-analyzer.inlayHints.expressionAdjustmentHints.hideOutsideUnsafe": {
+                    "markdownDescription": "Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.",
+                    "default": false,
+                    "type": "boolean"
+                },
                 "rust-analyzer.inlayHints.lifetimeElisionHints.enable": {
                     "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.",
                     "default": "never",