blob: 12dfac56fd3199f4826d112b0fb7bc6979a03392 [file] [log] [blame]
Ted Kremenek7296de92010-02-23 02:39:16 +00001//=- 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"
Ted Kremenek552eeaa2010-02-23 05:59:20 +000017#include "clang/AST/Expr.h"
18#include "clang/AST/ExprCXX.h"
John McCall31168b02011-06-15 23:02:42 +000019#include "clang/AST/ExprObjC.h"
Ted Kremenek552eeaa2010-02-23 05:59:20 +000020#include "clang/AST/StmtCXX.h"
Ted Kremenek7296de92010-02-23 02:39:16 +000021#include "clang/Analysis/Analyses/ReachableCode.h"
22#include "clang/Analysis/CFG.h"
Ted Kremenek552eeaa2010-02-23 05:59:20 +000023#include "clang/Analysis/AnalysisContext.h"
24#include "clang/Basic/SourceManager.h"
Ted Kremenek7296de92010-02-23 02:39:16 +000025
26using namespace clang;
27
Ted Kremenek552eeaa2010-02-23 05:59:20 +000028static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
29 SourceRange &R2) {
30 const Stmt *S = 0;
31 unsigned sn = 0;
32 R1 = R2 = SourceRange();
33
Zhongxing Xu2cd7a782010-09-16 01:25:47 +000034 if (sn < b.size()) {
Ted Kremenek96a7a592011-03-01 03:15:10 +000035 const CFGStmt *CS = b[sn].getAs<CFGStmt>();
Zhongxing Xu2cd7a782010-09-16 01:25:47 +000036 if (!CS)
Chandler Carruthb35635e2011-01-08 06:54:40 +000037 return SourceLocation();
38
Ted Kremenek96a7a592011-03-01 03:15:10 +000039 S = CS->getStmt();
Zhongxing Xu2cd7a782010-09-16 01:25:47 +000040 } else if (b.getTerminator())
Ted Kremenek552eeaa2010-02-23 05:59:20 +000041 S = b.getTerminator();
42 else
43 return SourceLocation();
44
Ted Kremenek8219b822010-12-16 07:46:53 +000045 if (const Expr *Ex = dyn_cast<Expr>(S))
46 S = Ex->IgnoreParenImpCasts();
47
Ted Kremenek552eeaa2010-02-23 05:59:20 +000048 switch (S->getStmtClass()) {
49 case Expr::BinaryOperatorClass: {
50 const BinaryOperator *BO = cast<BinaryOperator>(S);
John McCalle3027922010-08-25 11:45:40 +000051 if (BO->getOpcode() == BO_Comma) {
Ted Kremenek552eeaa2010-02-23 05:59:20 +000052 if (sn+1 < b.size())
Ted Kremenek96a7a592011-03-01 03:15:10 +000053 return b[sn+1].getAs<CFGStmt>()->getStmt()->getLocStart();
Ted Kremenek552eeaa2010-02-23 05:59:20 +000054 const CFGBlock *n = &b;
55 while (1) {
56 if (n->getTerminator())
57 return n->getTerminator()->getLocStart();
58 if (n->succ_size() != 1)
59 return SourceLocation();
60 n = n[0].succ_begin()[0];
61 if (n->pred_size() != 1)
62 return SourceLocation();
63 if (!n->empty())
Ted Kremenek96a7a592011-03-01 03:15:10 +000064 return n[0][0].getAs<CFGStmt>()->getStmt()->getLocStart();
Ted Kremenek552eeaa2010-02-23 05:59:20 +000065 }
66 }
67 R1 = BO->getLHS()->getSourceRange();
68 R2 = BO->getRHS()->getSourceRange();
69 return BO->getOperatorLoc();
70 }
71 case Expr::UnaryOperatorClass: {
72 const UnaryOperator *UO = cast<UnaryOperator>(S);
73 R1 = UO->getSubExpr()->getSourceRange();
74 return UO->getOperatorLoc();
75 }
76 case Expr::CompoundAssignOperatorClass: {
77 const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S);
78 R1 = CAO->getLHS()->getSourceRange();
79 R2 = CAO->getRHS()->getSourceRange();
80 return CAO->getOperatorLoc();
81 }
John McCallc07a0c72011-02-17 10:25:35 +000082 case Expr::BinaryConditionalOperatorClass:
Ted Kremenek552eeaa2010-02-23 05:59:20 +000083 case Expr::ConditionalOperatorClass: {
John McCallc07a0c72011-02-17 10:25:35 +000084 const AbstractConditionalOperator *CO =
85 cast<AbstractConditionalOperator>(S);
Ted Kremenek552eeaa2010-02-23 05:59:20 +000086 return CO->getQuestionLoc();
87 }
88 case Expr::MemberExprClass: {
89 const MemberExpr *ME = cast<MemberExpr>(S);
90 R1 = ME->getSourceRange();
91 return ME->getMemberLoc();
92 }
93 case Expr::ArraySubscriptExprClass: {
94 const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S);
95 R1 = ASE->getLHS()->getSourceRange();
96 R2 = ASE->getRHS()->getSourceRange();
97 return ASE->getRBracketLoc();
98 }
99 case Expr::CStyleCastExprClass: {
100 const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S);
101 R1 = CSC->getSubExpr()->getSourceRange();
102 return CSC->getLParenLoc();
103 }
104 case Expr::CXXFunctionalCastExprClass: {
105 const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S);
106 R1 = CE->getSubExpr()->getSourceRange();
107 return CE->getTypeBeginLoc();
108 }
Ted Kremenek552eeaa2010-02-23 05:59:20 +0000109 case Stmt::CXXTryStmtClass: {
110 return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
111 }
John McCall31168b02011-06-15 23:02:42 +0000112 case Expr::ObjCBridgedCastExprClass: {
113 const ObjCBridgedCastExpr *CSC = cast<ObjCBridgedCastExpr>(S);
114 R1 = CSC->getSubExpr()->getSourceRange();
115 return CSC->getLParenLoc();
116 }
Ted Kremenek552eeaa2010-02-23 05:59:20 +0000117 default: ;
118 }
119 R1 = S->getSourceRange();
120 return S->getLocStart();
121}
122
123static SourceLocation MarkLiveTop(const CFGBlock *Start,
124 llvm::BitVector &reachable,
125 SourceManager &SM) {
126
127 // Prep work worklist.
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000128 SmallVector<const CFGBlock*, 32> WL;
Ted Kremenek552eeaa2010-02-23 05:59:20 +0000129 WL.push_back(Start);
130
131 SourceRange R1, R2;
132 SourceLocation top = GetUnreachableLoc(*Start, R1, R2);
133
134 bool FromMainFile = false;
135 bool FromSystemHeader = false;
136 bool TopValid = false;
137
138 if (top.isValid()) {
139 FromMainFile = SM.isFromMainFile(top);
140 FromSystemHeader = SM.isInSystemHeader(top);
141 TopValid = true;
142 }
143
144 // Solve
Ted Kremenekf2b0a1b2010-09-09 00:06:10 +0000145 CFGBlock::FilterOptions FO;
146 FO.IgnoreDefaultsWithCoveredEnums = 1;
147
Ted Kremenek7296de92010-02-23 02:39:16 +0000148 while (!WL.empty()) {
149 const CFGBlock *item = WL.back();
150 WL.pop_back();
Ted Kremenek552eeaa2010-02-23 05:59:20 +0000151
152 SourceLocation c = GetUnreachableLoc(*item, R1, R2);
153 if (c.isValid()
154 && (!TopValid
155 || (SM.isFromMainFile(c) && !FromMainFile)
156 || (FromSystemHeader && !SM.isInSystemHeader(c))
157 || SM.isBeforeInTranslationUnit(c, top))) {
158 top = c;
159 FromMainFile = SM.isFromMainFile(top);
160 FromSystemHeader = SM.isInSystemHeader(top);
161 }
162
163 reachable.set(item->getBlockID());
Ted Kremenekf2b0a1b2010-09-09 00:06:10 +0000164 for (CFGBlock::filtered_succ_iterator I =
165 item->filtered_succ_start_end(FO); I.hasMore(); ++I)
Ted Kremenek552eeaa2010-02-23 05:59:20 +0000166 if (const CFGBlock *B = *I) {
167 unsigned blockID = B->getBlockID();
168 if (!reachable[blockID]) {
169 reachable.set(blockID);
170 WL.push_back(B);
171 }
172 }
173 }
174
175 return top;
176}
177
178static int LineCmp(const void *p1, const void *p2) {
179 SourceLocation *Line1 = (SourceLocation *)p1;
180 SourceLocation *Line2 = (SourceLocation *)p2;
181 return !(*Line1 < *Line2);
182}
183
184namespace {
185struct ErrLoc {
186 SourceLocation Loc;
187 SourceRange R1;
188 SourceRange R2;
189 ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2)
190 : Loc(l), R1(r1), R2(r2) { }
191};
192}
193namespace clang { namespace reachable_code {
194
195/// ScanReachableFromBlock - Mark all blocks reachable from Start.
196/// Returns the total number of blocks that were marked reachable.
197unsigned ScanReachableFromBlock(const CFGBlock &Start,
198 llvm::BitVector &Reachable) {
199 unsigned count = 0;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000200 SmallVector<const CFGBlock*, 32> WL;
Ted Kremenek552eeaa2010-02-23 05:59:20 +0000201
Nico Webercc2b8712011-04-02 19:45:15 +0000202 // Prep work queue
Ted Kremenek552eeaa2010-02-23 05:59:20 +0000203 Reachable.set(Start.getBlockID());
204 ++count;
205 WL.push_back(&Start);
206
Ted Kremenekf2b0a1b2010-09-09 00:06:10 +0000207 // Find the reachable blocks from 'Start'.
208 CFGBlock::FilterOptions FO;
209 FO.IgnoreDefaultsWithCoveredEnums = 1;
210
Ted Kremenek552eeaa2010-02-23 05:59:20 +0000211 while (!WL.empty()) {
212 const CFGBlock *item = WL.back();
213 WL.pop_back();
214
215 // Look at the successors and mark then reachable.
Ted Kremenekf2b0a1b2010-09-09 00:06:10 +0000216 for (CFGBlock::filtered_succ_iterator I= item->filtered_succ_start_end(FO);
217 I.hasMore(); ++I)
Ted Kremenek7296de92010-02-23 02:39:16 +0000218 if (const CFGBlock *B = *I) {
219 unsigned blockID = B->getBlockID();
220 if (!Reachable[blockID]) {
221 Reachable.set(blockID);
222 ++count;
223 WL.push_back(B);
224 }
225 }
226 }
227 return count;
228}
Ted Kremenek552eeaa2010-02-23 05:59:20 +0000229
230void FindUnreachableCode(AnalysisContext &AC, Callback &CB) {
231 CFG *cfg = AC.getCFG();
232 if (!cfg)
233 return;
234
235 // Scan for reachable blocks.
236 llvm::BitVector reachable(cfg->getNumBlockIDs());
237 unsigned numReachable = ScanReachableFromBlock(cfg->getEntry(), reachable);
238
239 // If there are no unreachable blocks, we're done.
240 if (numReachable == cfg->getNumBlockIDs())
241 return;
242
243 SourceRange R1, R2;
244
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000245 SmallVector<ErrLoc, 24> lines;
Ted Kremenek552eeaa2010-02-23 05:59:20 +0000246 bool AddEHEdges = AC.getAddEHEdges();
247
248 // First, give warnings for blocks with no predecessors, as they
249 // can't be part of a loop.
250 for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
251 CFGBlock &b = **I;
252 if (!reachable[b.getBlockID()]) {
253 if (b.pred_empty()) {
Marcin Swiderskia7d84a72010-10-29 05:21:47 +0000254 if (!AddEHEdges
255 && dyn_cast_or_null<CXXTryStmt>(b.getTerminator().getStmt())) {
Ted Kremenek552eeaa2010-02-23 05:59:20 +0000256 // When not adding EH edges from calls, catch clauses
257 // can otherwise seem dead. Avoid noting them as dead.
258 numReachable += ScanReachableFromBlock(b, reachable);
259 continue;
260 }
261 SourceLocation c = GetUnreachableLoc(b, R1, R2);
262 if (!c.isValid()) {
263 // Blocks without a location can't produce a warning, so don't mark
264 // reachable blocks from here as live.
265 reachable.set(b.getBlockID());
266 ++numReachable;
267 continue;
268 }
269 lines.push_back(ErrLoc(c, R1, R2));
270 // Avoid excessive errors by marking everything reachable from here
271 numReachable += ScanReachableFromBlock(b, reachable);
272 }
273 }
274 }
275
276 if (numReachable < cfg->getNumBlockIDs()) {
277 // And then give warnings for the tops of loops.
278 for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
279 CFGBlock &b = **I;
280 if (!reachable[b.getBlockID()])
281 // Avoid excessive errors by marking everything reachable from here
282 lines.push_back(ErrLoc(MarkLiveTop(&b, reachable,
283 AC.getASTContext().getSourceManager()),
284 SourceRange(), SourceRange()));
285 }
286 }
287
288 llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp);
289
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000290 for (SmallVectorImpl<ErrLoc>::iterator I=lines.begin(), E=lines.end();
Ted Kremenek552eeaa2010-02-23 05:59:20 +0000291 I != E; ++I)
292 if (I->Loc.isValid())
293 CB.HandleUnreachable(I->Loc, I->R1, I->R2);
294}
295
296}} // end namespace clang::reachable_code