Skip to content

Commit eb3963b

Browse files
committed
Auto merge of rust-lang#13817 - WaffleLapkin:hide_adjustment_hints_outside_of_unsafe, r=Veykril
feat: Add an option to hide adjustment hints outside of `unsafe` blocks and functions As the title suggests: this PR adds an option (namely `rust-analyzer.inlayHints.expressionAdjustmentHints.hideOutsideUnsafe`) that allows to hide adjustment hints outside of `unsafe` blocks and functions: ![2022-12-21_23-11](https://user-images.githubusercontent.com/38225716/208986376-d607de62-8290-4e16-b7fe-15b762dc5f60.png) Requested by `@BoxyUwU` <3
2 parents 271f7b4 + 1038db5 commit eb3963b

File tree

8 files changed

+182
-7
lines changed

8 files changed

+182
-7
lines changed

crates/hir/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ use once_cell::unsync::Lazy;
7474
use rustc_hash::FxHashSet;
7575
use stdx::{impl_from, never};
7676
use syntax::{
77-
ast::{self, Expr, HasAttrs as _, HasDocComments, HasName},
77+
ast::{self, HasAttrs as _, HasDocComments, HasName},
7878
AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T,
7979
};
8080

@@ -1082,7 +1082,7 @@ impl Variant {
10821082
db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
10831083
}
10841084

1085-
pub fn value(self, db: &dyn HirDatabase) -> Option<Expr> {
1085+
pub fn value(self, db: &dyn HirDatabase) -> Option<ast::Expr> {
10861086
self.source(db)?.value.expr()
10871087
}
10881088

crates/hir/src/semantics.rs

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ mod source_to_def;
55
use std::{cell::RefCell, fmt, iter, mem, ops};
66

77
use base_db::{FileId, FileRange};
8+
use either::Either;
89
use hir_def::{
9-
body, macro_id_to_def_id,
10+
body,
11+
expr::Expr,
12+
macro_id_to_def_id,
1013
resolver::{self, HasResolver, Resolver, TypeNs},
1114
type_ref::Mutability,
12-
AsMacroCall, FunctionId, MacroId, TraitId, VariantId,
15+
AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId,
1316
};
1417
use hir_expand::{
1518
db::AstDatabase,
@@ -438,8 +441,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
438441
}
439442

440443
pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
441-
let src = self.imp.find_file(src.syntax()).with_value(src).cloned();
442-
T::to_def(&self.imp, src)
444+
self.imp.to_def(src)
443445
}
444446

445447
pub fn to_module_def(&self, file: FileId) -> Option<Module> {
@@ -481,6 +483,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
481483
pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
482484
self.imp.is_unsafe_ident_pat(ident_pat)
483485
}
486+
487+
/// Returns `true` if the `node` is inside an `unsafe` context.
488+
pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
489+
self.imp.is_inside_unsafe(expr)
490+
}
484491
}
485492

486493
impl<'db> SemanticsImpl<'db> {
@@ -1243,6 +1250,11 @@ impl<'db> SemanticsImpl<'db> {
12431250
f(&mut ctx)
12441251
}
12451252

1253+
fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
1254+
let src = self.find_file(src.syntax()).with_value(src).cloned();
1255+
T::to_def(&self, src)
1256+
}
1257+
12461258
fn to_module_def(&self, file: FileId) -> impl Iterator<Item = Module> {
12471259
self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from)
12481260
}
@@ -1458,6 +1470,56 @@ impl<'db> SemanticsImpl<'db> {
14581470
.map(|ty| ty.original.is_packed(self.db))
14591471
.unwrap_or(false)
14601472
}
1473+
1474+
fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
1475+
let item_or_variant = |ancestor: SyntaxNode| {
1476+
if ast::Item::can_cast(ancestor.kind()) {
1477+
ast::Item::cast(ancestor).map(Either::Left)
1478+
} else {
1479+
ast::Variant::cast(ancestor).map(Either::Right)
1480+
}
1481+
};
1482+
let Some(enclosing_item) = expr.syntax().ancestors().find_map(item_or_variant) else { return false };
1483+
1484+
let def = match &enclosing_item {
1485+
Either::Left(ast::Item::Fn(it)) if it.unsafe_token().is_some() => return true,
1486+
Either::Left(ast::Item::Fn(it)) => {
1487+
self.to_def(it).map(<_>::into).map(DefWithBodyId::FunctionId)
1488+
}
1489+
Either::Left(ast::Item::Const(it)) => {
1490+
self.to_def(it).map(<_>::into).map(DefWithBodyId::ConstId)
1491+
}
1492+
Either::Left(ast::Item::Static(it)) => {
1493+
self.to_def(it).map(<_>::into).map(DefWithBodyId::StaticId)
1494+
}
1495+
Either::Left(_) => None,
1496+
Either::Right(it) => self.to_def(it).map(<_>::into).map(DefWithBodyId::VariantId),
1497+
};
1498+
let Some(def) = def else { return false };
1499+
let enclosing_node = enclosing_item.as_ref().either(|i| i.syntax(), |v| v.syntax());
1500+
1501+
let (body, source_map) = self.db.body_with_source_map(def);
1502+
1503+
let file_id = self.find_file(expr.syntax()).file_id;
1504+
1505+
let Some(mut parent) = expr.syntax().parent() else { return false };
1506+
loop {
1507+
if &parent == enclosing_node {
1508+
break false;
1509+
}
1510+
1511+
if let Some(parent) = ast::Expr::cast(parent.clone()) {
1512+
if let Some(expr_id) = source_map.node_expr(InFile { file_id, value: &parent }) {
1513+
if let Expr::Unsafe { .. } = body[expr_id] {
1514+
break true;
1515+
}
1516+
}
1517+
}
1518+
1519+
let Some(parent_) = parent.parent() else { break false };
1520+
parent = parent_;
1521+
}
1522+
}
14611523
}
14621524

14631525
fn macro_call_to_macro_id(

crates/ide/src/inlay_hints.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub struct InlayHintsConfig {
3333
pub parameter_hints: bool,
3434
pub chaining_hints: bool,
3535
pub adjustment_hints: AdjustmentHints,
36+
pub adjustment_hints_hide_outside_unsafe: bool,
3637
pub closure_return_type_hints: ClosureReturnTypeHints,
3738
pub binding_mode_hints: bool,
3839
pub lifetime_elision_hints: LifetimeElisionHints,
@@ -433,6 +434,7 @@ mod tests {
433434
lifetime_elision_hints: LifetimeElisionHints::Never,
434435
closure_return_type_hints: ClosureReturnTypeHints::Never,
435436
adjustment_hints: AdjustmentHints::Never,
437+
adjustment_hints_hide_outside_unsafe: false,
436438
binding_mode_hints: false,
437439
hide_named_constructor_hints: false,
438440
hide_closure_initialization_hints: false,

crates/ide/src/inlay_hints/adjustment.rs

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
//! ```
66
use hir::{Adjust, AutoBorrow, Mutability, OverloadedDeref, PointerCast, Safety, Semantics};
77
use ide_db::RootDatabase;
8-
98
use syntax::ast::{self, AstNode};
109

1110
use crate::{AdjustmentHints, InlayHint, InlayHintsConfig, InlayKind};
@@ -16,6 +15,10 @@ pub(super) fn hints(
1615
config: &InlayHintsConfig,
1716
expr: &ast::Expr,
1817
) -> Option<()> {
18+
if config.adjustment_hints_hide_outside_unsafe && !sema.is_inside_unsafe(expr) {
19+
return None;
20+
}
21+
1922
if config.adjustment_hints == AdjustmentHints::Never {
2023
return None;
2124
}
@@ -233,4 +236,96 @@ fn or_else() {
233236
"#,
234237
)
235238
}
239+
240+
#[test]
241+
fn adjustment_hints_unsafe_only() {
242+
check_with_config(
243+
InlayHintsConfig {
244+
adjustment_hints: AdjustmentHints::Always,
245+
adjustment_hints_hide_outside_unsafe: true,
246+
..DISABLED_CONFIG
247+
},
248+
r#"
249+
unsafe fn enabled() {
250+
f(&&());
251+
//^^^^&
252+
//^^^^*
253+
//^^^^*
254+
}
255+
256+
fn disabled() {
257+
f(&&());
258+
}
259+
260+
fn mixed() {
261+
f(&&());
262+
263+
unsafe {
264+
f(&&());
265+
//^^^^&
266+
//^^^^*
267+
//^^^^*
268+
}
269+
}
270+
271+
const _: () = {
272+
f(&&());
273+
274+
unsafe {
275+
f(&&());
276+
//^^^^&
277+
//^^^^*
278+
//^^^^*
279+
}
280+
};
281+
282+
static STATIC: () = {
283+
f(&&());
284+
285+
unsafe {
286+
f(&&());
287+
//^^^^&
288+
//^^^^*
289+
//^^^^*
290+
}
291+
};
292+
293+
enum E {
294+
Disable = { f(&&()); 0 },
295+
Enable = unsafe { f(&&()); 1 },
296+
//^^^^&
297+
//^^^^*
298+
//^^^^*
299+
}
300+
301+
const fn f(_: &()) {}
302+
"#,
303+
)
304+
}
305+
306+
#[test]
307+
fn adjustment_hints_unsafe_only_with_item() {
308+
check_with_config(
309+
InlayHintsConfig {
310+
adjustment_hints: AdjustmentHints::Always,
311+
adjustment_hints_hide_outside_unsafe: true,
312+
..DISABLED_CONFIG
313+
},
314+
r#"
315+
fn a() {
316+
struct Struct;
317+
impl Struct {
318+
fn by_ref(&self) {}
319+
}
320+
321+
_ = Struct.by_ref();
322+
323+
_ = unsafe { Struct.by_ref() };
324+
//^^^^^^(
325+
//^^^^^^&
326+
//^^^^^^)
327+
}
328+
"#,
329+
);
330+
}
236331
}

crates/ide/src/static_index.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ impl StaticIndex<'_> {
114114
closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock,
115115
lifetime_elision_hints: crate::LifetimeElisionHints::Never,
116116
adjustment_hints: crate::AdjustmentHints::Never,
117+
adjustment_hints_hide_outside_unsafe: false,
117118
hide_named_constructor_hints: false,
118119
hide_closure_initialization_hints: false,
119120
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.
@@ -1240,6 +1242,9 @@ impl Config {
12401242
},
12411243
AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly,
12421244
},
1245+
adjustment_hints_hide_outside_unsafe: self
1246+
.data
1247+
.inlayHints_expressionAdjustmentHints_hideOutsideUnsafe,
12431248
binding_mode_hints: self.data.inlayHints_bindingModeHints_enable,
12441249
param_names_for_lifetime_elision_hints: self
12451250
.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)