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+ } ;
711use ide_db:: RootDatabase ;
812
9- use syntax:: ast:: { self , AstNode } ;
13+ use syntax:: {
14+ ast:: { self , AstNode } ,
15+ SyntaxNode ,
16+ } ;
1017
1118use 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) ]
114178mod 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}
0 commit comments