 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
82.3% |
93 / 113 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
98.2% |
111 / 113 |
| |
|
Line Coverage: |
95.4% |
103 / 108 |
| |
 |
|
 |
1 : //==- DeadStores.cpp - Check for stores to dead variables --------*- 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 defines a DeadStores, a flow-sensitive checker that looks for
11 : // stores to variables that are no longer live.
12 : //
13 : //===----------------------------------------------------------------------===//
14 :
15 : #include "clang/Checker/Checkers/LocalCheckers.h"
16 : #include "clang/Analysis/Analyses/LiveVariables.h"
17 : #include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
18 : #include "clang/Checker/BugReporter/BugReporter.h"
19 : #include "clang/Checker/PathSensitive/GRExprEngine.h"
20 : #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
21 : #include "clang/Basic/Diagnostic.h"
22 : #include "clang/AST/ASTContext.h"
23 : #include "clang/AST/ParentMap.h"
24 : #include "llvm/ADT/SmallPtrSet.h"
25 :
26 : using namespace clang;
27 :
28 : namespace {
29 :
30 : class DeadStoreObs : public LiveVariables::ObserverTy {
31 : ASTContext &Ctx;
32 : BugReporter& BR;
33 : ParentMap& Parents;
34 : llvm::SmallPtrSet<VarDecl*, 20> Escaped;
35 :
36 : enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
37 :
38 : public:
39 : DeadStoreObs(ASTContext &ctx, BugReporter& br, ParentMap& parents,
40 252: llvm::SmallPtrSet<VarDecl*, 20> &escaped)
41 252: : Ctx(ctx), BR(br), Parents(parents), Escaped(escaped) {}
42 :
0: branch 2 not taken
0: branch 3 not taken
0: branch 7 not taken
252: branch 8 taken
43 252: virtual ~DeadStoreObs() {}
44 :
45 105: void Report(VarDecl* V, DeadStoreKind dsk, SourceLocation L, SourceRange R) {
0: branch 1 not taken
105: branch 2 taken
46 105: if (Escaped.count(V))
47 0: return;
48 :
49 105: std::string name = V->getNameAsString();
50 :
51 105: const char* BugType = 0;
52 105: std::string msg;
53 :
0: branch 0 not taken
30: branch 1 taken
40: branch 2 taken
20: branch 3 taken
15: branch 4 taken
54 105: switch (dsk) {
55 : default:
56 0: assert(false && "Impossible dead store type.");
57 :
58 : case DeadInit:
59 30: BugType = "Dead initialization";
60 : msg = "Value stored to '" + name +
61 30: "' during its initialization is never read";
62 30: break;
63 :
64 : case DeadIncrement:
65 40: BugType = "Dead increment";
66 : case Standard:
20: branch 0 taken
40: branch 1 taken
67 60: if (!BugType) BugType = "Dead assignment";
68 60: msg = "Value stored to '" + name + "' is never read";
69 60: break;
70 :
71 : case Enclosing:
72 15: BugType = "Dead nested assignment";
73 : msg = "Although the value stored to '" + name +
74 : "' is used in the enclosing expression, the value is never actually"
75 15: " read from '" + name + "'";
76 : break;
77 : }
78 :
79 105: BR.EmitBasicReport(BugType, "Dead store", msg, L, R);
80 : }
81 :
82 : void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val,
83 : DeadStoreKind dsk,
84 : const LiveVariables::AnalysisDataTy& AD,
85 251: const LiveVariables::ValTy& Live) {
86 :
0: branch 1 not taken
251: branch 2 taken
87 251: if (!VD->hasLocalStorage())
88 0: return;
89 : // Reference types confuse the dead stores checker. Skip them
90 : // for now.
15: branch 3 taken
236: branch 4 taken
91 251: if (VD->getType()->getAs<ReferenceType>())
92 15: return;
93 :
85: branch 1 taken
151: branch 2 taken
85: branch 4 taken
0: branch 5 not taken
75: branch 7 taken
10: branch 8 taken
75: branch 9 taken
161: branch 10 taken
94 236: if (!Live(VD, AD) &&
95 : !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>()))
96 : Report(VD, dsk, Ex->getSourceRange().getBegin(),
97 75: Val->getSourceRange());
98 : }
99 :
100 : void CheckDeclRef(DeclRefExpr* DR, Expr* Val, DeadStoreKind dsk,
101 : const LiveVariables::AnalysisDataTy& AD,
102 145: const LiveVariables::ValTy& Live) {
145: branch 2 taken
0: branch 3 not taken
103 145: if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
104 145: CheckVarDecl(VD, DR, Val, dsk, AD, Live);
105 145: }
106 :
107 80: bool isIncrement(VarDecl* VD, BinaryOperator* B) {
0: branch 1 not taken
80: branch 2 taken
108 80: if (B->isCompoundAssignmentOp())
109 0: return true;
110 :
111 80: Expr* RHS = B->getRHS()->IgnoreParenCasts();
112 80: BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
113 :
55: branch 0 taken
25: branch 1 taken
114 80: if (!BRHS)
115 55: return false;
116 :
117 : DeclRefExpr *DR;
118 :
20: branch 3 taken
5: branch 4 taken
119 25: if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts())))
10: branch 1 taken
10: branch 2 taken
120 20: if (DR->getDecl() == VD)
121 10: return true;
122 :
5: branch 3 taken
10: branch 4 taken
123 15: if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts())))
5: branch 1 taken
0: branch 2 not taken
124 5: if (DR->getDecl() == VD)
125 5: return true;
126 :
127 10: return false;
128 : }
129 :
130 : virtual void ObserveStmt(Stmt* S,
131 : const LiveVariables::AnalysisDataTy& AD,
132 3239: const LiveVariables::ValTy& Live) {
133 :
134 : // Skip statements in macros.
35: branch 2 taken
3204: branch 3 taken
135 3239: if (S->getLocStart().isMacroID())
136 35: return;
137 :
340: branch 1 taken
2864: branch 2 taken
138 3204: if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
131: branch 1 taken
209: branch 2 taken
139 340: if (!B->isAssignmentOp()) return; // Skip non-assignments.
140 :
131: branch 2 taken
0: branch 3 not taken
141 131: if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
131: branch 2 taken
0: branch 3 not taken
142 131: if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
143 : // Special case: check for assigning null to a pointer.
144 : // This is a common form of defensive programming.
25: branch 3 taken
106: branch 4 taken
145 131: if (VD->getType()->isPointerType()) {
20: branch 2 taken
5: branch 3 taken
146 25: if (B->getRHS()->isNullPointerConstant(Ctx,
147 : Expr::NPC_ValueDependentIsNull))
148 20: return;
149 : }
150 :
151 111: Expr* RHS = B->getRHS()->IgnoreParenCasts();
152 : // Special case: self-assignments. These are often used to shut up
153 : // "unused variable" compiler warnings.
5: branch 1 taken
106: branch 2 taken
154 111: if (DeclRefExpr* RhsDR = dyn_cast<DeclRefExpr>(RHS))
5: branch 2 taken
0: branch 3 not taken
155 5: if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
156 5: return;
157 :
158 : // Otherwise, issue a warning.
159 : DeadStoreKind dsk = Parents.isConsumedExpr(B)
160 : ? Enclosing
26: branch 1 taken
80: branch 2 taken
15: branch 4 taken
65: branch 5 taken
161 106: : (isIncrement(VD,B) ? DeadIncrement : Standard);
162 :
163 106: CheckVarDecl(VD, DR, B->getRHS(), dsk, AD, Live);
164 : }
165 : }
156: branch 1 taken
2708: branch 2 taken
166 2864: else if (UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
6: branch 1 taken
150: branch 2 taken
167 156: if (!U->isIncrementOp())
168 6: return;
169 :
170 : // Handle: ++x within a subexpression. The solution is not warn
171 : // about preincrements to dead variables when the preincrement occurs
172 : // as a subexpression. This can lead to false negatives, e.g. "(++x);"
173 : // A generalized dead code checker should find such issues.
145: branch 1 taken
5: branch 2 taken
5: branch 4 taken
140: branch 5 taken
5: branch 6 taken
145: branch 7 taken
174 150: if (U->isPrefix() && Parents.isConsumedExpr(U))
175 5: return;
176 :
177 145: Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
178 :
145: branch 1 taken
0: branch 2 not taken
179 145: if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(Ex))
180 145: CheckDeclRef(DR, U, DeadIncrement, AD, Live);
181 : }
342: branch 1 taken
2366: branch 2 taken
182 2708: else if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
183 : // Iterate through the decls. Warn if any initializers are complex
184 : // expressions that are not live (never used).
342: branch 2 taken
302: branch 3 taken
185 644: for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
186 : DI != DE; ++DI) {
187 :
188 342: VarDecl* V = dyn_cast<VarDecl>(*DI);
189 :
5: branch 0 taken
337: branch 1 taken
190 342: if (!V)
191 5: continue;
192 :
337: branch 1 taken
0: branch 2 not taken
193 337: if (V->hasLocalStorage()) {
194 : // Reference types confuse the dead stores checker. Skip them
195 : // for now.
15: branch 3 taken
322: branch 4 taken
196 337: if (V->getType()->getAs<ReferenceType>())
197 15: return;
198 :
281: branch 1 taken
41: branch 2 taken
199 322: if (Expr* E = V->getInit()) {
200 : // Don't warn on C++ objects (yet) until we can show that their
201 : // constructors/destructors don't have side effects.
10: branch 1 taken
271: branch 2 taken
202 281: if (isa<CXXConstructExpr>(E))
203 10: return;
204 :
0: branch 1 not taken
271: branch 2 taken
205 271: if (isa<CXXExprWithTemporaries>(E))
206 0: return;
207 :
208 : // A dead initialization is a variable that is dead after it
209 : // is initialized. We don't flag warnings for those variables
210 : // marked 'unused'.
55: branch 1 taken
216: branch 2 taken
45: branch 4 taken
10: branch 5 taken
45: branch 6 taken
226: branch 7 taken
211 271: if (!Live(V, AD) && V->getAttr<UnusedAttr>() == 0) {
212 : // Special case: check for initializations with constants.
213 : //
214 : // e.g. : int x = 0;
215 : //
216 : // If x is EVER assigned a new value later, don't issue
217 : // a warning. This is because such initialization can be
218 : // due to defensive programming.
10: branch 1 taken
35: branch 2 taken
219 45: if (E->isConstantInitializer(Ctx))
220 10: return;
221 :
222 : // Special case: check for initializations from constant
223 : // variables.
224 : //
225 : // e.g. extern const int MyConstant;
226 : // int x = MyConstant;
227 : //
10: branch 2 taken
25: branch 3 taken
228 35: if (DeclRefExpr *DRE=dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
10: branch 2 taken
0: branch 3 not taken
229 10: if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
5: branch 1 taken
5: branch 2 taken
5: branch 5 taken
0: branch 6 not taken
5: branch 7 taken
5: branch 8 taken
230 10: if (VD->hasGlobalStorage() &&
231 5: VD->getType().isConstQualified()) return;
232 :
233 30: Report(V, DeadInit, V->getLocation(), E->getSourceRange());
234 : }
235 : }
236 : }
237 : }
238 : }
239 : };
240 :
241 : } // end anonymous namespace
242 :
243 : //===----------------------------------------------------------------------===//
244 : // Driver function to invoke the Dead-Stores checker on a CFG.
245 : //===----------------------------------------------------------------------===//
246 :
247 : namespace {
248 252: class FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
249 : CFG *cfg;
250 : public:
251 252: FindEscaped(CFG *c) : cfg(c) {}
252 :
253 2557: CFG& getCFG() { return *cfg; }
254 :
255 : llvm::SmallPtrSet<VarDecl*, 20> Escaped;
256 :
257 156: void VisitUnaryOperator(UnaryOperator* U) {
258 : // Check for '&'. Any VarDecl whose value has its address-taken we
259 : // treat as escaped.
260 156: Expr* E = U->getSubExpr()->IgnoreParenCasts();
6: branch 1 taken
150: branch 2 taken
261 156: if (U->getOpcode() == UnaryOperator::AddrOf)
6: branch 1 taken
0: branch 2 not taken
262 6: if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E))
6: branch 2 taken
0: branch 3 not taken
263 6: if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
264 6: Escaped.insert(VD);
265 6: return;
266 : }
267 150: Visit(E);
268 : }
269 : };
270 : } // end anonymous namespace
271 :
272 :
273 : void clang::CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &pmap,
274 252: BugReporter& BR) {
275 252: FindEscaped FS(&cfg);
276 252: FS.getCFG().VisitBlockStmts(FS);
277 252: DeadStoreObs A(BR.getContext(), BR, pmap, FS.Escaped);
278 252: L.runOnAllBlocks(cfg, &A);
279 252: }
Generated: 2010-02-10 01:31 by zcov