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();
35 CFGStmt CS
= b
[sn
].getAs
<CFGStmt
>();
40 } else if (b
.getTerminator())
41 S
= b
.getTerminator();
43 return SourceLocation();
45 if (const Expr
*Ex
= dyn_cast
<Expr
>(S
))
46 S
= Ex
->IgnoreParenImpCasts();
48 switch (S
->getStmtClass()) {
49 case Expr::BinaryOperatorClass
: {
50 const BinaryOperator
*BO
= cast
<BinaryOperator
>(S
);
51 if (BO
->getOpcode() == BO_Comma
) {
53 return b
[sn
+1].getAs
<CFGStmt
>().getStmt()->getLocStart();
54 const CFGBlock
*n
= &b
;
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();
64 return n
[0][0].getAs
<CFGStmt
>().getStmt()->getLocStart();
67 R1
= BO
->getLHS()->getSourceRange();
68 R2
= BO
->getRHS()->getSourceRange();
69 return BO
->getOperatorLoc();
71 case Expr::UnaryOperatorClass
: {
72 const UnaryOperator
*UO
= cast
<UnaryOperator
>(S
);
73 R1
= UO
->getSubExpr()->getSourceRange();
74 return UO
->getOperatorLoc();
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();
82 case Expr::ConditionalOperatorClass
: {
83 const ConditionalOperator
*CO
= cast
<ConditionalOperator
>(S
);
84 return CO
->getQuestionLoc();
86 case Expr::MemberExprClass
: {
87 const MemberExpr
*ME
= cast
<MemberExpr
>(S
);
88 R1
= ME
->getSourceRange();
89 return ME
->getMemberLoc();
91 case Expr::ArraySubscriptExprClass
: {
92 const ArraySubscriptExpr
*ASE
= cast
<ArraySubscriptExpr
>(S
);
93 R1
= ASE
->getLHS()->getSourceRange();
94 R2
= ASE
->getRHS()->getSourceRange();
95 return ASE
->getRBracketLoc();
97 case Expr::CStyleCastExprClass
: {
98 const CStyleCastExpr
*CSC
= cast
<CStyleCastExpr
>(S
);
99 R1
= CSC
->getSubExpr()->getSourceRange();
100 return CSC
->getLParenLoc();
102 case Expr::CXXFunctionalCastExprClass
: {
103 const CXXFunctionalCastExpr
*CE
= cast
<CXXFunctionalCastExpr
>(S
);
104 R1
= CE
->getSubExpr()->getSourceRange();
105 return CE
->getTypeBeginLoc();
107 case Stmt::CXXTryStmtClass
: {
108 return cast
<CXXTryStmt
>(S
)->getHandler(0)->getCatchLoc();
112 R1
= S
->getSourceRange();
113 return S
->getLocStart();
116 static SourceLocation
MarkLiveTop(const CFGBlock
*Start
,
117 llvm::BitVector
&reachable
,
120 // Prep work worklist.
121 llvm::SmallVector
<const CFGBlock
*, 32> WL
;
125 SourceLocation top
= GetUnreachableLoc(*Start
, R1
, R2
);
127 bool FromMainFile
= false;
128 bool FromSystemHeader
= false;
129 bool TopValid
= false;
132 FromMainFile
= SM
.isFromMainFile(top
);
133 FromSystemHeader
= SM
.isInSystemHeader(top
);
138 CFGBlock::FilterOptions FO
;
139 FO
.IgnoreDefaultsWithCoveredEnums
= 1;
141 while (!WL
.empty()) {
142 const CFGBlock
*item
= WL
.back();
145 SourceLocation c
= GetUnreachableLoc(*item
, R1
, R2
);
148 || (SM
.isFromMainFile(c
) && !FromMainFile
)
149 || (FromSystemHeader
&& !SM
.isInSystemHeader(c
))
150 || SM
.isBeforeInTranslationUnit(c
, top
))) {
152 FromMainFile
= SM
.isFromMainFile(top
);
153 FromSystemHeader
= SM
.isInSystemHeader(top
);
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
);
171 static int LineCmp(const void *p1
, const void *p2
) {
172 SourceLocation
*Line1
= (SourceLocation
*)p1
;
173 SourceLocation
*Line2
= (SourceLocation
*)p2
;
174 return !(*Line1
< *Line2
);
182 ErrLoc(SourceLocation l
, SourceRange r1
, SourceRange r2
)
183 : Loc(l
), R1(r1
), R2(r2
) { }
186 namespace clang
{ namespace reachable_code
{
188 /// ScanReachableFromBlock - Mark all blocks reachable from Start.
189 /// Returns the total number of blocks that were marked reachable.
190 unsigned ScanReachableFromBlock(const CFGBlock
&Start
,
191 llvm::BitVector
&Reachable
) {
193 llvm::SmallVector
<const CFGBlock
*, 32> WL
;
196 Reachable
.set(Start
.getBlockID());
198 WL
.push_back(&Start
);
200 // Find the reachable blocks from 'Start'.
201 CFGBlock::FilterOptions FO
;
202 FO
.IgnoreDefaultsWithCoveredEnums
= 1;
204 while (!WL
.empty()) {
205 const CFGBlock
*item
= WL
.back();
208 // Look at the successors and mark then reachable.
209 for (CFGBlock::filtered_succ_iterator I
= item
->filtered_succ_start_end(FO
);
211 if (const CFGBlock
*B
= *I
) {
212 unsigned blockID
= B
->getBlockID();
213 if (!Reachable
[blockID
]) {
214 Reachable
.set(blockID
);
223 void FindUnreachableCode(AnalysisContext
&AC
, Callback
&CB
) {
224 CFG
*cfg
= AC
.getCFG();
228 // Scan for reachable blocks.
229 llvm::BitVector
reachable(cfg
->getNumBlockIDs());
230 unsigned numReachable
= ScanReachableFromBlock(cfg
->getEntry(), reachable
);
232 // If there are no unreachable blocks, we're done.
233 if (numReachable
== cfg
->getNumBlockIDs())
238 llvm::SmallVector
<ErrLoc
, 24> lines
;
239 bool AddEHEdges
= AC
.getAddEHEdges();
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
) {
245 if (!reachable
[b
.getBlockID()]) {
246 if (b
.pred_empty()) {
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
);
254 SourceLocation c
= GetUnreachableLoc(b
, R1
, R2
);
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());
262 lines
.push_back(ErrLoc(c
, R1
, R2
));
263 // Avoid excessive errors by marking everything reachable from here
264 numReachable
+= ScanReachableFromBlock(b
, reachable
);
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
) {
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()));
281 llvm::array_pod_sort(lines
.begin(), lines
.end(), LineCmp
);
283 for (llvm::SmallVectorImpl
<ErrLoc
>::iterator I
=lines
.begin(), E
=lines
.end();
285 if (I
->Loc
.isValid())
286 CB
.HandleUnreachable(I
->Loc
, I
->R1
, I
->R2
);
289 }} // end namespace clang::reachable_code