Auto merge of #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
This commit is contained in:
commit
eb3963b22e
@ -74,7 +74,7 @@
|
||||
use rustc_hash::FxHashSet;
|
||||
use stdx::{impl_from, never};
|
||||
use syntax::{
|
||||
ast::{self, Expr, HasAttrs as _, HasDocComments, HasName},
|
||||
ast::{self, HasAttrs as _, HasDocComments, HasName},
|
||||
AstNode, AstPtr, SmolStr, SyntaxNodePtr, TextRange, T,
|
||||
};
|
||||
|
||||
@ -1082,7 +1082,7 @@ pub(crate) fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> {
|
||||
db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
|
||||
}
|
||||
|
||||
pub fn value(self, db: &dyn HirDatabase) -> Option<Expr> {
|
||||
pub fn value(self, db: &dyn HirDatabase) -> Option<ast::Expr> {
|
||||
self.source(db)?.value.expr()
|
||||
}
|
||||
|
||||
|
@ -5,11 +5,14 @@
|
||||
use std::{cell::RefCell, fmt, iter, mem, ops};
|
||||
|
||||
use base_db::{FileId, FileRange};
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
body, macro_id_to_def_id,
|
||||
body,
|
||||
expr::Expr,
|
||||
macro_id_to_def_id,
|
||||
resolver::{self, HasResolver, Resolver, TypeNs},
|
||||
type_ref::Mutability,
|
||||
AsMacroCall, FunctionId, MacroId, TraitId, VariantId,
|
||||
AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId,
|
||||
};
|
||||
use hir_expand::{
|
||||
db::AstDatabase,
|
||||
@ -438,8 +441,7 @@ pub fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Fi
|
||||
}
|
||||
|
||||
pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
|
||||
let src = self.imp.find_file(src.syntax()).with_value(src).cloned();
|
||||
T::to_def(&self.imp, src)
|
||||
self.imp.to_def(src)
|
||||
}
|
||||
|
||||
pub fn to_module_def(&self, file: FileId) -> Option<Module> {
|
||||
@ -481,6 +483,11 @@ pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool {
|
||||
pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
|
||||
self.imp.is_unsafe_ident_pat(ident_pat)
|
||||
}
|
||||
|
||||
/// Returns `true` if the `node` is inside an `unsafe` context.
|
||||
pub fn is_inside_unsafe(&self, expr: &ast::Expr) -> bool {
|
||||
self.imp.is_inside_unsafe(expr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> SemanticsImpl<'db> {
|
||||
@ -1243,6 +1250,11 @@ fn with_ctx<F: FnOnce(&mut SourceToDefCtx<'_, '_>) -> T, T>(&self, f: F) -> T {
|
||||
f(&mut ctx)
|
||||
}
|
||||
|
||||
fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
|
||||
let src = self.find_file(src.syntax()).with_value(src).cloned();
|
||||
T::to_def(&self, src)
|
||||
}
|
||||
|
||||
fn to_module_def(&self, file: FileId) -> impl Iterator<Item = Module> {
|
||||
self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from)
|
||||
}
|
||||
@ -1458,6 +1470,56 @@ fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool {
|
||||
.map(|ty| ty.original.is_packed(self.db))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn is_inside_unsafe(&self, expr: &ast::Expr) -> 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) = expr.syntax().ancestors().find_map(item_or_variant) else { return false };
|
||||
|
||||
let def = match &enclosing_item {
|
||||
Either::Left(ast::Item::Fn(it)) if it.unsafe_token().is_some() => return true,
|
||||
Either::Left(ast::Item::Fn(it)) => {
|
||||
self.to_def(it).map(<_>::into).map(DefWithBodyId::FunctionId)
|
||||
}
|
||||
Either::Left(ast::Item::Const(it)) => {
|
||||
self.to_def(it).map(<_>::into).map(DefWithBodyId::ConstId)
|
||||
}
|
||||
Either::Left(ast::Item::Static(it)) => {
|
||||
self.to_def(it).map(<_>::into).map(DefWithBodyId::StaticId)
|
||||
}
|
||||
Either::Left(_) => None,
|
||||
Either::Right(it) => self.to_def(it).map(<_>::into).map(DefWithBodyId::VariantId),
|
||||
};
|
||||
let Some(def) = def else { return false };
|
||||
let enclosing_node = enclosing_item.as_ref().either(|i| i.syntax(), |v| v.syntax());
|
||||
|
||||
let (body, source_map) = self.db.body_with_source_map(def);
|
||||
|
||||
let file_id = self.find_file(expr.syntax()).file_id;
|
||||
|
||||
let Some(mut parent) = expr.syntax().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 Expr::Unsafe { .. } = body[expr_id] {
|
||||
break true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let Some(parent_) = parent.parent() else { break false };
|
||||
parent = parent_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn macro_call_to_macro_id(
|
||||
|
@ -33,6 +33,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,
|
||||
@ -433,6 +434,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,
|
||||
|
@ -5,7 +5,6 @@
|
||||
//! ```
|
||||
use hir::{Adjust, AutoBorrow, Mutability, OverloadedDeref, PointerCast, Safety, Semantics};
|
||||
use ide_db::RootDatabase;
|
||||
|
||||
use syntax::ast::{self, AstNode};
|
||||
|
||||
use crate::{AdjustmentHints, InlayHint, InlayHintsConfig, InlayKind};
|
||||
@ -16,6 +15,10 @@ pub(super) fn hints(
|
||||
config: &InlayHintsConfig,
|
||||
expr: &ast::Expr,
|
||||
) -> Option<()> {
|
||||
if config.adjustment_hints_hide_outside_unsafe && !sema.is_inside_unsafe(expr) {
|
||||
return None;
|
||||
}
|
||||
|
||||
if config.adjustment_hints == AdjustmentHints::Never {
|
||||
return None;
|
||||
}
|
||||
@ -233,4 +236,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() };
|
||||
//^^^^^^(
|
||||
//^^^^^^&
|
||||
//^^^^^^)
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -114,6 +114,7 @@ fn add_file(&mut self, file_id: FileId) {
|
||||
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,
|
||||
|
@ -329,6 +329,8 @@ struct ConfigData {
|
||||
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.
|
||||
@ -1240,6 +1242,9 @@ pub fn inlay_hints(&self) -> InlayHintsConfig {
|
||||
},
|
||||
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
|
||||
|
@ -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"`)::
|
||||
+
|
||||
--
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user