[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:
parent
a4b02c30de
commit
8d4c8e1498
|
@ -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">,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue