]> granicus.if.org Git - clang/commitdiff
[analyzer] Add -analyzer-purge option which can take on multiple values, remove ...
authorAnna Zaks <ganna@apple.com>
Fri, 30 Sep 2011 02:03:00 +0000 (02:03 +0000)
committerAnna Zaks <ganna@apple.com>
Fri, 30 Sep 2011 02:03:00 +0000 (02:03 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140838 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Driver/CC1Options.td
include/clang/Frontend/Analyses.def
include/clang/Frontend/AnalyzerOptions.h
include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
lib/Frontend/CompilerInvocation.cpp
lib/StaticAnalyzer/Core/AnalysisManager.cpp
lib/StaticAnalyzer/Core/CoreEngine.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
test/Analysis/null-deref-ps.c

index ad61f6a9f4928cb753e56e3447c070a1f960afdd..45c3a6614147a3280c499023ac08cf0b2a3aff94 100644 (file)
@@ -57,6 +57,10 @@ def analyzer_output : Separate<"-analyzer-output">,
 def analyzer_output_EQ : Joined<"-analyzer-output=">,
   Alias<analyzer_output>;
 
+def analyzer_purge : Separate<"-analyzer-purge">,
+  HelpText<"Source Code Analysis - Dead Symbol Removal Frequency">;
+def analyzer_purge_EQ : Joined<"-analyzer-purge=">, Alias<analyzer_purge>;
+
 def analyzer_opt_analyze_headers : Flag<"-analyzer-opt-analyze-headers">,
   HelpText<"Force the static analyzer to analyze functions defined in header files">;
 def analyzer_opt_analyze_nested_blocks : Flag<"-analyzer-opt-analyze-nested-blocks">,
@@ -68,8 +72,6 @@ def analyze_function : Separate<"-analyze-function">,
 def analyze_function_EQ : Joined<"-analyze-function=">, Alias<analyze_function>;
 def analyzer_eagerly_assume : Flag<"-analyzer-eagerly-assume">,
   HelpText<"Eagerly assume the truth/falseness of some symbolic constraints">;
-def analyzer_no_purge_dead : Flag<"-analyzer-no-purge-dead">,
-  HelpText<"Don't remove dead symbols, bindings, and constraints before processing a statement">;
 def analyzer_no_eagerly_trim_egraph : Flag<"-analyzer-no-eagerly-trim-egraph">,
   HelpText<"Don't eagerly remove uninteresting ExplodedNodes from the ExplodedGraph">;
 def trim_egraph : Flag<"-trim-egraph">,
index f2a3bbd384b8e32fd81d41c07cf28d9a767db049..010f889c0974e31be803093df894aebc4f29d6b3 100644 (file)
@@ -33,8 +33,16 @@ ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", cre
 ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer, true)
 ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer, true)
 
+#ifndef ANALYSIS_PURGE
+#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC)
+#endif
+
+ANALYSIS_PURGE(PurgeStmt,  "statement", "Purge symbols, bindings, and constraints before every statement")
+ANALYSIS_PURGE(PurgeBlock, "block", "Purge symbols, bindings, and constraints before every basic block")
+ANALYSIS_PURGE(PurgeNone,  "none", "Do not purge symbols, bindings, or constraints")
+
 #undef ANALYSIS_STORE
 #undef ANALYSIS_CONSTRAINTS
 #undef ANALYSIS_DIAGNOSTICS
-#undef ANALYSIS_STORE
+#undef ANALYSIS_PURGE
 
index 20e4156ad628417a529f482f466e63e5cd136495..3565a51d0751bad17cbeeacbc40cc1148a326bb1 100644 (file)
@@ -53,6 +53,13 @@ enum AnalysisDiagClients {
 NUM_ANALYSIS_DIAG_CLIENTS
 };
 
+/// AnalysisPurgeModes - Set of available strategies for dead symbol removal.
+enum AnalysisPurgeMode {
+#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) NAME,
+#include "clang/Frontend/Analyses.def"
+NumPurgeModes
+};
+
 class AnalyzerOptions {
 public:
   /// \brief Pair of checker name and enable/disable.
@@ -60,6 +67,7 @@ public:
   AnalysisStores AnalysisStoreOpt;
   AnalysisConstraints AnalysisConstraintsOpt;
   AnalysisDiagClients AnalysisDiagOpt;
+  AnalysisPurgeMode AnalysisPurgeOpt;
   std::string AnalyzeSpecificFunction;
   unsigned MaxNodes;
   unsigned MaxLoop;
@@ -68,7 +76,6 @@ public:
   unsigned AnalyzerDisplayProgress : 1;
   unsigned AnalyzeNestedBlocks : 1;
   unsigned EagerlyAssume : 1;
-  unsigned PurgeDead : 1;
   unsigned TrimGraph : 1;
   unsigned VisualizeEGDot : 1;
   unsigned VisualizeEGUbi : 1;
@@ -83,12 +90,12 @@ public:
     AnalysisStoreOpt = RegionStoreModel;
     AnalysisConstraintsOpt = RangeConstraintsModel;
     AnalysisDiagOpt = PD_HTML;
+    AnalysisPurgeOpt = PurgeStmt;
     ShowCheckerHelp = 0;
     AnalyzeAll = 0;
     AnalyzerDisplayProgress = 0;
     AnalyzeNestedBlocks = 0;
     EagerlyAssume = 0;
-    PurgeDead = 1;
     TrimGraph = 0;
     VisualizeEGDot = 0;
     VisualizeEGUbi = 0;
index 8a1c0bc153ac1b06d53e7f47fd665e5faaf90c2c..9c333ce268fd0a4193ca1d04e26516dc409ee197 100644 (file)
@@ -16,6 +16,7 @@
 #define LLVM_CLANG_GR_ANALYSISMANAGER_H
 
 #include "clang/Analysis/AnalysisContext.h"
+#include "clang/Frontend/AnalyzerOptions.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
 
@@ -60,7 +61,7 @@ class AnalysisManager : public BugReporterData {
 
   bool VisualizeEGDot;
   bool VisualizeEGUbi;
-  bool PurgeDead;
+  AnalysisPurgeMode PurgeDead;
 
   /// EargerlyAssume - A flag indicating how the engine should handle
   //   expressions such as: 'x = (y != 0)'.  When this flag is true then
@@ -82,11 +83,17 @@ public:
                   CheckerManager *checkerMgr,
                   idx::Indexer *idxer,
                   unsigned maxnodes, unsigned maxvisit,
-                  bool vizdot, bool vizubi, bool purge, bool eager, bool trim,
+                  bool vizdot, bool vizubi, AnalysisPurgeMode purge,
+                  bool eager, bool trim,
                   bool inlinecall, bool useUnoptimizedCFG,
                   bool addImplicitDtors, bool addInitializers,
                   bool eagerlyTrimEGraph);
 
+  /// Construct a clone of the given AnalysisManager with the given ASTContext
+  /// and DiagnosticsEngine.
+  AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
+                  AnalysisManager &ParentAM);
+
   ~AnalysisManager() { FlushDiagnostics(); }
   
   void ClearContexts() {
@@ -151,7 +158,7 @@ public:
 
   bool shouldTrimGraph() const { return TrimGraph; }
 
-  bool shouldPurgeDead() const { return PurgeDead; }
+  AnalysisPurgeMode getPurgeMode() const { return PurgeDead; }
 
   bool shouldEagerlyAssume() const { return EagerlyAssume; }
 
index 3426e19c0c2a3d2f1153d01659424903ccf9b4ea..671e3da29541615500370bf4f677d9d047c06704 100644 (file)
@@ -60,6 +60,16 @@ static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) {
   }
 }
 
+static const char *getAnalysisPurgeModeName(AnalysisPurgeMode Kind) {
+  switch (Kind) {
+  default:
+    llvm_unreachable("Unknown analysis client!");
+#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \
+  case NAME: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Serialization (to args)
 //===----------------------------------------------------------------------===//
@@ -80,6 +90,10 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
     Res.push_back("-analyzer-output");
     Res.push_back(getAnalysisDiagClientName(Opts.AnalysisDiagOpt));
   }
+  if (Opts.AnalysisPurgeOpt != PurgeStmt) {
+    Res.push_back("-analyzer-purge");
+    Res.push_back(getAnalysisPurgeModeName(Opts.AnalysisPurgeOpt));
+  }
   if (!Opts.AnalyzeSpecificFunction.empty()) {
     Res.push_back("-analyze-function");
     Res.push_back(Opts.AnalyzeSpecificFunction);
@@ -92,8 +106,6 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
     Res.push_back("-analyzer-opt-analyze-nested-blocks");
   if (Opts.EagerlyAssume)
     Res.push_back("-analyzer-eagerly-assume");
-  if (!Opts.PurgeDead)
-    Res.push_back("-analyzer-no-purge-dead");
   if (Opts.TrimGraph)
     Res.push_back("-trim-egraph");
   if (Opts.VisualizeEGDot)
@@ -930,6 +942,21 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
       Opts.AnalysisDiagOpt = Value;
   }
 
+  if (Arg *A = Args.getLastArg(OPT_analyzer_purge)) {
+    StringRef Name = A->getValue(Args);
+    AnalysisPurgeMode Value = llvm::StringSwitch<AnalysisPurgeMode>(Name)
+#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \
+      .Case(CMDFLAG, NAME)
+#include "clang/Frontend/Analyses.def"
+      .Default(NumPurgeModes);
+    // FIXME: Error handling.
+    if (Value == NumPurgeModes)
+      Diags.Report(diag::err_drv_invalid_value)
+        << A->getAsString(Args) << Name;
+    else
+      Opts.AnalysisPurgeOpt = Value;
+  }
+
   Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help);
   Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz);
   Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph);
@@ -937,7 +964,6 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
   Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress);
   Opts.AnalyzeNestedBlocks =
     Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks);
-  Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead);
   Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume);
   Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function);
   Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG);
index f43ce5ad666a3a98b5c38bb20ca0e3b8a3ecd2d1..17ec70d39b9062abd5a85a6e785a27db867dbdee 100644 (file)
@@ -22,7 +22,8 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
                                  CheckerManager *checkerMgr,
                                  idx::Indexer *idxer,
                                  unsigned maxnodes, unsigned maxvisit,
-                                 bool vizdot, bool vizubi, bool purge,
+                                 bool vizdot, bool vizubi,
+                                 AnalysisPurgeMode purge,
                                  bool eager, bool trim,
                                  bool inlinecall, bool useUnoptimizedCFG,
                                  bool addImplicitDtors, bool addInitializers,
@@ -39,6 +40,32 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
   AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
 }
 
+AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
+                                 AnalysisManager &ParentAM)
+  : AnaCtxMgr(ParentAM.AnaCtxMgr.getUseUnoptimizedCFG(),
+              ParentAM.AnaCtxMgr.getCFGBuildOptions().AddImplicitDtors,
+              ParentAM.AnaCtxMgr.getCFGBuildOptions().AddInitializers),
+    Ctx(ctx), Diags(diags),
+    LangInfo(ParentAM.LangInfo), PD(ParentAM.getPathDiagnosticConsumer()),
+    CreateStoreMgr(ParentAM.CreateStoreMgr),
+    CreateConstraintMgr(ParentAM.CreateConstraintMgr),
+    CheckerMgr(ParentAM.CheckerMgr),
+    Idxer(ParentAM.Idxer),
+    AScope(ScopeDecl),
+    MaxNodes(ParentAM.MaxNodes),
+    MaxVisit(ParentAM.MaxVisit),
+    VisualizeEGDot(ParentAM.VisualizeEGDot),
+    VisualizeEGUbi(ParentAM.VisualizeEGUbi),
+    PurgeDead(ParentAM.PurgeDead),
+    EagerlyAssume(ParentAM.EagerlyAssume),
+    TrimGraph(ParentAM.TrimGraph),
+    InlineCall(ParentAM.InlineCall),
+    EagerlyTrimEGraph(ParentAM.EagerlyTrimEGraph)
+{
+  AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd();
+}
+
+
 AnalysisContext *
 AnalysisManager::getAnalysisContextInAnotherTU(const Decl *D) {
   idx::Entity Ent = idx::Entity::get(const_cast<Decl *>(D), 
index e01c5d1090ad8d259d48e05468b06b996af9cb86..20b86a8fd322cc5f178b0b2abf8142c55785841a 100644 (file)
@@ -784,26 +784,8 @@ void CallEnterNodeBuilder::generateNode(const ProgramState *state) {
     // Create a new AnalysisManager with components of the callee's
     // TranslationUnit.
     // The Diagnostic is  actually shared when we create ASTUnits from AST files.
-    AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(), 
-                         OldMgr.getLangOptions(), 
-                         OldMgr.getPathDiagnosticConsumer(),
-                         OldMgr.getStoreManagerCreator(),
-                         OldMgr.getConstraintManagerCreator(),
-                         OldMgr.getCheckerManager(),
-                         OldMgr.getIndexer(),
-                         OldMgr.getMaxNodes(), OldMgr.getMaxVisit(),
-                         OldMgr.shouldVisualizeGraphviz(),
-                         OldMgr.shouldVisualizeUbigraph(),
-                         OldMgr.shouldPurgeDead(),
-                         OldMgr.shouldEagerlyAssume(),
-                         OldMgr.shouldTrimGraph(),
-                         OldMgr.shouldInlineCall(),
-                     OldMgr.getAnalysisContextManager().getUseUnoptimizedCFG(),
-                     OldMgr.getAnalysisContextManager().
-                         getCFGBuildOptions().AddImplicitDtors,
-                     OldMgr.getAnalysisContextManager().
-                         getCFGBuildOptions().AddInitializers,
-                     OldMgr.shouldEagerlyTrimExplodedGraph());
+    AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(), OldMgr);
+
     // Create the new engine.
     // FIXME: This cast isn't really safe.
     bool GCEnabled = static_cast<ExprEngine&>(Eng.SubEng).isObjCGCEnabled();
index d982a698d3dd376c4c32f9c93d7bea6319af3f3e..da9b70594b42dfa7966c9668e87d59130b296603 100644 (file)
@@ -242,7 +242,7 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
   const LocationContext *LC = EntryNode->getLocationContext();
   SymbolReaper SymReaper(LC, currentStmt, SymMgr, getStoreManager());
 
-  if (AMgr.shouldPurgeDead()) {
+  if (AMgr.getPurgeMode() != PurgeNone) {
     getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper);
 
     const StackFrameContext *SFC = LC->getCurrentStackFrame();
index 75ecb97fb798dc6ea17d478207ca0add940eca8a..876136ba685b9dc5e4b24f579ed6c5fcb244838f 100644 (file)
@@ -152,7 +152,7 @@ public:
                                   /* Indexer */ 0, 
                                   Opts.MaxNodes, Opts.MaxLoop,
                                   Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
-                                  Opts.PurgeDead, Opts.EagerlyAssume,
+                                  Opts.AnalysisPurgeOpt, Opts.EagerlyAssume,
                                   Opts.TrimGraph, Opts.InlineCall,
                                   Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
                                   Opts.CFGAddInitializers,
index f33b9d2b03722729003dacbeabfc51d0c1bab3b8..641dde2075582947e490ceaf222745fc0a46c121 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,experimental.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -analyzer-no-purge-dead -verify %s -Wreturn-type 
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,experimental.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -analyzer-purge=none -verify %s -Wreturn-type
 // RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,deadcode,experimental.core -std=gnu99 -analyzer-store=region -analyzer-constraints=range -verify %s -Wreturn-type 
 
 typedef unsigned uintptr_t;