Skip to content

Commit b84fb36

Browse files
committed
add arc_new_in_vec_from_slice lint
1 parent d5c62fd commit b84fb36

13 files changed

+170
-0
lines changed

CHANGELOG.md

+1
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_new_in_vec_from_elem`]: https://rust-lang.github.io/rust-clippy/master/index.html#arc_new_in_vec_from_elem
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
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use clippy_utils::diagnostics::span_lint_and_then;
2+
use clippy_utils::higher::VecArgs;
3+
use clippy_utils::last_path_segment;
4+
use clippy_utils::macros::{root_macro_call_first_node, MacroCall};
5+
use rustc_hir::{Expr, ExprKind, QPath, TyKind};
6+
use rustc_lint::{LateContext, LateLintPass};
7+
use rustc_session::{declare_lint_pass, declare_tool_lint};
8+
use rustc_span::sym;
9+
10+
declare_clippy_lint! {
11+
/// ### What it does
12+
/// Checks for `Arc::new` in `vec![elem; len]`
13+
///
14+
/// ### Why is this bad?
15+
/// This will create `elem` once and clone it `len` times - doing so with `Arc`
16+
/// is a bit misleading, as it will create references to the same pointer, rather
17+
/// than different `Arc` instances.
18+
///
19+
/// ### Example
20+
/// ```rust
21+
/// let v = vec![std::sync::Arc::new("some data".to_string()); 100];
22+
/// ```
23+
/// Use instead:
24+
/// ```rust
25+
/// let data = std::sync::Arc::new("some data".to_string());
26+
/// let v = vec![data; 100];
27+
/// ```
28+
#[clippy::version = "1.62.0"]
29+
pub ARC_NEW_IN_VEC_FROM_ELEM,
30+
suspicious,
31+
"calling `Arc::new` in `vec![elem; len]`"
32+
}
33+
declare_lint_pass!(ArcNewInVecFromElem => [ARC_NEW_IN_VEC_FROM_ELEM]);
34+
35+
impl LateLintPass<'_> for ArcNewInVecFromElem {
36+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
37+
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return; };
38+
39+
if let Some(VecArgs::Repeat(elem, _)) = VecArgs::hir(cx, expr) {
40+
if !is_arc_new(cx, elem) {
41+
return;
42+
}
43+
44+
yield_lint(cx, &macro_call);
45+
}
46+
}
47+
}
48+
49+
fn yield_lint(cx: &LateContext<'_>, macro_call: &MacroCall) {
50+
span_lint_and_then(
51+
cx,
52+
ARC_NEW_IN_VEC_FROM_ELEM,
53+
macro_call.span,
54+
"calling `Arc::new` in `vec![elem; len]`",
55+
|diag| {
56+
diag.note("each `Arc` will point to the same allocation");
57+
diag.help("if this is intentional, consider extracting the `Arc` initialization to a variable");
58+
},
59+
);
60+
}
61+
62+
/// Checks whether the given `expr` is a call to `Arc::new`
63+
fn is_arc_new(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
64+
if_chain! {
65+
if let ExprKind::Call(func, _args) = expr.kind;
66+
if let ExprKind::Path(ref func_path @ QPath::TypeRelative(ty, _)) = func.kind;
67+
if let TyKind::Path(ref ty_path) = ty.kind;
68+
if let Some(def_id) = cx.qpath_res(ty_path, ty.hir_id).opt_def_id();
69+
if cx.tcx.is_diagnostic_item(sym::Arc, def_id);
70+
71+
then {
72+
let func_segment = last_path_segment(func_path);
73+
74+
return func_segment.ident.name == sym::new;
75+
}
76+
}
77+
78+
false
79+
}

clippy_lints/src/lib.register_all.rs

+1
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_elem::ARC_NEW_IN_VEC_FROM_ELEM),
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

+1
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_elem::ARC_NEW_IN_VEC_FROM_ELEM,
3839
arithmetic::FLOAT_ARITHMETIC,
3940
arithmetic::INTEGER_ARITHMETIC,
4041
as_conversions::AS_CONVERSIONS,

clippy_lints/src/lib.register_suspicious.rs

+1
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_elem::ARC_NEW_IN_VEC_FROM_ELEM),
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

+2
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_elem;
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_elem::ArcNewInVecFromElem));
890892
// add lints here, do not remove this comment, it's used in `new_lint`
891893
}
892894

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#![warn(clippy::arc_new_in_vec_from_elem)]
2+
use std::sync::Mutex;
3+
4+
fn main() {
5+
let v = vec![
6+
std::sync::Arc::new(Mutex::new({
7+
let x = 1;
8+
dbg!(x);
9+
x
10+
}));
11+
2
12+
];
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error: calling `Arc::new` in `vec![elem; len]`
2+
--> $DIR/complex_case.rs:5:13
3+
|
4+
LL | let v = vec![
5+
| _____________^
6+
LL | | std::sync::Arc::new(Mutex::new({
7+
LL | | let x = 1;
8+
LL | | dbg!(x);
9+
... |
10+
LL | | 2
11+
LL | | ];
12+
| |_____^
13+
|
14+
= note: `-D clippy::arc-new-in-vec-from-elem` implied by `-D warnings`
15+
= note: each `Arc` will point to the same allocation
16+
= help: if this is intentional, consider extracting the `Arc` initialization to a variable
17+
18+
error: aborting due to previous error
19+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![warn(clippy::arc_new_in_vec_from_elem)]
2+
3+
#[derive(Clone)]
4+
struct Arc;
5+
6+
impl Arc {
7+
fn new() -> Self {
8+
Arc
9+
}
10+
}
11+
12+
fn main() {
13+
let v = vec![Arc::new(); 2];
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#![warn(clippy::arc_new_in_vec_from_elem)]
2+
use std::sync::Arc;
3+
4+
fn main() {
5+
let v = vec![Arc::new("x".to_string()); 2];
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error: calling `Arc::new` in `vec![elem; len]`
2+
--> $DIR/simple_case.rs:5:13
3+
|
4+
LL | let v = vec![Arc::new("x".to_string()); 2];
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::arc-new-in-vec-from-elem` implied by `-D warnings`
8+
= note: each `Arc` will point to the same allocation
9+
= help: if this is intentional, consider extracting the `Arc` initialization to a variable
10+
11+
error: aborting due to previous error
12+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![warn(clippy::arc_new_in_vec_from_elem)]
2+
use std::sync::{Arc, Mutex};
3+
4+
fn main() {
5+
let v = vec![String::new(); 2];
6+
let v1 = vec![1; 2];
7+
let v2 = vec![
8+
Box::new(std::sync::Arc::new({
9+
let y = 3;
10+
dbg!(y);
11+
y
12+
}));
13+
2
14+
];
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#![warn(clippy::arc_new_in_vec_from_elem)]
2+
use std::sync::Arc;
3+
4+
fn main() {
5+
let v = vec![Arc::new("x".to_string())];
6+
}

0 commit comments

Comments
 (0)