void Qt6DeprecatedAPIFixes::VisitStmt()

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