void QStringAllocations::VisitFromLatin1OrUtf8()

in src/checks/level2/qstring-allocations.cpp [644:700]


void QStringAllocations::VisitFromLatin1OrUtf8(Stmt *stmt)
{
    auto *callExpr = dyn_cast<CallExpr>(stmt);
    if (!callExpr) {
        return;
    }

    FunctionDecl *functionDecl = callExpr->getDirectCallee();
    if (!clazy::functionIsOneOf(functionDecl, {"fromLatin1", "fromUtf8"})) {
        return;
    }

    auto *methodDecl = dyn_cast<CXXMethodDecl>(functionDecl);
    if (!clazy::isOfClass(methodDecl, "QString")) {
        return;
    }

    bool isKnownLiteralOverload = false;
    for (auto e : Utils::functionParameters(functionDecl)) {
        if (e->getType().getAsString(lo()) == "QByteArrayView") {
            isKnownLiteralOverload = true;
        }
    }
    if (!isKnownLiteralOverload && (!Utils::callHasDefaultArguments(callExpr) || !hasCharPtrArgument(functionDecl, 2))) { // QString::fromLatin1("foo", 1) is ok
        return;
    }
    if (!containsStringLiteralNoCallExpr(callExpr)) {
        return;
    }

    if (!isOptionSet("no-msvc-compat")) {
        StringLiteral *lt = stringLiteralForCall(callExpr);
        if (lt && lt->getNumConcatenated() > 1) {
            return; // Nothing to do here, MSVC doesn't like it
        }
    }

    std::vector<ConditionalOperator *> ternaries;
    clazy::getChilds(callExpr, ternaries); // In Qt5 it is always 2 levels down, but in Qt6 more
    if (!ternaries.empty()) {
        auto *ternary = ternaries[0];
        if (Utils::ternaryOperatorIsOfStringLiteral(ternary)) {
            maybeEmitWarning(stmt->getBeginLoc(), std::string("QString::fromLatin1() being passed a literal"));
        }

        return;
    }

    const FromFunction fromFunction = clazy::name(functionDecl) == "fromLatin1" ? FromLatin1 : FromUtf8;
    const std::vector<FixItHint> fixits = fixItReplaceFromLatin1OrFromUtf8(callExpr, fromFunction);

    if (clazy::name(functionDecl) == "fromLatin1") {
        maybeEmitWarning(stmt->getBeginLoc(), std::string("QString::fromLatin1() being passed a literal"), fixits);
    } else {
        maybeEmitWarning(stmt->getBeginLoc(), std::string("QString::fromUtf8() being passed a literal"), fixits);
    }
}