@@ -5,11 +5,14 @@ mod source_to_def;
55use std:: { cell:: RefCell , fmt, iter, mem, ops} ;
66
77use base_db:: { FileId , FileRange } ;
8+ use either:: Either ;
89use 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} ;
1417use 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
486493impl < ' 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
14631525fn macro_call_to_macro_id (
0 commit comments