[cfe-commits] r52996 - in /cfe/trunk: Driver/ASTConsumers.cpp Driver/ASTConsumers.h Driver/AnalysisConsumer.cpp Driver/AnalysisConsumer.h Driver/clang.cpp test/Analysis/conditional-op-missing-lhs.c

Ted Kremenek kremenek at apple.com
Tue Jul 1 17:03:09 PDT 2008


Author: kremenek
Date: Tue Jul  1 19:03:09 2008
New Revision: 52996

URL: http://llvm.org/viewvc/llvm-project?rev=52996&view=rev
Log:
Added AnalysisConsumer, a meta-level ASTConsumer class to drive various
analyses. This potentially is the primordial origins of a Clang-equivalent
"PassManager".

The new AnalysisConsumer interface allows multiple analyses to be run from a
single invocation of Clang.

Migrated the logic of "-warn-dead-stores" and "-warn-uninit-values" to use the
new AnalysisConsumer interface. The new interface results in a significant code
reduction to incorporate an analysis into the Driver.

Updated a test case to (correctly) acknowledge that it contains a dead store
(this check wasn't being performed because it was previously masked by
-warn-uninit-values).

Added:
    cfe/trunk/Driver/AnalysisConsumer.cpp
    cfe/trunk/Driver/AnalysisConsumer.h
Modified:
    cfe/trunk/Driver/ASTConsumers.cpp
    cfe/trunk/Driver/ASTConsumers.h
    cfe/trunk/Driver/clang.cpp
    cfe/trunk/test/Analysis/conditional-op-missing-lhs.c

Modified: cfe/trunk/Driver/ASTConsumers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/ASTConsumers.cpp?rev=52996&r1=52995&r2=52996&view=diff

==============================================================================
--- cfe/trunk/Driver/ASTConsumers.cpp (original)
+++ cfe/trunk/Driver/ASTConsumers.cpp Tue Jul  1 19:03:09 2008
@@ -635,58 +635,6 @@
 }
 
 //===----------------------------------------------------------------------===//
-// DeadStores - run checker to locate dead stores in a function
-
-namespace {
-  class DeadStoreVisitor : public CFGVisitor {
-    Diagnostic &Diags;
-    ASTContext *Ctx;
-  public:
-    DeadStoreVisitor(Diagnostic &diags) : Diags(diags) {}
-    virtual void Initialize(ASTContext &Context) {
-      Ctx = &Context;
-    }
-    
-    virtual void VisitCFG(CFG& C, Decl& CD) {
-      llvm::OwningPtr<ParentMap> PM(new ParentMap(CD.getCodeBody()));
-      CheckDeadStores(C, *Ctx, *PM, Diags);
-    }
-    
-    virtual bool printFuncDeclStart() { return false; }
-  }; 
-} // end anonymous namespace
-
-ASTConsumer *clang::CreateDeadStoreChecker(Diagnostic &Diags) {
-  return new DeadStoreVisitor(Diags);
-}
-
-//===----------------------------------------------------------------------===//
-// Unitialized Values - run checker to flag potential uses of uninitalized
-//  variables.
-
-namespace {
-  class UninitValsVisitor : public CFGVisitor {
-    Diagnostic &Diags;
-    ASTContext *Ctx;
-  public:
-    UninitValsVisitor(Diagnostic &diags) : Diags(diags) {}
-    virtual void Initialize(ASTContext &Context) {
-      Ctx = &Context;
-    }
-    
-    virtual void VisitCFG(CFG& C, Decl&) { 
-      CheckUninitializedValues(C, *Ctx, Diags);
-    }
-    
-    virtual bool printFuncDeclStart() { return false; }
-  }; 
-} // end anonymous namespace
-
-ASTConsumer *clang::CreateUnitValsChecker(Diagnostic &Diags) {
-  return new UninitValsVisitor(Diags);
-}
-
-//===----------------------------------------------------------------------===//
 // CheckerConsumer - Generic Driver for running intra-procedural path-sensitive
 //  analyses.
 

Modified: cfe/trunk/Driver/ASTConsumers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/ASTConsumers.h?rev=52996&r1=52995&r2=52996&view=diff

==============================================================================
--- cfe/trunk/Driver/ASTConsumers.h (original)
+++ cfe/trunk/Driver/ASTConsumers.h Tue Jul  1 19:03:09 2008
@@ -30,7 +30,6 @@
 class Preprocessor;
 class PreprocessorFactory;
 
-
 ASTConsumer *CreateASTPrinter(std::ostream* OS = NULL);
 
 ASTConsumer *CreateASTDumper();
@@ -41,10 +40,6 @@
 
 ASTConsumer *CreateLiveVarAnalyzer(const std::string& fname);
 
-ASTConsumer *CreateDeadStoreChecker(Diagnostic &Diags);
-
-ASTConsumer *CreateUnitValsChecker(Diagnostic &Diags);
-  
 ASTConsumer *CreateGRSimpleVals(Diagnostic &Diags,
                                 Preprocessor* PP, PreprocessorFactory* PPF,
                                 const std::string& Function,
@@ -75,4 +70,6 @@
 
 } // end clang namespace
 
+#include "AnalysisConsumer.h"
+
 #endif

Added: cfe/trunk/Driver/AnalysisConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/AnalysisConsumer.cpp?rev=52996&view=auto

==============================================================================
--- cfe/trunk/Driver/AnalysisConsumer.cpp (added)
+++ cfe/trunk/Driver/AnalysisConsumer.cpp Tue Jul  1 19:03:09 2008
@@ -0,0 +1,248 @@
+//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// "Meta" ASTConsumer for running different source analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTConsumers.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "clang/AST/CFG.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+
+using namespace clang;
+
+  
+//===----------------------------------------------------------------------===//
+// Basic type definitions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+  
+  class AnalysisManager;
+  typedef void (*CodeAction)(AnalysisManager& Mgr);    
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer declaration.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+  class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
+    typedef llvm::ImmutableList<CodeAction> Actions;
+    Actions FunctionActions;
+    Actions ObjCMethodActions;
+
+    Actions::Factory F;
+    
+  public:
+    const bool Visualize;
+    const bool TrimGraph;
+    const LangOptions& LOpts;
+    Diagnostic &Diags;
+    ASTContext* Ctx;
+    Preprocessor* PP;
+    PreprocessorFactory* PPF;
+    const std::string HTMLDir;
+    const std::string FName;
+    llvm::OwningPtr<PathDiagnosticClient> PD;
+    bool AnalyzeAll;  
+
+    AnalysisConsumer(Diagnostic &diags, Preprocessor* pp,
+                     PreprocessorFactory* ppf,
+                     const LangOptions& lopts,
+                     const std::string& fname,
+                     const std::string& htmldir,
+                     bool visualize, bool trim, bool analyzeAll) 
+      : FunctionActions(F.GetEmptyList()), ObjCMethodActions(F.GetEmptyList()),
+        Visualize(visualize), TrimGraph(trim), LOpts(lopts), Diags(diags),
+        Ctx(0), PP(pp), PPF(ppf),
+        HTMLDir(htmldir),
+        FName(fname),
+        AnalyzeAll(analyzeAll) {}
+    
+    void addCodeAction(CodeAction action) {
+      FunctionActions = F.Concat(action, FunctionActions);
+      ObjCMethodActions = F.Concat(action, ObjCMethodActions);      
+    }
+    
+    virtual void Initialize(ASTContext &Context) {
+      Ctx = &Context;
+    }
+    
+    virtual void HandleTopLevelDecl(Decl *D);
+    void HandleCode(Decl* D, Stmt* Body, Actions actions);
+  };
+    
+  
+  class VISIBILITY_HIDDEN AnalysisManager {
+    Decl* D;
+    Stmt* Body;    
+    AnalysisConsumer& C;
+    
+    llvm::OwningPtr<CFG> cfg;
+    llvm::OwningPtr<LiveVariables> liveness;
+    llvm::OwningPtr<ParentMap> PM;
+
+  public:
+    AnalysisManager(AnalysisConsumer& c, Decl* d, Stmt* b) 
+    : D(d), Body(b), C(c) {}
+    
+    
+    Decl* getCodeDecl() const { return D; }
+    Stmt* getBody() const { return Body; }
+    
+    CFG* getCFG() {
+      if (!cfg) cfg.reset(CFG::buildCFG(getBody()));
+      return cfg.get();
+    }
+    
+    ParentMap* getParentMap() {
+      if (!PM) PM.reset(new ParentMap(getBody()));
+      return PM.get();
+    }
+    
+    ASTContext& getContext() {
+      return *C.Ctx;
+    }
+    
+    Diagnostic& getDiagnostic() {
+      return C.Diags;
+    }
+      
+    LiveVariables* getLiveVariables() {
+      if (!liveness) liveness.reset(new LiveVariables(*getCFG()));
+      return liveness.get();
+    }
+  };
+  
+} // end anonymous namespace
+
+namespace llvm {
+  template <> struct FoldingSetTrait<CodeAction> {
+    static inline void Profile(CodeAction X, FoldingSetNodeID& ID) {
+      ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
+    }
+  };   
+}
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer implementation.
+//===----------------------------------------------------------------------===//
+
+void AnalysisConsumer::HandleTopLevelDecl(Decl *D) { 
+  switch (D->getKind()) {
+    case Decl::Function: {
+      FunctionDecl* FD = cast<FunctionDecl>(D);
+      Stmt* Body = FD->getBody();
+      if (Body) HandleCode(FD, Body, FunctionActions);
+      break;
+    }
+      
+    case Decl::ObjCMethod: {
+      ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
+      Stmt* Body = MD->getBody();
+      if (Body) HandleCode(MD, Body, ObjCMethodActions);
+      break;
+    }
+      
+    default:
+      break;
+  }
+}
+
+void AnalysisConsumer::HandleCode(Decl* D, Stmt* Body, Actions actions) {
+  
+  // Don't run the actions if an error has occured with parsing the file.
+  if (Diags.hasErrorOccurred())
+    return;
+  
+  SourceLocation Loc = D->getLocation();
+  
+  // Only run actions on declarations defined in actual source.
+  if (!Loc.isFileID())
+    return;
+  
+  // Don't run the actions on declarations in header files unless
+  // otherwise specified.
+  if (!AnalyzeAll && !Ctx->getSourceManager().isFromMainFile(Loc))
+    return;  
+
+  // Create an AnalysisManager that will manage the state for analyzing
+  // this method/function.
+  AnalysisManager mgr(*this, D, Body);
+  
+  // Dispatch on the actions.  
+  for (Actions::iterator I = actions.begin(), 
+                         E = actions.end(); I != E; ++I)
+    ((*I).getHead())(mgr);  
+}
+
+//===----------------------------------------------------------------------===//
+// Analyses
+//===----------------------------------------------------------------------===//
+
+static void ActionDeadStores(AnalysisManager& mgr) {
+  CheckDeadStores(*mgr.getCFG(), mgr.getContext(), *mgr.getParentMap(),
+                  mgr.getDiagnostic());
+}
+
+static void ActionUninitVals(AnalysisManager& mgr) {
+  CheckUninitializedValues(*mgr.getCFG(), mgr.getContext(),
+                           mgr.getDiagnostic());
+}
+
+//===----------------------------------------------------------------------===//
+// AnalysisConsumer creation.
+//===----------------------------------------------------------------------===//
+
+ASTConsumer* clang::CreateAnalysisConsumer(Analyses* Beg, Analyses* End,
+                                           Diagnostic &diags, Preprocessor* pp,
+                                           PreprocessorFactory* ppf,
+                                           const LangOptions& lopts,
+                                           const std::string& fname,
+                                           const std::string& htmldir,
+                                           bool visualize, bool trim,
+                                           bool analyzeAll) {
+  
+  llvm::OwningPtr<AnalysisConsumer>
+  C(new AnalysisConsumer(diags, pp, ppf, lopts, fname, htmldir,
+                         visualize, trim, analyzeAll));
+  
+  for ( ; Beg != End ; ++Beg)
+    switch (*Beg) {
+      case WarnDeadStores:
+        C->addCodeAction(&ActionDeadStores);
+        break;
+        
+      case WarnUninitVals:
+        C->addCodeAction(&ActionUninitVals);
+        break;
+        
+      default: break;
+    }
+  
+  return C.take();
+}
+

Added: cfe/trunk/Driver/AnalysisConsumer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/AnalysisConsumer.h?rev=52996&view=auto

==============================================================================
--- cfe/trunk/Driver/AnalysisConsumer.h (added)
+++ cfe/trunk/Driver/AnalysisConsumer.h Tue Jul  1 19:03:09 2008
@@ -0,0 +1,34 @@
+//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// "Meta" ASTConsumer for running different source analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef DRIVER_ANALYSISCONSUMER_H
+#define DRIVER_ANALYSISCONSUMER_H
+
+namespace clang {
+
+enum Analyses {
+  WarnDeadStores,
+  WarnUninitVals
+};
+  
+ASTConsumer* CreateAnalysisConsumer(Analyses* Beg, Analyses* End,
+                                    Diagnostic &diags, Preprocessor* pp,
+                                    PreprocessorFactory* ppf,
+                                    const LangOptions& lopts,
+                                    const std::string& fname,
+                                    const std::string& htmldir,
+                                    bool visualize, bool trim,
+                                    bool analyzeAll);
+} // end clang namespace
+
+#endif

Modified: cfe/trunk/Driver/clang.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/clang.cpp?rev=52996&r1=52995&r2=52996&view=diff

==============================================================================
--- cfe/trunk/Driver/clang.cpp (original)
+++ cfe/trunk/Driver/clang.cpp Tue Jul  1 19:03:09 2008
@@ -78,16 +78,14 @@
   AnalysisGRSimpleVals,         // Perform graph-reachability constant prop.
   AnalysisGRSimpleValsView,     // Visualize results of path-sens. analysis.
   CheckerCFRef,                 // Run the Core Foundation Ref. Count Checker.
-  WarnDeadStores,               // Run DeadStores checker on parsed ASTs.
-  WarnDeadStoresCheck,          // Check diagnostics for "DeadStores".
-  WarnUninitVals,               // Run UnitializedVariables checker.
   TestSerialization,            // Run experimental serialization code.
   ParsePrintCallbacks,          // Parse and print each callback.
   ParseSyntaxOnly,              // Parse and perform semantic analysis.
   ParseNoop,                    // Parse with noop callbacks.
   RunPreprocessorOnly,          // Just lex, no output.
   PrintPreprocessedInput,       // -E mode.
-  DumpTokens                    // Token dump mode.
+  DumpTokens,                   // Token dump mode.
+  RunAnalysis                   // Run one or more source code analyses. 
 };
 
 static llvm::cl::opt<ProgActions> 
@@ -120,10 +118,6 @@
                         "Run parser, then build and view CFGs with Graphviz"),
              clEnumValN(AnalysisLiveVariables, "dump-live-variables",
                         "Print results of live variable analysis"),
-             clEnumValN(WarnDeadStores, "warn-dead-stores",
-                        "Flag warnings of stores to dead variables"),
-             clEnumValN(WarnUninitVals, "warn-uninit-values",
-                        "Flag warnings of uses of unitialized variables"),
              clEnumValN(AnalysisGRSimpleVals, "checker-simple",
                         "Perform path-sensitive constant propagation"),
              clEnumValN(CheckerCFRef, "checker-cfref",
@@ -181,6 +175,15 @@
     llvm::cl::desc("Force the static analyzer to analyze "
                    "functions defined in header files"));
 
+static llvm::cl::list<Analyses>
+AnalysisList(llvm::cl::desc("Available Source Code Analyses:"),
+llvm::cl::values(
+clEnumValN(WarnDeadStores, "warn-dead-stores",
+           "Flag warnings of stores to dead variables"),
+clEnumValN(WarnUninitVals, "warn-uninit-values",
+           "Flag warnings of uses of unitialized variables"),
+clEnumValEnd));          
+
 //===----------------------------------------------------------------------===//
 // Language Options
 //===----------------------------------------------------------------------===//
@@ -1199,12 +1202,6 @@
     case AnalysisLiveVariables:
       return CreateLiveVarAnalyzer(AnalyzeSpecificFunction);
       
-    case WarnDeadStores:    
-      return CreateDeadStoreChecker(Diag);
-      
-    case WarnUninitVals:
-      return CreateUnitValsChecker(Diag);
-      
     case AnalysisGRSimpleVals:
       return CreateGRSimpleVals(Diag, PP, PPF, AnalyzeSpecificFunction,
                                 OutputFile, VisualizeEG, TrimGraph, AnalyzeAll);
@@ -1228,6 +1225,15 @@
       
     case RewriteObjC:
       return CreateCodeRewriterTest(InFile, OutputFile, Diag, LangOpts);
+      
+    case RunAnalysis:
+      assert (!AnalysisList.empty());
+      return CreateAnalysisConsumer(&AnalysisList[0],
+                                    &AnalysisList[0]+AnalysisList.size(),
+                                    Diag, PP, PPF, LangOpts,
+                                    AnalyzeSpecificFunction,
+                                    OutputFile, VisualizeEG, TrimGraph,
+                                    AnalyzeAll);
   }
 }
 
@@ -1485,6 +1491,11 @@
     exit(1);
   }
   
+  // Are we invoking one or more source analyses?
+  if (!AnalysisList.empty() && ProgAction == ParseSyntaxOnly)
+    ProgAction = RunAnalysis;  
+  
+  
   llvm::OwningPtr<SourceManager> SourceMgr;
   
   for (unsigned i = 0, e = InputFilenames.size(); i != e; ++i) {

Modified: cfe/trunk/test/Analysis/conditional-op-missing-lhs.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/conditional-op-missing-lhs.c?rev=52996&r1=52995&r2=52996&view=diff

==============================================================================
--- cfe/trunk/test/Analysis/conditional-op-missing-lhs.c (original)
+++ cfe/trunk/test/Analysis/conditional-op-missing-lhs.c Tue Jul  1 19:03:09 2008
@@ -4,7 +4,7 @@
 {
 	int i;
 	
-	int j = i ? : 1; // expected-warning{{use of uninitialized variable}}
+	int j = i ? : 1; // expected-warning{{use of uninitialized variable}} //expected-warning{{Value stored to 'j' is never read}}
 }
 
 void *f2(int *i)





More information about the cfe-commits mailing list