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