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