Skip to content

Commit a6bc3af

Browse files
committed
add arc_new_in_vec_from_slice lint
1 parent d5c62fd commit a6bc3af

File tree

11 files changed

+140
-0
lines changed

11 files changed

+140
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3278,6 +3278,7 @@ Released 2018-09-13
32783278
[`allow_attributes_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason
32793279
[`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
32803280
[`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
3281+
[`arc_in_vec_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#arc_in_vec_init
32813282
[`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
32823283
[`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
32833284
[`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use rustc_hir::*;
2+
use rustc_lint::{LateContext, LateLintPass};
3+
use rustc_session::{declare_lint_pass, declare_tool_lint};
4+
use clippy_utils::diagnostics::span_lint_and_help;
5+
use clippy_utils::macros::{MacroCall, root_macro_call_first_node};
6+
use clippy_utils::{last_path_segment, match_def_path, paths};
7+
use rustc_span::sym;
8+
9+
declare_clippy_lint! {
10+
/// ### What it does
11+
/// Checks for `Arc::new` calls in vector initialization using the slice macro `vec![elem; len]`
12+
///
13+
/// ### Why is this bad?
14+
/// This vector initialization creates `elem` once and clones it `len` times - doing so with `Arc`
15+
/// is a bit missleading, because the vector will contain references to the same pointer, although
16+
/// it can look like it'll contain different `Arc` instances.
17+
///
18+
/// ### Example
19+
/// ```rust
20+
/// let v = vec![std::sync::Arc::new("some data".to_string()); 100];
21+
/// ```
22+
/// Use instead:
23+
/// ```rust
24+
/// let data = std::sync::Arc::new("some data".to_string());
25+
/// let v = vec![data; 100];
26+
/// ```
27+
#[clippy::version = "1.62.0"]
28+
pub ARC_NEW_IN_VEC_FROM_SLICE,
29+
suspicious,
30+
"default lint description"
31+
}
32+
declare_lint_pass!(ArcNewInVecFromSlice => [ARC_NEW_IN_VEC_FROM_SLICE]);
33+
34+
impl LateLintPass<'_> for ArcNewInVecFromSlice {
35+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
36+
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return; };
37+
if !macro_is_vec(cx, &macro_call) { return; }
38+
39+
if_chain! {
40+
if let ExprKind::Call(func, args) = expr.peel_drop_temps().kind;
41+
if let ExprKind::Path(QPath::Resolved(_ty, ref path)) = func.kind;
42+
if let Some(did) = path.res.opt_def_id();
43+
then {
44+
if !(match_def_path(cx, did, &paths::VEC_FROM_ELEM) && first_arg_is_arc_new(args)) { return; }
45+
46+
span_lint_and_help(
47+
cx,
48+
ARC_NEW_IN_VEC_FROM_SLICE,
49+
macro_call.span,
50+
"calling `Arc::new` in `vec![elem; len]`",
51+
None,
52+
"consider extracting `Arc` initialization to a variable",
53+
);
54+
}
55+
}
56+
}
57+
}
58+
59+
fn macro_is_vec(cx: &LateContext<'_>, macro_call: &MacroCall) -> bool {
60+
cx.tcx.is_diagnostic_item(sym::vec_macro, macro_call.def_id)
61+
}
62+
63+
fn first_arg_is_arc_new(args: &[Expr<'_>]) -> bool {
64+
let Some(first_arg) = args.get(0) else { return false; };
65+
if_chain! {
66+
if let ExprKind::Call(func, _args) = first_arg.kind;
67+
if let ExprKind::Path(ref func_path) = func.kind;
68+
if let ExprKind::Path(QPath::TypeRelative(ty, _)) = func.kind;
69+
if let TyKind::Path(ref ty_path) = ty.kind;
70+
let func_segment = last_path_segment(func_path);
71+
let ty_segment = last_path_segment(ty_path);
72+
73+
then {
74+
return ty_segment.ident.name.as_str() == "Arc" && func_segment.ident.name.as_str() == "new";
75+
}
76+
}
77+
78+
false
79+
}

clippy_lints/src/lib.register_all.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
store.register_group(true, "clippy::all", Some("clippy_all"), vec![
66
LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
77
LintId::of(approx_const::APPROX_CONSTANT),
8+
LintId::of(arc_new_in_vec_from_slice::ARC_NEW_IN_VEC_FROM_SLICE),
89
LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
910
LintId::of(assign_ops::ASSIGN_OP_PATTERN),
1011
LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ store.register_lints(&[
3535
utils::internal_lints::UNNECESSARY_SYMBOL_STR,
3636
absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS,
3737
approx_const::APPROX_CONSTANT,
38+
arc_new_in_vec_from_slice::ARC_NEW_IN_VEC_FROM_SLICE,
3839
arithmetic::FLOAT_ARITHMETIC,
3940
arithmetic::INTEGER_ARITHMETIC,
4041
as_conversions::AS_CONVERSIONS,

clippy_lints/src/lib.register_suspicious.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// Manual edits will be overwritten.
44

55
store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![
6+
LintId::of(arc_new_in_vec_from_slice::ARC_NEW_IN_VEC_FROM_SLICE),
67
LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
78
LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
89
LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE),

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ mod utils;
166166
// begin lints modules, do not remove this comment, it’s used in `update_lints`
167167
mod absurd_extreme_comparisons;
168168
mod approx_const;
169+
mod arc_new_in_vec_from_slice;
169170
mod arithmetic;
170171
mod as_conversions;
171172
mod asm_syntax;
@@ -887,6 +888,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
887888
store.register_late_pass(|| Box::new(bytes_count_to_len::BytesCountToLen));
888889
let max_include_file_size = conf.max_include_file_size;
889890
store.register_late_pass(move || Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
891+
store.register_late_pass(|| Box::new(arc_new_in_vec_from_slice::ArcNewInVecFromSlice));
890892
// add lints here, do not remove this comment, it's used in `new_lint`
891893
}
892894

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![warn(clippy::arc_new_in_vec_from_slice)]
2+
use std::sync::Mutex;
3+
4+
fn main() {
5+
let v = vec![std::sync::Arc::new(Mutex::new({
6+
let x = 1;
7+
dbg!(x);
8+
x
9+
})); 2];
10+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: calling `Arc::new` in `vec![elem; len]`
2+
--> $DIR/complex_case.rs:5:13
3+
|
4+
LL | let v = vec![std::sync::Arc::new(Mutex::new({
5+
| _____________^
6+
LL | | let x = 1;
7+
LL | | dbg!(x);
8+
LL | | x
9+
LL | | })); 2];
10+
| |___________^
11+
|
12+
= note: `-D clippy::arc-new-in-vec-from-slice` implied by `-D warnings`
13+
= help: consider extracting `Arc` initialization to a variable
14+
15+
error: aborting due to previous error
16+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![warn(clippy::arc_new_in_vec_from_slice)]
2+
use std::sync::{Mutex, Arc};
3+
4+
fn main() {
5+
let v = vec![String::new(); 2];
6+
let v1 = vec![1; 2];
7+
let v2 = vec![Box::new(std::sync::Arc::new({
8+
let y = 3;
9+
dbg!(y);
10+
y
11+
})); 2];
12+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#![warn(clippy::arc_new_in_vec_from_slice)]
2+
use std::sync::Arc;
3+
4+
fn main() {
5+
let v = vec![Arc::new("x".to_string()); 2];
6+
}

0 commit comments

Comments
 (0)