1
- use clippy_utils:: diagnostics:: span_lint_and_help ;
1
+ use clippy_utils:: diagnostics:: span_lint_and_then ;
2
2
use clippy_utils:: last_path_segment;
3
3
use clippy_utils:: ty:: { implements_trait, is_type_diagnostic_item} ;
4
- use if_chain:: if_chain;
5
-
6
4
use rustc_hir:: { Expr , ExprKind } ;
7
5
use rustc_lint:: LateContext ;
8
6
use rustc_lint:: LateLintPass ;
9
7
use rustc_middle:: ty;
8
+ use rustc_middle:: ty:: print:: with_forced_trimmed_paths;
9
+ use rustc_middle:: ty:: GenericArgKind ;
10
10
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
11
11
use rustc_span:: symbol:: sym;
12
12
@@ -15,58 +15,65 @@ declare_clippy_lint! {
15
15
/// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`.
16
16
///
17
17
/// ### 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`
20
20
///
21
21
/// ### Example
22
22
/// ```rust
23
23
/// # use std::cell::RefCell;
24
24
/// # use std::sync::Arc;
25
25
///
26
26
/// fn main() {
27
- /// // This is safe , as `i32` implements `Send` and `Sync`.
27
+ /// // This is fine , as `i32` implements `Send` and `Sync`.
28
28
/// let a = Arc::new(42);
29
29
///
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`
31
32
/// let b = Arc::new(RefCell::new(42));
32
33
/// }
33
34
/// ```
34
35
#[ clippy:: version = "1.72.0" ]
35
36
pub ARC_WITH_NON_SEND_SYNC ,
36
- correctness ,
37
+ suspicious ,
37
38
"using `Arc` with a type that does not implement `Send` or `Sync`"
38
39
}
39
40
declare_lint_pass ! ( ArcWithNonSendSync => [ ARC_WITH_NON_SEND_SYNC ] ) ;
40
41
41
42
impl LateLintPass < ' _ > for ArcWithNonSendSync {
42
43
fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) {
43
44
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`" ) ) ;
58
73
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
+ ) ) ;
70
77
}
71
78
}
72
79
}
0 commit comments