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