blob: 0f08b233b5467896b189d5b3b67a5b3cd4178c7b [file] [log] [blame]
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +00001//==- DeadStores.cpp - Check for stores to dead variables --------*- C++ -*-==//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner0bc735f2007-12-29 19:59:25 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +00007//
8//===----------------------------------------------------------------------===//
9//
Gabor Greif843e9342008-03-06 10:40:09 +000010// This file defines a DeadStores, a flow-sensitive checker that looks for
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +000011// stores to variables that are no longer live.
12//
13//===----------------------------------------------------------------------===//
14
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +000015#include "clang/Analysis/LocalCheckers.h"
Ted Kremenekcf6e41b2007-12-21 21:42:19 +000016#include "clang/Analysis/Analyses/LiveVariables.h"
Ted Kremenekfdd225e2007-09-25 04:31:27 +000017#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
Ted Kremenekd2f642b2008-04-14 17:39:48 +000018#include "clang/Analysis/PathSensitive/BugReporter.h"
19#include "clang/Analysis/PathSensitive/GRExprEngine.h"
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +000020#include "clang/Basic/Diagnostic.h"
Ted Kremenekce1cab92007-09-11 17:24:14 +000021#include "clang/AST/ASTContext.h"
Ted Kremenekc2b51d82008-01-08 18:19:08 +000022#include "llvm/Support/Compiler.h"
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +000023
24using namespace clang;
25
26namespace {
Ted Kremenekfdd225e2007-09-25 04:31:27 +000027
Ted Kremenekc2b51d82008-01-08 18:19:08 +000028class VISIBILITY_HIDDEN DeadStoreObs : public LiveVariables::ObserverTy {
Chris Lattnerc0508f92007-09-15 23:21:08 +000029 ASTContext &Ctx;
30 Diagnostic &Diags;
Ted Kremenekd2f642b2008-04-14 17:39:48 +000031 DiagnosticClient &Client;
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +000032public:
Ted Kremenekd2f642b2008-04-14 17:39:48 +000033 DeadStoreObs(ASTContext &ctx, Diagnostic &diags, DiagnosticClient &client)
34 : Ctx(ctx), Diags(diags), Client(client) {}
35
Ted Kremenekfdd225e2007-09-25 04:31:27 +000036 virtual ~DeadStoreObs() {}
37
Ted Kremenekc07ba352008-05-22 16:28:24 +000038 unsigned GetDiag(VarDecl* VD) {
39 std::string msg = "value stored to '" + std::string(VD->getName()) +
40 "' is never used";
41
42 return Diags.getCustomDiagID(Diagnostic::Warning, msg.c_str());
43
Ted Kremenek3eb817e2008-05-21 22:59:16 +000044 }
45
Ted Kremeneka23157e2008-05-05 23:12:21 +000046 void CheckDeclRef(DeclRefExpr* DR, Expr* Val,
47 const LiveVariables::AnalysisDataTy& AD,
48 const LiveVariables::ValTy& Live) {
49
50 if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
51 if (VD->hasLocalStorage() && !Live(VD, AD)) {
Ted Kremenek3eb817e2008-05-21 22:59:16 +000052 SourceRange R = Val->getSourceRange();
Ted Kremeneka23157e2008-05-05 23:12:21 +000053 Diags.Report(&Client,
54 Ctx.getFullLoc(DR->getSourceRange().getBegin()),
Ted Kremenek3eb817e2008-05-21 22:59:16 +000055 GetDiag(VD), 0, 0, &R, 1);
Ted Kremeneka23157e2008-05-05 23:12:21 +000056 }
57 }
58
Ted Kremenekfdd225e2007-09-25 04:31:27 +000059 virtual void ObserveStmt(Stmt* S,
60 const LiveVariables::AnalysisDataTy& AD,
61 const LiveVariables::ValTy& Live) {
Ted Kremenekce1cab92007-09-11 17:24:14 +000062
Ted Kremenek1c86b152008-04-14 18:28:25 +000063 // Skip statements in macros.
64 if (S->getLocStart().isMacroID())
65 return;
66
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +000067 if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
Ted Kremenekfdd225e2007-09-25 04:31:27 +000068 if (!B->isAssignmentOp()) return; // Skip non-assignments.
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +000069
Ted Kremenekc0576ca2007-09-10 17:36:42 +000070 if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
Ted Kremeneka23157e2008-05-05 23:12:21 +000071 CheckDeclRef(DR, B->getRHS(), AD, Live);
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +000072 }
Ted Kremeneka23157e2008-05-05 23:12:21 +000073 else if (UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
74 if (!U->isIncrementOp())
75 return;
76
77 Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
78
79 if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(Ex))
80 CheckDeclRef(DR, U, AD, Live);
81 }
82 else if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
Ted Kremenekfdd225e2007-09-25 04:31:27 +000083 // Iterate through the decls. Warn if any initializers are complex
84 // expressions that are not live (never used).
Ted Kremenekc967c9d2008-04-14 17:52:13 +000085 for (ScopedDecl* SD = DS->getDecl(); SD; SD = SD->getNextDeclarator()) {
86
87 VarDecl* V = dyn_cast<VarDecl>(SD);
88 if (!V) continue;
89
Ted Kremenekc6a1faf2007-09-28 20:48:41 +000090 if (V->hasLocalStorage())
91 if (Expr* E = V->getInit()) {
Ted Kremenek9d7af512008-04-15 04:11:48 +000092 if (!Live(V, AD)) {
Ted Kremenekc6a1faf2007-09-28 20:48:41 +000093 // Special case: check for initializations with constants.
94 //
95 // e.g. : int x = 0;
96 //
97 // If x is EVER assigned a new value later, don't issue
98 // a warning. This is because such initialization can be
99 // due to defensive programming.
100 if (!E->isConstantExpr(Ctx,NULL)) {
101 // Flag a warning.
102 SourceRange R = E->getSourceRange();
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000103 Diags.Report(&Client,
104 Ctx.getFullLoc(V->getLocation()),
Ted Kremenek3eb817e2008-05-21 22:59:16 +0000105 GetDiag(V), 0, 0, &R, 1);
Ted Kremenekc6a1faf2007-09-28 20:48:41 +0000106 }
Ted Kremenekce1cab92007-09-11 17:24:14 +0000107 }
Ted Kremenekfdd225e2007-09-25 04:31:27 +0000108 }
Ted Kremenekfdd225e2007-09-25 04:31:27 +0000109 }
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +0000110 }
111};
112
113} // end anonymous namespace
114
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000115//===----------------------------------------------------------------------===//
116// Driver function to invoke the Dead-Stores checker on a CFG.
117//===----------------------------------------------------------------------===//
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +0000118
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000119void clang::CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags) {
Ted Kremenek7cb15932008-03-13 16:55:07 +0000120 LiveVariables L(cfg);
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +0000121 L.runOnCFG(cfg);
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000122 DeadStoreObs A(Ctx, Diags, Diags.getClient());
Ted Kremenek7cb15932008-03-13 16:55:07 +0000123 L.runOnAllBlocks(cfg, &A);
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +0000124}
125
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000126//===----------------------------------------------------------------------===//
127// BugReporter-based invocation of the Dead-Stores checker.
128//===----------------------------------------------------------------------===//
129
130namespace {
131
132class VISIBILITY_HIDDEN DiagBugReport : public RangedBugReport {
133 std::list<std::string> Strs;
134 FullSourceLoc L;
135public:
Ted Kremenek95cc1ba2008-04-18 20:54:29 +0000136 DiagBugReport(BugType& D, FullSourceLoc l) :
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000137 RangedBugReport(D, NULL), L(l) {}
138
139 virtual ~DiagBugReport() {}
140 virtual FullSourceLoc getLocation(SourceManager&) { return L; }
141
142 void addString(const std::string& s) { Strs.push_back(s); }
143
144 typedef std::list<std::string>::const_iterator str_iterator;
145 str_iterator str_begin() const { return Strs.begin(); }
146 str_iterator str_end() const { return Strs.end(); }
147};
148
149class VISIBILITY_HIDDEN DiagCollector : public DiagnosticClient {
150 std::list<DiagBugReport> Reports;
Ted Kremenek95cc1ba2008-04-18 20:54:29 +0000151 BugType& D;
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000152public:
153 DiagCollector(BugType& d) : D(d) {}
154
155 virtual ~DiagCollector() {}
156
157 virtual void HandleDiagnostic(Diagnostic &Diags,
158 Diagnostic::Level DiagLevel,
159 FullSourceLoc Pos,
160 diag::kind ID,
161 const std::string *Strs,
162 unsigned NumStrs,
163 const SourceRange *Ranges,
164 unsigned NumRanges) {
165
166 // FIXME: Use a map from diag::kind to BugType, instead of having just
167 // one BugType.
168
169 Reports.push_back(DiagBugReport(D, Pos));
170 DiagBugReport& R = Reports.back();
171
172 for ( ; NumRanges ; --NumRanges, ++Ranges)
173 R.addRange(*Ranges);
174
175 for ( ; NumStrs ; --NumStrs, ++Strs)
176 R.addString(*Strs);
177 }
178
179 // Iterators.
180
181 typedef std::list<DiagBugReport>::iterator iterator;
182 iterator begin() { return Reports.begin(); }
183 iterator end() { return Reports.end(); }
184};
185
Ted Kremenek95cc1ba2008-04-18 20:54:29 +0000186class VISIBILITY_HIDDEN DeadStoresChecker : public BugTypeCacheLocation {
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000187public:
188 virtual const char* getName() const {
189 return "dead store";
190 }
191
192 virtual const char* getDescription() const {
Ted Kremenek1d5d1da2008-04-15 05:31:00 +0000193 return "Value stored to variable is never subsequently read.";
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000194 }
195
196 virtual void EmitWarnings(BugReporter& BR) {
197
198 // Run the dead store checker and collect the diagnostics.
199 DiagCollector C(*this);
200 DeadStoreObs A(BR.getContext(), BR.getDiagnostic(), C);
201 GRExprEngine& Eng = BR.getEngine();
202 Eng.getLiveness().runOnAllBlocks(Eng.getCFG(), &A);
203
204 // Emit the bug reports.
205
206 for (DiagCollector::iterator I = C.begin(), E = C.end(); I != E; ++I)
207 BR.EmitWarning(*I);
208 }
209};
210} // end anonymous namespace
211
212BugType* clang::MakeDeadStoresChecker() {
213 return new DeadStoresChecker();
214}