@@ -189,90 +189,98 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
189189            return ; 
190190        } 
191191
192-         let  mk_spans = |pos :  BytePos | { 
193-             let  source_map = cx. tcx . sess . source_map ( ) ; 
194-             let  span = Span :: new ( pos,  pos,  SyntaxContext :: root ( ) ,  None ) ; 
195-             let  help_span = source_map. span_extend_to_next_char ( span,  '\n' ,  true ) ; 
196-             let  span = if  source_map. is_multiline ( item. span )  { 
197-                 source_map. span_until_char ( item. span ,  '\n' ) 
198-             }  else  { 
199-                 item. span 
200-             } ; 
201-             ( span,  help_span) 
202-         } ; 
203- 
204-         let  item_has_safety_comment = item_has_safety_comment ( cx,  item) ; 
192+         let  item_has_safety_comment = item_has_safety_comment ( cx,  item. span ,  item. hir_id ( ) ) ; 
205193        match  item_has_safety_comment { 
206-             HasSafetyComment :: Yes ( pos)  => check_has_safety_comment ( cx,  item,  mk_spans ( pos) ) , 
207-             HasSafetyComment :: No  => check_has_no_safety_comment ( cx,  item) , 
194+             HasSafetyComment :: Yes ( pos)  => check_item_has_safety_comment ( cx,  item,  mk_spans ( cx ,  item . span ,   pos) ) , 
195+             HasSafetyComment :: No  => check_item_has_no_safety_comment ( cx,  item) , 
208196            HasSafetyComment :: Maybe  => { } , 
209197        } 
210198    } 
199+ 
200+     fn  check_impl_item ( & mut  self ,  cx :  & LateContext < ' _ > ,  item :  & hir:: ImplItem < ' _ > )  { 
201+         if  item. span . in_external_macro ( cx. tcx . sess . source_map ( ) )  { 
202+             return ; 
203+         } 
204+ 
205+         let  item_has_safety_comment = item_has_safety_comment ( cx,  item. span ,  item. hir_id ( ) ) ; 
206+         match  item_has_safety_comment { 
207+             HasSafetyComment :: Yes ( pos)  => check_impl_item_has_safety_comment ( cx,  item,  mk_spans ( cx,  item. span ,  pos) ) , 
208+             _ => { } , 
209+         } 
210+     } 
211+ } 
212+ 
213+ fn  mk_spans ( cx :  & LateContext < ' _ > ,  item_span :  Span ,  doc_pos :  BytePos )  -> ( Span ,  Span )  { 
214+     let  source_map = cx. tcx . sess . source_map ( ) ; 
215+     let  span = Span :: new ( doc_pos,  doc_pos,  SyntaxContext :: root ( ) ,  None ) ; 
216+     let  help_span = source_map. span_extend_to_next_char ( span,  '\n' ,  true ) ; 
217+     let  span = if  source_map. is_multiline ( item_span)  { 
218+         source_map. span_until_char ( item_span,  '\n' ) 
219+     }  else  { 
220+         item_span
221+     } ; 
222+     ( span,  help_span) 
223+ } 
224+ 
225+ fn  check_impl_item_has_safety_comment ( cx :  & LateContext < ' _ > ,  item :  & hir:: ImplItem < ' _ > ,  spans :  ( Span ,  Span ) )  { 
226+     match  & item. kind  { 
227+         & hir:: ImplItemKind :: Const ( ..,  body)  => { 
228+             if  !check_body_unsafeness ( cx,  body)  { 
229+                 lint_unnecessary_safety_comment ( cx,  cx. tcx . def_descr ( item. owner_id . to_def_id ( ) ) ,  spans,  body. hir_id ) 
230+             } 
231+         } , 
232+         hir:: ImplItemKind :: Type ( ..)  => { } , 
233+         _ => lint_unnecessary_safety_comment ( cx,  cx. tcx . def_descr ( item. owner_id . to_def_id ( ) ) ,  spans,  item. hir_id ( ) ) , 
234+     } 
211235} 
212236
213- fn  check_has_safety_comment ( cx :  & LateContext < ' _ > ,  item :  & hir:: Item < ' _ > ,  ( span ,  help_span ) :  ( Span ,  Span ) )  { 
237+ fn  check_item_has_safety_comment ( cx :  & LateContext < ' _ > ,  item :  & hir:: Item < ' _ > ,  spans :  ( Span ,  Span ) )  { 
214238    match  & item. kind  { 
215239        ItemKind :: Impl ( Impl  { 
216240            of_trait :  Some ( of_trait) , 
217241            ..
218-         } )  if  of_trait. safety . is_safe ( )  => { 
219-             if  !is_lint_allowed ( cx,  UNNECESSARY_SAFETY_COMMENT ,  item. hir_id ( ) )  { 
220-                 span_lint_and_then ( 
221-                     cx, 
222-                     UNNECESSARY_SAFETY_COMMENT , 
223-                     span, 
224-                     "impl has unnecessary safety comment" , 
225-                     |diag| { 
226-                         diag. span_help ( help_span,  "consider removing the safety comment" ) ; 
227-                     } , 
228-                 ) ; 
229-             } 
230-         } , 
242+         } )  if  of_trait. safety . is_safe ( )  => lint_unnecessary_safety_comment ( cx,  "impl" ,  spans,  item. hir_id ( ) ) , 
231243        ItemKind :: Impl ( _)  => { } , 
232244        // const and static items only need a safety comment if their body is an unsafe block, lint otherwise 
233245        & ItemKind :: Const ( ..,  body)  | & ItemKind :: Static ( ..,  body)  => { 
234-             if  !is_lint_allowed ( cx,  UNNECESSARY_SAFETY_COMMENT ,  body. hir_id )  { 
235-                 let  body = cx. tcx . hir_body ( body) ; 
236-                 if  !matches ! ( 
237-                     body. value. kind,  hir:: ExprKind :: Block ( block,  _) 
238-                     if  block. rules == BlockCheckMode :: UnsafeBlock ( UnsafeSource :: UserProvided ) 
239-                 )  { 
240-                     span_lint_and_then ( 
241-                         cx, 
242-                         UNNECESSARY_SAFETY_COMMENT , 
243-                         span, 
244-                         format ! ( 
245-                             "{} has unnecessary safety comment" , 
246-                             cx. tcx. def_descr( item. owner_id. to_def_id( ) ) , 
247-                         ) , 
248-                         |diag| { 
249-                             diag. span_help ( help_span,  "consider removing the safety comment" ) ; 
250-                         } , 
251-                     ) ; 
252-                 } 
246+             if  !check_body_unsafeness ( cx,  body)  { 
247+                 lint_unnecessary_safety_comment ( cx,  cx. tcx . def_descr ( item. owner_id . to_def_id ( ) ) ,  spans,  body. hir_id ) 
253248            } 
254249        } , 
255250        // Aside from unsafe impls and consts/statics with an unsafe block, items in general 
256251        // do not have safety invariants that need to be documented, so lint those. 
257-         _ => { 
258-             if  !is_lint_allowed ( cx,  UNNECESSARY_SAFETY_COMMENT ,  item. hir_id ( ) )  { 
259-                 span_lint_and_then ( 
260-                     cx, 
261-                     UNNECESSARY_SAFETY_COMMENT , 
262-                     span, 
263-                     format ! ( 
264-                         "{} has unnecessary safety comment" , 
265-                         cx. tcx. def_descr( item. owner_id. to_def_id( ) ) , 
266-                     ) , 
267-                     |diag| { 
268-                         diag. span_help ( help_span,  "consider removing the safety comment" ) ; 
269-                     } , 
270-                 ) ; 
271-             } 
272-         } , 
252+         _ => lint_unnecessary_safety_comment ( cx,  cx. tcx . def_descr ( item. owner_id . to_def_id ( ) ) ,  spans,  item. hir_id ( ) ) , 
273253    } 
274254} 
275- fn  check_has_no_safety_comment ( cx :  & LateContext < ' _ > ,  item :  & hir:: Item < ' _ > )  { 
255+ 
256+ fn  lint_unnecessary_safety_comment ( 
257+     cx :  & LateContext < ' _ > , 
258+     item_name :  & str , 
259+     ( span,  help_span) :  ( Span ,  Span ) , 
260+     hir_id :  HirId , 
261+ )  { 
262+     if  !is_lint_allowed ( cx,  UNNECESSARY_SAFETY_COMMENT ,  hir_id)  { 
263+         span_lint_and_then ( 
264+             cx, 
265+             UNNECESSARY_SAFETY_COMMENT , 
266+             span, 
267+             format ! ( "{item_name} has unnecessary safety comment" , ) , 
268+             |diag| { 
269+                 diag. span_help ( help_span,  "consider removing the safety comment" ) ; 
270+             } , 
271+         ) ; 
272+     } 
273+ } 
274+ 
275+ fn  check_body_unsafeness ( cx :  & LateContext < ' _ > ,  body :  hir:: BodyId )  -> bool  { 
276+     let  body = cx. tcx . hir_body ( body) ; 
277+     matches ! ( 
278+         body. value. kind,  hir:: ExprKind :: Block ( block,  _) 
279+         if  block. rules == BlockCheckMode :: UnsafeBlock ( UnsafeSource :: UserProvided ) 
280+     ) 
281+ } 
282+ 
283+ fn  check_item_has_no_safety_comment ( cx :  & LateContext < ' _ > ,  item :  & hir:: Item < ' _ > )  { 
276284    if  let  ItemKind :: Impl ( Impl  { 
277285        of_trait :  Some ( of_trait) , 
278286        ..
@@ -488,26 +496,29 @@ enum HasSafetyComment {
488496    Maybe , 
489497} 
490498
491- /// Checks if the lines immediately preceding the item contain a safety comment. 
499+ /// Checks if the lines immediately preceding the item/impl_item  contain a safety comment. 
492500#[ allow( clippy:: collapsible_match) ]  
493- fn  item_has_safety_comment ( cx :  & LateContext < ' _ > ,  item :   & hir :: Item < ' _ > )  -> HasSafetyComment  { 
494-     match  span_from_macro_expansion_has_safety_comment ( cx,  item . span )  { 
501+ fn  item_has_safety_comment ( cx :  & LateContext < ' _ > ,  span :   Span ,   hir_id :   HirId )  -> HasSafetyComment  { 
502+     match  span_from_macro_expansion_has_safety_comment ( cx,  span)  { 
495503        HasSafetyComment :: Maybe  => ( ) , 
496504        has_safety_comment => return  has_safety_comment, 
497505    } 
498506
499-     if  item . span . ctxt ( )  != SyntaxContext :: root ( )  { 
507+     if  span. ctxt ( )  != SyntaxContext :: root ( )  { 
500508        return  HasSafetyComment :: No ; 
501509    } 
502-     let  comment_start = match  cx. tcx . parent_hir_node ( item. hir_id ( ) )  { 
503-         Node :: Crate ( parent_mod)  => comment_start_before_item_in_mod ( cx,  parent_mod,  parent_mod. spans . inner_span ,  item) , 
504-         Node :: Item ( parent_item)  => { 
505-             if  let  ItemKind :: Mod ( _,  parent_mod)  = & parent_item. kind  { 
506-                 comment_start_before_item_in_mod ( cx,  parent_mod,  parent_item. span ,  item) 
507-             }  else  { 
508-                 // Doesn't support impls in this position. Pretend a comment was found. 
509-                 return  HasSafetyComment :: Maybe ; 
510-             } 
510+     let  comment_start = match  cx. tcx . parent_hir_node ( hir_id)  { 
511+         Node :: Crate ( parent_mod)  => { 
512+             comment_start_before_item ( cx,  & mod_items_hir_id ( parent_mod) ,  parent_mod. spans . inner_span ,  hir_id) 
513+         } , 
514+         Node :: Item ( parent_item)  => match  & parent_item. kind  { 
515+             ItemKind :: Mod ( _,  parent_mod)  => { 
516+                 comment_start_before_item ( cx,  & mod_items_hir_id ( parent_mod) ,  parent_item. span ,  hir_id) 
517+             } , 
518+             ItemKind :: Impl ( impl_block)  => { 
519+                 comment_start_before_item ( cx,  & impl_items_hir_id ( impl_block) ,  parent_item. span ,  hir_id) 
520+             } , 
521+             _ => return  HasSafetyComment :: Maybe , 
511522        } , 
512523        Node :: Stmt ( stmt)  => { 
513524            if  let  Node :: Block ( block)  = cx. tcx . parent_hir_node ( stmt. hir_id )  { 
@@ -527,7 +538,7 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf
527538    let  source_map = cx. sess ( ) . source_map ( ) ; 
528539    // If the comment is in the first line of the file, there is no preceding line 
529540    if  let  Some ( comment_start)  = comment_start
530-         && let  Ok ( unsafe_line)  = source_map. lookup_line ( item . span . lo ( ) ) 
541+         && let  Ok ( unsafe_line)  = source_map. lookup_line ( span. lo ( ) ) 
531542        && let  Ok ( comment_start_line)  = source_map. lookup_line ( comment_start. into ( ) ) 
532543        && let  include_first_line_of_file = matches ! ( comment_start,  CommentStartBeforeItem :: Start ) 
533544        && ( include_first_line_of_file || Arc :: ptr_eq ( & unsafe_line. sf ,  & comment_start_line. sf ) ) 
@@ -550,6 +561,18 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf
550561    HasSafetyComment :: Maybe 
551562} 
552563
564+ fn  mod_items_hir_id ( module :  & hir:: Mod < ' _ > )  -> Vec < HirId >  { 
565+     module. item_ids . iter ( ) . map ( |& item_id| item_id. hir_id ( ) ) . collect ( ) 
566+ } 
567+ 
568+ fn  impl_items_hir_id ( impl_block :  & Impl < ' _ > )  -> Vec < HirId >  { 
569+     impl_block
570+         . items 
571+         . iter ( ) 
572+         . map ( |& impl_item_id| impl_item_id. hir_id ( ) ) 
573+         . collect ( ) 
574+ } 
575+ 
553576/// Checks if the lines immediately preceding the item contain a safety comment. 
554577#[ allow( clippy:: collapsible_match) ]  
555578fn  stmt_has_safety_comment ( 
@@ -572,8 +595,6 @@ fn stmt_has_safety_comment(
572595        _ => return  HasSafetyComment :: Maybe , 
573596    } ; 
574597
575-     // if span_with_attrs_has_safety_comment(cx, span, hir_id, accept_comment_above_attrib 
576-     // } 
577598    let  mut  span = span; 
578599    if  accept_comment_above_attributes { 
579600        span = include_attrs_in_span ( cx,  hir_id,  span) ; 
@@ -617,30 +638,30 @@ impl From<CommentStartBeforeItem> for BytePos {
617638    } 
618639} 
619640
620- fn  comment_start_before_item_in_mod ( 
641+ fn  comment_start_before_item ( 
621642    cx :  & LateContext < ' _ > , 
622-     parent_mod :  & hir :: Mod < ' _ > , 
623-     parent_mod_span :  Span , 
624-     item :   & hir :: Item < ' _ > , 
643+     items_at_same_level :  & [ HirId ] , 
644+     parent_span :  Span , 
645+     target_item :   HirId , 
625646)  -> Option < CommentStartBeforeItem >  { 
626-     parent_mod . item_ids . iter ( ) . enumerate ( ) . find_map ( |( idx,  item_id ) | { 
627-         if  * item_id  == item . item_id ( )  { 
647+     items_at_same_level . iter ( ) . enumerate ( ) . find_map ( |( idx,  & hir_id ) | { 
648+         if  hir_id  == target_item  { 
628649            if  idx == 0  { 
629650                // mod A { /* comment */ unsafe impl T {} ... } 
630651                // ^------------------------------------------^ returns the start of this span 
631652                // ^---------------------^ finally checks comments in this range 
632-                 if  let  Some ( sp)  = walk_span_to_context ( parent_mod_span ,  SyntaxContext :: root ( ) )  { 
653+                 if  let  Some ( sp)  = walk_span_to_context ( parent_span ,  SyntaxContext :: root ( ) )  { 
633654                    return  Some ( CommentStartBeforeItem :: Offset ( sp. lo ( ) ) ) ; 
634655                } 
635656            }  else  { 
636657                // some_item /* comment */ unsafe impl T {} 
637658                // ^-------^ returns the end of this span 
638659                //         ^---------------^ finally checks comments in this range 
639-                 let  prev_item  = cx. tcx . hir_item ( parent_mod . item_ids [ idx - 1 ] ) ; 
640-                 if  prev_item . span . is_dummy ( )  { 
660+                 let  prev_item_span  = cx. tcx . hir_span ( items_at_same_level [ idx - 1 ] ) ; 
661+                 if  prev_item_span . is_dummy ( )  { 
641662                    return  Some ( CommentStartBeforeItem :: Start ) ; 
642663                } 
643-                 if  let  Some ( sp)  = walk_span_to_context ( prev_item . span ,  SyntaxContext :: root ( ) )  { 
664+                 if  let  Some ( sp)  = walk_span_to_context ( prev_item_span ,  SyntaxContext :: root ( ) )  { 
644665                    return  Some ( CommentStartBeforeItem :: Offset ( sp. hi ( ) ) ) ; 
645666                } 
646667            } 
@@ -695,7 +716,9 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
695716                ..
696717            } )  => { 
697718                return  maybe_mod_item
698-                     . and_then ( |item| comment_start_before_item_in_mod ( cx,  mod_,  * span,  & item) ) 
719+                     . and_then ( |item :  hir:: Item < ' _ > | { 
720+                         comment_start_before_item ( cx,  & mod_items_hir_id ( mod_) ,  * span,  item. hir_id ( ) ) 
721+                     } ) 
699722                    . map ( |comment_start| mod_. spans . inner_span . with_lo ( comment_start. into ( ) ) ) 
700723                    . or ( Some ( * span) ) ; 
701724            } , 
0 commit comments