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();
}
}
- 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);
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 => {
+ (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,
_ => "",
};
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)
}
/// 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,
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,
),
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)),
{
(
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)),
}
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" {
}
}
- 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,
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,
);
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,
.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,
}