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;
109use rustc_middle:: ty:: GenericArgKind ;
1110use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
1211use rustc_span:: symbol:: sym;
@@ -16,61 +15,65 @@ declare_clippy_lint! {
1615 /// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`.
1716 ///
1817 /// ### Why is this bad?
19- /// Wrapping a type in Arc doesn't add thread safety to the underlying data, so data races
20- /// 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`
2120 ///
2221 /// ### Example
2322 /// ```rust
2423 /// # use std::cell::RefCell;
2524 /// # use std::sync::Arc;
2625 ///
2726 /// fn main() {
28- /// // This is safe , as `i32` implements `Send` and `Sync`.
27+ /// // This is fine , as `i32` implements `Send` and `Sync`.
2928 /// let a = Arc::new(42);
3029 ///
31- /// // 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`
3232 /// let b = Arc::new(RefCell::new(42));
3333 /// }
3434 /// ```
3535 #[ clippy:: version = "1.72.0" ]
3636 pub ARC_WITH_NON_SEND_SYNC ,
37- correctness ,
37+ suspicious ,
3838 "using `Arc` with a type that does not implement `Send` or `Sync`"
3939}
4040declare_lint_pass ! ( ArcWithNonSendSync => [ ARC_WITH_NON_SEND_SYNC ] ) ;
4141
4242impl LateLintPass < ' _ > for ArcWithNonSendSync {
4343 fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) {
4444 let ty = cx. typeck_results ( ) . expr_ty ( expr) ;
45- if_chain ! {
46- if is_type_diagnostic_item( cx, ty, sym:: Arc ) ;
47- if let ExprKind :: Call ( func, [ arg] ) = expr. kind;
48- if let ExprKind :: Path ( func_path) = func. kind;
49- if last_path_segment( & func_path) . ident. name == sym:: new;
50- if let arg_ty = cx. typeck_results( ) . expr_ty( arg) ;
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)
5150 // make sure that the type is not and does not contain any type parameters
52- if arg_ty. walk( ) . all( |arg| {
51+ && arg_ty. walk ( ) . all ( |arg| {
5352 !matches ! ( arg. unpack( ) , GenericArgKind :: Type ( ty) if matches!( ty. kind( ) , ty:: Param ( _) ) )
54- } ) ;
55- if !cx. tcx
56- . lang_items( )
57- . sync_trait( )
58- . map_or( false , |id| implements_trait( cx, arg_ty, id, & [ ] ) ) ||
59- !cx. tcx
60- . get_diagnostic_item( sym:: Send )
61- . map_or( false , |id| implements_trait( cx, arg_ty, id, & [ ] ) ) ;
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`" ) ) ;
6273
63- then {
64- span_lint_and_help(
65- cx,
66- ARC_WITH_NON_SEND_SYNC ,
67- expr. span,
68- "usage of `Arc<T>` where `T` is not `Send` or `Sync`" ,
69- None ,
70- "consider using `Rc<T>` instead or wrapping `T` in a std::sync type like \
71- `Mutex<T>`",
72- ) ;
73- }
74+ diag. help( "consider using an `Rc` instead or wrapping the inner type with a `Mutex`" ) ;
75+ }
76+ ) ) ;
7477 }
7578 }
7679}
0 commit comments