void QStringAllocations::VisitOperatorCall()

in src/checks/level2/qstring-allocations.cpp [577:642]


void QStringAllocations::VisitOperatorCall(Stmt *stm)
{
    auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(stm);
    if (!operatorCall) {
        return;
    }

    if (clazy::returnTypeName(operatorCall, lo()) == "QTestData") {
        // QTest::newRow will static_assert when using QLatin1String
        // Q_STATIC_ASSERT_X(QMetaTypeId2<T>::Defined, "Type is not registered, please use the Q_DECLARE_METATYPE macro to make it known to Qt's meta-object
        // system");
        return;
    }

    std::vector<StringLiteral *> stringLiterals;
    clazy::getChilds<StringLiteral>(operatorCall, stringLiterals);

    //  We're only after string literals, str.contains(some_method_returning_const_char_is_fine())
    if (stringLiterals.empty()) {
        return;
    }

    FunctionDecl *funcDecl = operatorCall->getDirectCallee();
    if (!funcDecl) {
        return;
    }

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

    // For Qt6.8, we have the operators in the QString class deprecated and have defined them using macros
    // Meaning we only have a function and /not/ a method
    if (!methodDecl && funcDecl->isThisDeclarationADefinition() && funcDecl->getBeginLoc().isValid()) {
        StringRef fileName = sm().getFilename(sm().getExpansionLoc(funcDecl->getBeginLoc()));
        if (!fileName.contains("qstring.h")) {
            return;
        }
    }

    if (!hasCharPtrArgument(funcDecl)) {
        return;
    }

    std::vector<FixItHint> fixits;

    std::vector<StringLiteral *> literals;
    clazy::getChilds<StringLiteral>(stm, literals, 3);

    if (!isOptionSet("no-msvc-compat") && !literals.empty()) {
        if (literals[0]->getNumConcatenated() > 1) {
            return; // Nothing to do here, MSVC doesn't like it
        }
    }

    if (literals.empty()) {
        queueManualFixitWarning(stm->getBeginLoc(), "Couldn't find literal");
    } else {
        const std::string replacement = Utils::isAscii(literals[0]) ? "QLatin1String" : "QStringLiteral";
        fixits = fixItRawLiteral(literals[0], replacement, operatorCall);
    }

    std::string msg("QString(const char*) being called");
    maybeEmitWarning(stm->getBeginLoc(), msg, fixits);
}