@@ -95,12 +95,14 @@ declare_clippy_lint! {
95
95
#[ derive( Copy , Clone ) ]
96
96
pub struct UndocumentedUnsafeBlocks {
97
97
accept_comment_above_statement : bool ,
98
+ accept_comment_above_attributes : bool ,
98
99
}
99
100
100
101
impl 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 {
102
103
Self {
103
104
accept_comment_above_statement,
105
+ accept_comment_above_attributes,
104
106
}
105
107
}
106
108
}
@@ -114,7 +116,12 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
114
116
&& !is_lint_allowed ( cx, UNDOCUMENTED_UNSAFE_BLOCKS , block. hir_id )
115
117
&& !is_unsafe_from_proc_macro ( cx, block. span )
116
118
&& !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
+ )
118
125
{
119
126
let source_map = cx. tcx . sess . source_map ( ) ;
120
127
let span = if source_map. is_multiline ( block. span ) {
@@ -328,6 +335,7 @@ fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, span: Span) -> bool {
328
335
// has a safety comment
329
336
fn block_parents_have_safety_comment (
330
337
accept_comment_above_statement : bool ,
338
+ accept_comment_above_attributes : bool ,
331
339
cx : & LateContext < ' _ > ,
332
340
id : hir:: HirId ,
333
341
) -> bool {
@@ -343,33 +351,77 @@ fn block_parents_have_safety_comment(
343
351
} ) ,
344
352
) = get_parent_node ( cx. tcx , expr. hir_id )
345
353
{
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
+
346
362
// if unsafe block is part of a let/const/static statement,
347
363
// and accept_comment_above_statement is set to true
348
364
// 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
+ )
350
372
} 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
+ )
352
380
}
353
381
} ,
354
382
Node :: Stmt ( hir:: Stmt {
355
383
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 , .. } ) ,
359
387
..
360
388
} )
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 {
363
393
kind : hir:: ItemKind :: Const ( ..) | ItemKind :: Static ( ..) ,
364
394
span,
395
+ owner_id,
365
396
..
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
+ ) ,
367
403
_ => false ,
368
404
} ;
369
405
}
370
406
false
371
407
}
372
408
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
+
373
425
/// Checks if an expression is "branchy", e.g. loop, match/if/etc.
374
426
fn is_branchy ( expr : & hir:: Expr < ' _ > ) -> bool {
375
427
matches ! (
@@ -394,6 +446,15 @@ fn block_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
394
446
) || span_in_body_has_safety_comment ( cx, span)
395
447
}
396
448
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
+
397
458
enum HasSafetyComment {
398
459
Yes ( BytePos ) ,
399
460
No ,
0 commit comments