void Qt6QHashSignature::VisitStmt()

in src/checks/manuallevel/qt6-qhash-signature.cpp [87:181]


void Qt6QHashSignature::VisitStmt(clang::Stmt *stmt)
{
    auto *declRefExpr = dyn_cast<DeclRefExpr>(stmt);
    if (!declRefExpr) {
        return;
    }

    // checking if we're dealing with a qhash function
    std::string name = declRefExpr->getNameInfo().getAsString();
    if (!isInterestingFunction(name)) {
        return;
    }

    VarDecl *varDecl = m_context->lastDecl ? dyn_cast<VarDecl>(m_context->lastDecl) : nullptr;
    FieldDecl *fieldDecl = m_context->lastDecl ? dyn_cast<FieldDecl>(m_context->lastDecl) : nullptr;
    FunctionDecl *funcDecl = m_context->lastDecl ? dyn_cast<FunctionDecl>(m_context->lastFunctionDecl) : nullptr;

    if (!varDecl && !fieldDecl && !funcDecl) {
        return;
    }

    // need to check if this stmt is part of a return stmt, if it is, it's the lastFunctionDecl that is of interest
    // loop over the parent until I find a return statement.
    Stmt *parent = clazy::parent(m_context->parentMap, stmt);
    bool isPartReturnStmt = false;
    if (parent) {
        while (parent) {
            Stmt *ancester = clazy::parent(m_context->parentMap, parent);
            if (!ancester) {
                break;
            }
            auto *returnStmt = dyn_cast<ReturnStmt>(ancester);
            if (returnStmt) {
                isPartReturnStmt = true;
                break;
            }
            parent = ancester;
        }
    }

    // if the stmt is part of a return statement but there is no last functionDecl, it's a problem...
    if (isPartReturnStmt && !funcDecl) {
        return;
    }

    std::string message;
    std::string declType;
    SourceRange fixitRange;
    SourceLocation warningLocation;

    if (funcDecl && isPartReturnStmt) {
        // if the return correspond to a qHash function, we are not interested
        // the qHash function is taken care of during the VisitDecl
        if (isInterestingFunction(funcDecl->getNameAsString())) {
            return;
        }
        declType = funcDecl->getReturnType().getAsString();
        fixitRange = funcDecl->getReturnTypeSourceRange();
        warningLocation = funcDecl->getBeginLoc();
    } else if (varDecl) {
        declType = varDecl->getType().getAsString();
        fixitRange = varDecl->getTypeSourceInfo()->getTypeLoc().getSourceRange();
        warningLocation = varDecl->getBeginLoc();
    } else if (fieldDecl) {
        declType = fieldDecl->getType().getAsString();
        fixitRange = fieldDecl->getTypeSourceInfo()->getTypeLoc().getSourceRange();
        warningLocation = fieldDecl->getBeginLoc();
    }

    std::string qhashReturnType = declRefExpr->getDecl()->getAsFunction()->getReturnType().getAsString();
    if (declType == "size_t" && qhashReturnType == "size_t") {
        return;
    }

    std::vector<FixItHint> fixits;

    // if the type of the variable is correct, but the qHash is not returning the right type
    // just emit warning...
    if (declType == "size_t" && qhashReturnType != "size_t") {
        message = name + " should return size_t";
        emitWarning(declRefExpr->getBeginLoc(), message, fixits);
        return;
    }

    fixits.push_back(FixItHint::CreateReplacement(fixitRange, "size_t"));

    if (qhashReturnType != "size_t") {
        message = name + " should return size_t";
    } else {
        message = name + " returns size_t";
    }
    emitWarning(warningLocation, message, fixits);

    return;
}