[analyzer] Evaluate all non-checker config options before analysis

In earlier patches regarding AnalyzerOptions, a lot of effort went into
gathering all config options, and changing the interface so that potential
misuse can be eliminited.

Up until this point, AnalyzerOptions only evaluated an option when it was
querried. For example, if we had a "-no-false-positives" flag, AnalyzerOptions
would store an Optional field for it that would be None up until somewhere in
the code until the flag's getter function is called.

However, now that we're confident that we've gathered all configs, we can
evaluate off of them before analysis, so we can emit a error on invalid input
even if that prticular flag will not matter in that particular run of the
analyzer. Another very big benefit of this is that debug.ConfigDumper will now
show the value of all configs every single time.

Also, almost all options related class have a similar interface, so uniformity
is also a benefit.

The implementation for errors on invalid input will be commited shorty.

Differential Revision: https://reviews.llvm.org/D53692

llvm-svn: 348031
This commit is contained in:
Kristof Umann 2018-11-30 20:44:00 +00:00
parent be3f4bd36b
commit 549f9cd46f
22 changed files with 367 additions and 482 deletions

View File

@ -9,29 +9,6 @@
//
// This file defines the analyzer options avaible with -analyzer-config.
//
// This file is in part intended for method generation. If it's not included
// for that purpose, the following function-like macros should be predefined,
// through which all registered options are accessible:
//
// * ANALYZER_OPTION: Register a new option.
// * ANALYZER_OPTION_DEPENDS_ON_USER_MODE: Register a new option, default
// value depends on the "user-mode" option.
//
// Options where a simple getter method is sufficient are registered with the
// following macros:
//
// * ANALYZER_OPTION_GEN_FN: Register a new option, and generate a getter
// method for it in AnalyzerOptions.
//
// * ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE: Same as above, but
// generates a getter function that depends on the "user-mode" option.
//
// You can only include this file when both or none of the above two macros
// are defined!
// When they are defined, entries that do not generate functions won't appear,
// and when they aren't, all entries are converted to ANALYZER_OPTION or to
// ANALYZER_OPTION_DEPENDS_ON_USER_MODE.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ADT_STRINGREF_H
@ -53,22 +30,6 @@ define both 'ANALYZER_OPTION' and 'ANALYZER_OPTION_DEPENDS_ON_USER_MODE' macros!
#endif
#endif
#ifdef ANALYZER_OPTION_GEN_FN
#ifndef ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE
#error If you include this file with the intent of generating functions, \
define both 'ANALYZER_OPTION_GEN_FN' and \
'ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE' macros!
#endif
#endif
#ifdef ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE
#ifndef ANALYZER_OPTION_GEN_FN
#error If you include this file with the intent of generating functions, \
define both 'ANALYZER_OPTION_GEN_FN' and \
'ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE' macros!
#endif
#endif
#ifndef ANALYZER_OPTION
/// Create a new analyzer option, but dont generate a method for it in
/// AnalyzerOptions.
@ -105,231 +66,187 @@ define both 'ANALYZER_OPTION_GEN_FN' and \
SHALLOW_VAL, DEEP_VAL)
#endif
#ifndef ANALYZER_OPTION_GEN_FN
/// Create a new analyzer option, and generate a getter method for it in
/// AnalyzerOptions.
///
/// TYPE - The type of the option object that will be stored in
/// AnalyzerOptions. This file is expected to be icluded in translation
/// units where AnalyzerOptions.h is included, so types from that
/// header should be used.
/// NAME - The name of the option object.
/// CMDFLAG - The command line flag for the option.
/// (-analyzer-config CMDFLAG=VALUE)
/// DESC - Description of the flag.
/// DEFAULT_VAL - The default value for CMDFLAG.
/// CREATE_FN - Name of the getter function.
//
// If this def file wasn't included with the intent of generating functions,
// regard all entries as ANALYZER_OPTION.
#define ANALYZER_OPTION_GEN_FN(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL, \
CREATE_FN) \
ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL)
#endif
//===----------------------------------------------------------------------===//
// The "mode" option. Since some options depend on this, we list it on top of
// this file in order to make sure that the generated field for it is
// initialized before the rest.
//===----------------------------------------------------------------------===//
#ifndef ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE
/// Create a new analyzer option, and generate a getter method for it in
/// AnalyzerOptions, and make it's default value depend on the "user-mode"
/// option.
///
/// TYPE - The type of the option object that will be stored in
/// AnalyzerOptions. This file is expected to be icluded in translation
/// units where AnalyzerOptions.h is included, so types from that
/// header should be used.
/// NAME - The name of the option object.
/// CMDFLAG - The command line flag for the option.
/// (-analyzer-config CMDFLAG=VALUE)
/// DESC - Description of the flago.
/// SHALLOW_VAL - The default value for CMDFLAG, when "user-mode" was set to
/// "shallow".
/// DEEP_VAL - The default value for CMDFLAG, when "user-mode" was set to
/// "deep".
/// CREATE_FN - Name of the getter function.
//
// If this def file wasn't included with the intent of generating functions,
// regard all entries as ANALYZER_OPTION_DEPENDS_ON_USER_MODE.
#define ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE( \
TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL, DEEP_VAL, CREATE_FN) \
ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL, \
DEEP_VAL)
#endif
ANALYZER_OPTION(
StringRef, UserMode, "mode",
"(string) Controls the high-level analyzer mode, which influences the "
"default settings for some of the lower-level config options (such as "
"IPAMode). Value: \"deep\", \"shallow\".",
"deep")
//===----------------------------------------------------------------------===//
// Boolean analyzer options.
//===----------------------------------------------------------------------===//
ANALYZER_OPTION_GEN_FN(bool, IncludeImplicitDtorsInCFG, "cfg-implicit-dtors",
"Whether or not implicit destructors for C++ objects "
"should be included in the CFG.",
true, includeImplicitDtorsInCFG)
ANALYZER_OPTION(bool, ShouldIncludeImplicitDtorsInCFG, "cfg-implicit-dtors",
"Whether or not implicit destructors for C++ objects "
"should be included in the CFG.",
true)
ANALYZER_OPTION_GEN_FN(bool, IncludeTemporaryDtorsInCFG, "cfg-temporary-dtors",
"Whether or not the destructors for C++ temporary "
"objects should be included in the CFG.",
true, includeTemporaryDtorsInCFG)
ANALYZER_OPTION(bool, ShouldIncludeTemporaryDtorsInCFG, "cfg-temporary-dtors",
"Whether or not the destructors for C++ temporary "
"objects should be included in the CFG.",
true)
ANALYZER_OPTION_GEN_FN(
bool, IncludeLifetimeInCFG, "cfg-lifetime",
ANALYZER_OPTION(
bool, ShouldIncludeLifetimeInCFG, "cfg-lifetime",
"Whether or not end-of-lifetime information should be included in the CFG.",
false, includeLifetimeInCFG)
false)
ANALYZER_OPTION_GEN_FN(bool, IncludeLoopExitInCFG, "cfg-loopexit",
"Whether or not the end of the loop information should "
"be included in the CFG.",
false, includeLoopExitInCFG)
ANALYZER_OPTION(bool, ShouldIncludeLoopExitInCFG, "cfg-loopexit",
"Whether or not the end of the loop information should "
"be included in the CFG.",
false)
ANALYZER_OPTION_GEN_FN(bool, IncludeRichConstructorsInCFG,
"cfg-rich-constructors",
"Whether or not construction site information should be "
"included in the CFG C++ constructor elements.",
true, includeRichConstructorsInCFG)
ANALYZER_OPTION(bool, ShouldIncludeRichConstructorsInCFG,
"cfg-rich-constructors",
"Whether or not construction site information should be "
"included in the CFG C++ constructor elements.",
true)
ANALYZER_OPTION_GEN_FN(
bool, IncludeScopesInCFG, "cfg-scopes",
"Whether or not scope information should be included in the CFG.", false,
includeScopesInCFG)
ANALYZER_OPTION(
bool, ShouldIncludeScopesInCFG, "cfg-scopes",
"Whether or not scope information should be included in the CFG.", false)
ANALYZER_OPTION_GEN_FN(
bool, InlineTemplateFunctions, "c++-template-inlining",
"Whether or not templated functions may be considered for inlining.", true,
mayInlineTemplateFunctions)
ANALYZER_OPTION(
bool, MayInlineTemplateFunctions, "c++-template-inlining",
"Whether or not templated functions may be considered for inlining.", true)
ANALYZER_OPTION_GEN_FN(bool, InlineCXXStandardLibrary, "c++-stdlib-inlining",
"Whether or not C++ standard library functions may be "
"considered for inlining.",
true, mayInlineCXXStandardLibrary)
ANALYZER_OPTION(bool, MayInlineCXXStandardLibrary, "c++-stdlib-inlining",
"Whether or not C++ standard library functions may be "
"considered for inlining.",
true)
ANALYZER_OPTION_GEN_FN(
bool, InlineCXXAllocator, "c++-allocator-inlining",
"Whether or not allocator call may be considered for inlining.", true,
mayInlineCXXAllocator)
ANALYZER_OPTION(bool, MayInlineCXXAllocator, "c++-allocator-inlining",
"Whether or not allocator call may be considered for inlining.",
true)
ANALYZER_OPTION_GEN_FN(
bool, InlineCXXSharedPtrDtor, "c++-shared_ptr-inlining",
ANALYZER_OPTION(
bool, MayInlineCXXSharedPtrDtor, "c++-shared_ptr-inlining",
"Whether or not the destructor of C++ 'shared_ptr' may be considered for "
"inlining. This covers std::shared_ptr, std::tr1::shared_ptr, and "
"boost::shared_ptr, and indeed any destructor named '~shared_ptr'.",
false, mayInlineCXXSharedPtrDtor)
false)
ANALYZER_OPTION_GEN_FN(bool, InlineCXXTemporaryDtors, "c++-temp-dtor-inlining",
"Whether C++ temporary destructors should be inlined "
"during analysis. If temporary destructors are disabled "
"in the CFG via the 'cfg-temporary-dtors' option, "
"temporary destructors would not be inlined anyway.",
true, mayInlineCXXTemporaryDtors)
ANALYZER_OPTION(bool, MayInlineCXXTemporaryDtors, "c++-temp-dtor-inlining",
"Whether C++ temporary destructors should be inlined "
"during analysis. If temporary destructors are disabled "
"in the CFG via the 'cfg-temporary-dtors' option, "
"temporary destructors would not be inlined anyway.",
true)
ANALYZER_OPTION_GEN_FN(
bool, SuppressNullReturnPaths, "suppress-null-return-paths",
ANALYZER_OPTION(
bool, ShouldSuppressNullReturnPaths, "suppress-null-return-paths",
"Whether or not paths that go through null returns should be suppressed. "
"This is a heuristic for avoiding bug reports with paths that go through "
"inlined functions that are more defensive than their callers.",
true, shouldSuppressNullReturnPaths)
true)
ANALYZER_OPTION_GEN_FN(
bool, AvoidSuppressingNullArgumentPaths,
ANALYZER_OPTION(
bool, ShouldAvoidSuppressingNullArgumentPaths,
"avoid-suppressing-null-argument-paths",
"Whether a bug report should not be suppressed if its path includes a call "
"with a null argument, even if that call has a null return. This option "
"has no effect when #shouldSuppressNullReturnPaths() is false. This is a "
"has no effect when ShouldSuppressNullReturnPaths is false. This is a "
"counter-heuristic to avoid false negatives.",
false, shouldAvoidSuppressingNullArgumentPaths)
false)
ANALYZER_OPTION_GEN_FN(bool, SuppressInlinedDefensiveChecks,
"suppress-inlined-defensive-checks",
"Whether or not diagnostics containing inlined "
"defensive NULL checks should be suppressed.",
true, shouldSuppressInlinedDefensiveChecks)
ANALYZER_OPTION(bool, ShouldSuppressInlinedDefensiveChecks,
"suppress-inlined-defensive-checks",
"Whether or not diagnostics containing inlined "
"defensive NULL checks should be suppressed.",
true)
ANALYZER_OPTION_GEN_FN(bool, InlineCXXContainerMethods,
"c++-container-inlining",
"Whether or not methods of C++ container objects may be "
"considered for inlining.",
false, mayInlineCXXContainerMethods)
ANALYZER_OPTION(bool, MayInlineCXXContainerMethods, "c++-container-inlining",
"Whether or not methods of C++ container objects may be "
"considered for inlining.",
false)
ANALYZER_OPTION_GEN_FN(bool, SuppressFromCXXStandardLibrary,
"suppress-c++-stdlib",
"Whether or not diagnostics reported within the C++ "
"standard library should be suppressed.",
true, shouldSuppressFromCXXStandardLibrary)
ANALYZER_OPTION(bool, ShouldSuppressFromCXXStandardLibrary,
"suppress-c++-stdlib",
"Whether or not diagnostics reported within the C++ "
"standard library should be suppressed.",
true)
ANALYZER_OPTION_GEN_FN(bool, CrosscheckWithZ3, "crosscheck-with-z3",
"Whether bug reports should be crosschecked with the Z3 "
"constraint manager backend.",
false, shouldCrosscheckWithZ3)
ANALYZER_OPTION(bool, ShouldCrosscheckWithZ3, "crosscheck-with-z3",
"Whether bug reports should be crosschecked with the Z3 "
"constraint manager backend.",
false)
ANALYZER_OPTION_GEN_FN(bool, ReportIssuesInMainSourceFile,
"report-in-main-source-file",
"Whether or not the diagnostic report should be always "
"reported in the main source file and not the headers.",
false, shouldReportIssuesInMainSourceFile)
ANALYZER_OPTION(bool, ShouldReportIssuesInMainSourceFile,
"report-in-main-source-file",
"Whether or not the diagnostic report should be always "
"reported in the main source file and not the headers.",
false)
ANALYZER_OPTION_GEN_FN(
bool, WriteStableReportFilename, "stable-report-filename",
"Whether or not the report filename should be random or not.", false,
shouldWriteStableReportFilename)
ANALYZER_OPTION(bool, ShouldWriteStableReportFilename, "stable-report-filename",
"Whether or not the report filename should be random or not.",
false)
ANALYZER_OPTION_GEN_FN(
bool, SerializeStats, "serialize-stats",
ANALYZER_OPTION(
bool, ShouldSerializeStats, "serialize-stats",
"Whether the analyzer should serialize statistics to plist output. "
"Statistics would be serialized in JSON format inside the main dictionary "
"under the statistics key. Available only if compiled in assert mode or "
"with LLVM statistics explicitly enabled.",
false, shouldSerializeStats)
false)
ANALYZER_OPTION_GEN_FN(
bool, InlineObjCMethod, "objc-inlining",
"Whether ObjectiveC inlining is enabled, false otherwise.", true,
mayInlineObjCMethod)
ANALYZER_OPTION(bool, MayInlineObjCMethod, "objc-inlining",
"Whether ObjectiveC inlining is enabled, false otherwise.",
true)
ANALYZER_OPTION_GEN_FN(bool, PrunePaths, "prune-paths",
"Whether irrelevant parts of a bug report path should "
"be pruned out of the final output.",
true, shouldPrunePaths)
ANALYZER_OPTION(bool, ShouldPrunePaths, "prune-paths",
"Whether irrelevant parts of a bug report path should "
"be pruned out of the final output.",
true)
ANALYZER_OPTION_GEN_FN(
bool, ConditionalizeStaticInitializers,
ANALYZER_OPTION(
bool, ShouldConditionalizeStaticInitializers,
"cfg-conditional-static-initializers",
"Whether 'static' initializers should be in conditional logic in the CFG.",
true, shouldConditionalizeStaticInitializers)
true)
ANALYZER_OPTION_GEN_FN(bool, SynthesizeBodies, "faux-bodies",
"Whether the analyzer engine should synthesize fake "
"bodies for well-known functions.",
true, shouldSynthesizeBodies)
ANALYZER_OPTION(bool, ShouldSynthesizeBodies, "faux-bodies",
"Whether the analyzer engine should synthesize fake "
"bodies for well-known functions.",
true)
ANALYZER_OPTION_GEN_FN(
bool, ElideConstructors, "elide-constructors",
ANALYZER_OPTION(
bool, ShouldElideConstructors, "elide-constructors",
"Whether elidable C++ copy-constructors and move-constructors should be "
"actually elided during analysis. Both behaviors are allowed by the C++ "
"standard, and the analyzer, like CodeGen, defaults to eliding. Starting "
"with C++17 some elisions become mandatory, and in these cases the option "
"will be ignored.",
true, shouldElideConstructors)
true)
ANALYZER_OPTION_GEN_FN(
bool, InlineLambdas, "inline-lambdas",
ANALYZER_OPTION(
bool, ShouldInlineLambdas, "inline-lambdas",
"Whether lambdas should be inlined. Otherwise a sink node will be "
"generated each time a LambdaExpr is visited.",
true, shouldInlineLambdas)
true)
ANALYZER_OPTION_GEN_FN(bool, WidenLoops, "widen-loops",
"Whether the analysis should try to widen loops.", false,
shouldWidenLoops)
ANALYZER_OPTION(bool, ShouldWidenLoops, "widen-loops",
"Whether the analysis should try to widen loops.", false)
ANALYZER_OPTION_GEN_FN(
bool, UnrollLoops, "unroll-loops",
"Whether the analysis should try to unroll loops with known bounds.", false,
shouldUnrollLoops)
ANALYZER_OPTION(
bool, ShouldUnrollLoops, "unroll-loops",
"Whether the analysis should try to unroll loops with known bounds.", false)
ANALYZER_OPTION_GEN_FN(
bool, DisplayNotesAsEvents, "notes-as-events",
ANALYZER_OPTION(
bool, ShouldDisplayNotesAsEvents, "notes-as-events",
"Whether the bug reporter should transparently treat extra note diagnostic "
"pieces as event diagnostic pieces. Useful when the diagnostic consumer "
"doesn't support the extra note pieces.",
false, shouldDisplayNotesAsEvents)
false)
ANALYZER_OPTION_GEN_FN(
bool, AggressivelySimplifyBinaryOperation,
ANALYZER_OPTION(
bool, ShouldAggressivelySimplifyBinaryOperation,
"aggressive-binary-operation-simplification",
"Whether SValBuilder should rearrange comparisons and additive operations "
"of symbolic expressions which consist of a sum of a symbol and a concrete "
@ -342,10 +259,10 @@ ANALYZER_OPTION_GEN_FN(
"'<', '<=', '>', '>=', '+' or '-'. The rearrangement also happens with '-' "
"instead of '+' on either or both side and also if any or both integers "
"are missing.",
false, shouldAggressivelySimplifyBinaryOperation)
false)
ANALYZER_OPTION_GEN_FN(
bool, EagerlyAssume, "eagerly-assume",
ANALYZER_OPTION(
bool, ShouldEagerlyAssume, "eagerly-assume",
"Whether we should eagerly assume evaluations of conditionals, thus, "
"bifurcating the path. This indicates how the engine should handle "
"expressions such as: 'x = (y != 0)'. When this is true then the "
@ -353,69 +270,66 @@ ANALYZER_OPTION_GEN_FN(
"evaluating it to the integers 0 or 1 respectively. The upside is that "
"this can increase analysis precision until we have a better way to lazily "
"evaluate such logic. The downside is that it eagerly bifurcates paths.",
true, shouldEagerlyAssume)
true)
ANALYZER_OPTION_GEN_FN(
bool, NaiveCTU, "experimental-enable-naive-ctu-analysis",
ANALYZER_OPTION(
bool, IsNaiveCTUEnabled, "experimental-enable-naive-ctu-analysis",
"Whether naive cross translation unit analysis is enabled. This is an "
"experimental feature to inline functions from another translation units.",
false, naiveCTUEnabled)
false)
ANALYZER_OPTION_GEN_FN(bool, DisplayMacroExpansions, "expand-macros",
"Whether macros related to the bugpath should be "
"expanded and included in the plist output.",
false, shouldDisplayMacroExpansions)
ANALYZER_OPTION(bool, ShouldDisplayMacroExpansions, "expand-macros",
"Whether macros related to the bugpath should be "
"expanded and included in the plist output.",
false)
//===----------------------------------------------------------------------===//
// Unsinged analyzer options.
//===----------------------------------------------------------------------===//
ANALYZER_OPTION_GEN_FN(
ANALYZER_OPTION(
unsigned, AlwaysInlineSize, "ipa-always-inline-size",
"The size of the functions (in basic blocks), which should be considered "
"to be small enough to always inline.",
3, getAlwaysInlineSize)
3)
ANALYZER_OPTION_GEN_FN(
ANALYZER_OPTION(
unsigned, GraphTrimInterval, "graph-trim-interval",
"How often nodes in the ExplodedGraph should be recycled to save memory. "
"To disable node reclamation, set the option to 0.",
1000, getGraphTrimInterval)
1000)
ANALYZER_OPTION_GEN_FN(
ANALYZER_OPTION(
unsigned, MinCFGSizeTreatFunctionsAsLarge,
"min-cfg-size-treat-functions-as-large",
"The number of basic blocks a function needs to have to be considered "
"large for the 'max-times-inline-large' config option.",
14, getMinCFGSizeTreatFunctionsAsLarge)
14)
ANALYZER_OPTION_GEN_FN(unsigned, MaxSymbolComplexity, "max-symbol-complexity",
"The maximum complexity of symbolic constraint.", 35,
getMaxSymbolComplexity)
ANALYZER_OPTION(unsigned, MaxSymbolComplexity, "max-symbol-complexity",
"The maximum complexity of symbolic constraint.", 35)
ANALYZER_OPTION_GEN_FN(unsigned, MaxTimesInlineLarge, "max-times-inline-large",
"The maximum times a large function could be inlined.",
32, getMaxTimesInlineLarge)
ANALYZER_OPTION(unsigned, MaxTimesInlineLarge, "max-times-inline-large",
"The maximum times a large function could be inlined.", 32)
ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE(
ANALYZER_OPTION_DEPENDS_ON_USER_MODE(
unsigned, MaxInlinableSize, "max-inlinable-size",
"The bound on the number of basic blocks in an inlined function.",
/* SHALLOW_VAL */ 4, /* DEEP_VAL */ 100, getMaxInlinableSize)
/* SHALLOW_VAL */ 4, /* DEEP_VAL */ 100)
ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE(
ANALYZER_OPTION_DEPENDS_ON_USER_MODE(
unsigned, MaxNodesPerTopLevelFunction, "max-nodes",
"The maximum number of nodes the analyzer can generate while exploring a "
"top level function (for each exploded graph). 0 means no limit.",
/* SHALLOW_VAL */ 75000, /* DEEP_VAL */ 225000,
getMaxNodesPerTopLevelFunction)
/* SHALLOW_VAL */ 75000, /* DEEP_VAL */ 225000)
ANALYZER_OPTION_GEN_FN(
ANALYZER_OPTION(
unsigned, RegionStoreSmallStructLimit, "region-store-small-struct-limit",
"The largest number of fields a struct can have and still be considered "
"small This is currently used to decide whether or not it is worth forcing "
"a LazyCompoundVal on bind. To disable all small-struct-dependent "
"behavior, set the option to 0.",
2, getRegionStoreSmallStructLimit)
2)
//===----------------------------------------------------------------------===//
// String analyzer options.
@ -424,23 +338,16 @@ ANALYZER_OPTION_GEN_FN(
ANALYZER_OPTION(StringRef, CTUDir, "ctu-dir",
"The directory containing the CTU related files.", "")
ANALYZER_OPTION_GEN_FN(
StringRef, CTUIndexName, "ctu-index-name",
"the name of the file containing the CTU index of functions.",
"externalFnMap.txt", getCTUIndexName)
ANALYZER_OPTION(StringRef, CTUIndexName, "ctu-index-name",
"the name of the file containing the CTU index of functions.",
"externalFnMap.txt")
ANALYZER_OPTION_GEN_FN(
ANALYZER_OPTION(
StringRef, ModelPath, "model-path",
"The analyzer can inline an alternative implementation written in C at the "
"call site if the called function's body is not available. This is a path "
"where to look for those alternative implementations (called models).",
"", getModelPath)
ANALYZER_OPTION(StringRef, UserMode, "mode",
"Controls the high-level analyzer mode, which influences the "
"default settings for some of the lower-level config options "
"(such as IPAMode). Value: \"deep\", \"shallow\".",
"deep")
"")
ANALYZER_OPTION(
StringRef, CXXMemberInliningMode, "c++-inlining",
@ -461,7 +368,5 @@ ANALYZER_OPTION(
"\"bfs_block_dfs_contents\".",
"unexplored_first_queue")
#undef ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE
#undef ANALYZER_OPTION_GEN_FN
#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE
#undef ANALYZER_OPTION

View File

@ -20,6 +20,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include <string>
#include <utility>
#include <vector>
@ -170,6 +171,7 @@ public:
std::vector<std::pair<std::string, bool>> CheckersControlList;
/// A key-value table of use-specified configuration values.
// TODO: This shouldn't be public.
ConfigTable Config;
AnalysisStores AnalysisStoreOpt = RegionStoreModel;
AnalysisConstraints AnalysisConstraintsOpt = RangeConstraintsModel;
@ -220,33 +222,17 @@ public:
/// The mode of function selection used during inlining.
AnalysisInliningMode InliningMode = NoRedundancy;
private:
#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL) \
Optional<TYPE> NAME;
#define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC, \
SHALLOW_VAL, DEEP_VAL) \
Optional<TYPE> NAME;
ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL)
#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL) \
TYPE NAME;
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def"
#undef ANALYZER_OPTION
#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE
/// Query an option's string value.
///
/// If an option value is not provided, returns the given \p DefaultVal.
/// @param [in] OptionName Name for option to retrieve.
/// @param [in] DefaultVal Default value returned if no such option was
/// specified.
StringRef getStringOption(StringRef OptionName, StringRef DefaultVal);
void initOption(Optional<StringRef> &V, StringRef Name,
StringRef DefaultVal);
void initOption(Optional<bool> &V, StringRef Name, bool DefaultVal);
void initOption(Optional<unsigned> &V, StringRef Name,
unsigned DefaultVal);
public:
AnalyzerOptions()
: DisableAllChecks(false), ShowCheckerHelp(false),
ShowEnabledCheckerList(false), ShowConfigOptionsList(false),
@ -308,42 +294,15 @@ public:
const ento::CheckerBase *C,
bool SearchInParents = false) const;
#define ANALYZER_OPTION_GEN_FN(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL, \
CREATE_FN) \
TYPE CREATE_FN() { \
initOption(NAME, CMDFLAG, DEFAULT_VAL); \
return NAME.getValue(); \
}
#define ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE( \
TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL, DEEP_VAL, CREATE_FN) \
TYPE CREATE_FN() { \
switch (getUserMode()) { \
case UMK_Shallow: \
initOption(NAME, CMDFLAG, SHALLOW_VAL); \
break; \
case UMK_Deep: \
initOption(NAME, CMDFLAG, DEEP_VAL); \
break; \
} \
\
return NAME.getValue(); \
}
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def"
#undef ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE
#undef ANALYZER_OPTION_WITH_FN
/// Retrieves and sets the UserMode. This is a high-level option,
/// which is used to set other low-level options. It is not accessible
/// outside of AnalyzerOptions.
UserModeKind getUserMode();
UserModeKind getUserMode() const;
ExplorationStrategyKind getExplorationStrategy();
ExplorationStrategyKind getExplorationStrategy() const;
/// Returns the inter-procedural analysis mode.
IPAKind getIPAMode();
IPAKind getIPAMode() const;
/// Returns the option controlling which C++ member functions will be
/// considered for inlining.
@ -351,13 +310,28 @@ public:
/// This is controlled by the 'c++-inlining' config option.
///
/// \sa CXXMemberInliningMode
bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K);
StringRef getCTUDir();
bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K) const;
};
using AnalyzerOptionsRef = IntrusiveRefCntPtr<AnalyzerOptions>;
//===----------------------------------------------------------------------===//
// We'll use AnalyzerOptions in the frontend, but we can't link the frontend
// with clangStaticAnalyzerCore, because clangStaticAnalyzerCore depends on
// clangFrontend.
//
// For this reason, implement some methods in this header file.
//===----------------------------------------------------------------------===//
inline UserModeKind AnalyzerOptions::getUserMode() const {
auto K = llvm::StringSwitch<llvm::Optional<UserModeKind>>(UserMode)
.Case("shallow", UMK_Shallow)
.Case("deep", UMK_Deep)
.Default(None);
assert(K.hasValue() && "User mode is invalid.");
return K.getValue();
}
} // namespace clang
#endif // LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H

View File

@ -181,6 +181,9 @@ static void addDiagnosticArgs(ArgList &Args, OptSpecifier Group,
}
}
static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts,
DiagnosticsEngine &Diags);
static void getAllNoBuiltinFuncValues(ArgList &Args,
std::vector<std::string> &Funcs) {
SmallVector<const char *, 8> Values;
@ -343,6 +346,8 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
}
parseAnalyzerConfigs(Opts, Diags);
llvm::raw_string_ostream os(Opts.FullCompilerInvocation);
for (unsigned i = 0; i < Args.getNumInputArgStrings(); ++i) {
if (i != 0)
@ -354,6 +359,64 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
return Success;
}
static StringRef getStringOption(AnalyzerOptions::ConfigTable &Config,
StringRef OptionName, StringRef DefaultVal) {
return Config.insert({OptionName, DefaultVal}).first->second;
}
static void initOption(AnalyzerOptions::ConfigTable &Config,
StringRef &OptionField, StringRef Name,
StringRef DefaultVal) {
OptionField = getStringOption(Config, Name, DefaultVal);
}
static void initOption(AnalyzerOptions::ConfigTable &Config,
bool &OptionField, StringRef Name, bool DefaultVal) {
// FIXME: We should emit a warning here if the value is something other than
// "true", "false", or the empty string (meaning the default value),
// but the AnalyzerOptions doesn't have access to a diagnostic engine.
OptionField = llvm::StringSwitch<bool>(getStringOption(Config, Name,
(DefaultVal ? "true" : "false")))
.Case("true", true)
.Case("false", false)
.Default(DefaultVal);
}
static void initOption(AnalyzerOptions::ConfigTable &Config,
unsigned &OptionField, StringRef Name,
unsigned DefaultVal) {
OptionField = DefaultVal;
bool HasFailed = getStringOption(Config, Name, std::to_string(DefaultVal))
.getAsInteger(10, OptionField);
assert(!HasFailed && "analyzer-config option should be numeric");
(void)HasFailed;
}
static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts,
DiagnosticsEngine &Diags) {
// TODO: Emit warnings for incorrect options.
// TODO: There's no need to store the entire configtable, it'd be plenty
// enough tostore checker options.
#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL) \
initOption(AnOpts.Config, AnOpts.NAME, CMDFLAG, DEFAULT_VAL); \
#define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC, \
SHALLOW_VAL, DEEP_VAL) \
switch (AnOpts.getUserMode()) { \
case UMK_Shallow: \
initOption(AnOpts.Config, AnOpts.NAME, CMDFLAG, SHALLOW_VAL); \
break; \
case UMK_Deep: \
initOption(AnOpts.Config, AnOpts.NAME, CMDFLAG, DEEP_VAL); \
break; \
} \
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def"
#undef ANALYZER_OPTION
#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE
}
static bool ParseMigratorArgs(MigratorOptions &Opts, ArgList &Args) {
Opts.NoNSAllocReallocError = Args.hasArg(OPT_migrator_no_nsalloc_error);
Opts.NoFinalizeRemoval = Args.hasArg(OPT_migrator_no_finalize_removal);

View File

@ -182,7 +182,9 @@ public:
llvm::errs() << "[config]\n";
for (unsigned I = 0, E = Keys.size(); I != E; ++I)
llvm::errs() << Keys[I]->getKey() << " = " << Keys[I]->second << '\n';
llvm::errs() << Keys[I]->getKey() << " = "
<< (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second)
<< '\n';
llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n';
}

View File

@ -1094,7 +1094,7 @@ void MallocChecker::processNewAllocation(const CXXNewExpr *NE,
void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
CheckerContext &C) const {
if (!C.getAnalysisManager().getAnalyzerOptions().mayInlineCXXAllocator())
if (!C.getAnalysisManager().getAnalyzerOptions().MayInlineCXXAllocator)
processNewAllocation(NE, C, C.getSVal(NE));
}

View File

@ -22,16 +22,21 @@ AnalysisManager::AnalysisManager(ASTContext &ASTCtx, DiagnosticsEngine &diags,
AnalyzerOptions &Options,
CodeInjector *injector)
: AnaCtxMgr(
ASTCtx, Options.UnoptimizedCFG, Options.includeImplicitDtorsInCFG(),
/*AddInitializers=*/true, Options.includeTemporaryDtorsInCFG(),
Options.includeLifetimeInCFG(),
ASTCtx, Options.UnoptimizedCFG,
Options.ShouldIncludeImplicitDtorsInCFG,
/*AddInitializers=*/true,
Options.ShouldIncludeTemporaryDtorsInCFG,
Options.ShouldIncludeLifetimeInCFG,
// Adding LoopExit elements to the CFG is a requirement for loop
// unrolling.
Options.includeLoopExitInCFG() || Options.shouldUnrollLoops(),
Options.includeScopesInCFG(), Options.shouldSynthesizeBodies(),
Options.shouldConditionalizeStaticInitializers(),
/*addCXXNewAllocator=*/true, Options.includeRichConstructorsInCFG(),
Options.shouldElideConstructors(), injector),
Options.ShouldIncludeLoopExitInCFG ||
Options.ShouldUnrollLoops,
Options.ShouldIncludeScopesInCFG,
Options.ShouldSynthesizeBodies,
Options.ShouldConditionalizeStaticInitializers,
/*addCXXNewAllocator=*/true,
Options.ShouldIncludeRichConstructorsInCFG,
Options.ShouldElideConstructors, injector),
Ctx(ASTCtx), Diags(diags), LangOpts(ASTCtx.getLangOpts()),
PathConsumers(PDC), CreateStoreMgr(storemgr),
CreateConstraintMgr(constraintmgr), CheckerMgr(checkerMgr),

View File

@ -49,28 +49,11 @@ AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental /* = false */) {
return Result;
}
UserModeKind AnalyzerOptions::getUserMode() {
if (!UserMode.hasValue()) {
UserMode = getStringOption("mode", "deep");
}
auto K = llvm::StringSwitch<llvm::Optional<UserModeKind>>(*UserMode)
.Case("shallow", UMK_Shallow)
.Case("deep", UMK_Deep)
.Default(None);
assert(UserMode.hasValue() && "User mode is invalid.");
return K.getValue();
}
ExplorationStrategyKind
AnalyzerOptions::getExplorationStrategy() {
if (!ExplorationStrategy.hasValue()) {
ExplorationStrategy = getStringOption("exploration_strategy",
"unexplored_first_queue");
}
AnalyzerOptions::getExplorationStrategy() const {
auto K =
llvm::StringSwitch<llvm::Optional<ExplorationStrategyKind>>(
*ExplorationStrategy)
ExplorationStrategy)
.Case("dfs", ExplorationStrategyKind::DFS)
.Case("bfs", ExplorationStrategyKind::BFS)
.Case("unexplored_first",
@ -86,18 +69,8 @@ AnalyzerOptions::getExplorationStrategy() {
return K.getValue();
}
IPAKind AnalyzerOptions::getIPAMode() {
if (!IPAMode.hasValue()) {
switch (getUserMode()) {
case UMK_Shallow:
IPAMode = getStringOption("ipa", "inlining");
break;
case UMK_Deep:
IPAMode = getStringOption("ipa", "dynamic-bifurcate");
break;
}
}
auto K = llvm::StringSwitch<llvm::Optional<IPAKind>>(*IPAMode)
IPAKind AnalyzerOptions::getIPAMode() const {
auto K = llvm::StringSwitch<llvm::Optional<IPAKind>>(IPAMode)
.Case("none", IPAK_None)
.Case("basic-inlining", IPAK_BasicInlining)
.Case("inlining", IPAK_Inlining)
@ -110,17 +83,14 @@ IPAKind AnalyzerOptions::getIPAMode() {
}
bool
AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind Param) {
if (!CXXMemberInliningMode.hasValue()) {
CXXMemberInliningMode = getStringOption("c++-inlining", "destructors");
}
AnalyzerOptions::mayInlineCXXMemberFunction(
CXXInlineableMemberKind Param) const {
if (getIPAMode() < IPAK_Inlining)
return false;
auto K =
llvm::StringSwitch<llvm::Optional<CXXInlineableMemberKind>>(
*CXXMemberInliningMode)
CXXMemberInliningMode)
.Case("constructors", CIMK_Constructors)
.Case("destructors", CIMK_Destructors)
.Case("methods", CIMK_MemberFunctions)
@ -132,50 +102,6 @@ AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind Param) {
return *K >= Param;
}
StringRef AnalyzerOptions::getStringOption(StringRef OptionName,
StringRef DefaultVal) {
return Config.insert({OptionName, DefaultVal}).first->second;
}
static StringRef toString(bool B) { return (B ? "true" : "false"); }
template <typename T>
static StringRef toString(T) = delete;
void AnalyzerOptions::initOption(Optional<StringRef> &V, StringRef Name,
StringRef DefaultVal) {
if (V.hasValue())
return;
V = getStringOption(Name, DefaultVal);
}
void AnalyzerOptions::initOption(Optional<bool> &V, StringRef Name,
bool DefaultVal) {
if (V.hasValue())
return;
// FIXME: We should emit a warning here if the value is something other than
// "true", "false", or the empty string (meaning the default value),
// but the AnalyzerOptions doesn't have access to a diagnostic engine.
V = llvm::StringSwitch<bool>(getStringOption(Name, toString(DefaultVal)))
.Case("true", true)
.Case("false", false)
.Default(DefaultVal);
}
void AnalyzerOptions::initOption(Optional<unsigned> &V, StringRef Name,
unsigned DefaultVal) {
if (V.hasValue())
return;
V = DefaultVal;
bool HasFailed = getStringOption(Name, std::to_string(DefaultVal))
.getAsInteger(10, *V);
assert(!HasFailed && "analyzer-config option should be numeric");
(void)HasFailed;
}
StringRef AnalyzerOptions::getCheckerStringOption(StringRef OptionName,
StringRef DefaultVal,
const CheckerBase *C,
@ -210,7 +136,8 @@ bool AnalyzerOptions::getCheckerBooleanOption(StringRef Name, bool DefaultVal,
// but the AnalyzerOptions doesn't have access to a diagnostic engine.
assert(C);
return llvm::StringSwitch<bool>(
getCheckerStringOption(Name, toString(DefaultVal), C, SearchInParents))
getCheckerStringOption(Name, DefaultVal ? "true" : "false", C,
SearchInParents))
.Case("true", true)
.Case("false", false)
.Default(DefaultVal);
@ -227,12 +154,3 @@ int AnalyzerOptions::getCheckerIntegerOption(StringRef Name, int DefaultVal,
(void)HasFailed;
return Ret;
}
StringRef AnalyzerOptions::getCTUDir() {
if (!CTUDir.hasValue()) {
CTUDir = getStringOption("ctu-dir", "");
if (!llvm::sys::fs::is_directory(*CTUDir))
CTUDir = "";
}
return CTUDir.getValue();
}

View File

@ -1976,7 +1976,7 @@ static std::unique_ptr<PathDiagnostic> generatePathDiagnosticForConsumer(
// Finally, prune the diagnostic path of uninteresting stuff.
if (!PD->path.empty()) {
if (R->shouldPrunePath() && Opts.shouldPrunePaths()) {
if (R->shouldPrunePath() && Opts.ShouldPrunePaths) {
bool stillHasNotes =
removeUnneededCalls(PD->getMutablePieces(), R, LCM);
assert(stillHasNotes);
@ -2007,7 +2007,7 @@ static std::unique_ptr<PathDiagnostic> generatePathDiagnosticForConsumer(
removeEdgesToDefaultInitializers(PD->getMutablePieces());
}
if (GenerateDiagnostics && Opts.shouldDisplayMacroExpansions())
if (GenerateDiagnostics && Opts.ShouldDisplayMacroExpansions)
CompactMacroExpandedPieces(PD->getMutablePieces(), SM);
return PD;
@ -2621,7 +2621,7 @@ std::pair<BugReport*, std::unique_ptr<VisitorsDiagnosticsTy>> findValidReport(
generateVisitorsDiagnostics(R, ErrorNode, BRC);
if (R->isValid()) {
if (Opts.shouldCrosscheckWithZ3()) {
if (Opts.ShouldCrosscheckWithZ3) {
// If crosscheck is enabled, remove all visitors, add the refutation
// visitor and check again
R->clearVisitors();
@ -2963,7 +2963,7 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
}
PathPieces &Pieces = PD->getMutablePieces();
if (getAnalyzerOptions().shouldDisplayNotesAsEvents()) {
if (getAnalyzerOptions().ShouldDisplayNotesAsEvents) {
// For path diagnostic consumers that don't support extra notes,
// we may optionally convert those to path notes.
for (auto I = report->getNotes().rbegin(),
@ -3100,7 +3100,7 @@ BugReporter::generateDiagnosticForConsumerMap(
// report location to the last piece in the main source file.
AnalyzerOptions &Opts = getAnalyzerOptions();
for (auto const &P : *Out)
if (Opts.shouldReportIssuesInMainSourceFile() && !Opts.AnalyzeAll)
if (Opts.ShouldReportIssuesInMainSourceFile && !Opts.AnalyzeAll)
P.second->resetDiagnosticLocationToMainFile();
return Out;

View File

@ -676,8 +676,8 @@ public:
bool EnableNullFPSuppression, BugReport &BR,
const SVal V) {
AnalyzerOptions &Options = N->getState()->getAnalysisManager().options;
if (EnableNullFPSuppression && Options.shouldSuppressNullReturnPaths()
&& V.getAs<Loc>())
if (EnableNullFPSuppression &&
Options.ShouldSuppressNullReturnPaths && V.getAs<Loc>())
BR.addVisitor(llvm::make_unique<MacroNullReturnSuppressionVisitor>(
R->getAs<SubRegion>(), V));
}
@ -808,7 +808,8 @@ public:
AnalyzerOptions &Options = State->getAnalysisManager().options;
bool EnableNullFPSuppression = false;
if (InEnableNullFPSuppression && Options.shouldSuppressNullReturnPaths())
if (InEnableNullFPSuppression &&
Options.ShouldSuppressNullReturnPaths)
if (Optional<Loc> RetLoc = RetVal.getAs<Loc>())
EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
@ -877,7 +878,7 @@ public:
// future nodes. We want to emit a path note as well, in case
// the report is resurrected as valid later on.
if (EnableNullFPSuppression &&
Options.shouldAvoidSuppressingNullArgumentPaths())
Options.ShouldAvoidSuppressingNullArgumentPaths)
Mode = MaybeUnsuppress;
if (RetE->getType()->isObjCObjectPointerType()) {
@ -925,7 +926,7 @@ public:
visitNodeMaybeUnsuppress(const ExplodedNode *N,
BugReporterContext &BRC, BugReport &BR) {
#ifndef NDEBUG
assert(Options.shouldAvoidSuppressingNullArgumentPaths());
assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
#endif
// Are we at the entry node for this call?
@ -1378,7 +1379,7 @@ SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N)
: V(Value) {
// Check if the visitor is disabled.
AnalyzerOptions &Options = N->getState()->getAnalysisManager().options;
if (!Options.shouldSuppressInlinedDefensiveChecks())
if (!Options.ShouldSuppressInlinedDefensiveChecks)
IsSatisfied = true;
assert(N->getState()->isNull(V).isConstrainedTrue() &&
@ -2219,7 +2220,7 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
// the user's fault, we currently don't report them very well, and
// Note that this will not help for any other data structure libraries, like
// TR1, Boost, or llvm/ADT.
if (Options.shouldSuppressFromCXXStandardLibrary()) {
if (Options.ShouldSuppressFromCXXStandardLibrary) {
BR.markInvalid(getTag(), nullptr);
return;
} else {

View File

@ -554,13 +554,14 @@ RuntimeDefinition AnyFunctionCall::getRuntimeDefinition() const {
AnalyzerOptions &Opts = Engine->getAnalysisManager().options;
// Try to get CTU definition only if CTUDir is provided.
if (!Opts.naiveCTUEnabled())
if (!Opts.IsNaiveCTUEnabled)
return {};
cross_tu::CrossTranslationUnitContext &CTUCtx =
*Engine->getCrossTranslationUnitContext();
llvm::Expected<const FunctionDecl *> CTUDeclOrError =
CTUCtx.getCrossTUDefinition(FD, Opts.getCTUDir(), Opts.getCTUIndexName());
CTUCtx.getCrossTUDefinition(FD, Opts.CTUDir,
Opts.CTUIndexName);
if (!CTUDeclOrError) {
handleAllErrors(CTUDeclOrError.takeError(),

View File

@ -193,7 +193,7 @@ ExprEngine::ExprEngine(cross_tu::CrossTranslationUnitContext &CTU,
svalBuilder(StateMgr.getSValBuilder()), ObjCNoRet(mgr.getASTContext()),
BR(mgr, *this),
VisitedCallees(VisitedCalleesIn), HowToInline(HowToInlineIn) {
unsigned TrimInterval = mgr.options.getGraphTrimInterval();
unsigned TrimInterval = mgr.options.GraphTrimInterval;
if (TrimInterval != 0) {
// Enable eager node reclaimation when constructing the ExplodedGraph.
G.enableNodeReclamation(TrimInterval);
@ -746,7 +746,7 @@ void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) {
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
ProgramStateRef NewState = Pred->getState();
if(AMgr.options.shouldUnrollLoops())
if(AMgr.options.ShouldUnrollLoops)
NewState = processLoopEnd(S, NewState);
LoopExit PP(S, Pred->getLocationContext());
@ -878,7 +878,7 @@ void ExprEngine::ProcessNewAllocator(const CXXNewExpr *NE,
// TODO: We're not evaluating allocators for all cases just yet as
// we're not handling the return value correctly, which causes false
// positives when the alpha.cplusplus.NewDeleteLeaks check is on.
if (Opts.mayInlineCXXAllocator())
if (Opts.MayInlineCXXAllocator)
VisitCXXNewAllocatorCall(NE, Pred, Dst);
else {
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
@ -1093,7 +1093,7 @@ void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE,
// This is a fallback solution in case we didn't have a construction
// context when we were constructing the temporary. Otherwise the map should
// have been populated there.
if (!getAnalysisManager().options.includeTemporaryDtorsInCFG()) {
if (!getAnalysisManager().options.ShouldIncludeTemporaryDtorsInCFG) {
// In case we don't have temporary destructors in the CFG, do not mark
// the initialization - we would otherwise never clean it up.
Dst = PreVisit;
@ -1454,7 +1454,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
break;
case Stmt::LambdaExprClass:
if (AMgr.options.shouldInlineLambdas()) {
if (AMgr.options.ShouldInlineLambdas) {
Bldr.takeNodes(Pred);
VisitLambdaExpr(cast<LambdaExpr>(S), Pred, Dst);
Bldr.addNodes(Dst);
@ -1483,7 +1483,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.takeNodes(Pred);
if (AMgr.options.shouldEagerlyAssume() &&
if (AMgr.options.ShouldEagerlyAssume &&
(B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp;
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp);
@ -1747,7 +1747,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::UnaryOperatorClass: {
Bldr.takeNodes(Pred);
const auto *U = cast<UnaryOperator>(S);
if (AMgr.options.shouldEagerlyAssume() && (U->getOpcode() == UO_LNot)) {
if (AMgr.options.ShouldEagerlyAssume && (U->getOpcode() == UO_LNot)) {
ExplodedNodeSet Tmp;
VisitUnaryOperator(U, Pred, Tmp);
evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, U);
@ -1848,7 +1848,7 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
// If we reach a loop which has a known bound (and meets
// other constraints) then consider completely unrolling it.
if(AMgr.options.shouldUnrollLoops()) {
if(AMgr.options.ShouldUnrollLoops) {
unsigned maxBlockVisitOnPath = AMgr.options.maxBlockVisitOnPath;
const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator();
if (Term) {
@ -1870,7 +1870,7 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
// maximum number of times, widen the loop.
unsigned int BlockCount = nodeBuilder.getContext().blockCount();
if (BlockCount == AMgr.options.maxBlockVisitOnPath - 1 &&
AMgr.options.shouldWidenLoops()) {
AMgr.options.ShouldWidenLoops) {
const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator();
if (!(Term &&
(isa<ForStmt>(Term) || isa<WhileStmt>(Term) || isa<DoStmt>(Term))))
@ -2371,7 +2371,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
const auto *DeclRefEx = dyn_cast<DeclRefExpr>(Ex);
Optional<std::pair<SVal, QualType>> VInfo;
if (AMgr.options.shouldInlineLambdas() && DeclRefEx &&
if (AMgr.options.ShouldInlineLambdas && DeclRefEx &&
DeclRefEx->refersToEnclosingVariableOrCapture() && MD &&
MD->getParent()->isLambda()) {
// Lookup the field of the lambda.

View File

@ -159,7 +159,7 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction(
return std::make_pair(State, FieldVal);
}
case ConstructionContext::NewAllocatedObjectKind: {
if (AMgr.getAnalyzerOptions().mayInlineCXXAllocator()) {
if (AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
const auto *NECC = cast<NewAllocatedObjectConstructionContext>(CC);
const auto *NE = NECC->getCXXNewExpr();
SVal V = *getObjectUnderConstruction(State, NE, LCtx);
@ -210,7 +210,7 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction(
llvm_unreachable("Unhandled return value construction context!");
}
case ConstructionContext::ElidedTemporaryObjectKind: {
assert(AMgr.getAnalyzerOptions().shouldElideConstructors());
assert(AMgr.getAnalyzerOptions().ShouldElideConstructors);
const auto *TCC = cast<ElidedTemporaryObjectConstructionContext>(CC);
const CXXBindTemporaryExpr *BTE = TCC->getCXXBindTemporaryExpr();
const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr();
@ -706,7 +706,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
ProgramStateRef State = Pred->getState();
// Retrieve the stored operator new() return value.
if (AMgr.getAnalyzerOptions().mayInlineCXXAllocator()) {
if (AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
symVal = *getObjectUnderConstruction(State, CNE, LCtx);
State = finishObjectConstruction(State, CNE, LCtx);
}
@ -726,7 +726,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
CallEventRef<CXXAllocatorCall> Call =
CEMgr.getCXXAllocatorCall(CNE, State, LCtx);
if (!AMgr.getAnalyzerOptions().mayInlineCXXAllocator()) {
if (!AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
// Invalidate placement args.
// FIXME: Once we figure out how we want allocators to work,
// we should be using the usual pre-/(default-)eval-/post-call checks here.

View File

@ -349,7 +349,7 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
/*WasInlined=*/true);
} else if (CE &&
!(isa<CXXNewExpr>(CE) && // Called when visiting CXXNewExpr.
AMgr.getAnalyzerOptions().mayInlineCXXAllocator())) {
AMgr.getAnalyzerOptions().MayInlineCXXAllocator)) {
getCheckerManager().runCheckersForPostStmt(Dst, DstPostCall, CE,
*this, /*WasInlined=*/true);
} else {
@ -386,7 +386,7 @@ void ExprEngine::examineStackFrames(const Decl *D, const LocationContext *LCtx,
// Do not count the small functions when determining the stack depth.
AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(DI);
const CFG *CalleeCFG = CalleeADC->getCFG();
if (CalleeCFG->getNumBlockIDs() > AMgr.options.getAlwaysInlineSize())
if (CalleeCFG->getNumBlockIDs() > AMgr.options.AlwaysInlineSize)
++StackDepth;
}
LCtx = LCtx->getParent();
@ -683,7 +683,7 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
: nullptr;
if (CC && isa<NewAllocatedObjectConstructionContext>(CC) &&
!Opts.mayInlineCXXAllocator())
!Opts.MayInlineCXXAllocator)
return CIP_DisallowedOnce;
// FIXME: We don't handle constructors or destructors for arrays properly.
@ -712,7 +712,7 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
// If we don't handle temporary destructors, we shouldn't inline
// their constructors.
if (CallOpts.IsTemporaryCtorOrDtor &&
!Opts.includeTemporaryDtorsInCFG())
!Opts.ShouldIncludeTemporaryDtorsInCFG)
return CIP_DisallowedOnce;
// If we did not find the correct this-region, it would be pointless
@ -743,7 +743,8 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
return CIP_DisallowedOnce;
// Allow disabling temporary destructor inlining with a separate option.
if (CallOpts.IsTemporaryCtorOrDtor && !Opts.mayInlineCXXTemporaryDtors())
if (CallOpts.IsTemporaryCtorOrDtor &&
!Opts.MayInlineCXXTemporaryDtors)
return CIP_DisallowedOnce;
// If we did not find the correct this-region, it would be pointless
@ -754,13 +755,13 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
break;
}
case CE_CXXAllocator:
if (Opts.mayInlineCXXAllocator())
if (Opts.MayInlineCXXAllocator)
break;
// Do not inline allocators until we model deallocators.
// This is unfortunate, but basically necessary for smart pointers and such.
return CIP_DisallowedAlways;
case CE_ObjCMessage:
if (!Opts.mayInlineObjCMethod())
if (!Opts.MayInlineObjCMethod)
return CIP_DisallowedAlways;
if (!(Opts.getIPAMode() == IPAK_DynamicDispatch ||
Opts.getIPAMode() == IPAK_DynamicDispatchBifurcate))
@ -844,19 +845,19 @@ static bool mayInlineDecl(AnalysisManager &AMgr,
if (Ctx.getLangOpts().CPlusPlus) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeADC->getDecl())) {
// Conditionally control the inlining of template functions.
if (!Opts.mayInlineTemplateFunctions())
if (!Opts.MayInlineTemplateFunctions)
if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
return false;
// Conditionally control the inlining of C++ standard library functions.
if (!Opts.mayInlineCXXStandardLibrary())
if (!Opts.MayInlineCXXStandardLibrary)
if (Ctx.getSourceManager().isInSystemHeader(FD->getLocation()))
if (AnalysisDeclContext::isInStdNamespace(FD))
return false;
// Conditionally control the inlining of methods on objects that look
// like C++ containers.
if (!Opts.mayInlineCXXContainerMethods())
if (!Opts.MayInlineCXXContainerMethods)
if (!AMgr.isInCodeFile(FD->getLocation()))
if (isContainerMethod(Ctx, FD))
return false;
@ -865,7 +866,7 @@ static bool mayInlineDecl(AnalysisManager &AMgr,
// We don't currently do a good job modeling shared_ptr because we can't
// see the reference count, so treating as opaque is probably the best
// idea.
if (!Opts.mayInlineCXXSharedPtrDtor())
if (!Opts.MayInlineCXXSharedPtrDtor)
if (isCXXSharedPtrDtor(FD))
return false;
}
@ -878,7 +879,7 @@ static bool mayInlineDecl(AnalysisManager &AMgr,
return false;
// Do not inline large functions.
if (CalleeCFG->getNumBlockIDs() > Opts.getMaxInlinableSize())
if (CalleeCFG->getNumBlockIDs() > Opts.MaxInlinableSize)
return false;
// It is possible that the live variables analysis cannot be
@ -946,21 +947,21 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
unsigned StackDepth = 0;
examineStackFrames(D, Pred->getLocationContext(), IsRecursive, StackDepth);
if ((StackDepth >= Opts.InlineMaxStackDepth) &&
((CalleeCFG->getNumBlockIDs() > Opts.getAlwaysInlineSize())
((CalleeCFG->getNumBlockIDs() > Opts.AlwaysInlineSize)
|| IsRecursive))
return false;
// Do not inline large functions too many times.
if ((Engine.FunctionSummaries->getNumTimesInlined(D) >
Opts.getMaxTimesInlineLarge()) &&
Opts.MaxTimesInlineLarge) &&
CalleeCFG->getNumBlockIDs() >=
Opts.getMinCFGSizeTreatFunctionsAsLarge()) {
Opts.MinCFGSizeTreatFunctionsAsLarge) {
NumReachedInlineCountMax++;
return false;
}
if (HowToInline == Inline_Minimal &&
(CalleeCFG->getNumBlockIDs() > Opts.getAlwaysInlineSize()
(CalleeCFG->getNumBlockIDs() > Opts.AlwaysInlineSize
|| IsRecursive))
return false;

View File

@ -218,7 +218,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
int FD;
SmallString<128> Model, ResultPath;
if (!AnalyzerOpts.shouldWriteStableReportFilename()) {
if (!AnalyzerOpts.ShouldWriteStableReportFilename) {
llvm::sys::path::append(Model, Directory, "report-%%%%%%.html");
if (std::error_code EC =
llvm::sys::fs::make_absolute(Model)) {

View File

@ -471,7 +471,7 @@ static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM,
o << " </array>\n";
if (!AnOpts.shouldDisplayMacroExpansions())
if (!AnOpts.ShouldDisplayMacroExpansions)
return;
o << " <key>macro_expansions</key>\n"
@ -704,7 +704,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
EmitString(o << " ", SM.getFileEntryForID(FID)->getName()) << '\n';
o << " </array>\n";
if (llvm::AreStatisticsEnabled() && AnOpts.shouldSerializeStats()) {
if (llvm::AreStatisticsEnabled() && AnOpts.ShouldSerializeStats) {
o << " <key>statistics</key>\n";
std::string stats;
llvm::raw_string_ostream os(stats);

View File

@ -350,7 +350,7 @@ public:
if (SubEngine *Eng = StateMgr.getOwningEngine()) {
AnalyzerOptions &Options = Eng->getAnalysisManager().options;
SmallStructLimit =
Options.getRegionStoreSmallStructLimit();
Options.RegionStoreSmallStructLimit;
}
}

View File

@ -385,7 +385,7 @@ SVal SValBuilder::makeSymExprValNN(BinaryOperator::Opcode Op,
// instead of generating an Unknown value and propagate the taint info to it.
const unsigned MaxComp = StateMgr.getOwningEngine()
->getAnalysisManager()
.options.getMaxSymbolComplexity();
.options.MaxSymbolComplexity;
if (symLHS && symRHS &&
(symLHS->computeComplexity() + symRHS->computeComplexity()) < MaxComp)

View File

@ -459,7 +459,7 @@ static Optional<NonLoc> tryRearrange(ProgramStateRef State,
// FIXME: After putting complexity threshold to the symbols we can always
// rearrange additive operations but rearrange comparisons only if
// option is set.
if(!Opts.shouldAggressivelySimplifyBinaryOperation())
if(!Opts.ShouldAggressivelySimplifyBinaryOperation)
return None;
SymbolRef LSym = Lhs.getAsSymbol();

View File

@ -204,7 +204,7 @@ public:
PP(CI.getPreprocessor()), OutDir(outdir), Opts(std::move(opts)),
Plugins(plugins), Injector(injector), CTU(CI) {
DigestAnalyzerOptions();
if (Opts->PrintStats || Opts->shouldSerializeStats()) {
if (Opts->PrintStats || Opts->ShouldSerializeStats) {
AnalyzerTimers = llvm::make_unique<llvm::TimerGroup>(
"analyzer", "Analyzer timers");
TUTotalTimer = llvm::make_unique<llvm::Timer>(
@ -739,7 +739,7 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
// Execute the worklist algorithm.
Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
Mgr->options.getMaxNodesPerTopLevelFunction());
Mgr->options.MaxNodesPerTopLevelFunction);
if (!Mgr->options.DumpExplodedGraphTo.empty())
Eng.DumpGraph(Mgr->options.TrimGraph, Mgr->options.DumpExplodedGraphTo);

View File

@ -48,7 +48,7 @@ void ModelInjector::onBodySynthesis(const NamedDecl *D) {
FileID mainFileID = SM.getMainFileID();
AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts();
llvm::StringRef modelPath = analyzerOpts->getModelPath();
llvm::StringRef modelPath = analyzerOpts->ModelPath;
llvm::SmallString<128> fileName;

View File

@ -1,16 +1,16 @@
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 %s -o /dev/null -analyzer-checker=core,osx.cocoa,debug.ConfigDumper -analyzer-max-loop 34 > %t 2>&1
// RUN: FileCheck --input-file=%t %s --match-full-lines
void bar() {}
void foo() {
// Call bar 33 times so max-times-inline-large is met and
// min-blocks-for-inline-large is checked
for (int i = 0; i < 34; ++i) {
bar();
}
}
// CHECK: [config]
// CHECK-NEXT: aggressive-binary-operation-simplification = false
// CHECK-NEXT: avoid-suppressing-null-argument-paths = false
// CHECK-NEXT: c++-allocator-inlining = true
// CHECK-NEXT: c++-container-inlining = false
// CHECK-NEXT: c++-inlining = destructors
// CHECK-NEXT: c++-shared_ptr-inlining = false
// CHECK-NEXT: c++-stdlib-inlining = true
// CHECK-NEXT: c++-temp-dtor-inlining = true
// CHECK-NEXT: c++-template-inlining = true
// CHECK-NEXT: cfg-conditional-static-initializers = true
// CHECK-NEXT: cfg-implicit-dtors = true
// CHECK-NEXT: cfg-lifetime = false
@ -18,8 +18,13 @@ void foo() {
// CHECK-NEXT: cfg-rich-constructors = true
// CHECK-NEXT: cfg-scopes = false
// CHECK-NEXT: cfg-temporary-dtors = true
// CHECK-NEXT: crosscheck-with-z3 = false
// CHECK-NEXT: ctu-dir = ""
// CHECK-NEXT: ctu-index-name = externalFnMap.txt
// CHECK-NEXT: eagerly-assume = true
// CHECK-NEXT: elide-constructors = true
// CHECK-NEXT: expand-macros = false
// CHECK-NEXT: experimental-enable-naive-ctu-analysis = false
// CHECK-NEXT: exploration_strategy = unexplored_first_queue
// CHECK-NEXT: faux-bodies = true
// CHECK-NEXT: graph-trim-interval = 1000
@ -28,12 +33,22 @@ void foo() {
// CHECK-NEXT: ipa-always-inline-size = 3
// CHECK-NEXT: max-inlinable-size = 100
// CHECK-NEXT: max-nodes = 225000
// CHECK-NEXT: max-symbol-complexity = 35
// CHECK-NEXT: max-times-inline-large = 32
// CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14
// CHECK-NEXT: mode = deep
// CHECK-NEXT: model-path = ""
// CHECK-NEXT: notes-as-events = false
// CHECK-NEXT: objc-inlining = true
// CHECK-NEXT: prune-paths = true
// CHECK-NEXT: region-store-small-struct-limit = 2
// CHECK-NEXT: report-in-main-source-file = false
// CHECK-NEXT: serialize-stats = false
// CHECK-NEXT: stable-report-filename = false
// CHECK-NEXT: suppress-c++-stdlib = true
// CHECK-NEXT: suppress-inlined-defensive-checks = true
// CHECK-NEXT: suppress-null-return-paths = true
// CHECK-NEXT: unroll-loops = false
// CHECK-NEXT: widen-loops = false
// CHECK-NEXT: [stats]
// CHECK-NEXT: num-entries = 24
// CHECK-NEXT: num-entries = 48

View File

@ -1,24 +1,10 @@
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 %s -o /dev/null -analyzer-checker=core,osx.cocoa,debug.ConfigDumper -analyzer-max-loop 34 > %t 2>&1
// RUN: FileCheck --input-file=%t %s --match-full-lines
void bar() {}
void foo() {
// Call bar 33 times so max-times-inline-large is met and
// min-blocks-for-inline-large is checked
for (int i = 0; i < 34; ++i) {
bar();
}
}
class Foo {
public:
~Foo() {}
void baz() { Foo(); }
void bar() { const Foo &f = Foo(); }
void foo() { bar(); }
};
// CHECK: [config]
// CHECK-NEXT: aggressive-binary-operation-simplification = false
// CHECK-NEXT: avoid-suppressing-null-argument-paths = false
// CHECK-NEXT: c++-allocator-inlining = true
// CHECK-NEXT: c++-container-inlining = false
// CHECK-NEXT: c++-inlining = destructors
// CHECK-NEXT: c++-shared_ptr-inlining = false
@ -32,8 +18,12 @@ public:
// CHECK-NEXT: cfg-rich-constructors = true
// CHECK-NEXT: cfg-scopes = false
// CHECK-NEXT: cfg-temporary-dtors = true
// CHECK-NEXT: crosscheck-with-z3 = false
// CHECK-NEXT: ctu-dir = ""
// CHECK-NEXT: ctu-index-name = externalFnMap.txt
// CHECK-NEXT: eagerly-assume = true
// CHECK-NEXT: elide-constructors = true
// CHECK-NEXT:expand-macros = false
// CHECK-NEXT: experimental-enable-naive-ctu-analysis = false
// CHECK-NEXT: exploration_strategy = unexplored_first_queue
// CHECK-NEXT: faux-bodies = true
@ -43,12 +33,22 @@ public:
// CHECK-NEXT: ipa-always-inline-size = 3
// CHECK-NEXT: max-inlinable-size = 100
// CHECK-NEXT: max-nodes = 225000
// CHECK-NEXT: max-symbol-complexity = 35
// CHECK-NEXT: max-times-inline-large = 32
// CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14
// CHECK-NEXT: mode = deep
// CHECK-NEXT: model-path = ""
// CHECK-NEXT: notes-as-events = false
// CHECK-NEXT: objc-inlining = true
// CHECK-NEXT: prune-paths = true
// CHECK-NEXT: region-store-small-struct-limit = 2
// CHECK-NEXT: report-in-main-source-file = false
// CHECK-NEXT: serialize-stats = false
// CHECK-NEXT: stable-report-filename = false
// CHECK-NEXT: suppress-c++-stdlib = true
// CHECK-NEXT: suppress-inlined-defensive-checks = true
// CHECK-NEXT: suppress-null-return-paths = true
// CHECK-NEXT: unroll-loops = false
// CHECK-NEXT: widen-loops = false
// CHECK-NEXT: [stats]
// CHECK-NEXT: num-entries = 31
// CHECK-NEXT: num-entries = 48