File indexing completed on 2024-04-28 16:57:51
0001 /* 0002 This file is part of the clazy static checker. 0003 0004 Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com 0005 Author: Sérgio Martins <sergio.martins@kdab.com> 0006 0007 Copyright (C) 2015 Sergio Martins <smartins@kde.org> 0008 0009 This library is free software; you can redistribute it and/or 0010 modify it under the terms of the GNU Library General Public 0011 License as published by the Free Software Foundation; either 0012 version 2 of the License, or (at your option) any later version. 0013 0014 This library is distributed in the hope that it will be useful, 0015 but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0017 Library General Public License for more details. 0018 0019 You should have received a copy of the GNU Library General Public License 0020 along with this library; see the file COPYING.LIB. If not, write to 0021 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0022 Boston, MA 02110-1301, USA. 0023 */ 0024 0025 #include "LoopUtils.h" 0026 #include "StringUtils.h" 0027 #include "clazy_stl.h" 0028 #include "SourceCompatibilityHelpers.h" 0029 0030 #include <clang/AST/ParentMap.h> 0031 #include <clang/Basic/SourceLocation.h> 0032 #include <clang/AST/ExprCXX.h> 0033 #include <clang/AST/Decl.h> 0034 #include <clang/AST/Expr.h> 0035 #include <clang/AST/StmtCXX.h> 0036 #include <clang/Basic/LLVM.h> 0037 #include <llvm/ADT/StringRef.h> 0038 0039 namespace clang { 0040 class CXXConstructorDecl; 0041 } // namespace clang 0042 0043 using namespace std; 0044 using namespace clang; 0045 0046 Stmt *clazy::bodyFromLoop(Stmt *loop) 0047 { 0048 if (!loop) 0049 return nullptr; 0050 0051 if (auto forstm = dyn_cast<ForStmt>(loop)) 0052 return forstm->getBody(); 0053 0054 if (auto rangeLoop = dyn_cast<CXXForRangeStmt>(loop)) 0055 return rangeLoop->getBody(); 0056 0057 0058 if (auto whilestm = dyn_cast<WhileStmt>(loop)) 0059 return whilestm->getBody(); 0060 0061 0062 if (auto dostm = dyn_cast<DoStmt>(loop)) 0063 return dostm->getBody(); 0064 0065 return nullptr; 0066 } 0067 0068 bool clazy::loopCanBeInterrupted(clang::Stmt *stmt, const clang::SourceManager &sm, 0069 clang::SourceLocation onlyBeforeThisLoc) 0070 { 0071 if (!stmt) 0072 return false; 0073 0074 if (isa<ReturnStmt>(stmt) || isa<BreakStmt>(stmt) || isa<ContinueStmt>(stmt)) { 0075 if (onlyBeforeThisLoc.isValid()) { 0076 FullSourceLoc sourceLoc(clazy::getLocStart(stmt), sm); 0077 FullSourceLoc otherSourceLoc(onlyBeforeThisLoc, sm); 0078 if (sourceLoc.isBeforeInTranslationUnitThan(otherSourceLoc)) 0079 return true; 0080 } else { 0081 return true; 0082 } 0083 } 0084 0085 return clazy::any_of(stmt->children(), [&sm, onlyBeforeThisLoc](Stmt *s) { 0086 return clazy::loopCanBeInterrupted(s, sm, onlyBeforeThisLoc); 0087 }); 0088 } 0089 0090 clang::Expr *clazy::containerExprForLoop(Stmt *loop) 0091 { 0092 if (!loop) 0093 return nullptr; 0094 0095 if (auto rangeLoop = dyn_cast<CXXForRangeStmt>(loop)) 0096 return rangeLoop->getRangeInit(); 0097 0098 if (auto constructExpr = dyn_cast<CXXConstructExpr>(loop)) { 0099 if (constructExpr->getNumArgs() < 1) 0100 return nullptr; 0101 0102 CXXConstructorDecl *constructorDecl = constructExpr->getConstructor(); 0103 if (!constructorDecl || clazy::name(constructorDecl) != "QForeachContainer") 0104 return nullptr; 0105 0106 0107 return constructExpr; 0108 } 0109 0110 return nullptr; 0111 } 0112 0113 VarDecl* clazy::containerDeclForLoop(clang::Stmt *loop) 0114 { 0115 Expr *expr = containerExprForLoop(loop); 0116 if (!expr) 0117 return nullptr; 0118 0119 auto declRef = dyn_cast<DeclRefExpr>(expr); 0120 if (!declRef) 0121 return nullptr; 0122 0123 ValueDecl *valueDecl = declRef->getDecl(); 0124 return valueDecl ? dyn_cast<VarDecl>(valueDecl) : nullptr; 0125 } 0126 0127 Stmt* clazy::isInLoop(clang::ParentMap *pmap, clang::Stmt *stmt) 0128 { 0129 if (!stmt) 0130 return nullptr; 0131 0132 Stmt *p = pmap->getParent(stmt); 0133 while (p) { 0134 if (clazy::isLoop(p)) 0135 return p; 0136 p = pmap->getParent(p); 0137 } 0138 0139 return nullptr; 0140 }