mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-27 15:11:30 +00:00
Extend useless_conversion
lint with TryFrom
This commit is contained in:
parent
c41916d9bd
commit
4f8909fad9
5 changed files with 112 additions and 20 deletions
|
@ -1,13 +1,16 @@
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_sugg,
|
is_type_diagnostic_item, match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite,
|
||||||
|
span_lint_and_help, span_lint_and_sugg,
|
||||||
};
|
};
|
||||||
|
use if_chain::if_chain;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
|
use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
|
use rustc_middle::ty;
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// **What it does:** Checks for `Into`/`From`/`IntoIter` calls that useless converts
|
/// **What it does:** Checks for `Into`, `From`, `TryFrom`,`IntoIter` calls that useless converts
|
||||||
/// to the same type as caller.
|
/// to the same type as caller.
|
||||||
///
|
///
|
||||||
/// **Why is this bad?** Redundant code.
|
/// **Why is this bad?** Redundant code.
|
||||||
|
@ -26,7 +29,7 @@ declare_clippy_lint! {
|
||||||
/// ```
|
/// ```
|
||||||
pub USELESS_CONVERSION,
|
pub USELESS_CONVERSION,
|
||||||
complexity,
|
complexity,
|
||||||
"calls to `Into`/`From`/`IntoIter` that performs useless conversions to the same type"
|
"calls to `Into`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -68,7 +71,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion {
|
||||||
cx,
|
cx,
|
||||||
USELESS_CONVERSION,
|
USELESS_CONVERSION,
|
||||||
e.span,
|
e.span,
|
||||||
"useless conversion",
|
"Useless conversion to the same type",
|
||||||
"consider removing `.into()`",
|
"consider removing `.into()`",
|
||||||
sugg,
|
sugg,
|
||||||
Applicability::MachineApplicable, // snippet
|
Applicability::MachineApplicable, // snippet
|
||||||
|
@ -84,7 +87,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion {
|
||||||
cx,
|
cx,
|
||||||
USELESS_CONVERSION,
|
USELESS_CONVERSION,
|
||||||
e.span,
|
e.span,
|
||||||
"useless conversion",
|
"Useless conversion to the same type",
|
||||||
"consider removing `.into_iter()`",
|
"consider removing `.into_iter()`",
|
||||||
sugg,
|
sugg,
|
||||||
Applicability::MachineApplicable, // snippet
|
Applicability::MachineApplicable, // snippet
|
||||||
|
@ -94,11 +97,35 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion {
|
||||||
},
|
},
|
||||||
|
|
||||||
ExprKind::Call(ref path, ref args) => {
|
ExprKind::Call(ref path, ref args) => {
|
||||||
if let ExprKind::Path(ref qpath) = path.kind {
|
if_chain! {
|
||||||
if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id() {
|
if args.len() == 1;
|
||||||
|
if let ExprKind::Path(ref qpath) = path.kind;
|
||||||
|
if let Some(def_id) = cx.tables.qpath_res(qpath, path.hir_id).opt_def_id();
|
||||||
|
let a = cx.tables.expr_ty(e);
|
||||||
|
let b = cx.tables.expr_ty(&args[0]);
|
||||||
|
|
||||||
|
then {
|
||||||
|
if_chain! {
|
||||||
|
if match_def_path(cx, def_id, &paths::TRY_FROM);
|
||||||
|
if is_type_diagnostic_item(cx, a, sym!(result_type));
|
||||||
|
if let ty::Adt(_, substs) = a.kind;
|
||||||
|
if let Some(a_type) = substs.types().nth(0);
|
||||||
|
if same_tys(cx, a_type, b);
|
||||||
|
|
||||||
|
then {
|
||||||
|
let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from"));
|
||||||
|
span_lint_and_help(
|
||||||
|
cx,
|
||||||
|
USELESS_CONVERSION,
|
||||||
|
e.span,
|
||||||
|
"Useless conversion to the same type",
|
||||||
|
None,
|
||||||
|
&hint,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if match_def_path(cx, def_id, &paths::FROM_FROM) {
|
if match_def_path(cx, def_id, &paths::FROM_FROM) {
|
||||||
let a = cx.tables.expr_ty(e);
|
|
||||||
let b = cx.tables.expr_ty(&args[0]);
|
|
||||||
if same_tys(cx, a, b) {
|
if same_tys(cx, a, b) {
|
||||||
let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned();
|
let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned();
|
||||||
let sugg_msg =
|
let sugg_msg =
|
||||||
|
@ -107,7 +134,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion {
|
||||||
cx,
|
cx,
|
||||||
USELESS_CONVERSION,
|
USELESS_CONVERSION,
|
||||||
e.span,
|
e.span,
|
||||||
"useless conversion",
|
"Useless conversion to the same type",
|
||||||
&sugg_msg,
|
&sugg_msg,
|
||||||
sugg,
|
sugg,
|
||||||
Applicability::MachineApplicable, // snippet
|
Applicability::MachineApplicable, // snippet
|
||||||
|
|
|
@ -128,6 +128,7 @@ pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"
|
||||||
pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
|
pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
|
||||||
pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
|
pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
|
||||||
pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
|
pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
|
||||||
|
pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
|
||||||
pub const TRY_FROM_ERROR: [&str; 4] = ["std", "ops", "Try", "from_error"];
|
pub const TRY_FROM_ERROR: [&str; 4] = ["std", "ops", "Try", "from_error"];
|
||||||
pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"];
|
pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"];
|
||||||
pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
|
pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: useless conversion
|
error: Useless conversion to the same type
|
||||||
--> $DIR/useless_conversion.rs:6:13
|
--> $DIR/useless_conversion.rs:6:13
|
||||||
|
|
|
|
||||||
LL | let _ = T::from(val);
|
LL | let _ = T::from(val);
|
||||||
|
@ -10,55 +10,55 @@ note: the lint level is defined here
|
||||||
LL | #![deny(clippy::useless_conversion)]
|
LL | #![deny(clippy::useless_conversion)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: useless conversion
|
error: Useless conversion to the same type
|
||||||
--> $DIR/useless_conversion.rs:7:5
|
--> $DIR/useless_conversion.rs:7:5
|
||||||
|
|
|
|
||||||
LL | val.into()
|
LL | val.into()
|
||||||
| ^^^^^^^^^^ help: consider removing `.into()`: `val`
|
| ^^^^^^^^^^ help: consider removing `.into()`: `val`
|
||||||
|
|
||||||
error: useless conversion
|
error: Useless conversion to the same type
|
||||||
--> $DIR/useless_conversion.rs:19:22
|
--> $DIR/useless_conversion.rs:19:22
|
||||||
|
|
|
|
||||||
LL | let _: i32 = 0i32.into();
|
LL | let _: i32 = 0i32.into();
|
||||||
| ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
|
| ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
|
||||||
|
|
||||||
error: useless conversion
|
error: Useless conversion to the same type
|
||||||
--> $DIR/useless_conversion.rs:51:21
|
--> $DIR/useless_conversion.rs:51:21
|
||||||
|
|
|
|
||||||
LL | let _: String = "foo".to_string().into();
|
LL | let _: String = "foo".to_string().into();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
|
||||||
|
|
||||||
error: useless conversion
|
error: Useless conversion to the same type
|
||||||
--> $DIR/useless_conversion.rs:52:21
|
--> $DIR/useless_conversion.rs:52:21
|
||||||
|
|
|
|
||||||
LL | let _: String = From::from("foo".to_string());
|
LL | let _: String = From::from("foo".to_string());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
|
||||||
|
|
||||||
error: useless conversion
|
error: Useless conversion to the same type
|
||||||
--> $DIR/useless_conversion.rs:53:13
|
--> $DIR/useless_conversion.rs:53:13
|
||||||
|
|
|
|
||||||
LL | let _ = String::from("foo".to_string());
|
LL | let _ = String::from("foo".to_string());
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
|
||||||
|
|
||||||
error: useless conversion
|
error: Useless conversion to the same type
|
||||||
--> $DIR/useless_conversion.rs:54:13
|
--> $DIR/useless_conversion.rs:54:13
|
||||||
|
|
|
|
||||||
LL | let _ = String::from(format!("A: {:04}", 123));
|
LL | let _ = String::from(format!("A: {:04}", 123));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
|
||||||
|
|
||||||
error: useless conversion
|
error: Useless conversion to the same type
|
||||||
--> $DIR/useless_conversion.rs:55:13
|
--> $DIR/useless_conversion.rs:55:13
|
||||||
|
|
|
|
||||||
LL | let _ = "".lines().into_iter();
|
LL | let _ = "".lines().into_iter();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
|
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
|
||||||
|
|
||||||
error: useless conversion
|
error: Useless conversion to the same type
|
||||||
--> $DIR/useless_conversion.rs:56:13
|
--> $DIR/useless_conversion.rs:56:13
|
||||||
|
|
|
|
||||||
LL | let _ = vec![1, 2, 3].into_iter().into_iter();
|
LL | let _ = vec![1, 2, 3].into_iter().into_iter();
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
|
||||||
|
|
||||||
error: useless conversion
|
error: Useless conversion to the same type
|
||||||
--> $DIR/useless_conversion.rs:57:21
|
--> $DIR/useless_conversion.rs:57:21
|
||||||
|
|
|
|
||||||
LL | let _: String = format!("Hello {}", "world").into();
|
LL | let _: String = format!("Hello {}", "world").into();
|
||||||
|
|
25
tests/ui/useless_conversion_try.rs
Normal file
25
tests/ui/useless_conversion_try.rs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#![deny(clippy::useless_conversion)]
|
||||||
|
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
fn test_generic<T: Copy>(val: T) -> T {
|
||||||
|
T::try_from(val).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_generic2<T: Copy + Into<i32> + Into<U>, U: From<T>>(val: T) {
|
||||||
|
let _ = U::try_from(val).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
test_generic(10i32);
|
||||||
|
test_generic2::<i32, i32>(10i32);
|
||||||
|
|
||||||
|
let _: String = TryFrom::try_from("foo").unwrap();
|
||||||
|
let _ = String::try_from("foo").unwrap();
|
||||||
|
#[allow(clippy::useless_conversion)]
|
||||||
|
let _ = String::try_from("foo").unwrap();
|
||||||
|
|
||||||
|
let _: String = TryFrom::try_from("foo".to_string()).unwrap();
|
||||||
|
let _ = String::try_from("foo".to_string()).unwrap();
|
||||||
|
let _ = String::try_from(format!("A: {:04}", 123)).unwrap();
|
||||||
|
}
|
39
tests/ui/useless_conversion_try.stderr
Normal file
39
tests/ui/useless_conversion_try.stderr
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
error: Useless conversion to the same type
|
||||||
|
--> $DIR/useless_conversion_try.rs:6:5
|
||||||
|
|
|
||||||
|
LL | T::try_from(val).unwrap()
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/useless_conversion_try.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(clippy::useless_conversion)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= help: consider removing `T::try_from()`
|
||||||
|
|
||||||
|
error: Useless conversion to the same type
|
||||||
|
--> $DIR/useless_conversion_try.rs:22:21
|
||||||
|
|
|
||||||
|
LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider removing `TryFrom::try_from()`
|
||||||
|
|
||||||
|
error: Useless conversion to the same type
|
||||||
|
--> $DIR/useless_conversion_try.rs:23:13
|
||||||
|
|
|
||||||
|
LL | let _ = String::try_from("foo".to_string()).unwrap();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider removing `String::try_from()`
|
||||||
|
|
||||||
|
error: Useless conversion to the same type
|
||||||
|
--> $DIR/useless_conversion_try.rs:24:13
|
||||||
|
|
|
||||||
|
LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider removing `String::try_from()`
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
Loading…
Reference in a new issue