@@ -5,11 +5,14 @@ mod source_to_def;
5
5
use std:: { cell:: RefCell , fmt, iter, mem, ops} ;
6
6
7
7
use base_db:: { FileId , FileRange } ;
8
+ use either:: Either ;
8
9
use hir_def:: {
9
- body, macro_id_to_def_id,
10
+ body,
11
+ expr:: Expr ,
12
+ macro_id_to_def_id,
10
13
resolver:: { self , HasResolver , Resolver , TypeNs } ,
11
14
type_ref:: Mutability ,
12
- AsMacroCall , FunctionId , MacroId , TraitId , VariantId ,
15
+ AsMacroCall , DefWithBodyId , FunctionId , MacroId , TraitId , VariantId ,
13
16
} ;
14
17
use hir_expand:: {
15
18
db:: AstDatabase ,
@@ -438,8 +441,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
438
441
}
439
442
440
443
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)
443
445
}
444
446
445
447
pub fn to_module_def ( & self , file : FileId ) -> Option < Module > {
@@ -481,6 +483,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
481
483
pub fn is_unsafe_ident_pat ( & self , ident_pat : & ast:: IdentPat ) -> bool {
482
484
self . imp . is_unsafe_ident_pat ( ident_pat)
483
485
}
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
+ }
484
491
}
485
492
486
493
impl < ' db > SemanticsImpl < ' db > {
@@ -1243,6 +1250,11 @@ impl<'db> SemanticsImpl<'db> {
1243
1250
f ( & mut ctx)
1244
1251
}
1245
1252
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
+
1246
1258
fn to_module_def ( & self , file : FileId ) -> impl Iterator < Item = Module > {
1247
1259
self . with_ctx ( |ctx| ctx. file_to_def ( file) ) . into_iter ( ) . map ( Module :: from)
1248
1260
}
@@ -1458,6 +1470,56 @@ impl<'db> SemanticsImpl<'db> {
1458
1470
. map ( |ty| ty. original . is_packed ( self . db ) )
1459
1471
. unwrap_or ( false )
1460
1472
}
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
+ }
1461
1523
}
1462
1524
1463
1525
fn macro_call_to_macro_id (
0 commit comments