1- use  clippy_utils:: diagnostics:: span_lint_and_help ; 
1+ use  clippy_utils:: diagnostics:: span_lint_and_then ; 
22use  clippy_utils:: last_path_segment; 
33use  clippy_utils:: ty:: { implements_trait,  is_type_diagnostic_item} ; 
4- use  if_chain:: if_chain; 
5- 
64use  rustc_hir:: { Expr ,  ExprKind } ; 
75use  rustc_lint:: LateContext ; 
86use  rustc_lint:: LateLintPass ; 
97use  rustc_middle:: ty; 
8+ use  rustc_middle:: ty:: print:: with_forced_trimmed_paths; 
9+ use  rustc_middle:: ty:: GenericArgKind ; 
1010use  rustc_session:: { declare_lint_pass,  declare_tool_lint} ; 
1111use  rustc_span:: symbol:: sym; 
1212
@@ -15,58 +15,65 @@ declare_clippy_lint! {
1515     /// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`. 
1616     /// 
1717     /// ### Why is this bad? 
18-      /// Wrapping a type in  Arc doesn't add thread safety to the underlying data, so data races  
19-      /// could occur when touching the underlying data.  
18+      /// ` Arc<T>` is only `Send`/`Sync` when `T` is [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-Send-for-Arc%3CT%3E),  
19+      /// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc`  
2020     /// 
2121     /// ### Example 
2222     /// ```rust 
2323     /// # use std::cell::RefCell; 
2424     /// # use std::sync::Arc; 
2525     /// 
2626     /// fn main() { 
27-      ///     // This is safe , as `i32` implements `Send` and `Sync`. 
27+      ///     // This is fine , as `i32` implements `Send` and `Sync`. 
2828     ///     let a = Arc::new(42); 
2929     /// 
30-      ///     // This is not safe, as `RefCell` does not implement `Sync`. 
30+      ///     // `RefCell` is `!Sync`, so either the `Arc` should be replaced with an `Rc` 
31+      ///     // or the `RefCell` replaced with something like a `RwLock` 
3132     ///     let b = Arc::new(RefCell::new(42)); 
3233     /// } 
3334     /// ``` 
3435     #[ clippy:: version = "1.72.0" ] 
3536    pub  ARC_WITH_NON_SEND_SYNC , 
36-     correctness , 
37+     suspicious , 
3738    "using `Arc` with a type that does not implement `Send` or `Sync`" 
3839} 
3940declare_lint_pass ! ( ArcWithNonSendSync  => [ ARC_WITH_NON_SEND_SYNC ] ) ; 
4041
4142impl  LateLintPass < ' _ >  for  ArcWithNonSendSync  { 
4243    fn  check_expr ( & mut  self ,  cx :  & LateContext < ' _ > ,  expr :  & Expr < ' _ > )  { 
4344        let  ty = cx. typeck_results ( ) . expr_ty ( expr) ; 
44-         if_chain !  { 
45-             if  is_type_diagnostic_item( cx,  ty,  sym:: Arc ) ; 
46-             if  let  ExprKind :: Call ( func,  [ arg] )  = expr. kind; 
47-             if  let  ExprKind :: Path ( func_path)  = func. kind; 
48-             if  last_path_segment( & func_path) . ident. name == sym:: new; 
49-             if  let  arg_ty = cx. typeck_results( ) . expr_ty( arg) ; 
50-             if  !matches!( arg_ty. kind( ) ,  ty:: Param ( _) ) ; 
51-             if  !cx. tcx
52-                 . lang_items( ) 
53-                 . sync_trait( ) 
54-                 . map_or( false ,  |id| implements_trait( cx,  arg_ty,  id,  & [ ] ) )  ||
55-                 !cx. tcx
56-                 . get_diagnostic_item( sym:: Send ) 
57-                 . map_or( false ,  |id| implements_trait( cx,  arg_ty,  id,  & [ ] ) ) ; 
45+         if  is_type_diagnostic_item ( cx,  ty,  sym:: Arc ) 
46+             && let  ExprKind :: Call ( func,  [ arg] )  = expr. kind 
47+             && let  ExprKind :: Path ( func_path)  = func. kind 
48+             && last_path_segment ( & func_path) . ident . name  == sym:: new
49+             && let  arg_ty = cx. typeck_results ( ) . expr_ty ( arg) 
50+             // make sure that the type is not and does not contain any type parameters 
51+             && arg_ty. walk ( ) . all ( |arg| { 
52+                 !matches ! ( arg. unpack( ) ,  GenericArgKind :: Type ( ty)  if  matches!( ty. kind( ) ,  ty:: Param ( _) ) ) 
53+             } ) 
54+             && let  Some ( send)  = cx. tcx . get_diagnostic_item ( sym:: Send ) 
55+             && let  Some ( sync)  = cx. tcx . lang_items ( ) . sync_trait ( ) 
56+             && let  [ is_send,  is_sync]  = [ send,  sync] . map ( |id| implements_trait ( cx,  arg_ty,  id,  & [ ] ) ) 
57+             && !( is_send && is_sync) 
58+         { 
59+             span_lint_and_then ( 
60+                 cx, 
61+                 ARC_WITH_NON_SEND_SYNC , 
62+                 expr. span , 
63+                 "usage of an `Arc` that is not `Send` or `Sync`" , 
64+                 |diag| with_forced_trimmed_paths ! ( { 
65+                     if  !is_send { 
66+                         diag. note( format!( "the trait `Send` is not implemented for `{arg_ty}`" ) ) ; 
67+                     } 
68+                     if  !is_sync { 
69+                         diag. note( format!( "the trait `Sync` is not implemented for `{arg_ty}`" ) ) ; 
70+                     } 
71+ 
72+                     diag. note( format!( "required for `{ty}` to implement `Send` and `Sync`" ) ) ; 
5873
59-             then { 
60-                 span_lint_and_help( 
61-                     cx, 
62-                     ARC_WITH_NON_SEND_SYNC , 
63-                     expr. span, 
64-                     "usage of `Arc<T>` where `T` is not `Send` or `Sync`" , 
65-                     None , 
66-                     "consider using `Rc<T>` instead or wrapping `T` in a std::sync type like \  
67-                      `Mutex<T>`", 
68-                 ) ; 
69-             } 
74+                     diag. help( "consider using an `Rc` instead or wrapping the inner type with a `Mutex`" ) ; 
75+                 } 
76+             ) ) ; 
7077        } 
7178    } 
7279} 
0 commit comments