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 }