fn check_impl_dupe()

in gazebo_lint/src/lib.rs [423:478]


fn check_impl_dupe(cx: &LateContext, item: &Item) {
    fn is_cheap<'tcx>(
        cx: &LateContext<'tcx>,
        self_tys: rustc_middle::ty::Ty<'tcx>,
        dupe_trait: DefId,
    ) -> bool {
        match self_tys.kind() {
            TyKind::Adt(self_adt, sub) => {
                for variant in self_adt.variants.iter() {
                    let mut fields = variant.fields.iter();
                    if let Some(field) = fields.next() {
                        if fields.next().is_some() {
                            // only adt's of one field at most one field can be assumed dupe
                            // we don't want to mark a struct of 100 Arc's as dupe.
                            return false;
                        }
                        let field_ty = field.ty(cx.tcx, sub);

                        if !clippy::implements_trait(cx, field_ty, dupe_trait, sub) {
                            // the field isn't dupe, so the whole adt isn't
                            return false;
                        }
                    }
                    // empty fields => unit, which is dupe
                }

                // if we survived the loop, we can be dupe.
                true
            }
            _ => false,
        }
    }

    fn is_copy<'tcx>(cx: &LateContext<'tcx>, self_tys: rustc_middle::ty::Ty<'tcx>) -> bool {
        if let Some(copy_trait) = clippy::get_trait_def_id(cx, &["core", "marker", "Copy"]) {
            clippy::implements_trait(cx, self_tys, copy_trait, &[])
        } else {
            false
        }
    }

    if let Some(dupe_trait) = clippy::get_trait_def_id(cx, &["gazebo", "dupe", "Dupe"]) {
        if let Some(self_tys) =
            clippy::is_implementation_of_trait(cx, item, &["core", "clone", "Clone"])
        {
            if clippy::implements_trait(cx, self_tys, dupe_trait, &[]) {
                // already dupe
                return;
            }

            if is_copy(cx, self_tys) || is_cheap(cx, self_tys, dupe_trait) {
                emit_lint(cx, GAZEBO_LINT_IMPL_DUPE, item.span);
            }
        }
    }
}