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);
}