File indexing completed on 2024-05-12 05:40:56

0001 /*
0002     SPDX-FileCopyrightText: 2015 Klarälvdalens Datakonsult AB a KDAB Group company info@kdab.com
0003     SPDX-FileContributor: SĂ©rgio Martins <sergio.martins@kdab.com>
0004 
0005     SPDX-FileCopyrightText: 2015 Sergio Martins <smartins@kde.org>
0006     SPDX-FileCopyrightText: 2024 Alexander Lohnau <alexander.lohnau@gmx.de>
0007 
0008     SPDX-License-Identifier: LGPL-2.0-or-later
0009 */
0010 
0011 #include "qdatetime-utc.h"
0012 #include "FixItUtils.h"
0013 #include "Utils.h"
0014 
0015 #include <clang/AST/Decl.h>
0016 #include <clang/AST/DeclCXX.h>
0017 #include <clang/AST/Expr.h>
0018 #include <clang/AST/ExprCXX.h>
0019 #include <clang/AST/Stmt.h>
0020 #include <clang/Basic/Diagnostic.h>
0021 #include <clang/Basic/LLVM.h>
0022 #include <llvm/Support/Casting.h>
0023 
0024 #include <vector>
0025 
0026 class ClazyContext;
0027 
0028 using namespace clang;
0029 
0030 QDateTimeUtc::QDateTimeUtc(const std::string &name, ClazyContext *context)
0031     : CheckBase(name, context)
0032 {
0033 }
0034 
0035 void QDateTimeUtc::VisitStmt(clang::Stmt *stmt)
0036 {
0037     auto *secondCall = dyn_cast<CXXMemberCallExpr>(stmt);
0038     if (!secondCall || !secondCall->getMethodDecl()) {
0039         return;
0040     }
0041     CXXMethodDecl *secondMethod = secondCall->getMethodDecl();
0042     const std::string secondMethodName = secondMethod->getQualifiedNameAsString();
0043     const bool isMSecSinceEpoc = secondMethodName == "QDateTime::toMSecsSinceEpoch";
0044     const bool isSecSinceEpoc = secondMethodName == "QDateTime::toSecsSinceEpoch" || secondMethodName == "QDateTime::toTime_t";
0045     const bool isToUtcConversion = secondMethodName == "QDateTime::toUTC";
0046     if (!isMSecSinceEpoc && !isSecSinceEpoc && !isToUtcConversion) {
0047         return;
0048     }
0049 
0050     std::vector<CallExpr *> chainedCalls = Utils::callListForChain(secondCall);
0051     if (chainedCalls.size() != 2) {
0052         return;
0053     }
0054 
0055     CallExpr *firstCall = chainedCalls[chainedCalls.size() - 1];
0056     FunctionDecl *firstFunc = firstCall->getDirectCallee();
0057     if (!firstFunc) {
0058         return;
0059     }
0060 
0061     if (auto *firstMethod = dyn_cast<CXXMethodDecl>(firstFunc); !firstMethod
0062         || (firstMethod->getQualifiedNameAsString() != "QDateTime::currentDateTime"
0063             && firstMethod->getQualifiedNameAsString() != "QDateTime::currentDateTimeUtc")) {
0064         return;
0065     }
0066 
0067     std::string replacement = "::currentDateTimeUtc()";
0068     if (isMSecSinceEpoc) {
0069         replacement = "::currentMSecsSinceEpoch()";
0070     } else if (isSecSinceEpoc) {
0071         replacement = "::currentSecsSinceEpoch()";
0072     }
0073 
0074     std::vector<FixItHint> fixits;
0075     const bool success = clazy::transformTwoCallsIntoOneV2(&m_astContext, secondCall, replacement, fixits);
0076     if (!success) {
0077         queueManualFixitWarning(secondCall->getBeginLoc());
0078     }
0079 
0080     emitWarning(stmt->getBeginLoc(), "Use QDateTime" + replacement + " instead. It is significantly faster", fixits);
0081 }