@@ -11,10 +11,11 @@ use rustc_lint::{LateContext, LateLintPass, LintStore};
1111use rustc_middle:: ty:: TyKind ;
1212use rustc_session:: impl_lint_pass;
1313use rustc_span:: BytePos ;
14- use std:: collections:: HashMap ;
14+ use std:: collections:: { HashMap , HashSet } ;
1515use std:: sync:: Mutex ;
1616
1717use super :: no_allocation:: detect_allocation_in_mir;
18+ use super :: no_panic:: { PanicCategory , detect_panic_in_mir} ;
1819
1920// Helper: retrieve the concrete Self type of the impl the method belongs to, if any
2021fn get_self_type < ' tcx > (
@@ -60,7 +61,38 @@ impl FunctionLint {
6061 evaluate_function_match ( & self . matches , ctx, module_path, function_name, fn_def_id)
6162 }
6263
63- // Evaluates the complex matcher structure to determine if a function matches
64+ /// Helper method to check a single panic category and emit a lint if found
65+ fn check_panic_category (
66+ & self ,
67+ ctx : & LateContext < ' _ > ,
68+ fn_def_id : rustc_hir:: def_id:: DefId ,
69+ severity : cargo_pup_lint_config:: Severity ,
70+ category : PanicCategory ,
71+ rule_name : & str ,
72+ ) {
73+ if ctx. tcx . is_mir_available ( fn_def_id) {
74+ let mir = ctx. tcx . optimized_mir ( fn_def_id) ;
75+ let mut categories = HashSet :: new ( ) ;
76+ categories. insert ( category) ;
77+
78+ // Use a fresh cache for each check to avoid cross-category pollution
79+ let mut local_cache = HashMap :: new ( ) ;
80+
81+ if let Some ( violation) =
82+ detect_panic_in_mir ( ctx. tcx , mir, & mut local_cache, & categories)
83+ {
84+ span_lint_and_help (
85+ ctx,
86+ FUNCTION_LINT :: get_by_severity ( severity) ,
87+ self . name ( ) . as_str ( ) ,
88+ violation. span ,
89+ format ! ( "Function may panic: {}" , violation. reason) ,
90+ None ,
91+ format ! ( "Remove panic paths to satisfy the {} rule" , rule_name) ,
92+ ) ;
93+ }
94+ }
95+ }
6496}
6597
6698fn evaluate_function_match (
@@ -204,6 +236,40 @@ fn evaluate_function_match(
204236 }
205237 false
206238 }
239+ FunctionMatch :: IsUnsafe => {
240+ // Check if the function is unsafe by examining the HIR
241+ if let Some ( local_def_id) = fn_def_id. as_local ( ) {
242+ let node = ctx. tcx . hir_node_by_def_id ( local_def_id) ;
243+ match node {
244+ rustc_hir:: Node :: Item ( item) => {
245+ if let rustc_hir:: ItemKind :: Fn { sig, .. } = & item. kind {
246+ return matches ! (
247+ sig. header. safety,
248+ rustc_hir:: HeaderSafety :: Normal ( rustc_hir:: Safety :: Unsafe )
249+ ) ;
250+ }
251+ }
252+ rustc_hir:: Node :: TraitItem ( trait_item) => {
253+ if let rustc_hir:: TraitItemKind :: Fn ( sig, _) = & trait_item. kind {
254+ return matches ! (
255+ sig. header. safety,
256+ rustc_hir:: HeaderSafety :: Normal ( rustc_hir:: Safety :: Unsafe )
257+ ) ;
258+ }
259+ }
260+ rustc_hir:: Node :: ImplItem ( impl_item) => {
261+ if let rustc_hir:: ImplItemKind :: Fn ( sig, _) = & impl_item. kind {
262+ return matches ! (
263+ sig. header. safety,
264+ rustc_hir:: HeaderSafety :: Normal ( rustc_hir:: Safety :: Unsafe )
265+ ) ;
266+ }
267+ }
268+ _ => { }
269+ }
270+ }
271+ false
272+ }
207273 FunctionMatch :: AndMatches ( left, right) => {
208274 evaluate_function_match ( left, ctx, module_path, function_name, fn_def_id)
209275 && evaluate_function_match ( right, ctx, module_path, function_name, fn_def_id)
@@ -381,6 +447,33 @@ impl<'tcx> LateLintPass<'tcx> for FunctionLint {
381447 }
382448 }
383449 }
450+ FunctionRule :: NoUnwrap ( severity) => {
451+ self . check_panic_category (
452+ ctx,
453+ fn_def_id,
454+ * severity,
455+ PanicCategory :: Unwrap ,
456+ "NoUnwrap" ,
457+ ) ;
458+ }
459+ FunctionRule :: NoPanic ( severity) => {
460+ self . check_panic_category (
461+ ctx,
462+ fn_def_id,
463+ * severity,
464+ PanicCategory :: ExplicitPanic ,
465+ "NoPanic" ,
466+ ) ;
467+ }
468+ FunctionRule :: NoIndexPanic ( severity) => {
469+ self . check_panic_category (
470+ ctx,
471+ fn_def_id,
472+ * severity,
473+ PanicCategory :: IndexBounds ,
474+ "NoIndexPanic" ,
475+ ) ;
476+ }
384477 }
385478 }
386479 }
@@ -506,6 +599,33 @@ impl<'tcx> LateLintPass<'tcx> for FunctionLint {
506599 }
507600 }
508601 }
602+ FunctionRule :: NoUnwrap ( severity) => {
603+ self . check_panic_category (
604+ ctx,
605+ fn_def_id,
606+ * severity,
607+ PanicCategory :: Unwrap ,
608+ "NoUnwrap" ,
609+ ) ;
610+ }
611+ FunctionRule :: NoPanic ( severity) => {
612+ self . check_panic_category (
613+ ctx,
614+ fn_def_id,
615+ * severity,
616+ PanicCategory :: ExplicitPanic ,
617+ "NoPanic" ,
618+ ) ;
619+ }
620+ FunctionRule :: NoIndexPanic ( severity) => {
621+ self . check_panic_category (
622+ ctx,
623+ fn_def_id,
624+ * severity,
625+ PanicCategory :: IndexBounds ,
626+ "NoIndexPanic" ,
627+ ) ;
628+ }
509629 }
510630 }
511631 }
0 commit comments