File indexing completed on 2024-04-21 05:38:47

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 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "LoopUtils.h"
0011 #include "StringUtils.h"
0012 #include "clazy_stl.h"
0013 
0014 #include <clang/AST/Decl.h>
0015 #include <clang/AST/Expr.h>
0016 #include <clang/AST/ExprCXX.h>
0017 #include <clang/AST/ParentMap.h>
0018 #include <clang/AST/StmtCXX.h>
0019 #include <clang/Basic/LLVM.h>
0020 #include <clang/Basic/SourceLocation.h>
0021 #include <llvm/ADT/StringRef.h>
0022 
0023 namespace clang
0024 {
0025 class CXXConstructorDecl;
0026 } // namespace clang
0027 
0028 using namespace clang;
0029 
0030 Stmt *clazy::bodyFromLoop(Stmt *loop)
0031 {
0032     if (!loop) {
0033         return nullptr;
0034     }
0035 
0036     if (auto *forstm = dyn_cast<ForStmt>(loop)) {
0037         return forstm->getBody();
0038     }
0039 
0040     if (auto *rangeLoop = dyn_cast<CXXForRangeStmt>(loop)) {
0041         return rangeLoop->getBody();
0042     }
0043 
0044     if (auto *whilestm = dyn_cast<WhileStmt>(loop)) {
0045         return whilestm->getBody();
0046     }
0047 
0048     if (auto *dostm = dyn_cast<DoStmt>(loop)) {
0049         return dostm->getBody();
0050     }
0051 
0052     return nullptr;
0053 }
0054 
0055 bool clazy::loopCanBeInterrupted(clang::Stmt *stmt, const clang::SourceManager &sm, clang::SourceLocation onlyBeforeThisLoc)
0056 {
0057     if (!stmt) {
0058         return false;
0059     }
0060 
0061     if (isa<ReturnStmt>(stmt) || isa<BreakStmt>(stmt) || isa<ContinueStmt>(stmt)) {
0062         if (onlyBeforeThisLoc.isValid()) {
0063             FullSourceLoc sourceLoc(stmt->getBeginLoc(), sm);
0064             FullSourceLoc otherSourceLoc(onlyBeforeThisLoc, sm);
0065             if (sourceLoc.isBeforeInTranslationUnitThan(otherSourceLoc)) {
0066                 return true;
0067             }
0068         } else {
0069             return true;
0070         }
0071     }
0072 
0073     return clazy::any_of(stmt->children(), [&sm, onlyBeforeThisLoc](Stmt *s) {
0074         return clazy::loopCanBeInterrupted(s, sm, onlyBeforeThisLoc);
0075     });
0076 }
0077 
0078 clang::Expr *clazy::containerExprForLoop(Stmt *loop)
0079 {
0080     if (!loop) {
0081         return nullptr;
0082     }
0083 
0084     if (auto *rangeLoop = dyn_cast<CXXForRangeStmt>(loop)) {
0085         return rangeLoop->getRangeInit();
0086     }
0087 
0088     // foreach with C++14
0089     if (auto *constructExpr = dyn_cast<CXXConstructExpr>(loop)) {
0090         if (constructExpr->getNumArgs() < 1) {
0091             return nullptr;
0092         }
0093 
0094         CXXConstructorDecl *constructorDecl = constructExpr->getConstructor();
0095         if (!constructorDecl || clazy::name(constructorDecl) != "QForeachContainer") {
0096             return nullptr;
0097         }
0098 
0099         return constructExpr;
0100     }
0101 
0102     // foreach with C++17
0103     if (auto *bindTempExpr = dyn_cast<CXXBindTemporaryExpr>(loop)) {
0104         CallExpr *callExpr = dyn_cast<CallExpr>(bindTempExpr->getSubExpr());
0105         if (!callExpr)
0106             return nullptr;
0107         FunctionDecl *func = callExpr->getDirectCallee();
0108         if (!func || func->getQualifiedNameAsString() != "QtPrivate::qMakeForeachContainer") {
0109             return nullptr;
0110         }
0111         if (callExpr->getNumArgs() < 1) {
0112             return nullptr;
0113         }
0114         return callExpr->getArg(0);
0115     }
0116 
0117     return nullptr;
0118 }
0119 
0120 VarDecl *clazy::containerDeclForLoop(clang::Stmt *loop)
0121 {
0122     Expr *expr = containerExprForLoop(loop);
0123     if (!expr) {
0124         return nullptr;
0125     }
0126 
0127     auto *declRef = dyn_cast<DeclRefExpr>(expr);
0128     if (!declRef) {
0129         return nullptr;
0130     }
0131 
0132     ValueDecl *valueDecl = declRef->getDecl();
0133     return valueDecl ? dyn_cast<VarDecl>(valueDecl) : nullptr;
0134 }
0135 
0136 Stmt *clazy::isInLoop(clang::ParentMap *pmap, clang::Stmt *stmt)
0137 {
0138     if (!stmt) {
0139         return nullptr;
0140     }
0141 
0142     Stmt *p = pmap->getParent(stmt);
0143     while (p) {
0144         if (clazy::isLoop(p)) {
0145             return p;
0146         }
0147         p = pmap->getParent(p);
0148     }
0149 
0150     return nullptr;
0151 }