bool UnneededCast::handleNamedCast()

in src/checks/manuallevel/unneeded-cast.cpp [84:130]


bool UnneededCast::handleNamedCast(CXXNamedCastExpr *namedCast)
{
    if (!namedCast) {
        return false;
    }

    const bool isDynamicCast = isa<CXXDynamicCastExpr>(namedCast);
    const bool isStaticCast = isDynamicCast ? false : isa<CXXStaticCastExpr>(namedCast);

    if (!isDynamicCast && !isStaticCast) {
        return false;
    }

    if (namedCast->getBeginLoc().isMacroID()) {
        return false;
    }

    CXXRecordDecl *castFrom = namedCast ? Utils::namedCastInnerDecl(namedCast) : nullptr;
    if (!castFrom || !castFrom->hasDefinition() || std::distance(castFrom->bases_begin(), castFrom->bases_end()) > 1) {
        return false;
    }

    if (isStaticCast) {
        if (auto *implicitCast = dyn_cast<ImplicitCastExpr>(namedCast->getSubExpr())) {
            if (implicitCast->getCastKind() == CK_NullToPointer) {
                // static_cast<Foo*>(0) is OK, and sometimes needed
                return false;
            }
        }

        // static_cast to base is needed in ternary operators
        if (clazy::getFirstParentOfType<ConditionalOperator>(m_context->parentMap, namedCast) != nullptr) {
            return false;
        }
    }

    if (isDynamicCast && !isOptionSet("prefer-dynamic-cast-over-qobject") && clazy::isQObject(castFrom)) {
        emitWarning(namedCast->getBeginLoc(), "Use qobject_cast rather than dynamic_cast");
    }

    CXXRecordDecl *castTo = Utils::namedCastOuterDecl(namedCast);
    if (!castTo) {
        return false;
    }

    return maybeWarn(namedCast, castFrom, castTo);
}