]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/len_zero.rs
Auto merge of #9873 - smoelius:move-line-span, r=flip1995
[rust.git] / clippy_lints / src / len_zero.rs
index 530b0a90ebd8a8245fb129d1317dd06f64cd71fd..76b0c21327c870a296583c12e18d33bc294ce021 100644 (file)
@@ -10,7 +10,7 @@
     ItemKind, Mutability, Node, TraitItemRef, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, AssocKind, FnSig, Ty, TyS};
+use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{
     source_map::{Span, Spanned, Symbol},
@@ -134,7 +134,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>)
             if item.ident.name == sym::len;
             if let ImplItemKind::Fn(sig, _) = &item.kind;
             if sig.decl.implicit_self.has_implicit_self();
-            if cx.access_levels.is_exported(item.def_id);
+            if cx.access_levels.is_exported(item.def_id.def_id);
             if matches!(sig.decl.output, FnRetTy::Return(_));
             if let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id());
             if imp.of_trait.is_none();
@@ -210,7 +210,8 @@ fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) {
         }
     }
 
-    if cx.access_levels.is_exported(visited_trait.def_id) && trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
+    if cx.access_levels.is_exported(visited_trait.def_id.def_id)
+        && trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
     {
         let mut current_and_super_traits = DefIdSet::default();
         fill_trait_set(visited_trait.def_id.to_def_id(), &mut current_and_super_traits, cx);
@@ -248,24 +249,24 @@ enum LenOutput<'tcx> {
 fn parse_len_output<'tcx>(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option<LenOutput<'tcx>> {
     match *sig.output().kind() {
         ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral),
-        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did) => {
-            subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did))
+        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) => {
+            subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did()))
         },
-        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Result, adt.did) => subs
+        ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) => subs
             .type_at(0)
             .is_integral()
-            .then(|| LenOutput::Result(adt.did, subs.type_at(1))),
+            .then(|| LenOutput::Result(adt.did(), subs.type_at(1))),
         _ => None,
     }
 }
 
-impl LenOutput<'_> {
-    fn matches_is_empty_output(self, ty: Ty<'_>) -> bool {
+impl<'tcx> LenOutput<'tcx> {
+    fn matches_is_empty_output(self, ty: Ty<'tcx>) -> bool {
         match (self, ty.kind()) {
             (_, &ty::Bool) => true,
-            (Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did => subs.type_at(0).is_bool(),
-            (Self::Result(id, err_ty), &ty::Adt(adt, subs)) if id == adt.did => {
-                subs.type_at(0).is_bool() && TyS::same_type(subs.type_at(1), err_ty)
+            (Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(),
+            (Self::Result(id, err_ty), &ty::Adt(adt, subs)) if id == adt.did() => {
+                subs.type_at(0).is_bool() && subs.type_at(1) == err_ty
             },
             _ => false,
         }
@@ -278,23 +279,21 @@ fn expected_sig(self, self_kind: ImplicitSelfKind) -> String {
             _ => "",
         };
         match self {
-            Self::Integral => format!("expected signature: `({}self) -> bool`", self_ref),
-            Self::Option(_) => format!(
-                "expected signature: `({}self) -> bool` or `({}self) -> Option<bool>",
-                self_ref, self_ref
-            ),
-            Self::Result(..) => format!(
-                "expected signature: `({}self) -> bool` or `({}self) -> Result<bool>",
-                self_ref, self_ref
-            ),
+            Self::Integral => format!("expected signature: `({self_ref}self) -> bool`"),
+            Self::Option(_) => {
+                format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Option<bool>")
+            },
+            Self::Result(..) => {
+                format!("expected signature: `({self_ref}self) -> bool` or `({self_ref}self) -> Result<bool>")
+            },
         }
     }
 }
 
 /// Checks if the given signature matches the expectations for `is_empty`
-fn check_is_empty_sig(sig: FnSig<'_>, self_kind: ImplicitSelfKind, len_output: LenOutput<'_>) -> bool {
+fn check_is_empty_sig<'tcx>(sig: FnSig<'tcx>, self_kind: ImplicitSelfKind, len_output: LenOutput<'tcx>) -> bool {
     match &**sig.inputs_and_output {
-        [arg, res] if len_output.matches_is_empty_output(res) => {
+        [arg, res] if len_output.matches_is_empty_output(*res) => {
             matches!(
                 (arg.kind(), self_kind),
                 (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::ImmRef)
@@ -306,11 +305,11 @@ fn check_is_empty_sig(sig: FnSig<'_>, self_kind: ImplicitSelfKind, len_output: L
 }
 
 /// Checks if the given type has an `is_empty` method with the appropriate signature.
-fn check_for_is_empty(
-    cx: &LateContext<'_>,
+fn check_for_is_empty<'tcx>(
+    cx: &LateContext<'tcx>,
     span: Span,
     self_kind: ImplicitSelfKind,
-    output: LenOutput<'_>,
+    output: LenOutput<'tcx>,
     impl_ty: DefId,
     item_name: Symbol,
     item_kind: &str,
@@ -326,8 +325,7 @@ fn check_for_is_empty(
     let (msg, is_empty_span, self_kind) = match is_empty {
         None => (
             format!(
-                "{} `{}` has a public `len` method, but no `is_empty` method",
-                item_kind,
+                "{item_kind} `{}` has a public `len` method, but no `is_empty` method",
                 item_name.as_str(),
             ),
             None,
@@ -335,8 +333,7 @@ fn check_for_is_empty(
         ),
         Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => (
             format!(
-                "{} `{}` has a public `len` method, but a private `is_empty` method",
-                item_kind,
+                "{item_kind} `{}` has a public `len` method, but a private `is_empty` method",
                 item_name.as_str(),
             ),
             Some(cx.tcx.def_span(is_empty.def_id)),
@@ -348,8 +345,7 @@ fn check_for_is_empty(
         {
             (
                 format!(
-                    "{} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature",
-                    item_kind,
+                    "{item_kind} `{}` has a public `len` method, but the `is_empty` method has an unexpected signature",
                     item_name.as_str(),
                 ),
                 Some(cx.tcx.def_span(is_empty.def_id)),
@@ -370,7 +366,7 @@ fn check_for_is_empty(
 }
 
 fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
-    if let (&ExprKind::MethodCall(method_path, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
+    if let (&ExprKind::MethodCall(method_path, receiver, args, _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) {
         // check if we are in an is_empty() method
         if let Some(name) = get_item_name(cx, method) {
             if name.as_str() == "is_empty" {
@@ -378,16 +374,28 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
             }
         }
 
-        check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to);
+        check_len(
+            cx,
+            span,
+            method_path.ident.name,
+            receiver,
+            args,
+            &lit.node,
+            op,
+            compare_to,
+        );
     } else {
         check_empty_expr(cx, span, method, lit, op);
     }
 }
 
+// FIXME(flip1995): Figure out how to reduce the number of arguments
+#[allow(clippy::too_many_arguments)]
 fn check_len(
     cx: &LateContext<'_>,
     span: Span,
     method_name: Symbol,
+    receiver: &Expr<'_>,
     args: &[Expr<'_>],
     lit: &LitKind,
     op: &str,
@@ -399,18 +407,17 @@ fn check_len(
             return;
         }
 
-        if method_name == sym::len && args.len() == 1 && has_is_empty(cx, &args[0]) {
+        if method_name == sym::len && args.is_empty() && has_is_empty(cx, receiver) {
             let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
                 cx,
                 LEN_ZERO,
                 span,
                 &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
-                &format!("using `{}is_empty` is clearer and more explicit", op),
+                &format!("using `{op}is_empty` is clearer and more explicit"),
                 format!(
-                    "{}{}.is_empty()",
-                    op,
-                    snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
+                    "{op}{}.is_empty()",
+                    snippet_with_applicability(cx, receiver.span, "_", &mut applicability)
                 ),
                 applicability,
             );
@@ -426,10 +433,9 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex
             COMPARISON_TO_EMPTY,
             span,
             "comparison to empty slice",
-            &format!("using `{}is_empty` is clearer and more explicit", op),
+            &format!("using `{op}is_empty` is clearer and more explicit"),
             format!(
-                "{}{}.is_empty()",
-                op,
+                "{op}{}.is_empty()",
                 snippet_with_applicability(cx, lit1.span, "_", &mut applicability)
             ),
             applicability,
@@ -488,7 +494,7 @@ fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
                 .any(|item| is_is_empty(cx, item))
         }),
         ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
-        ty::Adt(id, _) => has_is_empty_impl(cx, id.did),
+        ty::Adt(id, _) => has_is_empty_impl(cx, id.did()),
         ty::Array(..) | ty::Slice(..) | ty::Str => true,
         _ => false,
     }