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,
};
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},
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,
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,
//! 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};
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;
}
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::{
"#,
)
}
+
+ #[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() };
+ //^^^^^^(
+ //^^^^^^&
+ //^^^^^^)
+}
+ "#,
+ );
+ }
}
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,
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.
},
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
--
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"`)::
+
--
"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",