@@ -278,83 +278,15 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
278278 }
279279
280280 pub fn is_unsafe_method_call ( & self , method_call_expr : ast:: MethodCallExpr ) -> bool {
281- method_call_expr
282- . expr ( )
283- . and_then ( |expr| {
284- let field_expr = if let ast:: Expr :: FieldExpr ( field_expr) = expr {
285- field_expr
286- } else {
287- return None ;
288- } ;
289- let ty = self . type_of_expr ( & field_expr. expr ( ) ?) ?;
290- if !ty. is_packed ( self . db ) {
291- return None ;
292- }
293-
294- let func = self . resolve_method_call ( & method_call_expr) ?;
295- let is_unsafe = func. has_self_param ( self . db )
296- && matches ! ( func. params( self . db) . first( ) , Some ( TypeRef :: Reference ( ..) ) ) ;
297- Some ( is_unsafe)
298- } )
299- . unwrap_or ( false )
281+ self . imp . is_unsafe_method_call ( method_call_expr)
300282 }
301283
302284 pub fn is_unsafe_ref_expr ( & self , ref_expr : & ast:: RefExpr ) -> bool {
303- ref_expr
304- . expr ( )
305- . and_then ( |expr| {
306- let field_expr = match expr {
307- ast:: Expr :: FieldExpr ( field_expr) => field_expr,
308- _ => return None ,
309- } ;
310- let expr = field_expr. expr ( ) ?;
311- self . type_of_expr ( & expr)
312- } )
313- // Binding a reference to a packed type is possibly unsafe.
314- . map ( |ty| ty. is_packed ( self . db ) )
315- . unwrap_or ( false )
316-
317- // FIXME This needs layout computation to be correct. It will highlight
318- // more than it should with the current implementation.
285+ self . imp . is_unsafe_ref_expr ( ref_expr)
319286 }
320287
321288 pub fn is_unsafe_bind_pat ( & self , bind_pat : & ast:: BindPat ) -> bool {
322- bind_pat
323- . syntax ( )
324- . parent ( )
325- . and_then ( |parent| {
326- // `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or
327- // `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`,
328- // so this tries to lookup the `BindPat` anywhere along that structure to the
329- // `RecordPat` so we can get the containing type.
330- let record_pat = ast:: RecordFieldPat :: cast ( parent. clone ( ) )
331- . and_then ( |record_pat| record_pat. syntax ( ) . parent ( ) )
332- . or_else ( || Some ( parent. clone ( ) ) )
333- . and_then ( |parent| {
334- ast:: RecordFieldPatList :: cast ( parent) ?
335- . syntax ( )
336- . parent ( )
337- . and_then ( ast:: RecordPat :: cast)
338- } ) ;
339-
340- // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
341- // this is initialized from a `FieldExpr`.
342- if let Some ( record_pat) = record_pat {
343- self . type_of_pat ( & ast:: Pat :: RecordPat ( record_pat) )
344- } else if let Some ( let_stmt) = ast:: LetStmt :: cast ( parent) {
345- let field_expr = match let_stmt. initializer ( ) ? {
346- ast:: Expr :: FieldExpr ( field_expr) => field_expr,
347- _ => return None ,
348- } ;
349-
350- self . type_of_expr ( & field_expr. expr ( ) ?)
351- } else {
352- None
353- }
354- } )
355- // Binding a reference to a packed type is possibly unsafe.
356- . map ( |ty| ty. is_packed ( self . db ) )
357- . unwrap_or ( false )
289+ self . imp . is_unsafe_bind_pat ( bind_pat)
358290 }
359291}
360292
@@ -640,6 +572,86 @@ impl<'db> SemanticsImpl<'db> {
640572 } ) ;
641573 InFile :: new ( file_id, node)
642574 }
575+
576+ pub fn is_unsafe_method_call ( & self , method_call_expr : ast:: MethodCallExpr ) -> bool {
577+ method_call_expr
578+ . expr ( )
579+ . and_then ( |expr| {
580+ let field_expr = if let ast:: Expr :: FieldExpr ( field_expr) = expr {
581+ field_expr
582+ } else {
583+ return None ;
584+ } ;
585+ let ty = self . type_of_expr ( & field_expr. expr ( ) ?) ?;
586+ if !ty. is_packed ( self . db ) {
587+ return None ;
588+ }
589+
590+ let func = self . resolve_method_call ( & method_call_expr) . map ( Function :: from) ?;
591+ let is_unsafe = func. has_self_param ( self . db )
592+ && matches ! ( func. params( self . db) . first( ) , Some ( TypeRef :: Reference ( ..) ) ) ;
593+ Some ( is_unsafe)
594+ } )
595+ . unwrap_or ( false )
596+ }
597+
598+ pub fn is_unsafe_ref_expr ( & self , ref_expr : & ast:: RefExpr ) -> bool {
599+ ref_expr
600+ . expr ( )
601+ . and_then ( |expr| {
602+ let field_expr = match expr {
603+ ast:: Expr :: FieldExpr ( field_expr) => field_expr,
604+ _ => return None ,
605+ } ;
606+ let expr = field_expr. expr ( ) ?;
607+ self . type_of_expr ( & expr)
608+ } )
609+ // Binding a reference to a packed type is possibly unsafe.
610+ . map ( |ty| ty. is_packed ( self . db ) )
611+ . unwrap_or ( false )
612+
613+ // FIXME This needs layout computation to be correct. It will highlight
614+ // more than it should with the current implementation.
615+ }
616+
617+ pub fn is_unsafe_bind_pat ( & self , bind_pat : & ast:: BindPat ) -> bool {
618+ bind_pat
619+ . syntax ( )
620+ . parent ( )
621+ . and_then ( |parent| {
622+ // `BindPat` can live under `RecordPat` directly under `RecordFieldPat` or
623+ // `RecordFieldPatList`. `RecordFieldPat` also lives under `RecordFieldPatList`,
624+ // so this tries to lookup the `BindPat` anywhere along that structure to the
625+ // `RecordPat` so we can get the containing type.
626+ let record_pat = ast:: RecordFieldPat :: cast ( parent. clone ( ) )
627+ . and_then ( |record_pat| record_pat. syntax ( ) . parent ( ) )
628+ . or_else ( || Some ( parent. clone ( ) ) )
629+ . and_then ( |parent| {
630+ ast:: RecordFieldPatList :: cast ( parent) ?
631+ . syntax ( )
632+ . parent ( )
633+ . and_then ( ast:: RecordPat :: cast)
634+ } ) ;
635+
636+ // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if
637+ // this is initialized from a `FieldExpr`.
638+ if let Some ( record_pat) = record_pat {
639+ self . type_of_pat ( & ast:: Pat :: RecordPat ( record_pat) )
640+ } else if let Some ( let_stmt) = ast:: LetStmt :: cast ( parent) {
641+ let field_expr = match let_stmt. initializer ( ) ? {
642+ ast:: Expr :: FieldExpr ( field_expr) => field_expr,
643+ _ => return None ,
644+ } ;
645+
646+ self . type_of_expr ( & field_expr. expr ( ) ?)
647+ } else {
648+ None
649+ }
650+ } )
651+ // Binding a reference to a packed type is possibly unsafe.
652+ . map ( |ty| ty. is_packed ( self . db ) )
653+ . unwrap_or ( false )
654+ }
643655}
644656
645657pub trait ToDef : AstNode + Clone {
0 commit comments