[analyzer] Add -analyzer-purge option which can take on multiple values, remove -analyzer-purge=none. (Small refactor as well: move the work of constructing AnalysisManager from the callers to the class itself.)

llvm-svn: 140838
This commit is contained in:
Anna Zaks 2011-09-30 02:03:00 +00:00
parent a4b02c30de
commit 8d4c8e1498
10 changed files with 94 additions and 35 deletions

View 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">,

View 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

View 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;

View 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; }

View 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);

View 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),

View 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();

View 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();

View 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,

View 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;