@@ -95,12 +95,14 @@ declare_clippy_lint! {
9595#[ derive( Copy , Clone ) ]
9696pub struct UndocumentedUnsafeBlocks {
9797 accept_comment_above_statement : bool ,
98+ accept_comment_above_attributes : bool ,
9899}
99100
100101impl UndocumentedUnsafeBlocks {
101- pub fn new ( accept_comment_above_statement : bool ) -> Self {
102+ pub fn new ( accept_comment_above_statement : bool , accept_comment_above_attributes : bool ) -> Self {
102103 Self {
103104 accept_comment_above_statement,
105+ accept_comment_above_attributes,
104106 }
105107 }
106108}
@@ -114,7 +116,12 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
114116 && !is_lint_allowed ( cx, UNDOCUMENTED_UNSAFE_BLOCKS , block. hir_id )
115117 && !is_unsafe_from_proc_macro ( cx, block. span )
116118 && !block_has_safety_comment ( cx, block. span )
117- && !block_parents_have_safety_comment ( self . accept_comment_above_statement , cx, block. hir_id )
119+ && !block_parents_have_safety_comment (
120+ self . accept_comment_above_statement ,
121+ self . accept_comment_above_attributes ,
122+ cx,
123+ block. hir_id ,
124+ )
118125 {
119126 let source_map = cx. tcx . sess . source_map ( ) ;
120127 let span = if source_map. is_multiline ( block. span ) {
@@ -328,6 +335,7 @@ fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, span: Span) -> bool {
328335// has a safety comment
329336fn block_parents_have_safety_comment (
330337 accept_comment_above_statement : bool ,
338+ accept_comment_above_attributes : bool ,
331339 cx : & LateContext < ' _ > ,
332340 id : hir:: HirId ,
333341) -> bool {
@@ -343,33 +351,77 @@ fn block_parents_have_safety_comment(
343351 } ) ,
344352 ) = get_parent_node ( cx. tcx , expr. hir_id )
345353 {
354+ let hir_id = match get_parent_node ( cx. tcx , expr. hir_id ) {
355+ Some ( Node :: Local ( hir:: Local { hir_id, .. } ) ) => * hir_id,
356+ Some ( Node :: Item ( hir:: Item { owner_id, .. } ) ) => {
357+ cx. tcx . hir ( ) . local_def_id_to_hir_id ( owner_id. def_id )
358+ } ,
359+ _ => unreachable ! ( ) ,
360+ } ;
361+
346362 // if unsafe block is part of a let/const/static statement,
347363 // and accept_comment_above_statement is set to true
348364 // we accept the safety comment in the line the precedes this statement.
349- accept_comment_above_statement && span_in_body_has_safety_comment ( cx, * span)
365+ accept_comment_above_statement
366+ && span_with_attrs_in_body_has_safety_comment (
367+ cx,
368+ * span,
369+ hir_id,
370+ accept_comment_above_attributes,
371+ )
350372 } else {
351- !is_branchy ( expr) && span_in_body_has_safety_comment ( cx, expr. span )
373+ !is_branchy ( expr)
374+ && span_with_attrs_in_body_has_safety_comment (
375+ cx,
376+ expr. span ,
377+ expr. hir_id ,
378+ accept_comment_above_attributes,
379+ )
352380 }
353381 } ,
354382 Node :: Stmt ( hir:: Stmt {
355383 kind :
356- hir:: StmtKind :: Local ( hir:: Local { span, .. } )
357- | hir:: StmtKind :: Expr ( hir:: Expr { span, .. } )
358- | hir:: StmtKind :: Semi ( hir:: Expr { span, .. } ) ,
384+ hir:: StmtKind :: Local ( hir:: Local { span, hir_id , .. } )
385+ | hir:: StmtKind :: Expr ( hir:: Expr { span, hir_id , .. } )
386+ | hir:: StmtKind :: Semi ( hir:: Expr { span, hir_id , .. } ) ,
359387 ..
360388 } )
361- | Node :: Local ( hir:: Local { span, .. } )
362- | Node :: Item ( hir:: Item {
389+ | Node :: Local ( hir:: Local { span, hir_id, .. } ) => {
390+ span_with_attrs_in_body_has_safety_comment ( cx, * span, * hir_id, accept_comment_above_attributes)
391+ } ,
392+ Node :: Item ( hir:: Item {
363393 kind : hir:: ItemKind :: Const ( ..) | ItemKind :: Static ( ..) ,
364394 span,
395+ owner_id,
365396 ..
366- } ) => span_in_body_has_safety_comment ( cx, * span) ,
397+ } ) => span_with_attrs_in_body_has_safety_comment (
398+ cx,
399+ * span,
400+ cx. tcx . hir ( ) . local_def_id_to_hir_id ( owner_id. def_id ) ,
401+ accept_comment_above_attributes,
402+ ) ,
367403 _ => false ,
368404 } ;
369405 }
370406 false
371407}
372408
409+ /// Extends `span` to also include its attributes, then checks if that span has a safety comment.
410+ fn span_with_attrs_in_body_has_safety_comment (
411+ cx : & LateContext < ' _ > ,
412+ span : Span ,
413+ hir_id : HirId ,
414+ accept_comment_above_attributes : bool ,
415+ ) -> bool {
416+ let span = if accept_comment_above_attributes {
417+ include_attrs_in_span ( cx, hir_id, span)
418+ } else {
419+ span
420+ } ;
421+
422+ span_in_body_has_safety_comment ( cx, span)
423+ }
424+
373425/// Checks if an expression is "branchy", e.g. loop, match/if/etc.
374426fn is_branchy ( expr : & hir:: Expr < ' _ > ) -> bool {
375427 matches ! (
@@ -394,6 +446,15 @@ fn block_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
394446 ) || span_in_body_has_safety_comment ( cx, span)
395447}
396448
449+ fn include_attrs_in_span ( cx : & LateContext < ' _ > , hir_id : HirId , span : Span ) -> Span {
450+ span. to ( cx
451+ . tcx
452+ . hir ( )
453+ . attrs ( hir_id)
454+ . iter ( )
455+ . fold ( span, |acc, attr| acc. to ( attr. span ) ) )
456+ }
457+
397458enum HasSafetyComment {
398459 Yes ( BytePos ) ,
399460 No ,
0 commit comments