From 01b105725888cab56ef240331b7c32e88ce24121 Mon Sep 17 00:00:00 2001 From: Alessio Cosenza Date: Wed, 29 Mar 2023 00:49:43 +0200 Subject: [PATCH 1/5] Add redundant type annotations lint --- CHANGELOG.md | 1 + clippy_lints/src/declared_lints.rs | 1 + clippy_lints/src/lib.rs | 2 + .../src/redundant_type_annotations.rs | 185 ++++++++++++++++++ tests/ui/redundant_type_annotations.rs | 160 +++++++++++++++ tests/ui/redundant_type_annotations.stderr | 94 +++++++++ 6 files changed, 443 insertions(+) create mode 100644 clippy_lints/src/redundant_type_annotations.rs create mode 100644 tests/ui/redundant_type_annotations.rs create mode 100644 tests/ui/redundant_type_annotations.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 4648af231a41..a65ac4d46deb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5110,6 +5110,7 @@ Released 2018-09-13 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate [`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes +[`redundant_type_annotations`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_type_annotations [`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index 68272e1a77a8..d014534cee91 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -543,6 +543,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::redundant_slicing::DEREF_BY_SLICING_INFO, crate::redundant_slicing::REDUNDANT_SLICING_INFO, crate::redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES_INFO, + crate::redundant_type_annotations::REDUNDANT_TYPE_ANNOTATIONS_INFO, crate::ref_option_ref::REF_OPTION_REF_INFO, crate::ref_patterns::REF_PATTERNS_INFO, crate::reference::DEREF_ADDROF_INFO, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 222b0cc09214..d53c6de54514 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -267,6 +267,7 @@ mod redundant_field_names; mod redundant_pub_crate; mod redundant_slicing; mod redundant_static_lifetimes; +mod redundant_type_annotations; mod ref_option_ref; mod ref_patterns; mod reference; @@ -1012,6 +1013,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(needless_else::NeedlessElse)); store.register_late_pass(|_| Box::new(missing_fields_in_debug::MissingFieldsInDebug)); store.register_late_pass(|_| Box::new(endian_bytes::EndianBytes)); + store.register_late_pass(|_| Box::new(redundant_type_annotations::RedundantTypeAnnotations)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs new file mode 100644 index 000000000000..30d06a2cbc71 --- /dev/null +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -0,0 +1,185 @@ +use clippy_utils::diagnostics::span_lint; +use rustc_ast::LitKind; +use rustc_hir as hir; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Warns about needless / redundant type annotations. + /// + /// ### Why is this bad? + /// Code without type annotations is shorter and in most cases + /// more idiomatic and easier to modify. + /// + /// ### Example + /// ```rust + /// let foo: String = String::new(); + /// ``` + /// Use instead: + /// ```rust + /// let foo = String::new(); + /// ``` + #[clippy::version = "1.70.0"] + pub REDUNDANT_TYPE_ANNOTATIONS, + pedantic, + "warns about needless / redundant type annotations." +} +declare_lint_pass!(RedundantTypeAnnotations => [REDUNDANT_TYPE_ANNOTATIONS]); + +fn is_same_type<'tcx>(cx: &LateContext<'tcx>, ty_resolved_path: hir::def::Res, func_return_type: Ty<'tcx>) -> bool { + // type annotation is primitive + if let hir::def::Res::PrimTy(primty) = ty_resolved_path + && func_return_type.is_primitive() + && let Some(func_return_type_sym) = func_return_type.primitive_symbol() + { + return primty.name() == func_return_type_sym; + } + + // type annotation is any other non generic type + if let hir::def::Res::Def(_, defid) = ty_resolved_path + && let Some(annotation_ty) = cx.tcx.type_of(defid).no_bound_vars() + { + return annotation_ty == func_return_type; + } + + false +} + +fn func_hir_id_to_func_ty<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::hir_id::HirId) -> Option> { + if let Some((defkind, func_defid)) = cx.typeck_results().type_dependent_def(hir_id) + && defkind == hir::def::DefKind::AssocFn + && let Some(init_ty) = cx.tcx.type_of(func_defid).no_bound_vars() + { + Some(init_ty) + } else { + None + } +} + +fn func_ty_to_return_type<'tcx>(cx: &LateContext<'tcx>, func_ty: Ty<'tcx>) -> Option> { + if func_ty.is_fn() + && let Some(return_type) = func_ty.fn_sig(cx.tcx).output().no_bound_vars() + { + Some(return_type) + } else { + None + } +} + +/// Extracts the fn Ty, e.g. `fn() -> std::string::String {f}` +fn extract_fn_ty<'tcx>( + cx: &LateContext<'tcx>, + call: &hir::Expr<'tcx>, + func_return_path: &hir::QPath<'tcx>, +) -> Option> { + match func_return_path { + // let a: String = f(); where f: fn f() -> String + hir::QPath::Resolved(_, resolved_path) => { + if let hir::def::Res::Def(_, defid) = resolved_path.res + && let Some(middle_ty_init) = cx.tcx.type_of(defid).no_bound_vars() + { + Some(middle_ty_init) + } else { + None + } + }, + // Associated functions like + // let a: String = String::new(); + // let a: String = String::get_string(); + hir::QPath::TypeRelative(..) => func_hir_id_to_func_ty(cx, call.hir_id), + hir::QPath::LangItem(..) => None, + } +} + +fn is_redundant_in_func_call<'tcx>( + cx: &LateContext<'tcx>, + ty_resolved_path: hir::def::Res, + call: &hir::Expr<'tcx>, +) -> bool { + if let hir::ExprKind::Path(init_path) = &call.kind { + let func_type = extract_fn_ty(cx, call, init_path); + + if let Some(func_type) = func_type + && let Some(init_return_type) = func_ty_to_return_type(cx, func_type) + { + return is_same_type(cx, ty_resolved_path, init_return_type); + } + } + + false +} + +impl LateLintPass<'_> for RedundantTypeAnnotations { + fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::Local<'tcx>) { + // type annotation part + if !local.span.from_expansion() + && let Some(ty) = &local.ty + + // initialization part + && let Some(init) = local.init + { + match &init.kind { + // When the initialization is a call to a function + hir::ExprKind::Call(init_call, _) => { + if let hir::TyKind::Path(ty_path) = &ty.kind + && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path + + && is_redundant_in_func_call(cx, resolved_path_ty.res, init_call) { + span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); + } + }, + hir::ExprKind::MethodCall(_, _, _, _) => { + if let hir::TyKind::Path(ty_path) = &ty.kind + && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path + + && let Some(func_ty) = func_hir_id_to_func_ty(cx, init.hir_id) + && let Some(return_type) = func_ty_to_return_type(cx, func_ty) + && is_same_type(cx, resolved_path_ty.res, return_type) + { + span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); + } + }, + // When the initialization is a path for example u32::MAX + hir::ExprKind::Path(init_path) => { + // TODO: check for non primty + if let hir::TyKind::Path(ty_path) = &ty.kind + && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path + && let hir::def::Res::PrimTy(primty) = resolved_path_ty.res + + && let hir::QPath::TypeRelative(init_ty, _) = init_path + && let hir::TyKind::Path(init_ty_path) = &init_ty.kind + && let hir::QPath::Resolved(_, resolved_init_ty_path) = init_ty_path + && let hir::def::Res::PrimTy(primty_init) = resolved_init_ty_path.res + + && primty == primty_init + { + span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); + } + }, + hir::ExprKind::Lit(init_lit) => { + match init_lit.node { + // In these cases the annotation is redundant + LitKind::Str(..) + | LitKind::ByteStr(..) + | LitKind::Byte(..) + | LitKind::Char(..) + | LitKind::Bool(..) + | LitKind::CStr(..) => { + span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); + }, + LitKind::Int(..) | LitKind::Float(..) => { + // If the initialization value is a suffixed literal we lint + if init_lit.node.is_suffixed() { + span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); + } + }, + LitKind::Err => (), + } + } + _ => () + } + }; + } +} diff --git a/tests/ui/redundant_type_annotations.rs b/tests/ui/redundant_type_annotations.rs new file mode 100644 index 000000000000..5722621e83a1 --- /dev/null +++ b/tests/ui/redundant_type_annotations.rs @@ -0,0 +1,160 @@ +#![allow(unused)] +#![warn(clippy::redundant_type_annotations)] + +#[derive(Debug, Default)] +struct Cake { + _data: T, +} + +fn make_something() -> T { + T::default() +} + +fn make_cake() -> Cake { + Cake::::default() +} + +fn plus_one>(val: T) -> T { + val + 1 +} + +struct Pie { + inner: u32, +} + +enum Pizza { + One, + Two, +} + +fn return_a_string() -> String { + String::new() +} + +fn return_a_struct() -> Pie { + Pie { inner: 5 } +} + +fn return_an_enum() -> Pizza { + Pizza::One +} + +fn return_an_int() -> u32 { + 5 +} + +impl Pie { + fn return_an_int(&self) -> u32 { + self.inner + } + + fn associated_return_an_int() -> u32 { + 5 + } + + fn new() -> Self { + Self { inner: 5 } + } + + fn associated_return_a_string() -> String { + String::from("") + } + + fn test_method_call(&self) { + let v: u32 = self.return_an_int(); // Should lint + } +} + +fn test_generics() { + // The type annotation is needed to determine T + let _c: Cake = make_something(); + + // The type annotation is needed to determine the topic + let _c: Cake = make_cake(); + + // This should lint (doesn't) + let _c: Cake = make_cake::(); + + // This should lint (doesn't) + let _c: u8 = make_something::(); + + // This should lint (doesn't) + let _c: u8 = plus_one(5_u8); + + // Annotation needed otherwise T is i32 + let _c: u8 = plus_one(5); +} + +fn test_non_locals() { + // This shouldn't lint + fn _arg(x: u32) -> u32 { + x + } + + // This could lint, but probably shouldn't + let _closure_arg = |x: u32| x; +} + +fn test_complex_types() { + // Shouldn't lint, since the literal will be i32 otherwise + let _u8: u8 = 128; + + // Should lint (doesn't) + let _tuple_i32: (i32, i32) = (12, 13); + + // Shouldn't lint, since the tuple will be i32 otherwise + let _tuple_u32: (u32, u32) = (1, 2); + + // Should lint, since the type is determined by the init value (doesn't) + let _tuple_u32: (u32, u32) = (3_u32, 4_u32); + + // Should lint (doesn't) + let _array: [i32; 3] = [5, 6, 7]; + + // Shouldn't lint + let _array: [u32; 2] = [8, 9]; +} + +fn test_functions() { + // Everything here should lint + + let _return: String = return_a_string(); + + let _return: Pie = return_a_struct(); + + let _return: Pizza = return_an_enum(); + + let _return: u32 = return_an_int(); + + let _return: String = String::new(); + + let new_pie: Pie = Pie::new(); + + let _return: u32 = new_pie.return_an_int(); + + let _return: String = String::from("test"); + + let _return: u32 = Pie::associated_return_an_int(); + + let _return: String = Pie::associated_return_a_string(); +} + +fn test_simple_types() { + let _var: u32 = u32::MAX; + + // Should lint + let _var: u32 = 5_u32; + + // Should lint + let _var: &str = "test"; + + // Should lint + let _var: &[u8] = b"test"; + + // Should lint + let _var: bool = false; +} + +fn main() {} + +// TODO: test refs diff --git a/tests/ui/redundant_type_annotations.stderr b/tests/ui/redundant_type_annotations.stderr new file mode 100644 index 000000000000..3356f4808608 --- /dev/null +++ b/tests/ui/redundant_type_annotations.stderr @@ -0,0 +1,94 @@ +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:64:9 + | +LL | let v: u32 = self.return_an_int(); // Should lint + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::redundant-type-annotations` implied by `-D warnings` + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:121:5 + | +LL | let _return: String = return_a_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:123:5 + | +LL | let _return: Pie = return_a_struct(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:125:5 + | +LL | let _return: Pizza = return_an_enum(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:127:5 + | +LL | let _return: u32 = return_an_int(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:129:5 + | +LL | let _return: String = String::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:131:5 + | +LL | let new_pie: Pie = Pie::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:133:5 + | +LL | let _return: u32 = new_pie.return_an_int(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:137:5 + | +LL | let _return: u32 = Pie::associated_return_an_int(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:139:5 + | +LL | let _return: String = Pie::associated_return_a_string(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:143:5 + | +LL | let _var: u32 = u32::MAX; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:146:5 + | +LL | let _var: u32 = 5_u32; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:149:5 + | +LL | let _var: &str = "test"; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:152:5 + | +LL | let _var: &[u8] = b"test"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:155:5 + | +LL | let _var: bool = false; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 15 previous errors + From 6776608f21a14fdc9ca3751cdac6ade48b3f0346 Mon Sep 17 00:00:00 2001 From: Alessio Cosenza Date: Tue, 25 Apr 2023 00:28:17 +0200 Subject: [PATCH 2/5] Move `redundant_type_annotations` to restriction --- clippy_lints/src/redundant_type_annotations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs index 30d06a2cbc71..f277adfa94d0 100644 --- a/clippy_lints/src/redundant_type_annotations.rs +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -23,7 +23,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.70.0"] pub REDUNDANT_TYPE_ANNOTATIONS, - pedantic, + restriction, "warns about needless / redundant type annotations." } declare_lint_pass!(RedundantTypeAnnotations => [REDUNDANT_TYPE_ANNOTATIONS]); From 6f26df1c9a2ca1e4d161c49733c460fd32fddb02 Mon Sep 17 00:00:00 2001 From: Alessio Cosenza Date: Fri, 19 May 2023 17:45:49 +0200 Subject: [PATCH 3/5] Extract common logic to function --- .../src/redundant_type_annotations.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs index f277adfa94d0..da139cdde92e 100644 --- a/clippy_lints/src/redundant_type_annotations.rs +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -111,6 +111,17 @@ fn is_redundant_in_func_call<'tcx>( false } +fn extract_primty<'tcx>(ty_kind: &hir::TyKind<'tcx>) -> Option { + if let hir::TyKind::Path(ty_path) = ty_kind + && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path + && let hir::def::Res::PrimTy(primty) = resolved_path_ty.res + { + Some(primty) + } else { + None + } +} + impl LateLintPass<'_> for RedundantTypeAnnotations { fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::Local<'tcx>) { // type annotation part @@ -144,14 +155,10 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { // When the initialization is a path for example u32::MAX hir::ExprKind::Path(init_path) => { // TODO: check for non primty - if let hir::TyKind::Path(ty_path) = &ty.kind - && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path - && let hir::def::Res::PrimTy(primty) = resolved_path_ty.res + if let Some(primty) = extract_primty(&ty.kind) && let hir::QPath::TypeRelative(init_ty, _) = init_path - && let hir::TyKind::Path(init_ty_path) = &init_ty.kind - && let hir::QPath::Resolved(_, resolved_init_ty_path) = init_ty_path - && let hir::def::Res::PrimTy(primty_init) = resolved_init_ty_path.res + && let Some(primty_init) = extract_primty(&init_ty.kind) && primty == primty_init { From 29ab954a2b8e9b89215f5cd7159931d283818da6 Mon Sep 17 00:00:00 2001 From: Alessio Cosenza Date: Fri, 19 May 2023 17:46:32 +0200 Subject: [PATCH 4/5] Add support to returned refs from `MethodCall` --- .../src/redundant_type_annotations.rs | 26 +++++--- tests/ui/redundant_type_annotations.rs | 60 ++++++++++++------- tests/ui/redundant_type_annotations.stderr | 46 ++++++++------ 3 files changed, 85 insertions(+), 47 deletions(-) diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs index da139cdde92e..18647891ac6b 100644 --- a/clippy_lints/src/redundant_type_annotations.rs +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -59,10 +59,8 @@ fn func_hir_id_to_func_ty<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::hir_id::Hir } fn func_ty_to_return_type<'tcx>(cx: &LateContext<'tcx>, func_ty: Ty<'tcx>) -> Option> { - if func_ty.is_fn() - && let Some(return_type) = func_ty.fn_sig(cx.tcx).output().no_bound_vars() - { - Some(return_type) + if func_ty.is_fn() { + Some(func_ty.fn_sig(cx.tcx).output().skip_binder()) } else { None } @@ -111,7 +109,7 @@ fn is_redundant_in_func_call<'tcx>( false } -fn extract_primty<'tcx>(ty_kind: &hir::TyKind<'tcx>) -> Option { +fn extract_primty(ty_kind: &hir::TyKind<'_>) -> Option { if let hir::TyKind::Path(ty_path) = ty_kind && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path && let hir::def::Res::PrimTy(primty) = resolved_path_ty.res @@ -142,12 +140,24 @@ impl LateLintPass<'_> for RedundantTypeAnnotations { } }, hir::ExprKind::MethodCall(_, _, _, _) => { - if let hir::TyKind::Path(ty_path) = &ty.kind - && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path + let mut is_ref = false; + let mut ty_kind = &ty.kind; + // If the annotation is a ref we "peel" it + if let hir::TyKind::Ref(_, mut_ty) = &ty.kind { + is_ref = true; + ty_kind = &mut_ty.ty.kind; + } + + if let hir::TyKind::Path(ty_path) = ty_kind + && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path && let Some(func_ty) = func_hir_id_to_func_ty(cx, init.hir_id) && let Some(return_type) = func_ty_to_return_type(cx, func_ty) - && is_same_type(cx, resolved_path_ty.res, return_type) + && is_same_type(cx, resolved_path_ty.res, if is_ref { + return_type.peel_refs() + } else { + return_type + }) { span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation"); } diff --git a/tests/ui/redundant_type_annotations.rs b/tests/ui/redundant_type_annotations.rs index 5722621e83a1..cc507b8d658c 100644 --- a/tests/ui/redundant_type_annotations.rs +++ b/tests/ui/redundant_type_annotations.rs @@ -18,8 +18,15 @@ fn plus_one>(val: T) -> T { val + 1 } +#[derive(Default)] +struct Slice { + inner: u32, +} + +#[derive(Default)] struct Pie { inner: u32, + inner_struct: Slice, } enum Pizza { @@ -32,7 +39,7 @@ fn return_a_string() -> String { } fn return_a_struct() -> Pie { - Pie { inner: 5 } + Pie::default() } fn return_an_enum() -> Pizza { @@ -48,12 +55,20 @@ impl Pie { self.inner } + fn return_a_ref(&self) -> &u32 { + &self.inner + } + + fn return_a_ref_to_struct(&self) -> &Slice { + &self.inner_struct + } + fn associated_return_an_int() -> u32 { 5 } fn new() -> Self { - Self { inner: 5 } + Self::default() } fn associated_return_a_string() -> String { @@ -61,7 +76,11 @@ impl Pie { } fn test_method_call(&self) { - let v: u32 = self.return_an_int(); // Should lint + // Everything here should be lint + + let v: u32 = self.return_an_int(); + let v: &u32 = self.return_a_ref(); + let v: &Slice = self.return_a_ref_to_struct(); } } @@ -72,21 +91,24 @@ fn test_generics() { // The type annotation is needed to determine the topic let _c: Cake = make_cake(); - // This should lint (doesn't) + // This could be lint, but currently doesn't let _c: Cake = make_cake::(); - // This should lint (doesn't) + // This could be lint, but currently doesn't let _c: u8 = make_something::(); - // This should lint (doesn't) + // This could be lint, but currently doesn't let _c: u8 = plus_one(5_u8); // Annotation needed otherwise T is i32 let _c: u8 = plus_one(5); + + // This could be lint, but currently doesn't + let _return: String = String::from("test"); } fn test_non_locals() { - // This shouldn't lint + // This shouldn't be lint fn _arg(x: u32) -> u32 { x } @@ -96,27 +118,27 @@ fn test_non_locals() { } fn test_complex_types() { - // Shouldn't lint, since the literal will be i32 otherwise + // Shouldn't be lint, since the literal will be i32 otherwise let _u8: u8 = 128; - // Should lint (doesn't) + // This could be lint, but currently doesn't let _tuple_i32: (i32, i32) = (12, 13); - // Shouldn't lint, since the tuple will be i32 otherwise + // Shouldn't be lint, since the tuple will be i32 otherwise let _tuple_u32: (u32, u32) = (1, 2); - // Should lint, since the type is determined by the init value (doesn't) + // Should be lint, since the type is determined by the init value, but currently doesn't let _tuple_u32: (u32, u32) = (3_u32, 4_u32); - // Should lint (doesn't) + // This could be lint, but currently doesn't let _array: [i32; 3] = [5, 6, 7]; - // Shouldn't lint + // Shouldn't be lint let _array: [u32; 2] = [8, 9]; } fn test_functions() { - // Everything here should lint + // Everything here should be lint let _return: String = return_a_string(); @@ -132,29 +154,23 @@ fn test_functions() { let _return: u32 = new_pie.return_an_int(); - let _return: String = String::from("test"); - let _return: u32 = Pie::associated_return_an_int(); let _return: String = Pie::associated_return_a_string(); } fn test_simple_types() { + // Everything here should be lint + let _var: u32 = u32::MAX; - // Should lint let _var: u32 = 5_u32; - // Should lint let _var: &str = "test"; - // Should lint let _var: &[u8] = b"test"; - // Should lint let _var: bool = false; } fn main() {} - -// TODO: test refs diff --git a/tests/ui/redundant_type_annotations.stderr b/tests/ui/redundant_type_annotations.stderr index 3356f4808608..e8b2fe5c3847 100644 --- a/tests/ui/redundant_type_annotations.stderr +++ b/tests/ui/redundant_type_annotations.stderr @@ -1,94 +1,106 @@ error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:64:9 + --> $DIR/redundant_type_annotations.rs:81:9 | -LL | let v: u32 = self.return_an_int(); // Should lint +LL | let v: u32 = self.return_an_int(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::redundant-type-annotations` implied by `-D warnings` error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:121:5 + --> $DIR/redundant_type_annotations.rs:82:9 + | +LL | let v: &u32 = self.return_a_ref(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:83:9 + | +LL | let v: &Slice = self.return_a_ref_to_struct(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: redundant type annotation + --> $DIR/redundant_type_annotations.rs:143:5 | LL | let _return: String = return_a_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:123:5 + --> $DIR/redundant_type_annotations.rs:145:5 | LL | let _return: Pie = return_a_struct(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:125:5 + --> $DIR/redundant_type_annotations.rs:147:5 | LL | let _return: Pizza = return_an_enum(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:127:5 + --> $DIR/redundant_type_annotations.rs:149:5 | LL | let _return: u32 = return_an_int(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:129:5 + --> $DIR/redundant_type_annotations.rs:151:5 | LL | let _return: String = String::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:131:5 + --> $DIR/redundant_type_annotations.rs:153:5 | LL | let new_pie: Pie = Pie::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:133:5 + --> $DIR/redundant_type_annotations.rs:155:5 | LL | let _return: u32 = new_pie.return_an_int(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:137:5 + --> $DIR/redundant_type_annotations.rs:157:5 | LL | let _return: u32 = Pie::associated_return_an_int(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:139:5 + --> $DIR/redundant_type_annotations.rs:159:5 | LL | let _return: String = Pie::associated_return_a_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:143:5 + --> $DIR/redundant_type_annotations.rs:165:5 | LL | let _var: u32 = u32::MAX; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:146:5 + --> $DIR/redundant_type_annotations.rs:167:5 | LL | let _var: u32 = 5_u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:149:5 + --> $DIR/redundant_type_annotations.rs:169:5 | LL | let _var: &str = "test"; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:152:5 + --> $DIR/redundant_type_annotations.rs:171:5 | LL | let _var: &[u8] = b"test"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> $DIR/redundant_type_annotations.rs:155:5 + --> $DIR/redundant_type_annotations.rs:173:5 | LL | let _var: bool = false; | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors From a9b468f2b51a251d0d718059299d0ccd0e561389 Mon Sep 17 00:00:00 2001 From: Alessio Cosenza Date: Mon, 29 May 2023 11:24:36 +0200 Subject: [PATCH 5/5] Add `Limitations` section --- clippy_lints/src/redundant_type_annotations.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs index 18647891ac6b..8e9234bba3c8 100644 --- a/clippy_lints/src/redundant_type_annotations.rs +++ b/clippy_lints/src/redundant_type_annotations.rs @@ -13,6 +13,14 @@ declare_clippy_lint! { /// Code without type annotations is shorter and in most cases /// more idiomatic and easier to modify. /// + /// ### Limitations + /// This lint doesn't support: + /// + /// - Generics + /// - Refs returned from anything else than a `MethodCall` + /// - Complex types (tuples, arrays, etc...) + /// - `Path` to anything else than a primitive type. + /// /// ### Example /// ```rust /// let foo: String = String::new();