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