blob: 802b990143d404575c61e2aab7a0a9b9e899564b [file] [log] [blame]
Ted Kremenek3d2eed82010-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 Kremenek72919a32010-02-23 05:59:20 +000017#include "clang/AST/Expr.h"
18#include "clang/AST/ExprCXX.h"
19#include "clang/AST/StmtCXX.h"
Ted Kremenek3d2eed82010-02-23 02:39:16 +000020#include "clang/Analysis/Analyses/ReachableCode.h"
21#include "clang/Analysis/CFG.h"
Ted Kremenek72919a32010-02-23 05:59:20 +000022#include "clang/Analysis/AnalysisContext.h"
23#include "clang/Basic/SourceManager.h"
Ted Kremenek3d2eed82010-02-23 02:39:16 +000024
25using namespace clang;
26
Ted Kremenek72919a32010-02-23 05:59:20 +000027static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1,
28 SourceRange &R2) {
29 const Stmt *S = 0;
30 unsigned sn = 0;
31 R1 = R2 = SourceRange();
32
Zhongxing Xub36cd3e2010-09-16 01:25:47 +000033 if (sn < b.size()) {
34 CFGStmt CS = b[sn].getAs<CFGStmt>();
35 if (!CS)
Chandler Carrutheeef9242011-01-08 06:54:40 +000036 return SourceLocation();
37
Zhongxing Xub36cd3e2010-09-16 01:25:47 +000038 S = CS.getStmt();
39 } else if (b.getTerminator())
Ted Kremenek72919a32010-02-23 05:59:20 +000040 S = b.getTerminator();
41 else
42 return SourceLocation();
43
Ted Kremenek892697d2010-12-16 07:46:53 +000044 if (const Expr *Ex = dyn_cast<Expr>(S))
45 S = Ex->IgnoreParenImpCasts();
46
Ted Kremenek72919a32010-02-23 05:59:20 +000047 switch (S->getStmtClass()) {
48 case Expr::BinaryOperatorClass: {
49 const BinaryOperator *BO = cast<BinaryOperator>(S);
John McCall2de56d12010-08-25 11:45:40 +000050 if (BO->getOpcode() == BO_Comma) {
Ted Kremenek72919a32010-02-23 05:59:20 +000051 if (sn+1 < b.size())
Zhongxing Xub36cd3e2010-09-16 01:25:47 +000052 return b[sn+1].getAs<CFGStmt>().getStmt()->getLocStart();
Ted Kremenek72919a32010-02-23 05:59:20 +000053 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())
Zhongxing Xub36cd3e2010-09-16 01:25:47 +000063 return n[0][0].getAs<CFGStmt>().getStmt()->getLocStart();
Ted Kremenek72919a32010-02-23 05:59:20 +000064 }
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::ConditionalOperatorClass: {
82 const ConditionalOperator *CO = cast<ConditionalOperator>(S);
83 return CO->getQuestionLoc();
84 }
85 case Expr::MemberExprClass: {
86 const MemberExpr *ME = cast<MemberExpr>(S);
87 R1 = ME->getSourceRange();
88 return ME->getMemberLoc();
89 }
90 case Expr::ArraySubscriptExprClass: {
91 const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S);
92 R1 = ASE->getLHS()->getSourceRange();
93 R2 = ASE->getRHS()->getSourceRange();
94 return ASE->getRBracketLoc();
95 }
96 case Expr::CStyleCastExprClass: {
97 const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S);
98 R1 = CSC->getSubExpr()->getSourceRange();
99 return CSC->getLParenLoc();
100 }
101 case Expr::CXXFunctionalCastExprClass: {
102 const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S);
103 R1 = CE->getSubExpr()->getSourceRange();
104 return CE->getTypeBeginLoc();
105 }
Ted Kremenek72919a32010-02-23 05:59:20 +0000106 case Stmt::CXXTryStmtClass: {
107 return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
108 }
109 default: ;
110 }
111 R1 = S->getSourceRange();
112 return S->getLocStart();
113}
114
115static SourceLocation MarkLiveTop(const CFGBlock *Start,
116 llvm::BitVector &reachable,
117 SourceManager &SM) {
118
119 // Prep work worklist.
120 llvm::SmallVector<const CFGBlock*, 32> WL;
121 WL.push_back(Start);
122
123 SourceRange R1, R2;
124 SourceLocation top = GetUnreachableLoc(*Start, R1, R2);
125
126 bool FromMainFile = false;
127 bool FromSystemHeader = false;
128 bool TopValid = false;
129
130 if (top.isValid()) {
131 FromMainFile = SM.isFromMainFile(top);
132 FromSystemHeader = SM.isInSystemHeader(top);
133 TopValid = true;
134 }
135
136 // Solve
Ted Kremenek8caec842010-09-09 00:06:10 +0000137 CFGBlock::FilterOptions FO;
138 FO.IgnoreDefaultsWithCoveredEnums = 1;
139
Ted Kremenek3d2eed82010-02-23 02:39:16 +0000140 while (!WL.empty()) {
141 const CFGBlock *item = WL.back();
142 WL.pop_back();
Ted Kremenek72919a32010-02-23 05:59:20 +0000143
144 SourceLocation c = GetUnreachableLoc(*item, R1, R2);
145 if (c.isValid()
146 && (!TopValid
147 || (SM.isFromMainFile(c) && !FromMainFile)
148 || (FromSystemHeader && !SM.isInSystemHeader(c))
149 || SM.isBeforeInTranslationUnit(c, top))) {
150 top = c;
151 FromMainFile = SM.isFromMainFile(top);
152 FromSystemHeader = SM.isInSystemHeader(top);
153 }
154
155 reachable.set(item->getBlockID());
Ted Kremenek8caec842010-09-09 00:06:10 +0000156 for (CFGBlock::filtered_succ_iterator I =
157 item->filtered_succ_start_end(FO); I.hasMore(); ++I)
Ted Kremenek72919a32010-02-23 05:59:20 +0000158 if (const CFGBlock *B = *I) {
159 unsigned blockID = B->getBlockID();
160 if (!reachable[blockID]) {
161 reachable.set(blockID);
162 WL.push_back(B);
163 }
164 }
165 }
166
167 return top;
168}
169
170static int LineCmp(const void *p1, const void *p2) {
171 SourceLocation *Line1 = (SourceLocation *)p1;
172 SourceLocation *Line2 = (SourceLocation *)p2;
173 return !(*Line1 < *Line2);
174}
175
176namespace {
177struct ErrLoc {
178 SourceLocation Loc;
179 SourceRange R1;
180 SourceRange R2;
181 ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2)
182 : Loc(l), R1(r1), R2(r2) { }
183};
184}
185namespace clang { namespace reachable_code {
186
187/// ScanReachableFromBlock - Mark all blocks reachable from Start.
188/// Returns the total number of blocks that were marked reachable.
189unsigned ScanReachableFromBlock(const CFGBlock &Start,
190 llvm::BitVector &Reachable) {
191 unsigned count = 0;
192 llvm::SmallVector<const CFGBlock*, 32> WL;
193
194 // Prep work queue
195 Reachable.set(Start.getBlockID());
196 ++count;
197 WL.push_back(&Start);
198
Ted Kremenek8caec842010-09-09 00:06:10 +0000199 // Find the reachable blocks from 'Start'.
200 CFGBlock::FilterOptions FO;
201 FO.IgnoreDefaultsWithCoveredEnums = 1;
202
Ted Kremenek72919a32010-02-23 05:59:20 +0000203 while (!WL.empty()) {
204 const CFGBlock *item = WL.back();
205 WL.pop_back();
206
207 // Look at the successors and mark then reachable.
Ted Kremenek8caec842010-09-09 00:06:10 +0000208 for (CFGBlock::filtered_succ_iterator I= item->filtered_succ_start_end(FO);
209 I.hasMore(); ++I)
Ted Kremenek3d2eed82010-02-23 02:39:16 +0000210 if (const CFGBlock *B = *I) {
211 unsigned blockID = B->getBlockID();
212 if (!Reachable[blockID]) {
213 Reachable.set(blockID);
214 ++count;
215 WL.push_back(B);
216 }
217 }
218 }
219 return count;
220}
Ted Kremenek72919a32010-02-23 05:59:20 +0000221
222void FindUnreachableCode(AnalysisContext &AC, Callback &CB) {
223 CFG *cfg = AC.getCFG();
224 if (!cfg)
225 return;
226
227 // Scan for reachable blocks.
228 llvm::BitVector reachable(cfg->getNumBlockIDs());
229 unsigned numReachable = ScanReachableFromBlock(cfg->getEntry(), reachable);
230
231 // If there are no unreachable blocks, we're done.
232 if (numReachable == cfg->getNumBlockIDs())
233 return;
234
235 SourceRange R1, R2;
236
237 llvm::SmallVector<ErrLoc, 24> lines;
238 bool AddEHEdges = AC.getAddEHEdges();
239
240 // First, give warnings for blocks with no predecessors, as they
241 // can't be part of a loop.
242 for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
243 CFGBlock &b = **I;
244 if (!reachable[b.getBlockID()]) {
245 if (b.pred_empty()) {
Marcin Swiderski4ba72a02010-10-29 05:21:47 +0000246 if (!AddEHEdges
247 && dyn_cast_or_null<CXXTryStmt>(b.getTerminator().getStmt())) {
Ted Kremenek72919a32010-02-23 05:59:20 +0000248 // When not adding EH edges from calls, catch clauses
249 // can otherwise seem dead. Avoid noting them as dead.
250 numReachable += ScanReachableFromBlock(b, reachable);
251 continue;
252 }
253 SourceLocation c = GetUnreachableLoc(b, R1, R2);
254 if (!c.isValid()) {
255 // Blocks without a location can't produce a warning, so don't mark
256 // reachable blocks from here as live.
257 reachable.set(b.getBlockID());
258 ++numReachable;
259 continue;
260 }
261 lines.push_back(ErrLoc(c, R1, R2));
262 // Avoid excessive errors by marking everything reachable from here
263 numReachable += ScanReachableFromBlock(b, reachable);
264 }
265 }
266 }
267
268 if (numReachable < cfg->getNumBlockIDs()) {
269 // And then give warnings for the tops of loops.
270 for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
271 CFGBlock &b = **I;
272 if (!reachable[b.getBlockID()])
273 // Avoid excessive errors by marking everything reachable from here
274 lines.push_back(ErrLoc(MarkLiveTop(&b, reachable,
275 AC.getASTContext().getSourceManager()),
276 SourceRange(), SourceRange()));
277 }
278 }
279
280 llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp);
281
282 for (llvm::SmallVectorImpl<ErrLoc>::iterator I=lines.begin(), E=lines.end();
283 I != E; ++I)
284 if (I->Loc.isValid())
285 CB.HandleUnreachable(I->Loc, I->R1, I->R2);
286}
287
288}} // end namespace clang::reachable_code