in src/checks/manuallevel/qt6-deprecated-api-fixes.cpp [510:785]
void Qt6DeprecatedAPIFixes::VisitStmt(clang::Stmt *stmt)
{
auto *oppCallExpr = dyn_cast<CXXOperatorCallExpr>(stmt);
auto *declRefExp = dyn_cast<DeclRefExpr>(stmt);
auto *membExpr = dyn_cast<MemberExpr>(stmt);
auto *consExpr = dyn_cast<CXXConstructExpr>(stmt);
SourceLocation warningLocation;
std::string replacement;
std::string message;
SourceRange fixitRange;
std::vector<FixItHint> fixits;
if (consExpr) {
auto *constructor = consExpr->getConstructor();
if (!constructor) {
return;
}
if (constructor->getDeclName().getAsString() == "QSplashScreen") {
if (consExpr->getNumArgs() == 0) {
return;
}
if (consExpr->getArg(0)->getType().getAsString(lo()) != "QWidget *") {
return;
}
message = "Use the constructor taking a QScreen * instead.";
warningLocation = stmt->getBeginLoc();
emitWarning(warningLocation, message, fixits);
return;
}
if (constructor->getDeclName().getAsString() != "QDateTime") {
return;
}
if (consExpr->getNumArgs() != 1) {
return;
}
if (consExpr->getArg(0)->getType().getAsString(lo()) != "const QDate") {
return;
}
Stmt *child = clazy::childAt(stmt, 0);
DeclRefExpr *decl = nullptr;
while (child) {
decl = dyn_cast<DeclRefExpr>(child);
if (!decl) {
child = clazy::childAt(child, 0);
continue;
}
break;
}
if (!decl) {
return;
}
replacement = decl->getNameInfo().getAsString();
QualType qualtype = decl->getType();
if (qualtype->isPointerType()) {
replacement += "->";
} else {
replacement += ".";
}
replacement += "startOfDay()";
warningLocation = stmt->getBeginLoc();
fixitRange = stmt->getSourceRange();
message = "deprecated constructor. Use QDate::startOfDay() instead.";
} else if (oppCallExpr) {
if (clazy::isOfClass(oppCallExpr, "QDir")) {
fixForDeprecatedOperator(stmt, "QDir");
return;
}
if (clazy::isOfClass(oppCallExpr, "QVariant")) {
fixForDeprecatedOperator(stmt, "QVariant");
return;
}
return;
} else if (declRefExp) {
warningLocation = declRefExp->getBeginLoc();
auto *decl = declRefExp->getDecl();
if (!decl) {
return;
}
auto *declContext = declRefExp->getDecl()->getDeclContext();
if (!declContext) {
return;
}
std::string functionName = declRefExp->getNameInfo().getAsString();
std::string enclosingNameSpace;
auto *enclNsContext = declContext->getEnclosingNamespaceContext();
if (enclNsContext) {
if (auto *ns = dyn_cast<NamespaceDecl>(declContext->getEnclosingNamespaceContext())) {
enclosingNameSpace = ns->getNameAsString();
}
}
// To catch QDir and QSet
std::string contextName;
if (declContext) {
if (clang::isa<clang::CXXRecordDecl>(declContext)) {
auto *recordDecl = llvm::dyn_cast<clang::CXXRecordDecl>(declContext);
contextName = recordDecl->getQualifiedNameAsString();
}
}
if (isQSetDepreprecatedOperator(functionName, contextName, message)) {
emitWarning(warningLocation, message, fixits);
return;
}
if (functionName == "addResourceSearchPath" && contextName == "QDir") {
message = "call function QDir::addResourceSearchPath(). Use function QDir::addSearchPath() with prefix instead";
emitWarning(warningLocation, message, fixits);
return;
}
if (functionName == "qrand" || functionName == "qsrand") {
// To catch qrand and qsrand from qglobal.
message = "use QRandomGenerator instead";
emitWarning(warningLocation, message, fixits);
return;
}
std::string declType;
declType = decl->getType().getAsString();
if (functionName == "AdjustToMinimumContentsLength" && declType == "enum QComboBox::SizeAdjustPolicy") {
message = "Use QComboBox::SizeAdjustPolicy::AdjustToContents or AdjustToContentsOnFirstShow instead";
emitWarning(warningLocation, message, fixits);
return;
}
if (functionName == "AllDockWidgetFeatures" && declType == "enum QDockWidget::DockWidgetFeature") {
message = "Use QComboBox::DockWidgetClosable|DockWidgetMovable|DockWidgetFloatable explicitly instead.";
emitWarning(warningLocation, message, fixits);
return;
}
if ((qStylePixelMetrix.find(functionName) != qStylePixelMetrix.end() && declType == "enum QStyle::PixelMetric")
|| (functionName == "SE_DialogButtonBoxLayoutItem" && declType == "enum QStyle::SubElement")) {
message = "this enum has been removed in Qt6";
emitWarning(warningLocation, message, fixits);
return;
}
if (functionName != "MatchRegExp" && enclosingNameSpace != "QTextStreamFunctions" && functionName != "KeepEmptyParts"
&& functionName != "SkipEmptyParts") {
return;
}
// To catch enum Qt::MatchFlag and enum QString::SplitBehavior
// Get out of this DeclRefExp to catch the potential Qt namespace surrounding it
bool isQtNamespaceExplicit = false;
DeclContext *newcontext = clazy::contextForDecl(m_context->lastDecl);
while (newcontext) {
if (clang::isa<NamespaceDecl>(newcontext)) {
auto *namesdecl = dyn_cast<clang::NamespaceDecl>(newcontext);
if (namesdecl->getNameAsString() == "Qt") {
isQtNamespaceExplicit = true;
}
}
newcontext = newcontext->getParent();
}
if (enclosingNameSpace == "QTextStreamFunctions") {
replacementForQTextStreamFunctions(functionName, message, replacement, isQtNamespaceExplicit);
} else if ((functionName == "KeepEmptyParts" || functionName == "SkipEmptyParts") && declType == "enum QString::SplitBehavior") {
replacementForQStringSplitBehavior(functionName, message, replacement, isQtNamespaceExplicit);
} else if (functionName == "MatchRegExp" && declType == "enum Qt::MatchFlag") {
message = "call Qt::MatchRegExp. Use Qt::MatchRegularExpression instead.";
if (isQtNamespaceExplicit) {
replacement = "MatchRegularExpression";
} else {
replacement = "Qt::MatchRegularExpression";
}
} else {
return;
}
fixitRange = declRefExp->getSourceRange();
} else if (membExpr) {
Stmt *child = clazy::childAt(stmt, 0);
DeclRefExpr *decl = nullptr;
while (child) {
decl = dyn_cast<DeclRefExpr>(child);
if (decl) {
break;
}
child = clazy::childAt(child, 0);
}
if (!decl) {
return;
}
std::string functionName = membExpr->getMemberNameInfo().getAsString();
std::string className = decl->getType().getAsString(lo());
warningLocation = membExpr->getEndLoc();
if (clazy::startsWith(className, "QMap<") && qMapFunctions.find(functionName) != qMapFunctions.end()) {
message = "Use QMultiMap for maps storing multiple values with the same key.";
emitWarning(warningLocation, message, fixits);
return;
}
if (clazy::startsWith(className, "QHash<") && qMapFunctions.find(functionName) != qMapFunctions.end()) {
// the name of the deprecated function are the same
message = "Use QMultiHash for maps storing multiple values with the same key.";
emitWarning(warningLocation, message, fixits);
return;
} else if (clazy::startsWith(className, "QDir") && functionName == "addResourceSearchPath") {
message = "call function QDir::addResourceSearchPath(). Use function QDir::addSearchPath() with prefix instead";
emitWarning(warningLocation, message, fixits);
return;
} else if (clazy::startsWith(className, "QTimeLine") && (functionName == "curveShape" || functionName == "setCurveShape")) {
if (functionName == "curveShape") {
message = "call QTimeLine::curveShape. Use QTimeLine::easingCurve instead";
} else {
message = "call QTimeLine::setCurveShape. Use QTimeLine::setEasingCurve instead";
}
emitWarning(warningLocation, message, fixits);
return;
} else if (clazy::startsWith(className, "QSet") && qSetDeprecatedFunctions.find(functionName) != qSetDeprecatedFunctions.end()) {
message = "QSet iterator categories changed from bidirectional to forward. Please port your code manually";
emitWarning(warningLocation, message, fixits);
return;
} else if (clazy::startsWith(className, "QHash") && qHashDeprecatedFunctions.find(functionName) != qHashDeprecatedFunctions.end()) {
message = "QHash iterator categories changed from bidirectional to forward. Please port your code manually";
emitWarning(warningLocation, message, fixits);
return;
} else if (clazy::startsWith(className, "QComboBox") && functionName == "currentIndexChanged") {
if (!warningForQComboBox(membExpr, message, lo())) {
return;
}
emitWarning(warningLocation, message, fixits);
return;
} else if (clazy::startsWith(className, "QTextBrowser") && functionName == "highlighted") {
if (!warningForQTextBrowser(membExpr, message, lo())) {
return;
}
emitWarning(warningLocation, message, fixits);
return;
} else if (clazy::startsWith(className, "QGraphicsView") && qGraphicsViewFunctions.find(functionName) != qGraphicsViewFunctions.end()) {
warningForGraphicsViews(functionName, message);
emitWarning(warningLocation, message, fixits);
return;
} else if (className == "QDate" && functionName == "toString") {
Stmt *parent = clazy::parent(m_context->parentMap, stmt);
if (!replacementForQDate(parent, message, replacement, warningLocation, fixitRange, lo())) {
return;
}
fixits.push_back(FixItHint::CreateReplacement(fixitRange, replacement));
emitWarning(warningLocation, message, fixits);
return;
} else if (clazy::startsWith(className, "QResource") && functionName == "isCompressed") {
replacementForQResource(functionName, message, replacement);
} else if (clazy::startsWith(className, "QSignalMapper") && functionName == "mapped") {
replacementForQSignalMapper(membExpr, message, replacement, lo());
} else if (clazy::startsWith(className, "QWizard") && functionName == "visitedPages") {
replacementForQWizard(functionName, message, replacement);
} else if (clazy::startsWith(className, "QButtonGroup")
&& qButtonGroupDeprecatedFunctions.find(functionName) != qButtonGroupDeprecatedFunctions.end()) {
if (!replacementForQButtonGroup(membExpr, message, replacement)) {
return;
}
} else if (clazy::startsWith(className, "QComboBox") && (functionName == "activated" || functionName == "highlighted")) {
if (!replacementForQComboBox(membExpr, functionName, message, replacement, lo())) {
return;
}
} else {
return;
}
fixitRange = SourceRange(membExpr->getEndLoc());
} else {
return;
}
fixits.push_back(FixItHint::CreateReplacement(fixitRange, replacement));
emitWarning(warningLocation, message, fixits);
return;
}