Hooked up the dead-store checker to the BugReporter interface. Now dead-store
warnings are emitted as part of the warnings registered by GRSimpleVals.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49658 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/DeadStores.cpp b/lib/Analysis/DeadStores.cpp
index 0848336..2e57757 100644
--- a/lib/Analysis/DeadStores.cpp
+++ b/lib/Analysis/DeadStores.cpp
@@ -15,6 +15,8 @@
#include "clang/Analysis/LocalCheckers.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/ASTContext.h"
#include "llvm/Support/Compiler.h"
@@ -26,8 +28,11 @@
class VISIBILITY_HIDDEN DeadStoreObs : public LiveVariables::ObserverTy {
ASTContext &Ctx;
Diagnostic &Diags;
+ DiagnosticClient &Client;
public:
- DeadStoreObs(ASTContext &ctx,Diagnostic &diags) : Ctx(ctx), Diags(diags){}
+ DeadStoreObs(ASTContext &ctx, Diagnostic &diags, DiagnosticClient &client)
+ : Ctx(ctx), Diags(diags), Client(client) {}
+
virtual ~DeadStoreObs() {}
virtual void ObserveStmt(Stmt* S,
@@ -41,7 +46,8 @@
if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
if (VD->hasLocalStorage() && !Live(VD,AD)) {
SourceRange R = B->getRHS()->getSourceRange();
- Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()),
+ Diags.Report(&Client,
+ Ctx.getFullLoc(DR->getSourceRange().getBegin()),
diag::warn_dead_store, 0, 0, &R, 1);
}
}
@@ -63,7 +69,8 @@
if (!E->isConstantExpr(Ctx,NULL)) {
// Flag a warning.
SourceRange R = E->getSourceRange();
- Diags.Report(Ctx.getFullLoc(V->getLocation()),
+ Diags.Report(&Client,
+ Ctx.getFullLoc(V->getLocation()),
diag::warn_dead_store, 0, 0, &R, 1);
}
}
@@ -74,14 +81,103 @@
} // end anonymous namespace
-namespace clang {
+//===----------------------------------------------------------------------===//
+// Driver function to invoke the Dead-Stores checker on a CFG.
+//===----------------------------------------------------------------------===//
-void CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags) {
-
+void clang::CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags) {
LiveVariables L(cfg);
L.runOnCFG(cfg);
- DeadStoreObs A(Ctx, Diags);
+ DeadStoreObs A(Ctx, Diags, Diags.getClient());
L.runOnAllBlocks(cfg, &A);
}
-} // end namespace clang
+//===----------------------------------------------------------------------===//
+// BugReporter-based invocation of the Dead-Stores checker.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class VISIBILITY_HIDDEN DiagBugReport : public RangedBugReport {
+ std::list<std::string> Strs;
+ FullSourceLoc L;
+public:
+ DiagBugReport(const BugType& D, FullSourceLoc l) :
+ RangedBugReport(D, NULL), L(l) {}
+
+ virtual ~DiagBugReport() {}
+ virtual FullSourceLoc getLocation(SourceManager&) { return L; }
+
+ void addString(const std::string& s) { Strs.push_back(s); }
+
+ typedef std::list<std::string>::const_iterator str_iterator;
+ str_iterator str_begin() const { return Strs.begin(); }
+ str_iterator str_end() const { return Strs.end(); }
+};
+
+class VISIBILITY_HIDDEN DiagCollector : public DiagnosticClient {
+ std::list<DiagBugReport> Reports;
+ const BugType& D;
+public:
+ DiagCollector(BugType& d) : D(d) {}
+
+ virtual ~DiagCollector() {}
+
+ virtual void HandleDiagnostic(Diagnostic &Diags,
+ Diagnostic::Level DiagLevel,
+ FullSourceLoc Pos,
+ diag::kind ID,
+ const std::string *Strs,
+ unsigned NumStrs,
+ const SourceRange *Ranges,
+ unsigned NumRanges) {
+
+ // FIXME: Use a map from diag::kind to BugType, instead of having just
+ // one BugType.
+
+ Reports.push_back(DiagBugReport(D, Pos));
+ DiagBugReport& R = Reports.back();
+
+ for ( ; NumRanges ; --NumRanges, ++Ranges)
+ R.addRange(*Ranges);
+
+ for ( ; NumStrs ; --NumStrs, ++Strs)
+ R.addString(*Strs);
+ }
+
+ // Iterators.
+
+ typedef std::list<DiagBugReport>::iterator iterator;
+ iterator begin() { return Reports.begin(); }
+ iterator end() { return Reports.end(); }
+};
+
+class VISIBILITY_HIDDEN DeadStoresChecker : public BugType {
+public:
+ virtual const char* getName() const {
+ return "dead store";
+ }
+
+ virtual const char* getDescription() const {
+ return "Value stored to variable is never used.";
+ }
+
+ virtual void EmitWarnings(BugReporter& BR) {
+
+ // Run the dead store checker and collect the diagnostics.
+ DiagCollector C(*this);
+ DeadStoreObs A(BR.getContext(), BR.getDiagnostic(), C);
+ GRExprEngine& Eng = BR.getEngine();
+ Eng.getLiveness().runOnAllBlocks(Eng.getCFG(), &A);
+
+ // Emit the bug reports.
+
+ for (DiagCollector::iterator I = C.begin(), E = C.end(); I != E; ++I)
+ BR.EmitWarning(*I);
+ }
+};
+} // end anonymous namespace
+
+BugType* clang::MakeDeadStoresChecker() {
+ return new DeadStoresChecker();
+}