@@ -12,6 +12,7 @@ use std::{
1212
1313use either:: Either ;
1414use hir_def:: {
15+ expr_store:: ExprOrPatSource ,
1516 hir:: { Expr , ExprOrPatId } ,
1617 lower:: LowerCtx ,
1718 nameres:: { MacroSubNs , ModuleOrigin } ,
@@ -30,6 +31,7 @@ use hir_expand::{
3031 name:: AsName ,
3132 ExpandResult , FileRange , InMacroFile , MacroCallId , MacroFileId , MacroFileIdExt ,
3233} ;
34+ use hir_ty:: diagnostics:: unsafe_operations_for_body;
3335use intern:: { sym, Symbol } ;
3436use itertools:: Itertools ;
3537use rustc_hash:: { FxHashMap , FxHashSet } ;
@@ -48,8 +50,8 @@ use crate::{
4850 db:: HirDatabase ,
4951 semantics:: source_to_def:: { ChildContainer , SourceToDefCache , SourceToDefCtx } ,
5052 source_analyzer:: { name_hygiene, resolve_hir_path, SourceAnalyzer } ,
51- Access , Adjust , Adjustment , Adt , AutoBorrow , BindingMode , BuiltinAttr , Callable , Const ,
52- ConstParam , Crate , DeriveHelper , Enum , Field , Function , GenericSubstitution , HasSource ,
53+ Adjust , Adjustment , Adt , AutoBorrow , BindingMode , BuiltinAttr , Callable , Const , ConstParam ,
54+ Crate , DefWithBody , DeriveHelper , Enum , Field , Function , GenericSubstitution , HasSource ,
5355 HirFileId , Impl , InFile , InlineAsmOperand , ItemInNs , Label , LifetimeParam , Local , Macro ,
5456 Module , ModuleDef , Name , OverloadedDeref , Path , ScopeDef , Static , Struct , ToolModule , Trait ,
5557 TraitAlias , TupleField , Type , TypeAlias , TypeParam , Union , Variant , VariantDef ,
@@ -1555,6 +1557,19 @@ impl<'db> SemanticsImpl<'db> {
15551557 . matched_arm
15561558 }
15571559
1560+ pub fn get_unsafe_ops ( & self , def : DefWithBody ) -> FxHashSet < ExprOrPatSource > {
1561+ let def = DefWithBodyId :: from ( def) ;
1562+ let ( body, source_map) = self . db . body_with_source_map ( def) ;
1563+ let infer = self . db . infer ( def) ;
1564+ let mut res = FxHashSet :: default ( ) ;
1565+ unsafe_operations_for_body ( self . db , & infer, def, & body, & mut |node| {
1566+ if let Ok ( node) = source_map. expr_or_pat_syntax ( node) {
1567+ res. insert ( node) ;
1568+ }
1569+ } ) ;
1570+ res
1571+ }
1572+
15581573 pub fn is_unsafe_macro_call ( & self , macro_call : & ast:: MacroCall ) -> bool {
15591574 let Some ( mac) = self . resolve_macro_call ( macro_call) else { return false } ;
15601575 if mac. is_asm_or_global_asm ( self . db ) {
@@ -1682,6 +1697,15 @@ impl<'db> SemanticsImpl<'db> {
16821697 Some ( res)
16831698 }
16841699
1700+ pub fn body_for ( & self , node : InFile < & SyntaxNode > ) -> Option < DefWithBody > {
1701+ let container = self . with_ctx ( |ctx| ctx. find_container ( node) ) ?;
1702+
1703+ match container {
1704+ ChildContainer :: DefWithBodyId ( def) => Some ( def. into ( ) ) ,
1705+ _ => None ,
1706+ }
1707+ }
1708+
16851709 /// Returns none if the file of the node is not part of a crate.
16861710 fn analyze ( & self , node : & SyntaxNode ) -> Option < SourceAnalyzer > {
16871711 let node = self . find_file ( node) ;
@@ -1783,91 +1807,6 @@ impl<'db> SemanticsImpl<'db> {
17831807 InFile :: new ( file_id, node)
17841808 }
17851809
1786- pub fn is_unsafe_method_call ( & self , method_call_expr : & ast:: MethodCallExpr ) -> bool {
1787- method_call_expr
1788- . receiver ( )
1789- . and_then ( |expr| {
1790- let field_expr = match expr {
1791- ast:: Expr :: FieldExpr ( field_expr) => field_expr,
1792- _ => return None ,
1793- } ;
1794- let ty = self . type_of_expr ( & field_expr. expr ( ) ?) ?. original ;
1795- if !ty. is_packed ( self . db ) {
1796- return None ;
1797- }
1798-
1799- let func = self . resolve_method_call ( method_call_expr) ?;
1800- let res = match func. self_param ( self . db ) ?. access ( self . db ) {
1801- Access :: Shared | Access :: Exclusive => true ,
1802- Access :: Owned => false ,
1803- } ;
1804- Some ( res)
1805- } )
1806- . unwrap_or ( false )
1807- }
1808-
1809- pub fn is_unsafe_ref_expr ( & self , ref_expr : & ast:: RefExpr ) -> bool {
1810- ref_expr
1811- . expr ( )
1812- . and_then ( |expr| {
1813- let field_expr = match expr {
1814- ast:: Expr :: FieldExpr ( field_expr) => field_expr,
1815- _ => return None ,
1816- } ;
1817- let expr = field_expr. expr ( ) ?;
1818- self . type_of_expr ( & expr)
1819- } )
1820- // Binding a reference to a packed type is possibly unsafe.
1821- . map ( |ty| ty. original . is_packed ( self . db ) )
1822- . unwrap_or ( false )
1823-
1824- // FIXME This needs layout computation to be correct. It will highlight
1825- // more than it should with the current implementation.
1826- }
1827-
1828- pub fn is_unsafe_ident_pat ( & self , ident_pat : & ast:: IdentPat ) -> bool {
1829- if ident_pat. ref_token ( ) . is_none ( ) {
1830- return false ;
1831- }
1832-
1833- ident_pat
1834- . syntax ( )
1835- . parent ( )
1836- . and_then ( |parent| {
1837- // `IdentPat` can live under `RecordPat` directly under `RecordPatField` or
1838- // `RecordPatFieldList`. `RecordPatField` also lives under `RecordPatFieldList`,
1839- // so this tries to lookup the `IdentPat` anywhere along that structure to the
1840- // `RecordPat` so we can get the containing type.
1841- let record_pat = ast:: RecordPatField :: cast ( parent. clone ( ) )
1842- . and_then ( |record_pat| record_pat. syntax ( ) . parent ( ) )
1843- . or_else ( || Some ( parent. clone ( ) ) )
1844- . and_then ( |parent| {
1845- ast:: RecordPatFieldList :: cast ( parent) ?
1846- . syntax ( )
1847- . parent ( )
1848- . and_then ( ast:: RecordPat :: cast)
1849- } ) ;
1850-
1851- // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
1852- // this is initialized from a `FieldExpr`.
1853- if let Some ( record_pat) = record_pat {
1854- self . type_of_pat ( & ast:: Pat :: RecordPat ( record_pat) )
1855- } else if let Some ( let_stmt) = ast:: LetStmt :: cast ( parent) {
1856- let field_expr = match let_stmt. initializer ( ) ? {
1857- ast:: Expr :: FieldExpr ( field_expr) => field_expr,
1858- _ => return None ,
1859- } ;
1860-
1861- self . type_of_expr ( & field_expr. expr ( ) ?)
1862- } else {
1863- None
1864- }
1865- } )
1866- // Binding a reference to a packed type is possibly unsafe.
1867- . map ( |ty| ty. original . is_packed ( self . db ) )
1868- . unwrap_or ( false )
1869- }
1870-
18711810 /// Returns `true` if the `node` is inside an `unsafe` context.
18721811 pub fn is_inside_unsafe ( & self , expr : & ast:: Expr ) -> bool {
18731812 let Some ( enclosing_item) =
0 commit comments