Skip to content

Commit ee3088f

Browse files
committed
Auto merge of rust-lang#5631 - ThibsG:ExtendUselessConversion, r=matthiaskrgr
Extend useless conversion This PR extends `useless_conversion` lint with `TryFrom` and `TryInto` fixes: rust-lang#5344 changelog: Extend `useless_conversion` with `TryFrom` and `TryInto`
2 parents 2a2208f + 1801841 commit ee3088f

File tree

6 files changed

+199
-25
lines changed

6 files changed

+199
-25
lines changed

clippy_lints/src/useless_conversion.rs

+65-14
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
use crate::utils::{
2-
match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_sugg,
2+
is_type_diagnostic_item, match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite,
3+
span_lint_and_help, span_lint_and_sugg,
34
};
5+
use if_chain::if_chain;
46
use rustc_errors::Applicability;
57
use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
68
use rustc_lint::{LateContext, LateLintPass};
9+
use rustc_middle::ty;
710
use rustc_session::{declare_tool_lint, impl_lint_pass};
811

912
declare_clippy_lint! {
10-
/// **What it does:** Checks for `Into`/`From`/`IntoIter` calls that useless converts
11-
/// to the same type as caller.
13+
/// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`,`IntoIter` calls
14+
/// that useless converts to the same type as caller.
1215
///
1316
/// **Why is this bad?** Redundant code.
1417
///
@@ -26,7 +29,7 @@ declare_clippy_lint! {
2629
/// ```
2730
pub USELESS_CONVERSION,
2831
complexity,
29-
"calls to `Into`/`From`/`IntoIter` that performs useless conversions to the same type"
32+
"calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type"
3033
}
3134

3235
#[derive(Default)]
@@ -36,6 +39,7 @@ pub struct UselessConversion {
3639

3740
impl_lint_pass!(UselessConversion => [USELESS_CONVERSION]);
3841

42+
#[allow(clippy::too_many_lines)]
3943
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion {
4044
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) {
4145
if e.span.from_expansion() {
@@ -63,12 +67,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion {
6367
let b = cx.tables.expr_ty(&args[0]);
6468
if same_tys(cx, a, b) {
6569
let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
66-
6770
span_lint_and_sugg(
6871
cx,
6972
USELESS_CONVERSION,
7073
e.span,
71-
"useless conversion",
74+
"useless conversion to the same type",
7275
"consider removing `.into()`",
7376
sugg,
7477
Applicability::MachineApplicable, // snippet
@@ -84,30 +87,78 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion {
8487
cx,
8588
USELESS_CONVERSION,
8689
e.span,
87-
"useless conversion",
90+
"useless conversion to the same type",
8891
"consider removing `.into_iter()`",
8992
sugg,
9093
Applicability::MachineApplicable, // snippet
9194
);
9295
}
9396
}
97+
if match_trait_method(cx, e, &paths::TRY_INTO_TRAIT) && &*name.ident.as_str() == "try_into" {
98+
if_chain! {
99+
let a = cx.tables.expr_ty(e);
100+
let b = cx.tables.expr_ty(&args[0]);
101+
if is_type_diagnostic_item(cx, a, sym!(result_type));
102+
if let ty::Adt(_, substs) = a.kind;
103+
if let Some(a_type) = substs.types().next();
104+
if same_tys(cx, a_type, b);
105+
106+
then {
107+
span_lint_and_help(
108+
cx,
109+
USELESS_CONVERSION,
110+
e.span,
111+
"useless conversion to the same type",
112+
None,
113+
"consider removing `.try_into()`",
114+
);
115+
}
116+
}
117+
}
94118
},
95119

96120
ExprKind::Call(ref path, ref args) => {
97-
if let ExprKind::Path(ref qpath) = path.kind {
98-
if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id() {
99-
if match_def_path(cx, def_id, &paths::FROM_FROM) {
100-
let a = cx.tables.expr_ty(e);
101-
let b = cx.tables.expr_ty(&args[0]);
102-
if same_tys(cx, a, b) {
121+
if_chain! {
122+
if args.len() == 1;
123+
if let ExprKind::Path(ref qpath) = path.kind;
124+
if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id();
125+
let a = cx.tables.expr_ty(e);
126+
let b = cx.tables.expr_ty(&args[0]);
127+
128+
then {
129+
if_chain! {
130+
if match_def_path(cx, def_id, &paths::TRY_FROM);
131+
if is_type_diagnostic_item(cx, a, sym!(result_type));
132+
if let ty::Adt(_, substs) = a.kind;
133+
if let Some(a_type) = substs.types().next();
134+
if same_tys(cx, a_type, b);
135+
136+
then {
137+
let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from"));
138+
span_lint_and_help(
139+
cx,
140+
USELESS_CONVERSION,
141+
e.span,
142+
"useless conversion to the same type",
143+
None,
144+
&hint,
145+
);
146+
}
147+
}
148+
149+
if_chain! {
150+
if match_def_path(cx, def_id, &paths::FROM_FROM);
151+
if same_tys(cx, a, b);
152+
153+
then {
103154
let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned();
104155
let sugg_msg =
105156
format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
106157
span_lint_and_sugg(
107158
cx,
108159
USELESS_CONVERSION,
109160
e.span,
110-
"useless conversion",
161+
"useless conversion to the same type",
111162
&sugg_msg,
112163
sugg,
113164
Applicability::MachineApplicable, // snippet

clippy_lints/src/utils/paths.rs

+2
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,10 @@ pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"
128128
pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
129129
pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
130130
pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
131+
pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
131132
pub const TRY_FROM_ERROR: [&str; 4] = ["std", "ops", "Try", "from_error"];
132133
pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"];
134+
pub const TRY_INTO_TRAIT: [&str; 3] = ["core", "convert", "TryInto"];
133135
pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
134136
pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
135137
pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];

src/lintlist/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2421,7 +2421,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
24212421
Lint {
24222422
name: "useless_conversion",
24232423
group: "complexity",
2424-
desc: "calls to `Into`/`From`/`IntoIter` that performs useless conversions to the same type",
2424+
desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type",
24252425
deprecation: None,
24262426
module: "useless_conversion",
24272427
},

tests/ui/useless_conversion.stderr

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: useless conversion
1+
error: useless conversion to the same type
22
--> $DIR/useless_conversion.rs:6:13
33
|
44
LL | let _ = T::from(val);
@@ -10,55 +10,55 @@ note: the lint level is defined here
1010
LL | #![deny(clippy::useless_conversion)]
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
1212

13-
error: useless conversion
13+
error: useless conversion to the same type
1414
--> $DIR/useless_conversion.rs:7:5
1515
|
1616
LL | val.into()
1717
| ^^^^^^^^^^ help: consider removing `.into()`: `val`
1818

19-
error: useless conversion
19+
error: useless conversion to the same type
2020
--> $DIR/useless_conversion.rs:19:22
2121
|
2222
LL | let _: i32 = 0i32.into();
2323
| ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
2424

25-
error: useless conversion
25+
error: useless conversion to the same type
2626
--> $DIR/useless_conversion.rs:51:21
2727
|
2828
LL | let _: String = "foo".to_string().into();
2929
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
3030

31-
error: useless conversion
31+
error: useless conversion to the same type
3232
--> $DIR/useless_conversion.rs:52:21
3333
|
3434
LL | let _: String = From::from("foo".to_string());
3535
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
3636

37-
error: useless conversion
37+
error: useless conversion to the same type
3838
--> $DIR/useless_conversion.rs:53:13
3939
|
4040
LL | let _ = String::from("foo".to_string());
4141
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
4242

43-
error: useless conversion
43+
error: useless conversion to the same type
4444
--> $DIR/useless_conversion.rs:54:13
4545
|
4646
LL | let _ = String::from(format!("A: {:04}", 123));
4747
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
4848

49-
error: useless conversion
49+
error: useless conversion to the same type
5050
--> $DIR/useless_conversion.rs:55:13
5151
|
5252
LL | let _ = "".lines().into_iter();
5353
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
5454

55-
error: useless conversion
55+
error: useless conversion to the same type
5656
--> $DIR/useless_conversion.rs:56:13
5757
|
5858
LL | let _ = vec![1, 2, 3].into_iter().into_iter();
5959
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
6060

61-
error: useless conversion
61+
error: useless conversion to the same type
6262
--> $DIR/useless_conversion.rs:57:21
6363
|
6464
LL | let _: String = format!("Hello {}", "world").into();

tests/ui/useless_conversion_try.rs

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#![deny(clippy::useless_conversion)]
2+
3+
use std::convert::{TryFrom, TryInto};
4+
5+
fn test_generic<T: Copy>(val: T) -> T {
6+
let _ = T::try_from(val).unwrap();
7+
val.try_into().unwrap()
8+
}
9+
10+
fn test_generic2<T: Copy + Into<i32> + Into<U>, U: From<T>>(val: T) {
11+
// ok
12+
let _: i32 = val.try_into().unwrap();
13+
let _: U = val.try_into().unwrap();
14+
let _ = U::try_from(val).unwrap();
15+
}
16+
17+
fn main() {
18+
test_generic(10i32);
19+
test_generic2::<i32, i32>(10i32);
20+
21+
let _: String = "foo".try_into().unwrap();
22+
let _: String = TryFrom::try_from("foo").unwrap();
23+
let _ = String::try_from("foo").unwrap();
24+
#[allow(clippy::useless_conversion)]
25+
{
26+
let _ = String::try_from("foo").unwrap();
27+
let _: String = "foo".try_into().unwrap();
28+
}
29+
let _: String = "foo".to_string().try_into().unwrap();
30+
let _: String = TryFrom::try_from("foo".to_string()).unwrap();
31+
let _ = String::try_from("foo".to_string()).unwrap();
32+
let _ = String::try_from(format!("A: {:04}", 123)).unwrap();
33+
let _: String = format!("Hello {}", "world").try_into().unwrap();
34+
let _: String = "".to_owned().try_into().unwrap();
35+
let _: String = match String::from("_").try_into() {
36+
Ok(a) => a,
37+
Err(_) => "".into(),
38+
};
39+
// FIXME this is a false negative
40+
#[allow(clippy::cmp_owned)]
41+
if String::from("a") == TryInto::<String>::try_into(String::from("a")).unwrap() {}
42+
}
+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
error: useless conversion to the same type
2+
--> $DIR/useless_conversion_try.rs:6:13
3+
|
4+
LL | let _ = T::try_from(val).unwrap();
5+
| ^^^^^^^^^^^^^^^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/useless_conversion_try.rs:1:9
9+
|
10+
LL | #![deny(clippy::useless_conversion)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
= help: consider removing `T::try_from()`
13+
14+
error: useless conversion to the same type
15+
--> $DIR/useless_conversion_try.rs:7:5
16+
|
17+
LL | val.try_into().unwrap()
18+
| ^^^^^^^^^^^^^^
19+
|
20+
= help: consider removing `.try_into()`
21+
22+
error: useless conversion to the same type
23+
--> $DIR/useless_conversion_try.rs:29:21
24+
|
25+
LL | let _: String = "foo".to_string().try_into().unwrap();
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
27+
|
28+
= help: consider removing `.try_into()`
29+
30+
error: useless conversion to the same type
31+
--> $DIR/useless_conversion_try.rs:30:21
32+
|
33+
LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap();
34+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35+
|
36+
= help: consider removing `TryFrom::try_from()`
37+
38+
error: useless conversion to the same type
39+
--> $DIR/useless_conversion_try.rs:31:13
40+
|
41+
LL | let _ = String::try_from("foo".to_string()).unwrap();
42+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43+
|
44+
= help: consider removing `String::try_from()`
45+
46+
error: useless conversion to the same type
47+
--> $DIR/useless_conversion_try.rs:32:13
48+
|
49+
LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap();
50+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
51+
|
52+
= help: consider removing `String::try_from()`
53+
54+
error: useless conversion to the same type
55+
--> $DIR/useless_conversion_try.rs:33:21
56+
|
57+
LL | let _: String = format!("Hello {}", "world").try_into().unwrap();
58+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
59+
|
60+
= help: consider removing `.try_into()`
61+
62+
error: useless conversion to the same type
63+
--> $DIR/useless_conversion_try.rs:34:21
64+
|
65+
LL | let _: String = "".to_owned().try_into().unwrap();
66+
| ^^^^^^^^^^^^^^^^^^^^^^^^
67+
|
68+
= help: consider removing `.try_into()`
69+
70+
error: useless conversion to the same type
71+
--> $DIR/useless_conversion_try.rs:35:27
72+
|
73+
LL | let _: String = match String::from("_").try_into() {
74+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
75+
|
76+
= help: consider removing `.try_into()`
77+
78+
error: aborting due to 9 previous errors
79+

0 commit comments

Comments
 (0)