Index: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h =================================================================== --- include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -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 #include #include @@ -170,6 +171,7 @@ std::vector> 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 @@ /// The mode of function selection used during inlining. AnalysisInliningMode InliningMode = NoRedundancy; -private: - -#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL) \ - Optional NAME; #define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC, \ SHALLOW_VAL, DEEP_VAL) \ - Optional 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 &V, StringRef Name, - StringRef DefaultVal); - - void initOption(Optional &V, StringRef Name, bool DefaultVal); - - void initOption(Optional &V, StringRef Name, - unsigned DefaultVal); -public: AnalyzerOptions() : DisableAllChecks(false), ShowCheckerHelp(false), ShowEnabledCheckerList(false), ShowConfigOptionsList(false), @@ -308,42 +294,15 @@ 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 @@ /// 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; +//===----------------------------------------------------------------------===// +// 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>(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 Index: include/clang/StaticAnalyzer/Core/AnalyzerOptions.def =================================================================== --- include/clang/StaticAnalyzer/Core/AnalyzerOptions.def +++ include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -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 @@ #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 @@ 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_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, ShouldIncludeImplicitDtorsInCFG, "cfg-implicit-dtors", + "Whether or not implicit destructors for C++ objects " + "should be included in the CFG.", + true) + +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_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_GEN_FN( - bool, IncludeScopesInCFG, "cfg-scopes", - "Whether or not scope information should be included in the CFG.", false, - includeScopesInCFG) - -ANALYZER_OPTION_GEN_FN( - bool, InlineTemplateFunctions, "c++-template-inlining", - "Whether or not templated functions may be considered for inlining.", true, - mayInlineTemplateFunctions) - -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_GEN_FN( - bool, InlineCXXAllocator, "c++-allocator-inlining", - "Whether or not allocator call may be considered for inlining.", true, - mayInlineCXXAllocator) +ANALYZER_OPTION(bool, ShouldIncludeLoopExitInCFG, "cfg-loopexit", + "Whether or not the end of the loop information should " + "be included in the CFG.", + false) + +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, InlineCXXSharedPtrDtor, "c++-shared_ptr-inlining", +ANALYZER_OPTION( + bool, ShouldIncludeScopesInCFG, "cfg-scopes", + "Whether or not scope information should be included in the CFG.", false) + +ANALYZER_OPTION( + bool, MayInlineTemplateFunctions, "c++-template-inlining", + "Whether or not templated functions may be considered for inlining.", true) + +ANALYZER_OPTION(bool, MayInlineCXXStandardLibrary, "c++-stdlib-inlining", + "Whether or not C++ standard library functions may be " + "considered for inlining.", + true) + +ANALYZER_OPTION(bool, MayInlineCXXAllocator, "c++-allocator-inlining", + "Whether or not allocator call may be considered for inlining.", + true) + +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_GEN_FN(bool, InlineCXXContainerMethods, - "c++-container-inlining", - "Whether or not methods of C++ container objects may be " - "considered for inlining.", - false, mayInlineCXXContainerMethods) - -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_GEN_FN(bool, CrosscheckWithZ3, "crosscheck-with-z3", - "Whether bug reports should be crosschecked with the Z3 " - "constraint manager backend.", - false, shouldCrosscheckWithZ3) - -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_GEN_FN( - bool, WriteStableReportFilename, "stable-report-filename", - "Whether or not the report filename should be random or not.", false, - shouldWriteStableReportFilename) +ANALYZER_OPTION(bool, ShouldSuppressInlinedDefensiveChecks, + "suppress-inlined-defensive-checks", + "Whether or not diagnostics containing inlined " + "defensive NULL checks should be suppressed.", + true) + +ANALYZER_OPTION(bool, MayInlineCXXContainerMethods, "c++-container-inlining", + "Whether or not methods of C++ container objects may be " + "considered for inlining.", + false) + +ANALYZER_OPTION(bool, ShouldSuppressFromCXXStandardLibrary, + "suppress-c++-stdlib", + "Whether or not diagnostics reported within the C++ " + "standard library should be suppressed.", + true) + +ANALYZER_OPTION(bool, ShouldCrosscheckWithZ3, "crosscheck-with-z3", + "Whether bug reports should be crosschecked with the Z3 " + "constraint manager backend.", + false) + +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(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_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, MayInlineObjCMethod, "objc-inlining", + "Whether ObjectiveC inlining is enabled, false otherwise.", + true) + +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_GEN_FN( - bool, UnrollLoops, "unroll-loops", - "Whether the analysis should try to unroll loops with known bounds.", false, - shouldUnrollLoops) +ANALYZER_OPTION(bool, ShouldWidenLoops, "widen-loops", + "Whether the analysis should try to widen loops.", false) + +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 @@ "'<', '<=', '>', '>=', '+' 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 @@ "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(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 @@ "\"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 Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -181,6 +181,9 @@ } } +static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts, + DiagnosticsEngine &Diags); + static void getAllNoBuiltinFuncValues(ArgList &Args, std::vector &Funcs) { SmallVector Values; @@ -343,6 +346,8 @@ } } + 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 @@ 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(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); Index: lib/StaticAnalyzer/Checkers/DebugCheckers.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/DebugCheckers.cpp +++ lib/StaticAnalyzer/Checkers/DebugCheckers.cpp @@ -182,7 +182,9 @@ 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'; } Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1094,7 +1094,7 @@ 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)); } Index: lib/StaticAnalyzer/Core/AnalysisManager.cpp =================================================================== --- lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -22,16 +22,21 @@ 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), Index: lib/StaticAnalyzer/Core/AnalyzerOptions.cpp =================================================================== --- lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -49,28 +49,11 @@ return Result; } -UserModeKind AnalyzerOptions::getUserMode() { - if (!UserMode.hasValue()) { - UserMode = getStringOption("mode", "deep"); - } - - auto K = llvm::StringSwitch>(*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>( - *ExplorationStrategy) + ExplorationStrategy) .Case("dfs", ExplorationStrategyKind::DFS) .Case("bfs", ExplorationStrategyKind::BFS) .Case("unexplored_first", @@ -86,18 +69,8 @@ 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>(*IPAMode) +IPAKind AnalyzerOptions::getIPAMode() const { + auto K = llvm::StringSwitch>(IPAMode) .Case("none", IPAK_None) .Case("basic-inlining", IPAK_BasicInlining) .Case("inlining", IPAK_Inlining) @@ -110,17 +83,14 @@ } 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>( - *CXXMemberInliningMode) + CXXMemberInliningMode) .Case("constructors", CIMK_Constructors) .Case("destructors", CIMK_Destructors) .Case("methods", CIMK_MemberFunctions) @@ -132,50 +102,6 @@ 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 -static StringRef toString(T) = delete; - -void AnalyzerOptions::initOption(Optional &V, StringRef Name, - StringRef DefaultVal) { - if (V.hasValue()) - return; - - V = getStringOption(Name, DefaultVal); -} - -void AnalyzerOptions::initOption(Optional &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(getStringOption(Name, toString(DefaultVal))) - .Case("true", true) - .Case("false", false) - .Default(DefaultVal); -} - -void AnalyzerOptions::initOption(Optional &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 @@ // but the AnalyzerOptions doesn't have access to a diagnostic engine. assert(C); return llvm::StringSwitch( - 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 @@ (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(); -} Index: lib/StaticAnalyzer/Core/BugReporter.cpp =================================================================== --- lib/StaticAnalyzer/Core/BugReporter.cpp +++ lib/StaticAnalyzer/Core/BugReporter.cpp @@ -1976,7 +1976,7 @@ // 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 @@ removeEdgesToDefaultInitializers(PD->getMutablePieces()); } - if (GenerateDiagnostics && Opts.shouldDisplayMacroExpansions()) + if (GenerateDiagnostics && Opts.ShouldDisplayMacroExpansions) CompactMacroExpandedPieces(PD->getMutablePieces(), SM); return PD; @@ -2621,7 +2621,7 @@ 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 @@ } 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 @@ // 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; Index: lib/StaticAnalyzer/Core/BugReporterVisitors.cpp =================================================================== --- lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -676,8 +676,8 @@ bool EnableNullFPSuppression, BugReport &BR, const SVal V) { AnalyzerOptions &Options = N->getState()->getAnalysisManager().options; - if (EnableNullFPSuppression && Options.shouldSuppressNullReturnPaths() - && V.getAs()) + if (EnableNullFPSuppression && + Options.ShouldSuppressNullReturnPaths && V.getAs()) BR.addVisitor(llvm::make_unique( R->getAs(), V)); } @@ -808,7 +808,8 @@ AnalyzerOptions &Options = State->getAnalysisManager().options; bool EnableNullFPSuppression = false; - if (InEnableNullFPSuppression && Options.shouldSuppressNullReturnPaths()) + if (InEnableNullFPSuppression && + Options.ShouldSuppressNullReturnPaths) if (Optional RetLoc = RetVal.getAs()) EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue(); @@ -877,7 +878,7 @@ // 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 @@ 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 @@ : 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 @@ // 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 { Index: lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- lib/StaticAnalyzer/Core/CallEvent.cpp +++ lib/StaticAnalyzer/Core/CallEvent.cpp @@ -554,13 +554,14 @@ 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 CTUDeclOrError = - CTUCtx.getCrossTUDefinition(FD, Opts.getCTUDir(), Opts.getCTUIndexName()); + CTUCtx.getCrossTUDefinition(FD, Opts.CTUDir, + Opts.CTUIndexName); if (!CTUDeclOrError) { handleAllErrors(CTUDeclOrError.takeError(), Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -193,7 +193,7 @@ 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 @@ 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 @@ // 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 @@ // 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 @@ break; case Stmt::LambdaExprClass: - if (AMgr.options.shouldInlineLambdas()) { + if (AMgr.options.ShouldInlineLambdas) { Bldr.takeNodes(Pred); VisitLambdaExpr(cast(S), Pred, Dst); Bldr.addNodes(Dst); @@ -1483,7 +1483,7 @@ Bldr.takeNodes(Pred); - if (AMgr.options.shouldEagerlyAssume() && + if (AMgr.options.ShouldEagerlyAssume && (B->isRelationalOp() || B->isEqualityOp())) { ExplodedNodeSet Tmp; VisitBinaryOperator(cast(S), Pred, Tmp); @@ -1747,7 +1747,7 @@ case Stmt::UnaryOperatorClass: { Bldr.takeNodes(Pred); const auto *U = cast(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 @@ 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 @@ // 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(Term) || isa(Term) || isa(Term)))) @@ -2371,7 +2371,7 @@ const auto *DeclRefEx = dyn_cast(Ex); Optional> VInfo; - if (AMgr.options.shouldInlineLambdas() && DeclRefEx && + if (AMgr.options.ShouldInlineLambdas && DeclRefEx && DeclRefEx->refersToEnclosingVariableOrCapture() && MD && MD->getParent()->isLambda()) { // Lookup the field of the lambda. Index: lib/StaticAnalyzer/Core/ExprEngineCXX.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -159,7 +159,7 @@ return std::make_pair(State, FieldVal); } case ConstructionContext::NewAllocatedObjectKind: { - if (AMgr.getAnalyzerOptions().mayInlineCXXAllocator()) { + if (AMgr.getAnalyzerOptions().MayInlineCXXAllocator) { const auto *NECC = cast(CC); const auto *NE = NECC->getCXXNewExpr(); SVal V = *getObjectUnderConstruction(State, NE, LCtx); @@ -210,7 +210,7 @@ llvm_unreachable("Unhandled return value construction context!"); } case ConstructionContext::ElidedTemporaryObjectKind: { - assert(AMgr.getAnalyzerOptions().shouldElideConstructors()); + assert(AMgr.getAnalyzerOptions().ShouldElideConstructors); const auto *TCC = cast(CC); const CXXBindTemporaryExpr *BTE = TCC->getCXXBindTemporaryExpr(); const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr(); @@ -706,7 +706,7 @@ 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 @@ CallEventRef 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. Index: lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -349,7 +349,7 @@ /*WasInlined=*/true); } else if (CE && !(isa(CE) && // Called when visiting CXXNewExpr. - AMgr.getAnalyzerOptions().mayInlineCXXAllocator())) { + AMgr.getAnalyzerOptions().MayInlineCXXAllocator)) { getCheckerManager().runCheckersForPostStmt(Dst, DstPostCall, CE, *this, /*WasInlined=*/true); } else { @@ -386,7 +386,7 @@ // 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 @@ : nullptr; if (CC && isa(CC) && - !Opts.mayInlineCXXAllocator()) + !Opts.MayInlineCXXAllocator) return CIP_DisallowedOnce; // FIXME: We don't handle constructors or destructors for arrays properly. @@ -712,7 +712,7 @@ // 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 @@ 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 @@ 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 @@ if (Ctx.getLangOpts().CPlusPlus) { if (const FunctionDecl *FD = dyn_cast(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 @@ // 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 @@ 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 @@ 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; Index: lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp =================================================================== --- lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -218,7 +218,7 @@ 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)) { Index: lib/StaticAnalyzer/Core/PlistDiagnostics.cpp =================================================================== --- lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -471,7 +471,7 @@ o << " \n"; - if (!AnOpts.shouldDisplayMacroExpansions()) + if (!AnOpts.ShouldDisplayMacroExpansions) return; o << " macro_expansions\n" @@ -704,7 +704,7 @@ EmitString(o << " ", SM.getFileEntryForID(FID)->getName()) << '\n'; o << " \n"; - if (llvm::AreStatisticsEnabled() && AnOpts.shouldSerializeStats()) { + if (llvm::AreStatisticsEnabled() && AnOpts.ShouldSerializeStats) { o << " statistics\n"; std::string stats; llvm::raw_string_ostream os(stats); Index: lib/StaticAnalyzer/Core/RegionStore.cpp =================================================================== --- lib/StaticAnalyzer/Core/RegionStore.cpp +++ lib/StaticAnalyzer/Core/RegionStore.cpp @@ -350,7 +350,7 @@ if (SubEngine *Eng = StateMgr.getOwningEngine()) { AnalyzerOptions &Options = Eng->getAnalysisManager().options; SmallStructLimit = - Options.getRegionStoreSmallStructLimit(); + Options.RegionStoreSmallStructLimit; } } Index: lib/StaticAnalyzer/Core/SValBuilder.cpp =================================================================== --- lib/StaticAnalyzer/Core/SValBuilder.cpp +++ lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -385,7 +385,7 @@ // 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) Index: lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp =================================================================== --- lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -459,7 +459,7 @@ // 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(); Index: lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp =================================================================== --- lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -204,7 +204,7 @@ 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( "analyzer", "Analyzer timers"); TUTotalTimer = llvm::make_unique( @@ -739,7 +739,7 @@ // 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); Index: lib/StaticAnalyzer/Frontend/ModelInjector.cpp =================================================================== --- lib/StaticAnalyzer/Frontend/ModelInjector.cpp +++ lib/StaticAnalyzer/Frontend/ModelInjector.cpp @@ -48,7 +48,7 @@ FileID mainFileID = SM.getMainFileID(); AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts(); - llvm::StringRef modelPath = analyzerOpts->getModelPath(); + llvm::StringRef modelPath = analyzerOpts->ModelPath; llvm::SmallString<128> fileName; Index: test/Analysis/analyzer-config.c =================================================================== --- test/Analysis/analyzer-config.c +++ test/Analysis/analyzer-config.c @@ -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 @@ // 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 @@ // 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 Index: test/Analysis/analyzer-config.cpp =================================================================== --- test/Analysis/analyzer-config.cpp +++ test/Analysis/analyzer-config.cpp @@ -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 @@ // 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 @@ // 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