ReachableCode.cpp revision 72919a334752bc87001a7e3a0b6e5892768fac20
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() == BinaryOperator::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 while (!WL.empty()) { 135 const CFGBlock *item = WL.back(); 136 WL.pop_back(); 137 138 SourceLocation c = GetUnreachableLoc(*item, R1, R2); 139 if (c.isValid() 140 && (!TopValid 141 || (SM.isFromMainFile(c) && !FromMainFile) 142 || (FromSystemHeader && !SM.isInSystemHeader(c)) 143 || SM.isBeforeInTranslationUnit(c, top))) { 144 top = c; 145 FromMainFile = SM.isFromMainFile(top); 146 FromSystemHeader = SM.isInSystemHeader(top); 147 } 148 149 reachable.set(item->getBlockID()); 150 for (CFGBlock::const_succ_iterator I=item->succ_begin(), E=item->succ_end(); 151 I != E; ++I) 152 if (const CFGBlock *B = *I) { 153 unsigned blockID = B->getBlockID(); 154 if (!reachable[blockID]) { 155 reachable.set(blockID); 156 WL.push_back(B); 157 } 158 } 159 } 160 161 return top; 162} 163 164static int LineCmp(const void *p1, const void *p2) { 165 SourceLocation *Line1 = (SourceLocation *)p1; 166 SourceLocation *Line2 = (SourceLocation *)p2; 167 return !(*Line1 < *Line2); 168} 169 170namespace { 171struct ErrLoc { 172 SourceLocation Loc; 173 SourceRange R1; 174 SourceRange R2; 175 ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2) 176 : Loc(l), R1(r1), R2(r2) { } 177}; 178} 179namespace clang { namespace reachable_code { 180 181/// ScanReachableFromBlock - Mark all blocks reachable from Start. 182/// Returns the total number of blocks that were marked reachable. 183unsigned ScanReachableFromBlock(const CFGBlock &Start, 184 llvm::BitVector &Reachable) { 185 unsigned count = 0; 186 llvm::SmallVector<const CFGBlock*, 32> WL; 187 188 // Prep work queue 189 Reachable.set(Start.getBlockID()); 190 ++count; 191 WL.push_back(&Start); 192 193 // Find the reachable blocks from 'Start'. 194 while (!WL.empty()) { 195 const CFGBlock *item = WL.back(); 196 WL.pop_back(); 197 198 // Look at the successors and mark then reachable. 199 for (CFGBlock::const_succ_iterator I=item->succ_begin(), E=item->succ_end(); 200 I != E; ++I) 201 if (const CFGBlock *B = *I) { 202 unsigned blockID = B->getBlockID(); 203 if (!Reachable[blockID]) { 204 Reachable.set(blockID); 205 ++count; 206 WL.push_back(B); 207 } 208 } 209 } 210 return count; 211} 212 213void FindUnreachableCode(AnalysisContext &AC, Callback &CB) { 214 CFG *cfg = AC.getCFG(); 215 if (!cfg) 216 return; 217 218 // Scan for reachable blocks. 219 llvm::BitVector reachable(cfg->getNumBlockIDs()); 220 unsigned numReachable = ScanReachableFromBlock(cfg->getEntry(), reachable); 221 222 // If there are no unreachable blocks, we're done. 223 if (numReachable == cfg->getNumBlockIDs()) 224 return; 225 226 SourceRange R1, R2; 227 228 llvm::SmallVector<ErrLoc, 24> lines; 229 bool AddEHEdges = AC.getAddEHEdges(); 230 231 // First, give warnings for blocks with no predecessors, as they 232 // can't be part of a loop. 233 for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { 234 CFGBlock &b = **I; 235 if (!reachable[b.getBlockID()]) { 236 if (b.pred_empty()) { 237 if (!AddEHEdges && dyn_cast_or_null<CXXTryStmt>(b.getTerminator())) { 238 // When not adding EH edges from calls, catch clauses 239 // can otherwise seem dead. Avoid noting them as dead. 240 numReachable += ScanReachableFromBlock(b, reachable); 241 continue; 242 } 243 SourceLocation c = GetUnreachableLoc(b, R1, R2); 244 if (!c.isValid()) { 245 // Blocks without a location can't produce a warning, so don't mark 246 // reachable blocks from here as live. 247 reachable.set(b.getBlockID()); 248 ++numReachable; 249 continue; 250 } 251 lines.push_back(ErrLoc(c, R1, R2)); 252 // Avoid excessive errors by marking everything reachable from here 253 numReachable += ScanReachableFromBlock(b, reachable); 254 } 255 } 256 } 257 258 if (numReachable < cfg->getNumBlockIDs()) { 259 // And then give warnings for the tops of loops. 260 for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { 261 CFGBlock &b = **I; 262 if (!reachable[b.getBlockID()]) 263 // Avoid excessive errors by marking everything reachable from here 264 lines.push_back(ErrLoc(MarkLiveTop(&b, reachable, 265 AC.getASTContext().getSourceManager()), 266 SourceRange(), SourceRange())); 267 } 268 } 269 270 llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp); 271 272 for (llvm::SmallVectorImpl<ErrLoc>::iterator I=lines.begin(), E=lines.end(); 273 I != E; ++I) 274 if (I->Loc.isValid()) 275 CB.HandleUnreachable(I->Loc, I->R1, I->R2); 276} 277 278}} // end namespace clang::reachable_code 279