@@ -68,7 +68,8 @@ impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
6868 && !in_external_macro ( cx. tcx . sess , block. span )
6969 && !is_lint_allowed ( cx, UNDOCUMENTED_UNSAFE_BLOCKS , block. hir_id )
7070 && !is_unsafe_from_proc_macro ( cx, block. span )
71- && !block_has_safety_comment ( cx, block)
71+ && !block_has_safety_comment ( cx, block. span )
72+ && !block_parents_have_safety_comment ( cx, block. hir_id )
7273 {
7374 let source_map = cx. tcx . sess . source_map ( ) ;
7475 let span = if source_map. is_multiline ( block. span ) {
@@ -126,8 +127,41 @@ fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, span: Span) -> bool {
126127 . map_or ( true , |src| !src. starts_with ( "unsafe" ) )
127128}
128129
130+ // Checks if any parent {expression, statement, block, local, const, static}
131+ // has a safety comment
132+ fn block_parents_have_safety_comment ( cx : & LateContext < ' _ > , id : hir:: HirId ) -> bool {
133+ if let Some ( node) = get_parent_node ( cx. tcx , id) {
134+ return match node {
135+ Node :: Expr ( expr) => !is_branchy ( expr) && span_in_body_has_safety_comment ( cx, expr. span ) ,
136+ Node :: Stmt ( hir:: Stmt {
137+ kind :
138+ hir:: StmtKind :: Local ( hir:: Local { span, .. } )
139+ | hir:: StmtKind :: Expr ( hir:: Expr { span, .. } )
140+ | hir:: StmtKind :: Semi ( hir:: Expr { span, .. } ) ,
141+ ..
142+ } )
143+ | Node :: Local ( hir:: Local { span, .. } )
144+ | Node :: Item ( hir:: Item {
145+ kind : hir:: ItemKind :: Const ( ..) | ItemKind :: Static ( ..) ,
146+ span,
147+ ..
148+ } ) => span_in_body_has_safety_comment ( cx, * span) ,
149+ _ => false ,
150+ } ;
151+ }
152+ false
153+ }
154+
155+ /// Checks if an expression is "branchy", e.g. loop, match/if/etc.
156+ fn is_branchy ( expr : & hir:: Expr < ' _ > ) -> bool {
157+ matches ! (
158+ expr. kind,
159+ hir:: ExprKind :: If ( ..) | hir:: ExprKind :: Loop ( ..) | hir:: ExprKind :: Match ( ..)
160+ )
161+ }
162+
129163/// Checks if the lines immediately preceding the block contain a safety comment.
130- fn block_has_safety_comment ( cx : & LateContext < ' _ > , block : & hir :: Block < ' _ > ) -> bool {
164+ fn block_has_safety_comment ( cx : & LateContext < ' _ > , span : Span ) -> bool {
131165 // This intentionally ignores text before the start of a function so something like:
132166 // ```
133167 // // SAFETY: reason
@@ -136,7 +170,7 @@ fn block_has_safety_comment(cx: &LateContext<'_>, block: &hir::Block<'_>) -> boo
136170 // won't work. This is to avoid dealing with where such a comment should be place relative to
137171 // attributes and doc comments.
138172
139- span_from_macro_expansion_has_safety_comment ( cx, block . span ) || span_in_body_has_safety_comment ( cx, block . span )
173+ span_from_macro_expansion_has_safety_comment ( cx, span) || span_in_body_has_safety_comment ( cx, span)
140174}
141175
142176/// Checks if the lines immediately preceding the item contain a safety comment.
0 commit comments