1 //=- ReachableCodePathInsensitive.cpp ---------------------------*- C++ --*-==//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements a flow-sensitive, path-insensitive analysis of
11 // determining reachable blocks within a CFG.
13 //===----------------------------------------------------------------------===//
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"
25 using namespace clang;
27 static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
31 R1 = R2 = SourceRange();
34 const CFGStmt *CS = b[sn].getAs<CFGStmt>();
36 return SourceLocation();
39 } else if (b.getTerminator())
40 S = b.getTerminator();
42 return SourceLocation();
44 if (const Expr *Ex = dyn_cast<Expr>(S))
45 S = Ex->IgnoreParenImpCasts();
47 switch (S->getStmtClass()) {
48 case Expr::BinaryOperatorClass: {
49 const BinaryOperator *BO = cast<BinaryOperator>(S);
50 if (BO->getOpcode() == BO_Comma) {
52 return b[sn+1].getAs<CFGStmt>()->getStmt()->getLocStart();
53 const CFGBlock *n = &b;
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();
63 return n[0][0].getAs<CFGStmt>()->getStmt()->getLocStart();
66 R1 = BO->getLHS()->getSourceRange();
67 R2 = BO->getRHS()->getSourceRange();
68 return BO->getOperatorLoc();
70 case Expr::UnaryOperatorClass: {
71 const UnaryOperator *UO = cast<UnaryOperator>(S);
72 R1 = UO->getSubExpr()->getSourceRange();
73 return UO->getOperatorLoc();
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();
81 case Expr::BinaryConditionalOperatorClass:
82 case Expr::ConditionalOperatorClass: {
83 const AbstractConditionalOperator *CO =
84 cast<AbstractConditionalOperator>(S);
85 return CO->getQuestionLoc();
87 case Expr::MemberExprClass: {
88 const MemberExpr *ME = cast<MemberExpr>(S);
89 R1 = ME->getSourceRange();
90 return ME->getMemberLoc();
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();
98 case Expr::CStyleCastExprClass: {
99 const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S);
100 R1 = CSC->getSubExpr()->getSourceRange();
101 return CSC->getLParenLoc();
103 case Expr::CXXFunctionalCastExprClass: {
104 const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S);
105 R1 = CE->getSubExpr()->getSourceRange();
106 return CE->getTypeBeginLoc();
108 case Stmt::CXXTryStmtClass: {
109 return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
113 R1 = S->getSourceRange();
114 return S->getLocStart();
117 static SourceLocation MarkLiveTop(const CFGBlock *Start,
118 llvm::BitVector &reachable,
121 // Prep work worklist.
122 llvm::SmallVector<const CFGBlock*, 32> WL;
126 SourceLocation top = GetUnreachableLoc(*Start, R1, R2);
128 bool FromMainFile = false;
129 bool FromSystemHeader = false;
130 bool TopValid = false;
133 FromMainFile = SM.isFromMainFile(top);
134 FromSystemHeader = SM.isInSystemHeader(top);
139 CFGBlock::FilterOptions FO;
140 FO.IgnoreDefaultsWithCoveredEnums = 1;
142 while (!WL.empty()) {
143 const CFGBlock *item = WL.back();
146 SourceLocation c = GetUnreachableLoc(*item, R1, R2);
149 || (SM.isFromMainFile(c) && !FromMainFile)
150 || (FromSystemHeader && !SM.isInSystemHeader(c))
151 || SM.isBeforeInTranslationUnit(c, top))) {
153 FromMainFile = SM.isFromMainFile(top);
154 FromSystemHeader = SM.isInSystemHeader(top);
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);
172 static int LineCmp(const void *p1, const void *p2) {
173 SourceLocation *Line1 = (SourceLocation *)p1;
174 SourceLocation *Line2 = (SourceLocation *)p2;
175 return !(*Line1 < *Line2);
183 ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2)
184 : Loc(l), R1(r1), R2(r2) { }
187 namespace clang { namespace reachable_code {
189 /// ScanReachableFromBlock - Mark all blocks reachable from Start.
190 /// Returns the total number of blocks that were marked reachable.
191 unsigned ScanReachableFromBlock(const CFGBlock &Start,
192 llvm::BitVector &Reachable) {
194 llvm::SmallVector<const CFGBlock*, 32> WL;
197 Reachable.set(Start.getBlockID());
199 WL.push_back(&Start);
201 // Find the reachable blocks from 'Start'.
202 CFGBlock::FilterOptions FO;
203 FO.IgnoreDefaultsWithCoveredEnums = 1;
205 while (!WL.empty()) {
206 const CFGBlock *item = WL.back();
209 // Look at the successors and mark then reachable.
210 for (CFGBlock::filtered_succ_iterator I= item->filtered_succ_start_end(FO);
212 if (const CFGBlock *B = *I) {
213 unsigned blockID = B->getBlockID();
214 if (!Reachable[blockID]) {
215 Reachable.set(blockID);
224 void FindUnreachableCode(AnalysisContext &AC, Callback &CB) {
225 CFG *cfg = AC.getCFG();
229 // Scan for reachable blocks.
230 llvm::BitVector reachable(cfg->getNumBlockIDs());
231 unsigned numReachable = ScanReachableFromBlock(cfg->getEntry(), reachable);
233 // If there are no unreachable blocks, we're done.
234 if (numReachable == cfg->getNumBlockIDs())
239 llvm::SmallVector<ErrLoc, 24> lines;
240 bool AddEHEdges = AC.getAddEHEdges();
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) {
246 if (!reachable[b.getBlockID()]) {
247 if (b.pred_empty()) {
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);
255 SourceLocation c = GetUnreachableLoc(b, R1, R2);
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());
263 lines.push_back(ErrLoc(c, R1, R2));
264 // Avoid excessive errors by marking everything reachable from here
265 numReachable += ScanReachableFromBlock(b, reachable);
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) {
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()));
282 llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp);
284 for (llvm::SmallVectorImpl<ErrLoc>::iterator I=lines.begin(), E=lines.end();
286 if (I->Loc.isValid())
287 CB.HandleUnreachable(I->Loc, I->R1, I->R2);
290 }} // end namespace clang::reachable_code