in src/checks/level2/qstring-allocations.cpp [210:336]
void QStringAllocations::VisitCtor(CXXConstructExpr *ctorExpr)
{
CXXConstructorDecl *ctorDecl = ctorExpr->getConstructor();
if (!clazy::isOfClass(ctorDecl, "QString")) {
return;
}
if (Utils::insideCTORCall(m_context->parentMap, ctorExpr, {"QRegExp", "QIcon"})) {
// https://blogs.kde.org/2015/11/05/qregexp-qstringliteral-crash-exit
return;
}
if (!isOptionSet("no-msvc-compat")) {
auto *initializerList = clazy::getFirstParentOfType<InitListExpr>(m_context->parentMap, ctorExpr);
if (initializerList != nullptr) {
return; // Nothing to do here, MSVC doesn't like it
}
StringLiteral *lt = stringLiteralForCall(ctorExpr);
if (lt && lt->getNumConcatenated() > 1) {
return; // Nothing to do here, MSVC doesn't like it
}
}
bool isQLatin1String = false;
std::string paramType;
if (hasCharPtrArgument(ctorDecl, 1)) {
paramType = "const char*";
} else if (ctorDecl->param_size() == 1
&& (clazy::hasArgumentOfType(ctorDecl, "QLatin1String", lo()) || clazy::hasArgumentOfType(ctorDecl, "QLatin1StringView", lo()))) {
paramType = "QLatin1String";
isQLatin1String = true;
} else {
return;
}
std::string msg = std::string("QString(") + paramType + std::string(") being called");
if (isQLatin1String) {
ConditionalOperator *ternary = nullptr;
Latin1Expr qlatin1expr = qlatin1CtorExpr(ctorExpr, ternary);
if (!qlatin1expr.isValid()) {
return;
}
auto *qlatin1Ctor = qlatin1expr.qlatin1ctorexpr;
if (qlatin1Ctor->getBeginLoc().isMacroID()) {
auto macroName = Lexer::getImmediateMacroName(qlatin1Ctor->getBeginLoc(), sm(), lo());
if (macroName == "Q_GLOBAL_STATIC_WITH_ARGS") { // bug #391807
return;
}
}
std::vector<FixItHint> fixits;
if (qlatin1expr.enableFixit) {
if (!qlatin1Ctor->getBeginLoc().isMacroID()) {
if (!ternary) {
fixits = fixItReplaceWordWithWord(qlatin1Ctor, "QStringLiteral", "QLatin1String");
bool shouldRemoveQString = qlatin1Ctor->getBeginLoc().getRawEncoding() != ctorExpr->getBeginLoc().getRawEncoding()
&& dyn_cast_or_null<CXXBindTemporaryExpr>(clazy::parent(m_context->parentMap, ctorExpr));
if (shouldRemoveQString) {
// This is the case of QString(QLatin1String("foo")), which we just fixed to be QString(QStringLiteral("foo")), so now remove QString
auto removalFixits = clazy::fixItRemoveToken(&m_astContext, ctorExpr, true);
if (removalFixits.empty()) {
queueManualFixitWarning(ctorExpr->getBeginLoc(), "Internal error: invalid start or end location");
} else {
clazy::append(removalFixits, fixits);
}
}
} else {
fixits = fixItReplaceWordWithWordInTernary(ternary);
}
} else {
queueManualFixitWarning(qlatin1Ctor->getBeginLoc(), "Can't use QStringLiteral in macro");
}
}
maybeEmitWarning(ctorExpr->getBeginLoc(), msg, fixits);
} else {
std::vector<FixItHint> fixits;
if (clazy::hasChildren(ctorExpr)) {
auto *pointerDecay = dyn_cast<ImplicitCastExpr>(*(ctorExpr->child_begin()));
if (clazy::hasChildren(pointerDecay)) {
auto *lt = dyn_cast<StringLiteral>(*pointerDecay->child_begin());
if (lt) {
Stmt *grandParent = clazy::parent(m_context->parentMap, lt, 2);
Stmt *grandGrandParent = clazy::parent(m_context->parentMap, lt, 3);
Stmt *grandGrandGrandParent = clazy::parent(m_context->parentMap, lt, 4);
if (grandParent == ctorExpr && grandGrandParent && isa<CXXBindTemporaryExpr>(grandGrandParent) && grandGrandGrandParent
&& isa<CXXFunctionalCastExpr>(grandGrandGrandParent)) {
// This is the case of QString("foo"), replace QString
const bool literalIsEmpty = lt->getLength() == 0;
if (literalIsEmpty && clazy::getFirstParentOfType<MemberExpr>(m_context->parentMap, ctorExpr) == nullptr) {
fixits = fixItReplaceWordWithWord(ctorExpr, "QLatin1String", "QString");
} else if (!ctorExpr->getBeginLoc().isMacroID()) {
fixits = fixItReplaceWordWithWord(ctorExpr, "QStringLiteral", "QString");
} else {
queueManualFixitWarning(ctorExpr->getBeginLoc(), "Can't use QStringLiteral in macro.");
}
} else {
auto *parentMemberCallExpr =
clazy::getFirstParentOfType<CXXMemberCallExpr>(m_context->parentMap,
lt,
/*maxDepth=*/6); // 6 seems like a nice max from the ASTs I've seen
std::string replacement = "QStringLiteral";
if (parentMemberCallExpr) {
FunctionDecl *fDecl = parentMemberCallExpr->getDirectCallee();
if (fDecl) {
auto *method = dyn_cast<CXXMethodDecl>(fDecl);
if (method && betterTakeQLatin1String(method, lt)) {
replacement = "QLatin1String";
}
}
}
fixits = fixItRawLiteral(lt, replacement, nullptr);
}
}
}
}
maybeEmitWarning(ctorExpr->getBeginLoc(), msg, fixits);
}
}