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 }