Skip to content

Commit 45e5f28

Browse files
authored
Merge pull request #2067 from jugglerchris/no_effect_with_drop
Fix #2061 (don't suggest removing types which implement Drop)
2 parents 12a7d14 + dcaaab3 commit 45e5f28

File tree

4 files changed

+199
-132
lines changed

4 files changed

+199
-132
lines changed

clippy_lints/src/no_effect.rs

+19-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
22
use rustc::hir::def::Def;
33
use rustc::hir::{BiAnd, BiOr, BlockCheckMode, Expr, Expr_, Stmt, StmtSemi, UnsafeSource};
4-
use utils::{in_macro, snippet_opt, span_lint, span_lint_and_sugg};
4+
use utils::{in_macro, snippet_opt, span_lint, span_lint_and_sugg, has_drop};
55
use std::ops::Deref;
66

77
/// **What it does:** Checks for statements which have no effect.
@@ -45,7 +45,8 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool {
4545
return false;
4646
}
4747
match expr.node {
48-
Expr_::ExprLit(..) | Expr_::ExprClosure(.., _) | Expr_::ExprPath(..) => true,
48+
Expr_::ExprLit(..) | Expr_::ExprClosure(.., _) => true,
49+
Expr_::ExprPath(..) => !has_drop(cx, expr),
4950
Expr_::ExprIndex(ref a, ref b) | Expr_::ExprBinary(_, ref a, ref b) => {
5051
has_no_effect(cx, a) && has_no_effect(cx, b)
5152
},
@@ -59,7 +60,7 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool {
5960
Expr_::ExprAddrOf(_, ref inner) |
6061
Expr_::ExprBox(ref inner) => has_no_effect(cx, inner),
6162
Expr_::ExprStruct(_, ref fields, ref base) => {
62-
fields.iter().all(|field| has_no_effect(cx, &field.expr)) && match *base {
63+
!has_drop(cx, expr) && fields.iter().all(|field| has_no_effect(cx, &field.expr)) && match *base {
6364
Some(ref base) => has_no_effect(cx, base),
6465
None => true,
6566
}
@@ -68,7 +69,7 @@ fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool {
6869
let def = cx.tables.qpath_def(qpath, callee.hir_id);
6970
match def {
7071
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..) => {
71-
args.iter().all(|arg| has_no_effect(cx, arg))
72+
!has_drop(cx, expr) && args.iter().all(|arg| has_no_effect(cx, arg))
7273
},
7374
_ => false,
7475
}
@@ -145,18 +146,23 @@ fn reduce_expression<'a>(cx: &LateContext, expr: &'a Expr) -> Option<Vec<&'a Exp
145146
Expr_::ExprTupField(ref inner, _) |
146147
Expr_::ExprAddrOf(_, ref inner) |
147148
Expr_::ExprBox(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
148-
Expr_::ExprStruct(_, ref fields, ref base) => Some(
149-
fields
150-
.iter()
151-
.map(|f| &f.expr)
152-
.chain(base)
153-
.map(Deref::deref)
154-
.collect(),
155-
),
149+
Expr_::ExprStruct(_, ref fields, ref base) => {
150+
if has_drop(cx, expr) {
151+
None
152+
} else {
153+
Some(
154+
fields
155+
.iter()
156+
.map(|f| &f.expr)
157+
.chain(base)
158+
.map(Deref::deref)
159+
.collect())
160+
}
161+
},
156162
Expr_::ExprCall(ref callee, ref args) => if let Expr_::ExprPath(ref qpath) = callee.node {
157163
let def = cx.tables.qpath_def(qpath, callee.hir_id);
158164
match def {
159-
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..) => {
165+
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..) if !has_drop(cx, expr) => {
160166
Some(args.iter().collect())
161167
},
162168
_ => None,

clippy_lints/src/utils/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,15 @@ pub fn implements_trait<'a, 'tcx>(
358358
})
359359
}
360360

361+
/// Check whether this type implements Drop.
362+
pub fn has_drop(cx: &LateContext, expr: &Expr) -> bool {
363+
let struct_ty = cx.tables.expr_ty(expr);
364+
match struct_ty.ty_adt_def() {
365+
Some(def) => def.has_dtor(cx.tcx),
366+
_ => false,
367+
}
368+
}
369+
361370
/// Resolve the definition of a node from its `HirId`.
362371
pub fn resolve_node(cx: &LateContext, qpath: &QPath, id: HirId) -> def::Def {
363372
cx.tables.qpath_def(qpath, id)

tests/ui/no_effect.rs

+41-1
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,38 @@ enum Enum {
1616
Tuple(i32),
1717
Struct { field: i32 },
1818
}
19-
19+
struct DropUnit;
20+
impl Drop for DropUnit {
21+
fn drop(&mut self) {}
22+
}
23+
struct DropStruct {
24+
field: i32
25+
}
26+
impl Drop for DropStruct {
27+
fn drop(&mut self) {}
28+
}
29+
struct DropTuple(i32);
30+
impl Drop for DropTuple {
31+
fn drop(&mut self) {}
32+
}
33+
enum DropEnum {
34+
Tuple(i32),
35+
Struct { field: i32 },
36+
}
37+
impl Drop for DropEnum {
38+
fn drop(&mut self) {}
39+
}
40+
struct FooString {
41+
s: String,
42+
}
2043
union Union {
2144
a: u8,
2245
b: f64,
2346
}
2447

2548
fn get_number() -> i32 { 0 }
2649
fn get_struct() -> Struct { Struct { field: 0 } }
50+
fn get_drop_struct() -> DropStruct { DropStruct { field: 0 } }
2751

2852
unsafe fn unsafe_fn() -> i32 { 0 }
2953

@@ -57,10 +81,17 @@ fn main() {
5781
[42; 55][13];
5882
let mut x = 0;
5983
|| x += 5;
84+
let s: String = "foo".into();
85+
FooString { s: s };
6086

6187
// Do not warn
6288
get_number();
6389
unsafe { unsafe_fn() };
90+
DropUnit;
91+
DropStruct { field: 0 };
92+
DropTuple(0);
93+
DropEnum::Tuple(0);
94+
DropEnum::Struct { field: 0 };
6495

6596
Tuple(get_number());
6697
Struct { field: get_number() };
@@ -81,4 +112,13 @@ fn main() {
81112
[get_number(); 55];
82113
[42; 55][get_number() as usize];
83114
{get_number()};
115+
FooString { s: String::from("blah"), };
116+
117+
// Do not warn
118+
DropTuple(get_number());
119+
DropStruct { field: get_number() };
120+
DropStruct { field: get_number() };
121+
DropStruct { ..get_drop_struct() };
122+
DropEnum::Tuple(get_number());
123+
DropEnum::Struct { field: get_number() };
84124
}

0 commit comments

Comments
 (0)