]> granicus.if.org Git - clang/commitdiff
Added "Dead Stores", a flow-sensitive checker that checks for stores
authorTed Kremenek <kremenek@apple.com>
Thu, 6 Sep 2007 23:00:42 +0000 (23:00 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 6 Sep 2007 23:00:42 +0000 (23:00 +0000)
to variables that are no longer live.  This analysis is built on top
of CFGs and the LiveVariables analysis.

changes to driver:
 added driver option "-check-dead-stores" to run the analysis

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41754 91177308-0d34-0410-b5e6-96231b3b80d8

Analysis/LiveVariables.cpp
Driver/ASTStreamers.cpp
Driver/ASTStreamers.h
Driver/Makefile
Driver/clang.cpp
clang.xcodeproj/project.pbxproj
include/clang/Analysis/LiveVariables.h
include/clang/Basic/DiagnosticKinds.def

index 629065190223aa95b52ce558967cfaa29c8a2749..b5248fe99e34940a83604100b4cc895753198522 100644 (file)
@@ -372,7 +372,7 @@ void LiveVariables::runOnBlock(const CFGBlock* B, LiveVariablesAuditor* Auditor)
 // liveness queries
 //
 
-bool LiveVariables::IsLive(const CFGBlock* B, const Decl* D) const {
+bool LiveVariables::isLive(const CFGBlock* B, const Decl* D) const {
   BlockLivenessMap::const_iterator I = LiveAtBlockEntryMap.find(B);
   assert (I != LiveAtBlockEntryMap.end());
   
@@ -382,6 +382,12 @@ bool LiveVariables::IsLive(const CFGBlock* B, const Decl* D) const {
   return I->second[VI->second.Idx];
 }
 
+bool LiveVariables::isLive(llvm::BitVector& Live, const Decl* D) const {
+  VarInfoMap::const_iterator VI = VarInfos.find(D);
+  assert (VI != VarInfos.end());
+  return Live[VI->second.Idx];
+}
+
 bool LiveVariables::KillsVar(const Stmt* S, const Decl* D) const {
   VarInfoMap::const_iterator VI = VarInfos.find(D);
   assert (VI != VarInfos.end());
@@ -404,6 +410,15 @@ const LiveVariables::VarInfo& LiveVariables::getVarInfo(const Decl* D) const {
   return const_cast<LiveVariables*>(this)->getVarInfo(D);
 }
 
+//===----------------------------------------------------------------------===//
+// Defaults for LiveVariablesAuditor
+
+void LiveVariablesAuditor::AuditStmt(Stmt* S, LiveVariables& L,
+                                     llvm::BitVector& V) {}
+
+void LiveVariablesAuditor::AuditBlockExit(const CFGBlock* B, LiveVariables& L,
+                                          llvm::BitVector& V) {}
+                            
 //===----------------------------------------------------------------------===//
 // printing liveness state for debugging
 //
index b5ea29328e228cf6bd610676d390f8f54de70304..95d39fa35287f2b06be8066e90c76a59a5c4fd28 100644 (file)
@@ -15,6 +15,7 @@
 #include "clang/AST/AST.h"
 #include "clang/AST/CFG.h"
 #include "clang/Analysis/LiveVariables.h"
+#include "clang/Analysis/LocalCheckers.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/ASTStreamer.h"
 using namespace clang;
@@ -209,4 +210,30 @@ void clang::AnalyzeLiveVariables(Preprocessor &PP, unsigned MainFileID)
   ASTStreamer_Terminate(Streamer);
 }
 
+void clang::RunDeadStoresCheck(Preprocessor &PP, unsigned MainFileID,bool Stats)
+{
+  ASTContext Context(PP.getTargetInfo(), PP.getIdentifierTable());
+  ASTStreamerTy *Streamer = ASTStreamer_Init(PP, Context, MainFileID);
+  
+  while (Decl *D = ASTStreamer_ReadTopLevelDecl(Streamer)) {
+    if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {      
+      if (FD->getBody()) {
+        if (CFG* C = CFG::buildCFG(FD->getBody())) {
+          clang::CheckDeadStores(*C,PP);
+        }
+        else
+          fprintf(stderr," Error processing CFG.\n");
+      }
+    }
+  }
+  
+  if (Stats) {
+    fprintf(stderr, "\nSTATISTICS:\n");
+    ASTStreamer_PrintStats(Streamer);
+    Context.PrintStats();
+  }
+  
+  ASTStreamer_Terminate(Streamer);
+}
+
 
index 34ce8647b0e1a41a8933fe5e7c88b36a2d6aa823..f568e8e866e10108faf51150cda2dedc2f32e62d 100644 (file)
@@ -29,6 +29,8 @@ void DumpCFGs(Preprocessor &PP, unsigned MainFileID,
               
 void AnalyzeLiveVariables(Preprocessor &PP, unsigned MainFileID);
 
+void RunDeadStoresCheck(Preprocessor &PP, unsigned MainFileID, bool Stats);
+
 } // end clang namespace
 
 #endif
index eca316e2042cd7f24ea919e7a52bd13fae3dfe3b..3577a2bca14d0765e9e4afdc68e680b513abcef7 100644 (file)
@@ -3,6 +3,6 @@ CPPFLAGS += -I$(PROJ_SRC_DIR)/../include
 CXXFLAGS = -fno-rtti
 
 TOOLNAME = clang
-USEDLIBS = clangCodeGen.a clangSEMA.a clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a LLVMCore.a LLVMSupport.a LLVMSystem.a
+USEDLIBS = clangCodeGen.a clangAnalysis.a clangSEMA.a clangAST.a clangParse.a clangLex.a clangBasic.a LLVMCore.a LLVMSupport.a LLVMSystem.a
 
 include $(LEVEL)/Makefile.common
index ed540aed06e93522968c8f2ba0f6cf66780769cb..79a09f17611c1d7ca91db0106f7a7a3fdcf417b0 100644 (file)
@@ -53,8 +53,9 @@ enum ProgActions {
   ParseASTCheck,                // Parse ASTs and check diagnostics.
   ParseAST,                     // Parse ASTs.
   ParseCFGDump,                 // Parse ASTS. Build CFGs. Print CFGs.
-  ParseCFGView,                 // Parse ASTS. Build CFGs. View CFGs (Graphviz).
+  ParseCFGView,                 // Parse ASTS. Build CFGs. View CFGs.
   AnalysisLiveVariables,        // Print results of live-variable analysis.
+  WarnDeadStores,               // Run DeadStores checker on parsed ASTs.
   ParsePrintCallbacks,          // Parse and print each callback.
   ParseSyntaxOnly,              // Parse and perform semantic analysis.
   ParseNoop,                    // Parse with noop callbacks.
@@ -93,6 +94,8 @@ ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore,
                         "Run parser, then build and view CFGs with Graphviz."),
              clEnumValN(AnalysisLiveVariables, "dump-live-variables",
                         "Print results of live variable analysis."),
+             clEnumValN(WarnDeadStores, "check-dead-stores",
+                        "Flag warnings of stores to dead variables."),
              clEnumValN(EmitLLVM, "emit-llvm",
                         "Build ASTs then convert to LLVM, emit .ll file"),
              clEnumValEnd));
@@ -851,7 +854,10 @@ static void ProcessInputFile(Preprocessor &PP, unsigned MainFileID,
     break;
   case AnalysisLiveVariables:
     AnalyzeLiveVariables(PP, MainFileID);
-    break;  
+    break;
+  case WarnDeadStores:
+    RunDeadStoresCheck(PP, MainFileID, Stats);
+    break;
   case EmitLLVM:
     EmitLLVMFromASTs(PP, MainFileID, Stats);
     break;
index 21ec8d128e85683469aa0c4d9c565c4eae6588c9..0ca23958c7d4da21dd41f84d48841bdb04ff2f4c 100644 (file)
@@ -13,6 +13,7 @@
                1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; };
                1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */; };
                35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */; };
+               355CF6840C90A8D400A08AA3 /* DeadStores.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 355CF6830C90A8D400A08AA3 /* DeadStores.cpp */; };
                356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */; };
                84D9A8880C1A57E100AC7ABC /* AttributeList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */; };
                84D9A88C0C1A581300AC7ABC /* AttributeList.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 84D9A88B0C1A581300AC7ABC /* AttributeList.h */; };
                1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = CodeGen/CGBuiltin.cpp; sourceTree = "<group>"; };
                35260CA40C7F75C000D66CE9 /* ExprCXX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ExprCXX.cpp; path = AST/ExprCXX.cpp; sourceTree = "<group>"; };
                3547129D0C88881300B3E1D5 /* PrettyPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PrettyPrinter.h; path = clang/AST/PrettyPrinter.h; sourceTree = "<group>"; };
+               355CF6820C90A8B600A08AA3 /* LocalCheckers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LocalCheckers.h; path = clang/Analysis/LocalCheckers.h; sourceTree = "<group>"; };
+               355CF6830C90A8D400A08AA3 /* DeadStores.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DeadStores.cpp; path = Analysis/DeadStores.cpp; sourceTree = "<group>"; };
                356EF9B20C8F7DBA006650F5 /* LiveVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LiveVariables.h; path = clang/Analysis/LiveVariables.h; sourceTree = "<group>"; };
                356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LiveVariables.cpp; path = Analysis/LiveVariables.cpp; sourceTree = "<group>"; };
                84D9A8870C1A57E100AC7ABC /* AttributeList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AttributeList.cpp; path = Parse/AttributeList.cpp; sourceTree = "<group>"; };
                        name = Products;
                        sourceTree = "<group>";
                };
+               355CF6850C90A8D600A08AA3 /* LocalCheckers */ = {
+                       isa = PBXGroup;
+                       children = (
+                               355CF6830C90A8D400A08AA3 /* DeadStores.cpp */,
+                       );
+                       name = LocalCheckers;
+                       sourceTree = "<group>";
+               };
                356EF9AF0C8F7DA4006650F5 /* Analysis */ = {
                        isa = PBXGroup;
                        children = (
+                               355CF6820C90A8B600A08AA3 /* LocalCheckers.h */,
                                356EF9B20C8F7DBA006650F5 /* LiveVariables.h */,
                        );
                        name = Analysis;
                        isa = PBXGroup;
                        children = (
                                356EF9B40C8F7DDF006650F5 /* LiveVariables.cpp */,
+                               355CF6850C90A8D600A08AA3 /* LocalCheckers */,
                        );
                        name = Analysis;
                        sourceTree = "<group>";
                                35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */,
                                DE2255FC0C8004E600D370A5 /* ParseDeclCXX.cpp in Sources */,
                                356EF9B50C8F7DDF006650F5 /* LiveVariables.cpp in Sources */,
+                               355CF6840C90A8D400A08AA3 /* DeadStores.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 4f1e5c595a752582d5e9ca7c50fa3f9a977e2c26..c63dc7c0d248a13c9bc0397b0ffe083ab5573fbf 100644 (file)
@@ -30,14 +30,14 @@ namespace clang {
   
 class LiveVariablesAuditor {
 public:
-  virtual ~LiveVariablesAuditor();
+  virtual ~LiveVariablesAuditor() {}
 
   /// AuditStmt - A callback invoked right before invoking the liveness
   ///  transfer function on the given statement.  If the liveness information
   ///  has been previously calculated by running LiveVariables::runOnCFG,
   ///  then V contains the liveness information after the execution of
   ///  the given statement.
-  virtual void AuditStmt(Stmt* S, LiveVariables& L, llvm::BitVector& V) = 0;
+  virtual void AuditStmt(Stmt* S, LiveVariables& L, llvm::BitVector& V);
 
   /// AuditBlockExit - A callback invoked right before invoking the liveness
   ///  transfer function on the given block.  If the liveness information
@@ -45,7 +45,7 @@ public:
   ///  then V contains the liveness information after the execution of
   ///  the given block.
   virtual void AuditBlockExit(const CFGBlock* B, LiveVariables& L,
-                              llvm::BitVector& V) = 0;  
+                              llvm::BitVector& V);  
 };
 
 class LiveVariables {
@@ -100,7 +100,12 @@ public:
   
   /// IsLive - Return true if a variable is live at beginning of a specified
   //    block.
-  bool IsLive(const CFGBlock* B, const Decl* D) const;
+  bool isLive(const CFGBlock* B, const Decl* D) const;
+  
+  /// IsLive - Return true if a variable is live according to the provided
+  ///  livness bitvector.  This is typically used by classes that subclass
+  ///  LiveVariablesAuditor.
+  bool isLive(llvm::BitVector& V, const Decl* D) const;
   
   /// getVarInfo - Return the liveness information associated with a given
   ///  variable.
index 5009fa724eed48cacd2062ea20a19f60bd9c462b..a3249d742b0ccabc98489e2df72718ae1ca9e2a6 100644 (file)
@@ -748,6 +748,9 @@ DIAG(warn_ret_stack_ref, WARNING,
 DIAG(warn_floatingpoint_eq, WARNING,
   "comparing floating point with == or != is unsafe")
 
+// CHECK: stores to variables that are no longer live (dead stores)
+DIAG(warn_dead_store, WARNING, "value stored to variable is never used")
+
 // CFString checking
 DIAG(err_cfstring_literal_not_string_constant, ERROR,
   "CFString literal is not a string constant")