ReachableCode.cpp revision eeef924c4fcb79a3bcc8782afce343e641bbcb83
1//=- ReachableCodePathInsensitive.cpp ---------------------------*- C++ --*-==// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements a flow-sensitive, path-insensitive analysis of 11// determining reachable blocks within a CFG. 12// 13//===----------------------------------------------------------------------===// 14 15#include "llvm/ADT/BitVector.h" 16#include "llvm/ADT/SmallVector.h" 17#include "clang/AST/Expr.h" 18#include "clang/AST/ExprCXX.h" 19#include "clang/AST/StmtCXX.h" 20#include "clang/Analysis/Analyses/ReachableCode.h" 21#include "clang/Analysis/CFG.h" 22#include "clang/Analysis/AnalysisContext.h" 23#include "clang/Basic/SourceManager.h" 24 25using namespace clang; 26 27static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1, 28 SourceRange &R2) { 29 const Stmt *S = 0; 30 unsigned sn = 0; 31 R1 = R2 = SourceRange(); 32 33 if (sn < b.size()) { 34 CFGStmt CS = b[sn].getAs<CFGStmt>(); 35 if (!CS) 36 return SourceLocation(); 37 38 S = CS.getStmt(); 39 } else if (b.getTerminator()) 40 S = b.getTerminator(); 41 else 42 return SourceLocation(); 43 44 if (const Expr *Ex = dyn_cast<Expr>(S)) 45 S = Ex->IgnoreParenImpCasts(); 46 47 switch (S->getStmtClass()) { 48 case Expr::BinaryOperatorClass: { 49 const BinaryOperator *BO = cast<BinaryOperator>(S); 50 if (BO->getOpcode() == BO_Comma) { 51 if (sn+1 < b.size()) 52 return b[sn+1].getAs<CFGStmt>().getStmt()->getLocStart(); 53 const CFGBlock *n = &b; 54 while (1) { 55 if (n->getTerminator()) 56 return n->getTerminator()->getLocStart(); 57 if (n->succ_size() != 1) 58 return SourceLocation(); 59 n = n[0].succ_begin()[0]; 60 if (n->pred_size() != 1) 61 return SourceLocation(); 62 if (!n->empty()) 63 return n[0][0].getAs<CFGStmt>().getStmt()->getLocStart(); 64 } 65 } 66 R1 = BO->getLHS()->getSourceRange(); 67 R2 = BO->getRHS()->getSourceRange(); 68 return BO->getOperatorLoc(); 69 } 70 case Expr::UnaryOperatorClass: { 71 const UnaryOperator *UO = cast<UnaryOperator>(S); 72 R1 = UO->getSubExpr()->getSourceRange(); 73 return UO->getOperatorLoc(); 74 } 75 case Expr::CompoundAssignOperatorClass: { 76 const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S); 77 R1 = CAO->getLHS()->getSourceRange(); 78 R2 = CAO->getRHS()->getSourceRange(); 79 return CAO->getOperatorLoc(); 80 } 81 case Expr::ConditionalOperatorClass: { 82 const ConditionalOperator *CO = cast<ConditionalOperator>(S); 83 return CO->getQuestionLoc(); 84 } 85 case Expr::MemberExprClass: { 86 const MemberExpr *ME = cast<MemberExpr>(S); 87 R1 = ME->getSourceRange(); 88 return ME->getMemberLoc(); 89 } 90 case Expr::ArraySubscriptExprClass: { 91 const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S); 92 R1 = ASE->getLHS()->getSourceRange(); 93 R2 = ASE->getRHS()->getSourceRange(); 94 return ASE->getRBracketLoc(); 95 } 96 case Expr::CStyleCastExprClass: { 97 const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S); 98 R1 = CSC->getSubExpr()->getSourceRange(); 99 return CSC->getLParenLoc(); 100 } 101 case Expr::CXXFunctionalCastExprClass: { 102 const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S); 103 R1 = CE->getSubExpr()->getSourceRange(); 104 return CE->getTypeBeginLoc(); 105 } 106 case Stmt::CXXTryStmtClass: { 107 return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc(); 108 } 109 default: ; 110 } 111 R1 = S->getSourceRange(); 112 return S->getLocStart(); 113} 114 115static SourceLocation MarkLiveTop(const CFGBlock *Start, 116 llvm::BitVector &reachable, 117 SourceManager &SM) { 118 119 // Prep work worklist. 120 llvm::SmallVector<const CFGBlock*, 32> WL; 121 WL.push_back(Start); 122 123 SourceRange R1, R2; 124 SourceLocation top = GetUnreachableLoc(*Start, R1, R2); 125 126 bool FromMainFile = false; 127 bool FromSystemHeader = false; 128 bool TopValid = false; 129 130 if (top.isValid()) { 131 FromMainFile = SM.isFromMainFile(top); 132 FromSystemHeader = SM.isInSystemHeader(top); 133 TopValid = true; 134 } 135 136 // Solve 137 CFGBlock::FilterOptions FO; 138 FO.IgnoreDefaultsWithCoveredEnums = 1; 139 140 while (!WL.empty()) { 141 const CFGBlock *item = WL.back(); 142 WL.pop_back(); 143 144 SourceLocation c = GetUnreachableLoc(*item, R1, R2); 145 if (c.isValid() 146 && (!TopValid 147 || (SM.isFromMainFile(c) && !FromMainFile) 148 || (FromSystemHeader && !SM.isInSystemHeader(c)) 149 || SM.isBeforeInTranslationUnit(c, top))) { 150 top = c; 151 FromMainFile = SM.isFromMainFile(top); 152 FromSystemHeader = SM.isInSystemHeader(top); 153 } 154 155 reachable.set(item->getBlockID()); 156 for (CFGBlock::filtered_succ_iterator I = 157 item->filtered_succ_start_end(FO); I.hasMore(); ++I) 158 if (const CFGBlock *B = *I) { 159 unsigned blockID = B->getBlockID(); 160 if (!reachable[blockID]) { 161 reachable.set(blockID); 162 WL.push_back(B); 163 } 164 } 165 } 166 167 return top; 168} 169 170static int LineCmp(const void *p1, const void *p2) { 171 SourceLocation *Line1 = (SourceLocation *)p1; 172 SourceLocation *Line2 = (SourceLocation *)p2; 173 return !(*Line1 < *Line2); 174} 175 176namespace { 177struct ErrLoc { 178 SourceLocation Loc; 179 SourceRange R1; 180 SourceRange R2; 181 ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2) 182 : Loc(l), R1(r1), R2(r2) { } 183}; 184} 185namespace clang { namespace reachable_code { 186 187/// ScanReachableFromBlock - Mark all blocks reachable from Start. 188/// Returns the total number of blocks that were marked reachable. 189unsigned ScanReachableFromBlock(const CFGBlock &Start, 190 llvm::BitVector &Reachable) { 191 unsigned count = 0; 192 llvm::SmallVector<const CFGBlock*, 32> WL; 193 194 // Prep work queue 195 Reachable.set(Start.getBlockID()); 196 ++count; 197 WL.push_back(&Start); 198 199 // Find the reachable blocks from 'Start'. 200 CFGBlock::FilterOptions FO; 201 FO.IgnoreDefaultsWithCoveredEnums = 1; 202 203 while (!WL.empty()) { 204 const CFGBlock *item = WL.back(); 205 WL.pop_back(); 206 207 // Look at the successors and mark then reachable. 208 for (CFGBlock::filtered_succ_iterator I= item->filtered_succ_start_end(FO); 209 I.hasMore(); ++I) 210 if (const CFGBlock *B = *I) { 211 unsigned blockID = B->getBlockID(); 212 if (!Reachable[blockID]) { 213 Reachable.set(blockID); 214 ++count; 215 WL.push_back(B); 216 } 217 } 218 } 219 return count; 220} 221 222void FindUnreachableCode(AnalysisContext &AC, Callback &CB) { 223 CFG *cfg = AC.getCFG(); 224 if (!cfg) 225 return; 226 227 // Scan for reachable blocks. 228 llvm::BitVector reachable(cfg->getNumBlockIDs()); 229 unsigned numReachable = ScanReachableFromBlock(cfg->getEntry(), reachable); 230 231 // If there are no unreachable blocks, we're done. 232 if (numReachable == cfg->getNumBlockIDs()) 233 return; 234 235 SourceRange R1, R2; 236 237 llvm::SmallVector<ErrLoc, 24> lines; 238 bool AddEHEdges = AC.getAddEHEdges(); 239 240 // First, give warnings for blocks with no predecessors, as they 241 // can't be part of a loop. 242 for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { 243 CFGBlock &b = **I; 244 if (!reachable[b.getBlockID()]) { 245 if (b.pred_empty()) { 246 if (!AddEHEdges 247 && dyn_cast_or_null<CXXTryStmt>(b.getTerminator().getStmt())) { 248 // When not adding EH edges from calls, catch clauses 249 // can otherwise seem dead. Avoid noting them as dead. 250 numReachable += ScanReachableFromBlock(b, reachable); 251 continue; 252 } 253 SourceLocation c = GetUnreachableLoc(b, R1, R2); 254 if (!c.isValid()) { 255 // Blocks without a location can't produce a warning, so don't mark 256 // reachable blocks from here as live. 257 reachable.set(b.getBlockID()); 258 ++numReachable; 259 continue; 260 } 261 lines.push_back(ErrLoc(c, R1, R2)); 262 // Avoid excessive errors by marking everything reachable from here 263 numReachable += ScanReachableFromBlock(b, reachable); 264 } 265 } 266 } 267 268 if (numReachable < cfg->getNumBlockIDs()) { 269 // And then give warnings for the tops of loops. 270 for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { 271 CFGBlock &b = **I; 272 if (!reachable[b.getBlockID()]) 273 // Avoid excessive errors by marking everything reachable from here 274 lines.push_back(ErrLoc(MarkLiveTop(&b, reachable, 275 AC.getASTContext().getSourceManager()), 276 SourceRange(), SourceRange())); 277 } 278 } 279 280 llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp); 281 282 for (llvm::SmallVectorImpl<ErrLoc>::iterator I=lines.begin(), E=lines.end(); 283 I != E; ++I) 284 if (I->Loc.isValid()) 285 CB.HandleUnreachable(I->Loc, I->R1, I->R2); 286} 287 288}} // end namespace clang::reachable_code 289