blob: fb241fd5525b3c5abf6da1ba42877ca31a802b17 [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 Kremenek3eb817e2008-05-21 22:59:16 +000023#include <sstream>
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +000024
25using namespace clang;
26
27namespace {
Ted Kremenekfdd225e2007-09-25 04:31:27 +000028
Ted Kremenekc2b51d82008-01-08 18:19:08 +000029class VISIBILITY_HIDDEN DeadStoreObs : public LiveVariables::ObserverTy {
Chris Lattnerc0508f92007-09-15 23:21:08 +000030 ASTContext &Ctx;
31 Diagnostic &Diags;
Ted Kremenekd2f642b2008-04-14 17:39:48 +000032 DiagnosticClient &Client;
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +000033public:
Ted Kremenekd2f642b2008-04-14 17:39:48 +000034 DeadStoreObs(ASTContext &ctx, Diagnostic &diags, DiagnosticClient &client)
35 : Ctx(ctx), Diags(diags), Client(client) {}
36
Ted Kremenekfdd225e2007-09-25 04:31:27 +000037 virtual ~DeadStoreObs() {}
38
Ted Kremenek3eb817e2008-05-21 22:59:16 +000039 unsigned GetDiag(VarDecl* VD) {
40 std::ostringstream os;
41 os << "value stored to '" << VD->getName() << "' is never used";
42 return Diags.getCustomDiagID(Diagnostic::Warning, os.str().c_str());
43 }
44
Ted Kremeneka23157e2008-05-05 23:12:21 +000045 void CheckDeclRef(DeclRefExpr* DR, Expr* Val,
46 const LiveVariables::AnalysisDataTy& AD,
47 const LiveVariables::ValTy& Live) {
48
49 if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
50 if (VD->hasLocalStorage() && !Live(VD, AD)) {
Ted Kremenek3eb817e2008-05-21 22:59:16 +000051 SourceRange R = Val->getSourceRange();
Ted Kremeneka23157e2008-05-05 23:12:21 +000052 Diags.Report(&Client,
53 Ctx.getFullLoc(DR->getSourceRange().getBegin()),
Ted Kremenek3eb817e2008-05-21 22:59:16 +000054 GetDiag(VD), 0, 0, &R, 1);
Ted Kremeneka23157e2008-05-05 23:12:21 +000055 }
56 }
57
Ted Kremenekfdd225e2007-09-25 04:31:27 +000058 virtual void ObserveStmt(Stmt* S,
59 const LiveVariables::AnalysisDataTy& AD,
60 const LiveVariables::ValTy& Live) {
Ted Kremenekce1cab92007-09-11 17:24:14 +000061
Ted Kremenek1c86b152008-04-14 18:28:25 +000062 // Skip statements in macros.
63 if (S->getLocStart().isMacroID())
64 return;
65
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +000066 if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
Ted Kremenekfdd225e2007-09-25 04:31:27 +000067 if (!B->isAssignmentOp()) return; // Skip non-assignments.
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +000068
Ted Kremenekc0576ca2007-09-10 17:36:42 +000069 if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
Ted Kremeneka23157e2008-05-05 23:12:21 +000070 CheckDeclRef(DR, B->getRHS(), AD, Live);
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +000071 }
Ted Kremeneka23157e2008-05-05 23:12:21 +000072 else if (UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
73 if (!U->isIncrementOp())
74 return;
75
76 Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
77
78 if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(Ex))
79 CheckDeclRef(DR, U, AD, Live);
80 }
81 else if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
Ted Kremenekfdd225e2007-09-25 04:31:27 +000082 // Iterate through the decls. Warn if any initializers are complex
83 // expressions that are not live (never used).
Ted Kremenekc967c9d2008-04-14 17:52:13 +000084 for (ScopedDecl* SD = DS->getDecl(); SD; SD = SD->getNextDeclarator()) {
85
86 VarDecl* V = dyn_cast<VarDecl>(SD);
87 if (!V) continue;
88
Ted Kremenekc6a1faf2007-09-28 20:48:41 +000089 if (V->hasLocalStorage())
90 if (Expr* E = V->getInit()) {
Ted Kremenek9d7af512008-04-15 04:11:48 +000091 if (!Live(V, AD)) {
Ted Kremenekc6a1faf2007-09-28 20:48:41 +000092 // Special case: check for initializations with constants.
93 //
94 // e.g. : int x = 0;
95 //
96 // If x is EVER assigned a new value later, don't issue
97 // a warning. This is because such initialization can be
98 // due to defensive programming.
99 if (!E->isConstantExpr(Ctx,NULL)) {
100 // Flag a warning.
101 SourceRange R = E->getSourceRange();
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000102 Diags.Report(&Client,
103 Ctx.getFullLoc(V->getLocation()),
Ted Kremenek3eb817e2008-05-21 22:59:16 +0000104 GetDiag(V), 0, 0, &R, 1);
Ted Kremenekc6a1faf2007-09-28 20:48:41 +0000105 }
Ted Kremenekce1cab92007-09-11 17:24:14 +0000106 }
Ted Kremenekfdd225e2007-09-25 04:31:27 +0000107 }
Ted Kremenekfdd225e2007-09-25 04:31:27 +0000108 }
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +0000109 }
110};
111
112} // end anonymous namespace
113
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000114//===----------------------------------------------------------------------===//
115// Driver function to invoke the Dead-Stores checker on a CFG.
116//===----------------------------------------------------------------------===//
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +0000117
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000118void clang::CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags) {
Ted Kremenek7cb15932008-03-13 16:55:07 +0000119 LiveVariables L(cfg);
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +0000120 L.runOnCFG(cfg);
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000121 DeadStoreObs A(Ctx, Diags, Diags.getClient());
Ted Kremenek7cb15932008-03-13 16:55:07 +0000122 L.runOnAllBlocks(cfg, &A);
Ted Kremenek1ed6d2e2007-09-06 23:01:46 +0000123}
124
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000125//===----------------------------------------------------------------------===//
126// BugReporter-based invocation of the Dead-Stores checker.
127//===----------------------------------------------------------------------===//
128
129namespace {
130
131class VISIBILITY_HIDDEN DiagBugReport : public RangedBugReport {
132 std::list<std::string> Strs;
133 FullSourceLoc L;
134public:
Ted Kremenek95cc1ba2008-04-18 20:54:29 +0000135 DiagBugReport(BugType& D, FullSourceLoc l) :
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000136 RangedBugReport(D, NULL), L(l) {}
137
138 virtual ~DiagBugReport() {}
139 virtual FullSourceLoc getLocation(SourceManager&) { return L; }
140
141 void addString(const std::string& s) { Strs.push_back(s); }
142
143 typedef std::list<std::string>::const_iterator str_iterator;
144 str_iterator str_begin() const { return Strs.begin(); }
145 str_iterator str_end() const { return Strs.end(); }
146};
147
148class VISIBILITY_HIDDEN DiagCollector : public DiagnosticClient {
149 std::list<DiagBugReport> Reports;
Ted Kremenek95cc1ba2008-04-18 20:54:29 +0000150 BugType& D;
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000151public:
152 DiagCollector(BugType& d) : D(d) {}
153
154 virtual ~DiagCollector() {}
155
156 virtual void HandleDiagnostic(Diagnostic &Diags,
157 Diagnostic::Level DiagLevel,
158 FullSourceLoc Pos,
159 diag::kind ID,
160 const std::string *Strs,
161 unsigned NumStrs,
162 const SourceRange *Ranges,
163 unsigned NumRanges) {
164
165 // FIXME: Use a map from diag::kind to BugType, instead of having just
166 // one BugType.
167
168 Reports.push_back(DiagBugReport(D, Pos));
169 DiagBugReport& R = Reports.back();
170
171 for ( ; NumRanges ; --NumRanges, ++Ranges)
172 R.addRange(*Ranges);
173
174 for ( ; NumStrs ; --NumStrs, ++Strs)
175 R.addString(*Strs);
176 }
177
178 // Iterators.
179
180 typedef std::list<DiagBugReport>::iterator iterator;
181 iterator begin() { return Reports.begin(); }
182 iterator end() { return Reports.end(); }
183};
184
Ted Kremenek95cc1ba2008-04-18 20:54:29 +0000185class VISIBILITY_HIDDEN DeadStoresChecker : public BugTypeCacheLocation {
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000186public:
187 virtual const char* getName() const {
188 return "dead store";
189 }
190
191 virtual const char* getDescription() const {
Ted Kremenek1d5d1da2008-04-15 05:31:00 +0000192 return "Value stored to variable is never subsequently read.";
Ted Kremenekd2f642b2008-04-14 17:39:48 +0000193 }
194
195 virtual void EmitWarnings(BugReporter& BR) {
196
197 // Run the dead store checker and collect the diagnostics.
198 DiagCollector C(*this);
199 DeadStoreObs A(BR.getContext(), BR.getDiagnostic(), C);
200 GRExprEngine& Eng = BR.getEngine();
201 Eng.getLiveness().runOnAllBlocks(Eng.getCFG(), &A);
202
203 // Emit the bug reports.
204
205 for (DiagCollector::iterator I = C.begin(), E = C.end(); I != E; ++I)
206 BR.EmitWarning(*I);
207 }
208};
209} // end anonymous namespace
210
211BugType* clang::MakeDeadStoresChecker() {
212 return new DeadStoresChecker();
213}