in src/checks/manuallevel/qt6-deprecated-api-fixes.cpp [413:508]
void Qt6DeprecatedAPIFixes::fixForDeprecatedOperator(Stmt *stmt, const std::string &className)
{
// only interested in '=' operator for QDir
std::vector<FixItHint> fixits;
std::string message;
std::string replacement;
SourceLocation warningLocation;
SourceRange fixitRange;
Stmt *child = clazy::childAt(stmt, 0);
bool foundOperator = false;
DeclRefExpr *decl = nullptr;
while (child) {
decl = dyn_cast<DeclRefExpr>(child);
if (!decl) {
child = clazy::childAt(child, 0);
continue;
}
if (className == "QDir") {
foundOperator = foundQDirDeprecatedOperator(decl, lo());
} else if (className == "QVariant") {
foundOperator = foundQVariantDeprecatedOperator(decl);
}
if (foundOperator) {
warningLocation = decl->getLocation();
break;
}
child = clazy::childAt(child, 0);
}
if (!foundOperator) {
return;
}
// Getting the two arguments of the operator to build the replacement
auto *oppCallExpr = dyn_cast<CXXOperatorCallExpr>(stmt);
auto *arg0Size = oppCallExpr->getArg(0);
auto *arg1Size = oppCallExpr->getArg(1);
auto charRange = Lexer::getAsCharRange(arg0Size->getSourceRange(), m_sm, lo());
auto replacementVar1 = Lexer::getSourceText(charRange, m_sm, lo());
charRange = Lexer::getAsCharRange(arg1Size->getSourceRange(), m_sm, lo());
auto replacementVar2 = Lexer::getSourceText(charRange, m_sm, lo());
replacementVar1 = replacementVar1.rtrim(' ');
replacementVar2 = replacementVar2.ltrim(' ');
if (className == "QDir") {
message = " function setPath() has to be used in Qt6";
// Get the quality type of the operator first argument.
// qdir_var1 = var2 => qdir_var1->setPath(var2) or qdir_var1.setPath(var2)
// the qdir_var1 correspond to second child of the QDir operator
child = clazy::childAt(stmt, 1);
bool isPointer = false;
while (child) {
auto *castExpr = dyn_cast<ImplicitCastExpr>(child);
auto *parent = dyn_cast<ParenExpr>(child);
if (castExpr || parent) {
child = clazy::childAt(child, 0);
continue;
}
auto *uni = dyn_cast<UnaryOperator>(child);
if (uni) {
#if LLVM_VERSION_MAJOR >= 19
#define STRING_EQUALS(a, b) a == b
#else
#define STRING_EQUALS(a, b) a.equals(b)
#endif
if (STRING_EQUALS(clang::UnaryOperator::getOpcodeStr(uni->getOpcode()), "*")) {
isPointer = true;
}
}
break;
}
if (isPointer) {
while (replacementVar1.consume_front("(")) {
replacementVar1.consume_back(")");
}
replacementVar1.consume_front("*");
}
replacement = buildReplacementforQDir(decl, isPointer, replacementVar1.str(), replacementVar2.str());
} else if (className == "QVariant") {
message = " operator does not exist in Qt6. Using QVariant::compare() instead.";
replacement = buildReplacementForQVariant(decl, replacementVar1.str(), replacementVar2.str());
}
// If a macro is present in the stmt range the spelling location is used
// This is producing a wrong fix. So we're forcing the use of expansion location
FullSourceLoc endLoc(stmt->getEndLoc(), m_sm);
SourceRange range(stmt->getBeginLoc(), endLoc.getExpansionLoc());
fixitRange = range;
fixits.push_back(FixItHint::CreateReplacement(fixitRange, replacement));
emitWarning(warningLocation, message, fixits);
return;
}