@@ -46,6 +46,7 @@ pub enum ReviewRisk {
4646 TypeLayout ,
4747 Effect ,
4848 Boundary ,
49+ Unsafe ,
4950}
5051
5152impl ReviewRisk {
@@ -56,6 +57,7 @@ impl ReviewRisk {
5657 Self :: TypeLayout => "type-layout" ,
5758 Self :: Effect => "effect" ,
5859 Self :: Boundary => "boundary" ,
60+ Self :: Unsafe => "unsafe" ,
5961 }
6062 }
6163}
@@ -232,6 +234,10 @@ fn review_fixes(code: &str) -> Vec<ReviewFix> {
232234 "review_local_manage_boundary" ,
233235 "Review the changed local ownership and manage boundary." ,
234236 ) ,
237+ code:: REVIEW_UNSAFE_NATIVE_ADDED => (
238+ "review_unsafe_native_boundary" ,
239+ "Review the new unsafe or native boundary and require explicit justification." ,
240+ ) ,
235241 _ => ( "review_change" , "Review this source-level contract change." ) ,
236242 } ;
237243 vec ! [ ReviewFix {
@@ -383,6 +389,31 @@ fn compare_function(old: &FunctionSig, new: &FunctionSig, findings: &mut Vec<Rev
383389 Some ( effects_contract ( & new. effects ) ) ,
384390 ) ) ;
385391 }
392+ let old_unsafe_native = unsafe_native_effects ( & old. effects ) ;
393+ let new_unsafe_native = unsafe_native_effects ( & new. effects ) ;
394+ let added_unsafe_native: BTreeSet < _ > = new_unsafe_native
395+ . difference ( & old_unsafe_native)
396+ . cloned ( )
397+ . collect ( ) ;
398+ if !added_unsafe_native. is_empty ( ) {
399+ findings. push ( review_finding (
400+ code:: REVIEW_UNSAFE_NATIVE_ADDED ,
401+ ReviewRisk :: Unsafe ,
402+ format ! (
403+ "function `{}` added unsafe/native boundary: {}." ,
404+ old. name,
405+ effects_contract( & added_unsafe_native)
406+ ) ,
407+ paired_spans (
408+ & old. span ,
409+ & new. span ,
410+ "old function" ,
411+ "new unsafe/native boundary" ,
412+ ) ,
413+ Some ( effects_contract ( & old_unsafe_native) ) ,
414+ Some ( effects_contract ( & new_unsafe_native) ) ,
415+ ) ) ;
416+ }
386417 if old. boundary != new. boundary {
387418 findings. push ( review_finding (
388419 code:: REVIEW_BOUNDARY_CHANGED ,
@@ -513,6 +544,14 @@ fn effects_contract(effects: &BTreeSet<String>) -> String {
513544 effects. iter ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) . join ( ", " )
514545}
515546
547+ fn unsafe_native_effects ( effects : & BTreeSet < String > ) -> BTreeSet < String > {
548+ effects
549+ . iter ( )
550+ . filter ( |effect| matches ! ( effect. as_str( ) , "unsafe" | "native" ) )
551+ . cloned ( )
552+ . collect ( )
553+ }
554+
516555fn type_contract ( ty : & TypeSig ) -> String {
517556 format ! (
518557 "{} {} {{ {} }}" ,
0 commit comments