2023-07-17 03:19:29 -05:00
use clippy_utils ::diagnostics ::span_lint_and_then ;
2023-07-02 07:35:19 -05:00
use clippy_utils ::ty ::{ implements_trait , is_type_diagnostic_item } ;
2023-07-31 16:53:53 -05:00
use clippy_utils ::{ is_from_proc_macro , last_path_segment } ;
2023-07-02 07:35:19 -05:00
use rustc_hir ::{ Expr , ExprKind } ;
2023-07-17 03:19:29 -05:00
use rustc_lint ::{ LateContext , LateLintPass } ;
2023-07-02 07:35:19 -05:00
use rustc_middle ::ty ;
2023-07-17 03:19:29 -05:00
use rustc_middle ::ty ::print ::with_forced_trimmed_paths ;
use rustc_middle ::ty ::GenericArgKind ;
2023-12-01 11:21:58 -06:00
use rustc_session ::declare_lint_pass ;
2023-07-02 07:35:19 -05:00
use rustc_span ::symbol ::sym ;
declare_clippy_lint! {
/// ### What it does.
/// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`.
///
/// ### Why is this bad?
2023-11-16 12:13:24 -06:00
/// `Arc<T>` is an Atomic `RC<T>` and guarantees that updates to the reference counter are
/// Atomic. This is useful in multiprocessing scenarios. To send an `Arc<T>` across processes
/// and make use of the atomic ref counter, `T` must be [both `Send` and `Sync`](https://doc.rust-lang.org/std/sync/struct.Arc.html#impl-Send-for-Arc%3CT%3E),
2023-07-17 03:19:29 -05:00
/// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc`
2023-07-02 07:35:19 -05:00
///
/// ### Example
2023-11-02 11:35:56 -05:00
/// ```no_run
2023-07-02 07:35:19 -05:00
/// # use std::cell::RefCell;
/// # use std::sync::Arc;
///
/// fn main() {
2023-07-17 03:19:29 -05:00
/// // This is fine, as `i32` implements `Send` and `Sync`.
2023-07-02 07:35:19 -05:00
/// let a = Arc::new(42);
///
2023-07-17 03:19:29 -05:00
/// // `RefCell` is `!Sync`, so either the `Arc` should be replaced with an `Rc`
/// // or the `RefCell` replaced with something like a `RwLock`
2023-07-02 07:35:19 -05:00
/// let b = Arc::new(RefCell::new(42));
/// }
/// ```
#[ clippy::version = " 1.72.0 " ]
pub ARC_WITH_NON_SEND_SYNC ,
2023-07-17 03:19:29 -05:00
suspicious ,
2023-11-16 12:13:24 -06:00
" using `Arc` with a type that does not implement `Send` and `Sync` "
2023-07-02 07:35:19 -05:00
}
declare_lint_pass! ( ArcWithNonSendSync = > [ ARC_WITH_NON_SEND_SYNC ] ) ;
2023-07-31 16:53:53 -05:00
impl < ' tcx > LateLintPass < ' tcx > for ArcWithNonSendSync {
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) {
if ! expr . span . from_expansion ( )
& & let ty = cx . typeck_results ( ) . expr_ty ( expr )
& & is_type_diagnostic_item ( cx , ty , sym ::Arc )
2023-07-17 03:19:29 -05:00
& & let ExprKind ::Call ( func , [ arg ] ) = expr . kind
& & let ExprKind ::Path ( func_path ) = func . kind
& & last_path_segment ( & func_path ) . ident . name = = sym ::new
& & let arg_ty = cx . typeck_results ( ) . expr_ty ( arg )
// make sure that the type is not and does not contain any type parameters
& & arg_ty . walk ( ) . all ( | arg | {
! matches! ( arg . unpack ( ) , GenericArgKind ::Type ( ty ) if matches! ( ty . kind ( ) , ty ::Param ( _ ) ) )
} )
& & let Some ( send ) = cx . tcx . get_diagnostic_item ( sym ::Send )
& & let Some ( sync ) = cx . tcx . lang_items ( ) . sync_trait ( )
& & let [ is_send , is_sync ] = [ send , sync ] . map ( | id | implements_trait ( cx , arg_ty , id , & [ ] ) )
& & ! ( is_send & & is_sync )
2023-07-31 16:53:53 -05:00
& & ! is_from_proc_macro ( cx , expr )
2023-07-17 03:19:29 -05:00
{
span_lint_and_then (
cx ,
ARC_WITH_NON_SEND_SYNC ,
expr . span ,
2023-11-16 12:13:24 -06:00
" usage of an `Arc` that is not `Send` and `Sync` " ,
2023-11-02 11:35:56 -05:00
| diag | {
with_forced_trimmed_paths! ( {
2023-11-16 12:13:24 -06:00
diag . note ( format! ( " `Arc< {arg_ty} >` is not `Send` and `Sync` as: " ) ) ;
2023-11-02 11:35:56 -05:00
if ! is_send {
2023-11-16 12:13:24 -06:00
diag . note ( format! ( " - the trait `Send` is not implemented for ` {arg_ty} ` " ) ) ;
2023-11-02 11:35:56 -05:00
}
if ! is_sync {
2023-11-16 12:13:24 -06:00
diag . note ( format! ( " - the trait `Sync` is not implemented for ` {arg_ty} ` " ) ) ;
2023-11-02 11:35:56 -05:00
}
2023-07-17 03:19:29 -05:00
2023-11-16 12:13:24 -06:00
diag . help ( " consider using an `Rc` instead. `Arc` does not provide benefits for non `Send` and `Sync` types " ) ;
diag . note ( " if you intend to use `Arc` with `Send` and `Sync` traits " ) ;
2023-07-02 07:35:19 -05:00
2023-11-16 12:13:24 -06:00
diag . note ( format! (
" wrap the inner type with a `Mutex` or implement `Send` and `Sync` for `{arg_ty}` "
) ) ;
2023-11-02 11:35:56 -05:00
} ) ;
} ,
) ;
2023-07-02 07:35:19 -05:00
}
}
}