Skip to content

Commit 3bfe704

Browse files
committed
Add an option to hide adjustment hints outside of unsafe blocks
1 parent 4748357 commit 3bfe704

File tree

7 files changed

+181
-4
lines changed

7 files changed

+181
-4
lines changed

crates/hir/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ use hir_def::{
5050
per_ns::PerNs,
5151
resolver::{HasResolver, Resolver},
5252
src::HasSource as _,
53-
AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
54-
EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
53+
AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, EnumId, EnumVariantId,
54+
FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
5555
LocalEnumVariantId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId,
5656
TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
5757
};
@@ -107,13 +107,16 @@ pub use {
107107
hir_def::{
108108
adt::StructKind,
109109
attr::{Attr, Attrs, AttrsWithOwner, Documentation},
110+
body::{Body, BodySourceMap},
110111
builtin_attr::AttributeTemplate,
112+
expr::Expr,
111113
find_path::PrefixKind,
112114
import_map,
113115
nameres::ModuleSource,
114116
path::{ModPath, PathKind},
115117
type_ref::{Mutability, TypeRef},
116118
visibility::Visibility,
119+
DefWithBodyId,
117120
},
118121
hir_expand::{
119122
name::{known, Name},

crates/ide/src/inlay_hints.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub struct InlayHintsConfig {
2828
pub parameter_hints: bool,
2929
pub chaining_hints: bool,
3030
pub adjustment_hints: AdjustmentHints,
31+
pub adjustment_hints_hide_outside_unsafe: bool,
3132
pub closure_return_type_hints: ClosureReturnTypeHints,
3233
pub binding_mode_hints: bool,
3334
pub lifetime_elision_hints: LifetimeElisionHints,
@@ -343,6 +344,7 @@ mod tests {
343344
lifetime_elision_hints: LifetimeElisionHints::Never,
344345
closure_return_type_hints: ClosureReturnTypeHints::Never,
345346
adjustment_hints: AdjustmentHints::Never,
347+
adjustment_hints_hide_outside_unsafe: false,
346348
binding_mode_hints: false,
347349
hide_named_constructor_hints: false,
348350
hide_closure_initialization_hints: false,

crates/ide/src/inlay_hints/adjustment.rs

Lines changed: 158 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,17 @@
33
//! let _: u32 = /* <never-to-any> */ loop {};
44
//! let _: &u32 = /* &* */ &mut 0;
55
//! ```
6-
use hir::{Adjust, AutoBorrow, Mutability, OverloadedDeref, PointerCast, Safety, Semantics};
6+
use either::Either;
7+
use hir::{
8+
db::DefDatabase, Adjust, AutoBorrow, InFile, Mutability, OverloadedDeref, PointerCast, Safety,
9+
Semantics,
10+
};
711
use ide_db::RootDatabase;
812

9-
use syntax::ast::{self, AstNode};
13+
use syntax::{
14+
ast::{self, AstNode},
15+
SyntaxNode,
16+
};
1017

1118
use crate::{AdjustmentHints, InlayHint, InlayHintsConfig, InlayKind};
1219

@@ -16,6 +23,10 @@ pub(super) fn hints(
1623
config: &InlayHintsConfig,
1724
expr: &ast::Expr,
1825
) -> Option<()> {
26+
if config.adjustment_hints_hide_outside_unsafe && !is_inside_unsafe(sema, expr.syntax()) {
27+
return None;
28+
}
29+
1930
if config.adjustment_hints == AdjustmentHints::Never {
2031
return None;
2132
}
@@ -110,6 +121,59 @@ pub(super) fn hints(
110121
Some(())
111122
}
112123

124+
fn is_inside_unsafe(sema: &Semantics<'_, RootDatabase>, node: &SyntaxNode) -> bool {
125+
let item_or_variant = |ancestor: SyntaxNode| {
126+
if ast::Item::can_cast(ancestor.kind()) {
127+
ast::Item::cast(ancestor).map(Either::Left)
128+
} else {
129+
ast::Variant::cast(ancestor).map(Either::Right)
130+
}
131+
};
132+
let Some(enclosing_item) = node.ancestors().find_map(item_or_variant) else { return false };
133+
134+
let def = match &enclosing_item {
135+
Either::Left(ast::Item::Fn(it)) => {
136+
sema.to_def(it).map(<_>::into).map(hir::DefWithBodyId::FunctionId)
137+
}
138+
Either::Left(ast::Item::Const(it)) => {
139+
sema.to_def(it).map(<_>::into).map(hir::DefWithBodyId::ConstId)
140+
}
141+
Either::Left(ast::Item::Static(it)) => {
142+
sema.to_def(it).map(<_>::into).map(hir::DefWithBodyId::StaticId)
143+
}
144+
Either::Left(_) => None,
145+
Either::Right(it) => sema.to_def(it).map(<_>::into).map(hir::DefWithBodyId::VariantId),
146+
};
147+
let Some(def) = def else { return false };
148+
let enclosing_node = enclosing_item.as_ref().either(|i| i.syntax(), |v| v.syntax());
149+
150+
if ast::Fn::cast(enclosing_node.clone()).and_then(|f| f.unsafe_token()).is_some() {
151+
return true;
152+
}
153+
154+
let (body, source_map) = sema.db.body_with_source_map(def);
155+
156+
let file_id = sema.hir_file_for(node);
157+
158+
let Some(mut parent) = node.parent() else { return false };
159+
loop {
160+
if &parent == enclosing_node {
161+
break false;
162+
}
163+
164+
if let Some(parent) = ast::Expr::cast(parent.clone()) {
165+
if let Some(expr_id) = source_map.node_expr(InFile { file_id, value: &parent }) {
166+
if let hir::Expr::Unsafe { .. } = body[expr_id] {
167+
break true;
168+
}
169+
}
170+
}
171+
172+
let Some(parent_) = parent.parent() else { break false };
173+
parent = parent_;
174+
}
175+
}
176+
113177
#[cfg(test)]
114178
mod tests {
115179
use crate::{
@@ -233,4 +297,96 @@ fn or_else() {
233297
"#,
234298
)
235299
}
300+
301+
#[test]
302+
fn adjustment_hints_unsafe_only() {
303+
check_with_config(
304+
InlayHintsConfig {
305+
adjustment_hints: AdjustmentHints::Always,
306+
adjustment_hints_hide_outside_unsafe: true,
307+
..DISABLED_CONFIG
308+
},
309+
r#"
310+
unsafe fn enabled() {
311+
f(&&());
312+
//^^^^&
313+
//^^^^*
314+
//^^^^*
315+
}
316+
317+
fn disabled() {
318+
f(&&());
319+
}
320+
321+
fn mixed() {
322+
f(&&());
323+
324+
unsafe {
325+
f(&&());
326+
//^^^^&
327+
//^^^^*
328+
//^^^^*
329+
}
330+
}
331+
332+
const _: () = {
333+
f(&&());
334+
335+
unsafe {
336+
f(&&());
337+
//^^^^&
338+
//^^^^*
339+
//^^^^*
340+
}
341+
};
342+
343+
static STATIC: () = {
344+
f(&&());
345+
346+
unsafe {
347+
f(&&());
348+
//^^^^&
349+
//^^^^*
350+
//^^^^*
351+
}
352+
};
353+
354+
enum E {
355+
Disable = { f(&&()); 0 },
356+
Enable = unsafe { f(&&()); 1 },
357+
//^^^^&
358+
//^^^^*
359+
//^^^^*
360+
}
361+
362+
const fn f(_: &()) {}
363+
"#,
364+
)
365+
}
366+
367+
#[test]
368+
fn adjustment_hints_unsafe_only_with_item() {
369+
check_with_config(
370+
InlayHintsConfig {
371+
adjustment_hints: AdjustmentHints::Always,
372+
adjustment_hints_hide_outside_unsafe: true,
373+
..DISABLED_CONFIG
374+
},
375+
r#"
376+
fn a() {
377+
struct Struct;
378+
impl Struct {
379+
fn by_ref(&self) {}
380+
}
381+
382+
_ = Struct.by_ref();
383+
384+
_ = unsafe { Struct.by_ref() };
385+
//^^^^^^(
386+
//^^^^^^&
387+
//^^^^^^)
388+
}
389+
"#,
390+
);
391+
}
236392
}

crates/ide/src/static_index.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ impl StaticIndex<'_> {
113113
closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock,
114114
lifetime_elision_hints: crate::LifetimeElisionHints::Never,
115115
adjustment_hints: crate::AdjustmentHints::Never,
116+
adjustment_hints_hide_outside_unsafe: false,
116117
hide_named_constructor_hints: false,
117118
hide_closure_initialization_hints: false,
118119
param_names_for_lifetime_elision_hints: false,

crates/rust-analyzer/src/config.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,8 @@ config_data! {
329329
inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef = "\"never\"",
330330
/// Whether to show inlay hints for type adjustments.
331331
inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = "\"never\"",
332+
/// Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
333+
inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = "false",
332334
/// Whether to show inlay type hints for elided lifetimes in function signatures.
333335
inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = "\"never\"",
334336
/// Whether to prefer using parameter names as the name for elided lifetime hints if possible.
@@ -1224,6 +1226,9 @@ impl Config {
12241226
},
12251227
AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly,
12261228
},
1229+
adjustment_hints_hide_outside_unsafe: self
1230+
.data
1231+
.inlayHints_expressionAdjustmentHints_hideOutsideUnsafe,
12271232
binding_mode_hints: self.data.inlayHints_bindingModeHints_enable,
12281233
param_names_for_lifetime_elision_hints: self
12291234
.data

docs/user/generated_config.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,11 @@ Whether to show inlay type hints for return types of closures.
459459
--
460460
Whether to show inlay hints for type adjustments.
461461
--
462+
[[rust-analyzer.inlayHints.expressionAdjustmentHints.hideOutsideUnsafe]]rust-analyzer.inlayHints.expressionAdjustmentHints.hideOutsideUnsafe (default: `false`)::
463+
+
464+
--
465+
Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
466+
--
462467
[[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`)::
463468
+
464469
--

editors/code/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,11 @@
975975
"Only show auto borrow and dereference adjustment hints."
976976
]
977977
},
978+
"rust-analyzer.inlayHints.expressionAdjustmentHints.hideOutsideUnsafe": {
979+
"markdownDescription": "Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.",
980+
"default": false,
981+
"type": "boolean"
982+
},
978983
"rust-analyzer.inlayHints.lifetimeElisionHints.enable": {
979984
"markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.",
980985
"default": "never",

0 commit comments

Comments
 (0)