Index: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h =================================================================== --- include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -119,6 +119,24 @@ IPAK_DynamicDispatchBifurcate = 5 }; +enum class ExplorationStrategyKind { + DFS, + BFS, + UnexploredFirst, + UnexploredFirstQueue, + UnexploredFirstLocationQueue, + BFSBlockDFSContents, +}; + +/// Describes the kinds for high-level analyzer mode. +enum UserModeKind { + /// Perform shallow but fast analyzes. + UMK_Shallow = 1, + + /// Perform deep analyzes. + UMK_Deep = 2 +}; + class AnalyzerOptions : public RefCountedBase { public: using ConfigTable = llvm::StringMap; @@ -179,157 +197,16 @@ /// The mode of function selection used during inlining. AnalysisInliningMode InliningMode = NoRedundancy; - enum class ExplorationStrategyKind { - DFS, - BFS, - UnexploredFirst, - UnexploredFirstQueue, - UnexploredFirstLocationQueue, - BFSBlockDFSContents, - }; - private: - /// Describes the kinds for high-level analyzer mode. - enum UserModeKind { - /// Perform shallow but fast analyzes. - UMK_Shallow = 1, - - /// Perform deep analyzes. - UMK_Deep = 2 - }; - - llvm::Optional ExplorationStrategy; - - /// Controls the high-level analyzer mode, which influences the default - /// settings for some of the lower-level config options (such as IPAMode). - /// \sa getUserMode - llvm::Optional UserMode; - - /// Controls the mode of inter-procedural analysis. - llvm::Optional IPAMode; - - /// Controls which C++ member functions will be considered for inlining. - llvm::Optional CXXMemberInliningMode; - - /// \sa includeImplicitDtorsInCFG - Optional IncludeImplicitDtorsInCFG; - - /// \sa includeTemporaryDtorsInCFG - Optional IncludeTemporaryDtorsInCFG; - - /// \sa IncludeLifetimeInCFG - Optional IncludeLifetimeInCFG; - - /// \sa IncludeLoopExitInCFG - Optional IncludeLoopExitInCFG; - - /// \sa IncludeRichConstructorsInCFG - Optional IncludeRichConstructorsInCFG; - - /// \sa mayInlineCXXStandardLibrary - Optional InlineCXXStandardLibrary; - - /// \sa includeScopesInCFG - Optional IncludeScopesInCFG; - - /// \sa mayInlineTemplateFunctions - Optional InlineTemplateFunctions; - - /// \sa mayInlineCXXAllocator - Optional InlineCXXAllocator; - - /// \sa mayInlineCXXContainerMethods - Optional InlineCXXContainerMethods; - - /// \sa mayInlineCXXSharedPtrDtor - Optional InlineCXXSharedPtrDtor; - - /// \sa mayInlineCXXTemporaryDtors - Optional InlineCXXTemporaryDtors; - - /// \sa mayInlineObjCMethod - Optional ObjCInliningMode; - - // Cache of the "ipa-always-inline-size" setting. - // \sa getAlwaysInlineSize - Optional AlwaysInlineSize; - - /// \sa shouldSuppressNullReturnPaths - Optional SuppressNullReturnPaths; - - // \sa getMaxInlinableSize - Optional MaxInlinableSize; - - /// \sa shouldAvoidSuppressingNullArgumentPaths - Optional AvoidSuppressingNullArgumentPaths; - - /// \sa shouldSuppressInlinedDefensiveChecks - Optional SuppressInlinedDefensiveChecks; - - /// \sa shouldSuppressFromCXXStandardLibrary - Optional SuppressFromCXXStandardLibrary; - - /// \sa shouldCrosscheckWithZ3 - Optional CrosscheckWithZ3; - /// \sa reportIssuesInMainSourceFile - Optional ReportIssuesInMainSourceFile; - - /// \sa StableReportFilename - Optional StableReportFilename; - - Optional SerializeStats; - - /// \sa getGraphTrimInterval - Optional GraphTrimInterval; - - /// \sa getMaxSymbolComplexity - Optional MaxSymbolComplexity; - - /// \sa getMaxTimesInlineLarge - Optional MaxTimesInlineLarge; - - /// \sa getMinCFGSizeTreatFunctionsAsLarge - Optional MinCFGSizeTreatFunctionsAsLarge; - - /// \sa getMaxNodesPerTopLevelFunction - Optional MaxNodesPerTopLevelFunction; - - /// \sa shouldInlineLambdas - Optional InlineLambdas; - - /// \sa shouldWidenLoops - Optional WidenLoops; - - /// \sa shouldUnrollLoops - Optional UnrollLoops; - - /// \sa shouldDisplayNotesAsEvents - Optional DisplayNotesAsEvents; - - /// \sa shouldAggressivelySimplifyBinaryOperation - Optional AggressiveBinaryOperationSimplification; - - /// \sa shouldEagerlyAssume - Optional EagerlyAssumeBinOpBifurcation; - - /// \sa getCTUDir - Optional CTUDir; - - /// \sa getCTUIndexName - Optional CTUIndexName; - - /// \sa naiveCTUEnabled - Optional NaiveCTU; - - /// \sa shouldElideConstructors - Optional ElideConstructors; - - /// \sa getModelPath - Optional ModelPath; - - /// \sa getRegionStoreSmallStructLimit - Optional RegionStoreSmallStructLimit; +#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; +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def" +#undef ANALYZER_OPTION +#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE /// A helper function that retrieves option for a given full-qualified /// checker name. @@ -365,7 +242,7 @@ eagerlyAssumeBinOpBifurcation(false), TrimGraph(false), visualizeExplodedGraphWithGraphViz(false), UnoptimizedCFG(false), - PrintStats(false), NoRetryExhausted(false), CXXMemberInliningMode() {} + PrintStats(false), NoRetryExhausted(false) {} /// Interprets an option's string value as a boolean. The "true" string is /// interpreted as true and the "false" string is interpreted as false. @@ -420,7 +297,6 @@ const ento::CheckerBase *C = nullptr, bool SearchInParents = false); - unsigned getOptionAsUInt(Optional &V, StringRef Name, unsigned DefaultVal, const ento::CheckerBase *C = nullptr, @@ -448,6 +324,19 @@ const ento::CheckerBase *C = nullptr, bool SearchInParents = false); +#define ANALYZER_OPTION_GEN_FN(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL, \ + CREATE_FN) \ + TYPE CREATE_FN(); + +#define ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE( \ + TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL, DEEP_VAL, CREATE_FN) \ + TYPE CREATE_FN(); + +#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. @@ -466,286 +355,7 @@ /// \sa CXXMemberInliningMode bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K); - /// Returns true if ObjectiveC inlining is enabled, false otherwise. - bool mayInlineObjCMethod(); - - /// Returns whether or not the destructors for C++ temporary objects should - /// be included in the CFG. - /// - /// This is controlled by the 'cfg-temporary-dtors' config option, which - /// accepts the values "true" and "false". - bool includeTemporaryDtorsInCFG(); - - /// Returns whether or not implicit destructors for C++ objects should - /// be included in the CFG. - /// - /// This is controlled by the 'cfg-implicit-dtors' config option, which - /// accepts the values "true" and "false". - bool includeImplicitDtorsInCFG(); - - /// Returns whether or not end-of-lifetime information should be included in - /// the CFG. - /// - /// This is controlled by the 'cfg-lifetime' config option, which accepts - /// the values "true" and "false". - bool includeLifetimeInCFG(); - - /// Returns whether or not the end of the loop information should be included - /// in the CFG. - /// - /// This is controlled by the 'cfg-loopexit' config option, which accepts - /// the values "true" and "false". - bool includeLoopExitInCFG(); - - /// Returns whether or not construction site information should be included - /// in the CFG C++ constructor elements. - /// - /// This is controlled by the 'cfg-rich-constructors' config options, - /// which accepts the values "true" and "false". - bool includeRichConstructorsInCFG(); - - /// Returns whether or not scope information should be included in the CFG. - /// - /// This is controlled by the 'cfg-scope-info' config option, which accepts - /// the values "true" and "false". - bool includeScopesInCFG(); - - /// Returns whether or not C++ standard library functions may be considered - /// for inlining. - /// - /// This is controlled by the 'c++-stdlib-inlining' config option, which - /// accepts the values "true" and "false". - bool mayInlineCXXStandardLibrary(); - - /// Returns whether or not templated functions may be considered for inlining. - /// - /// This is controlled by the 'c++-template-inlining' config option, which - /// accepts the values "true" and "false". - bool mayInlineTemplateFunctions(); - - /// Returns whether or not allocator call may be considered for inlining. - /// - /// This is controlled by the 'c++-allocator-inlining' config option, which - /// accepts the values "true" and "false". - bool mayInlineCXXAllocator(); - - /// Returns whether or not methods of C++ container objects may be considered - /// for inlining. - /// - /// This is controlled by the 'c++-container-inlining' config option, which - /// accepts the values "true" and "false". - bool mayInlineCXXContainerMethods(); - - /// Returns 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". - /// - /// This is controlled by the 'c++-shared_ptr-inlining' config option, which - /// accepts the values "true" and "false". - bool mayInlineCXXSharedPtrDtor(); - - /// Returns true if 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. - /// - /// This is controlled by the 'c++-temp-dtor-inlining' config option, which - /// accepts the values "true" and "false". - bool mayInlineCXXTemporaryDtors(); - - /// Returns 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. - /// - /// This is controlled by the 'suppress-null-return-paths' config option, - /// which accepts the values "true" and "false". - bool shouldSuppressNullReturnPaths(); - - /// Returns whether a bug report should \em 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 counter-heuristic to avoid false negatives. - /// - /// This is controlled by the 'avoid-suppressing-null-argument-paths' config - /// option, which accepts the values "true" and "false". - bool shouldAvoidSuppressingNullArgumentPaths(); - - /// Returns whether or not diagnostics containing inlined defensive NULL - /// checks should be suppressed. - /// - /// This is controlled by the 'suppress-inlined-defensive-checks' config - /// option, which accepts the values "true" and "false". - bool shouldSuppressInlinedDefensiveChecks(); - - /// Returns whether or not diagnostics reported within the C++ standard - /// library should be suppressed. - /// - /// This is controlled by the 'suppress-c++-stdlib' config option, - /// which accepts the values "true" and "false". - bool shouldSuppressFromCXXStandardLibrary(); - - /// Returns whether bug reports should be crosschecked with the Z3 - /// constraint manager backend. - /// - /// This is controlled by the 'crosscheck-with-z3' config option, - /// which accepts the values "true" and "false". - bool shouldCrosscheckWithZ3(); - - /// Returns whether or not the diagnostic report should be always reported - /// in the main source file and not the headers. - /// - /// This is controlled by the 'report-in-main-source-file' config option, - /// which accepts the values "true" and "false". - bool shouldReportIssuesInMainSourceFile(); - - /// Returns whether or not the report filename should be random or not. - /// - /// This is controlled by the 'stable-report-filename' config option, - /// which accepts the values "true" and "false". Default = false - bool shouldWriteStableReportFilename(); - - /// \return Whether the analyzer should - /// serialize statistics to plist output. - /// Statistics would be serialized in JSON format inside the main dictionary - /// under the \c statistics key. - /// Available only if compiled in assert mode or with LLVM statistics - /// explicitly enabled. - bool shouldSerializeStats(); - - /// Returns whether irrelevant parts of a bug report path should be pruned - /// out of the final output. - /// - /// This is controlled by the 'prune-paths' config option, which accepts the - /// values "true" and "false". - bool shouldPrunePaths(); - - /// Returns true if 'static' initializers should be in conditional logic - /// in the CFG. - bool shouldConditionalizeStaticInitializers(); - - // Returns the size of the functions (in basic blocks), which should be - // considered to be small enough to always inline. - // - // This is controlled by "ipa-always-inline-size" analyzer-config option. - unsigned getAlwaysInlineSize(); - - // Returns the bound on the number of basic blocks in an inlined function - // (50 by default). - // - // This is controlled by "-analyzer-config max-inlinable-size" option. - unsigned getMaxInlinableSize(); - - /// Returns true if the analyzer engine should synthesize fake bodies - /// for well-known functions. - bool shouldSynthesizeBodies(); - - /// Returns how often nodes in the ExplodedGraph should be recycled to save - /// memory. - /// - /// This is controlled by the 'graph-trim-interval' config option. To disable - /// node reclamation, set the option to "0". - unsigned getGraphTrimInterval(); - - /// Returns the maximum complexity of symbolic constraint (50 by default). - /// - /// This is controlled by "-analyzer-config max-symbol-complexity" option. - unsigned getMaxSymbolComplexity(); - - /// Returns the maximum times a large function could be inlined. - /// - /// This is controlled by the 'max-times-inline-large' config option. - unsigned getMaxTimesInlineLarge(); - - /// Returns the number of basic blocks a function needs to have to be - /// considered large for the 'max-times-inline-large' config option. - /// - /// This is controlled by the 'min-cfg-size-treat-functions-as-large' config - /// option. - unsigned getMinCFGSizeTreatFunctionsAsLarge(); - - /// Returns the maximum number of nodes the analyzer can generate while - /// exploring a top level function (for each exploded graph). - /// 150000 is default; 0 means no limit. - /// - /// This is controlled by the 'max-nodes' config option. - unsigned getMaxNodesPerTopLevelFunction(); - - /// Returns true if lambdas should be inlined. Otherwise a sink node will be - /// generated each time a LambdaExpr is visited. - bool shouldInlineLambdas(); - - /// Returns true if the analysis should try to widen loops. - /// This is controlled by the 'widen-loops' config option. - bool shouldWidenLoops(); - - /// Returns true if the analysis should try to unroll loops with known bounds. - /// This is controlled by the 'unroll-loops' config option. - bool shouldUnrollLoops(); - - /// Returns true if 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. - /// - /// This is controlled by the 'extra-notes-as-events' option, which defaults - /// to false when unset. - bool shouldDisplayNotesAsEvents(); - - /// Returns true if SValBuilder should rearrange comparisons and additive - /// operations of symbolic expressions which consist of a sum of a symbol and - /// a concrete integer into the format where symbols are on the left-hand - /// side and the integer is on the right. This is only done if both symbols - /// and both concrete integers are signed, greater than or equal to the - /// quarter of the minimum value of the type and less than or equal to the - /// quarter of the maximum value of that type. - /// - /// A + n B + m becomes A - B m - n, where A and B symbolic, - /// n and m are integers. is any of '==', '!=', '<', '<=', '>', '>=', - /// '+' or '-'. The rearrangement also happens with '-' instead of '+' on - // either or both side and also if any or both integers are missing. - bool shouldAggressivelySimplifyBinaryOperation(); - - /// Returns true if 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 subexpression 'y != 0' will be - /// eagerly assumed to be true or false, thus 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. - bool shouldEagerlyAssume(); - - /// Returns the directory containing the CTU related files. StringRef getCTUDir(); - - /// Returns the name of the file containing the CTU index of functions. - StringRef getCTUIndexName(); - - /// Returns true when naive cross translation unit analysis is enabled. - /// This is an experimental feature to inline functions from another - /// translation units. - bool naiveCTUEnabled(); - - /// Returns true if 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. - bool shouldElideConstructors(); - - /// Returns the maximum number of nodes the analyzer can generate while - /// exploring a top level function (for each exploded graph). 0 means no limit. - unsigned getRegionStoreSmallStructLimit(); - - StringRef getModelPath(); }; using AnalyzerOptionsRef = IntrusiveRefCntPtr; Index: include/clang/StaticAnalyzer/Core/AnalyzerOptions.def =================================================================== --- /dev/null +++ include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -0,0 +1,478 @@ +//===-- AnalyzerOptions.def - Metadata about Static Analyses ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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 +#error This .def file is expected to be included in translation units where \ +"llvm/ADT/StringRef.h" is already included! +#endif + +#ifdef ANALYZER_OPTION +#ifndef ANALYZER_OPTION_DEPENDS_ON_USER_MODE +#error If you didn't include this file with the intent of generating methods, \ +define both 'ANALYZER_OPTION' and 'ANALYZER_OPTION_DEPENDS_ON_USER_MODE' macros! +#endif +#endif + +#ifndef ANALYZER_OPTION_DEPENDS_ON_USER_MODE +#ifdef ANALYZER_OPTION +#error If you didn't include this file with the intent of generating methods, \ +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. +/// +/// 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. +#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL) +#endif + +#ifndef ANALYZER_OPTION_DEPENDS_ON_USER_MODE +/// Create a new analyzer option, but dont generate a method for it in +/// AnalyzerOptions. It's value depends on the option "user-mode". +/// +/// 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. +/// 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". +#define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC, \ + 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 + +#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 + +//===----------------------------------------------------------------------===// +// Boolean analyzer options. +//===----------------------------------------------------------------------===// + +ANALYZER_OPTION_GEN_FN( + bool, IncludeImplicitDtorsInCFG, "cfg-implicit-dtors", + "(bool) Whether or not implicit destructors for C++ objects should be " + "included in the CFG. (default: true)", + true, includeImplicitDtorsInCFG) + +ANALYZER_OPTION_GEN_FN( + bool, IncludeTemporaryDtorsInCFG, "cfg-temporary-dtors", + "(bool) Whether or not the destructors for C++ temporary objects should be " + "included in the CFG. (default: true)", + true, includeTemporaryDtorsInCFG) + +ANALYZER_OPTION_GEN_FN(bool, IncludeLifetimeInCFG, "cfg-lifetime", + "(bool) Whether or not end-of-lifetime information " + "should be included in the CFG. (default: false)", + false, includeLifetimeInCFG) + +ANALYZER_OPTION_GEN_FN(bool, IncludeLoopExitInCFG, "cfg-loopexit", + "(bool) Whether or not the end of the loop information " + "should be included in the CFG. (default: false)", + false, includeLoopExitInCFG) + +ANALYZER_OPTION_GEN_FN( + bool, IncludeRichConstructorsInCFG, "cfg-rich-constructors", + "(bool) Whether or not construction site information should be included in " + "the CFG C++ constructor elements. (default: true)", + true, includeRichConstructorsInCFG) + +ANALYZER_OPTION_GEN_FN(bool, IncludeScopesInCFG, "cfg-scopes", + "(bool) Whether or not scope information should be " + "included in the CFG. (default: false)", + false, includeScopesInCFG) + +ANALYZER_OPTION_GEN_FN( + bool, InlineTemplateFunctions, "c++-template-inlining", + "(bool) Whether or not templated functions may be considered for inlining.", + true, mayInlineTemplateFunctions) + +ANALYZER_OPTION_GEN_FN( + bool, InlineCXXStandardLibrary, "c++-stdlib-inlining", + "(bool) Whether or not C++ standard library functions may be " + "considered for inlining. (default: true)", + true, mayInlineCXXStandardLibrary) + +ANALYZER_OPTION_GEN_FN(bool, InlineCXXAllocator, "c++-allocator-inlining", + "(bool) Whether or not allocator call may be " + "considered for inlining. (default: true)", + true, mayInlineCXXAllocator) + +ANALYZER_OPTION_GEN_FN( + bool, InlineCXXSharedPtrDtor, "c++-shared_ptr-inlining", + "(bool) 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'. " + "(default: false)", + false, mayInlineCXXSharedPtrDtor) + +ANALYZER_OPTION_GEN_FN( + bool, InlineCXXTemporaryDtors, "c++-temp-dtor-inlining", + "(bool) 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. (default: true)", + true, mayInlineCXXTemporaryDtors) + +ANALYZER_OPTION_GEN_FN( + bool, SuppressNullReturnPaths, "suppress-null-return-paths", + "(bool) 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. (default: true)", + true, shouldSuppressNullReturnPaths) + +ANALYZER_OPTION_GEN_FN( + bool, AvoidSuppressingNullArgumentPaths, + "avoid-suppressing-null-argument-paths", + "(bool) 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 counter-heuristic to " + "avoid false negatives. (default: false)", + false, shouldAvoidSuppressingNullArgumentPaths) + +ANALYZER_OPTION_GEN_FN( + bool, SuppressInlinedDefensiveChecks, "suppress-inlined-defensive-checks", + "(bool) Whether or not diagnostics containing inlined defensive NULL " + "checks should be suppressed. (default: true)", + true, shouldSuppressInlinedDefensiveChecks) + +ANALYZER_OPTION_GEN_FN( + bool, InlineCXXContainerMethods, "c++-container-inlining", + "(bool) Whether or not methods of C++ container objects may be considered " + "for inlining. (default: false)", + false, mayInlineCXXContainerMethods) + +ANALYZER_OPTION_GEN_FN( + bool, SuppressFromCXXStandardLibrary, "suppress-c++-stdlib", + "(bool) Whether or not diagnostics reported within the C++ standard " + "library should be suppressed. (default: true)", + true, shouldSuppressFromCXXStandardLibrary) + +ANALYZER_OPTION_GEN_FN( + bool, CrosscheckWithZ3, "crosscheck-with-z3", + "(bool) Whether bug reports should be crosschecked with the Z3 constraint " + "manager backend. (default: false)", + false, shouldCrosscheckWithZ3) + +ANALYZER_OPTION_GEN_FN( + bool, ReportIssuesInMainSourceFile, "report-in-main-source-file", + "(bool) Whether or not the diagnostic report should be always reported in " + "the main source file and not the headers. (default: false)", + false, shouldReportIssuesInMainSourceFile) + +ANALYZER_OPTION_GEN_FN(bool, WriteStableReportFilename, + "stable-report-filename", + "(bool) Whether or not the report filename should be " + "random or not. (default: false)", + false, shouldWriteStableReportFilename) + +ANALYZER_OPTION_GEN_FN( + bool, SerializeStats, "serialize-stats", + "(bool) 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. (default: false)", + false, shouldSerializeStats) + +ANALYZER_OPTION_GEN_FN(bool, InlineObjCMethod, "objc-inlining", + "(bool) Whether ObjectiveC inlining is enabled, false " + "otherwise. (default: false)", + true, mayInlineObjCMethod) + +ANALYZER_OPTION_GEN_FN( + bool, PrunePaths, "prune-paths", + "(bool) Whether irrelevant parts of a bug report path should be pruned out " + "of the final output. (default: true)", + true, shouldPrunePaths) + +ANALYZER_OPTION_GEN_FN(bool, ConditionalizeStaticInitializers, + "cfg-conditional-static-initializers", + "(bool) Whether 'static' initializers should be in " + "conditional logic in the CFG. (default: true)", + true, shouldConditionalizeStaticInitializers) + +ANALYZER_OPTION_GEN_FN(bool, SynthesizeBodies, "faux-bodies", + "(bool) Whether the analyzer engine should synthesize " + "fake bodies for well-known functions. (default: true)", + true, shouldSynthesizeBodies) + +ANALYZER_OPTION_GEN_FN( + bool, ElideConstructors, "elide-constructors", + "(bool) 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. (default: true)", + true, shouldElideConstructors) + +ANALYZER_OPTION_GEN_FN( + bool, InlineLambdas, "inline-lambdas", + "(bool) Whether lambdas should be inlined. Otherwise a sink node will be " + "generated each time a LambdaExpr is visited. (default: true)", + true, shouldInlineLambdas) + +ANALYZER_OPTION_GEN_FN( + bool, WidenLoops, "widen-loops", + "(bool) Whether the analysis should try to widen loops. This is controlled " + "by the '' config option. (default: false)", + false, shouldWidenLoops) + +ANALYZER_OPTION_GEN_FN(bool, UnrollLoops, "unroll-loops", + "(bool) Whether the analysis should try to unroll " + "loops with known bounds. (default: false)", + false, shouldUnrollLoops) + +ANALYZER_OPTION_GEN_FN( + bool, DisplayNotesAsEvents, "notes-as-events", + "(bool) 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. (default: false)", + false, shouldDisplayNotesAsEvents) + +ANALYZER_OPTION_GEN_FN( + bool, AggressivelySimplifyBinaryOperation, + "aggressive-binary-operation-simplification", + "(bool) Whether SValBuilder should rearrange comparisons and additive " + "operations of symbolic expressions which consist of a sum of a symbol and " + "a concrete integer into the format where symbols are on the left-hand " + "side and the integer is on the right. This is only done if both symbols " + "and both concrete integers are signed, greater than or equal to the " + "quarter of the minimum value of the type and less than or equal to the " + "quarter of the maximum value of that type. A + n B + m becomes A " + "- B m - n, where A and B symbolic, n and m are integers. is any " + "of '==', '!=', '<', '<=', '>', '>=', '+' or '-'. The rearrangement also " + "happens with '-' instead of '+' on either or both side and also if any or " + "both integers are missing. (default: false)", + false, shouldAggressivelySimplifyBinaryOperation) + +ANALYZER_OPTION_GEN_FN( + bool, EagerlyAssume, "eagerly-assume", + "(bool) 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 " + "subexpression 'y != 0' will be eagerly assumed to be true or false, thus " + "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. " + "(default: true)", + true, shouldEagerlyAssume) + +ANALYZER_OPTION_GEN_FN( + bool, NaiveCTU, "experimental-enable-naive-ctu-analysis", + "(bool) Whether naive cross translation unit analysis is enabled. This is " + "an experimental feature to inline functions from another translation " + "units. (default: false)", + false, naiveCTUEnabled) + +//===----------------------------------------------------------------------===// +// Unsinged analyzer options. +//===----------------------------------------------------------------------===// + +ANALYZER_OPTION_GEN_FN( + unsigned, AlwaysInlineSize, "ipa-always-inline-size", + "(unsigned) The size of the functions (in basic blocks), which should be " + "considered to be small enough to always inline. (default: 3)", + 3, getAlwaysInlineSize) + +ANALYZER_OPTION_GEN_FN(unsigned, GraphTrimInterval, "graph-trim-interval", + "(unsigned) How often nodes in the ExplodedGraph " + "should be recycled to save memory. To disable node " + "reclamation, set the option to 0. (default: 1000)", + 1000, getGraphTrimInterval) + +ANALYZER_OPTION_GEN_FN(unsigned, MinCFGSizeTreatFunctionsAsLarge, + "min-cfg-size-treat-functions-as-large", + "(unsigned) The number of basic blocks a function " + "needs to have to be considered large for the " + "'max-times-inline-large' config option. (default: 14)", + 14, getMinCFGSizeTreatFunctionsAsLarge) + +ANALYZER_OPTION_GEN_FN( + unsigned, MaxSymbolComplexity, "max-symbol-complexity", + "(unsigned) The maximum complexity of symbolic constraint (default: 35).", + 35, getMaxSymbolComplexity) + +ANALYZER_OPTION_GEN_FN(unsigned, MaxTimesInlineLarge, "max-times-inline-large", + "(unsigned) The maximum times a large function could " + "be inlined. (default: 32)", + 32, getMaxTimesInlineLarge) + +ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE( + unsigned, MaxInlinableSize, "max-inlinable-size", + "(unsigned) The bound on the number of basic blocks in an inlined " + "function. (default: 4 in shallow mode, 100 in deep mode)", + /* SHALLOW_VAL */ 4, /* DEEP_VAL */ 100, getMaxInlinableSize) + +ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE( + unsigned, MaxNodesPerTopLevelFunction, "max-nodes", + "(unsigned) The maximum number of nodes the analyzer can generate while " + "exploring a top level function (for each exploded graph). 0 means no " + "limit. (default: 75000 in shallow mode, 225000 in deep mode)", + /* SHALLOW_VAL */ 75000, /* DEEP_VAL */ 225000, + getMaxNodesPerTopLevelFunction) + +ANALYZER_OPTION_GEN_FN( + unsigned, RegionStoreSmallStructLimit, "region-store-small-struct-limit", + "(unsigned) Returns the maximum number of nodes the analyzer can generate " + "while exploring a top level function (for each exploded graph). 0 means " + "no limit. (default: 2)", + 2, getRegionStoreSmallStructLimit) + +//===----------------------------------------------------------------------===// +// String analyzer options. +//===----------------------------------------------------------------------===// + +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. (default: \"externalFnMap.txt\")", + "externalFnMap.txt", getCTUIndexName) + +ANALYZER_OPTION_GEN_FN(StringRef, ModelPath, "model-path", "", "", getModelPath) + +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") + +ANALYZER_OPTION(StringRef, CXXMemberInliningMode, "c++-inlining", + "(string) Controls which C++ member functions will be " + "considered for inlining. Value: \"constructors\", " + "\"destructors\", \"methods\".", + "destructors") + +ANALYZER_OPTION_DEPENDS_ON_USER_MODE( + StringRef, IPAMode, "ipa", + "(string) Controls the mode of inter-procedural analysis. Value: " + "\"none\", " + "\"basic-inlining\", \"inlining\", \"dynamic\", " + "\"dynamic-bifurcate\".", + /* SHALLOW_VAL */ "inlining", /* DEEP_VAL */ "dynamic-bifurcate") + +ANALYZER_OPTION( + StringRef, ExplorationStrategy, "exploration_strategy", + "(string) Value: \"dfs\", \"bfs\", \"unexplored_first\", " + "\"unexplored_first_queue\", \"unexplored_first_location_queue\", " + "\"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/StaticAnalyzer/Core/AnalyzerOptions.cpp =================================================================== --- lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -49,91 +49,87 @@ return Result; } -AnalyzerOptions::UserModeKind AnalyzerOptions::getUserMode() { +UserModeKind AnalyzerOptions::getUserMode() { if (!UserMode.hasValue()) { - StringRef ModeStr = getOptionAsString("mode", "deep"); - UserMode = llvm::StringSwitch>(ModeStr) - .Case("shallow", UMK_Shallow) - .Case("deep", UMK_Deep) - .Default(None); - assert(UserMode.getValue() && "User mode is invalid."); + UserMode = getOptionAsString("mode", "deep"); } - return UserMode.getValue(); + + 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(); } -AnalyzerOptions::ExplorationStrategyKind +ExplorationStrategyKind AnalyzerOptions::getExplorationStrategy() { if (!ExplorationStrategy.hasValue()) { - StringRef StratStr = getOptionAsString("exploration_strategy", - "unexplored_first_queue"); - ExplorationStrategy = - llvm::StringSwitch>(StratStr) - .Case("dfs", ExplorationStrategyKind::DFS) - .Case("bfs", ExplorationStrategyKind::BFS) - .Case("unexplored_first", - ExplorationStrategyKind::UnexploredFirst) - .Case("unexplored_first_queue", - ExplorationStrategyKind::UnexploredFirstQueue) - .Case("unexplored_first_location_queue", - ExplorationStrategyKind::UnexploredFirstLocationQueue) - .Case("bfs_block_dfs_contents", - ExplorationStrategyKind::BFSBlockDFSContents) - .Default(None); - assert(ExplorationStrategy.hasValue() && - "User mode is invalid."); + ExplorationStrategy = getOptionAsString("exploration_strategy", + "unexplored_first_queue"); } - return ExplorationStrategy.getValue(); + auto K = + llvm::StringSwitch>( + *ExplorationStrategy) + .Case("dfs", ExplorationStrategyKind::DFS) + .Case("bfs", ExplorationStrategyKind::BFS) + .Case("unexplored_first", + ExplorationStrategyKind::UnexploredFirst) + .Case("unexplored_first_queue", + ExplorationStrategyKind::UnexploredFirstQueue) + .Case("unexplored_first_location_queue", + ExplorationStrategyKind::UnexploredFirstLocationQueue) + .Case("bfs_block_dfs_contents", + ExplorationStrategyKind::BFSBlockDFSContents) + .Default(None); + assert(K.hasValue() && "User mode is invalid."); + return K.getValue(); } IPAKind AnalyzerOptions::getIPAMode() { if (!IPAMode.hasValue()) { - // Use the User Mode to set the default IPA value. - // Note, we have to add the string to the Config map for the ConfigDumper - // checker to function properly. - const char *DefaultIPA = nullptr; - UserModeKind HighLevelMode = getUserMode(); - if (HighLevelMode == UMK_Shallow) - DefaultIPA = "inlining"; - else if (HighLevelMode == UMK_Deep) - DefaultIPA = "dynamic-bifurcate"; - assert(DefaultIPA); - - // Lookup the ipa configuration option, use the default from User Mode. - StringRef ModeStr = getOptionAsString("ipa", DefaultIPA); - IPAMode = llvm::StringSwitch>(ModeStr) - .Case("none", IPAK_None) - .Case("basic-inlining", IPAK_BasicInlining) - .Case("inlining", IPAK_Inlining) - .Case("dynamic", IPAK_DynamicDispatch) - .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate) - .Default(None); - assert(IPAMode.hasValue() && "IPA Mode is invalid."); + switch (getUserMode()) { + case UMK_Shallow: + IPAMode = getOptionAsString("ipa", "inlining"); + break; + case UMK_Deep: + IPAMode = getOptionAsString("ipa", "dynamic-bifurcate"); + break; + } } + auto K = llvm::StringSwitch>(*IPAMode) + .Case("none", IPAK_None) + .Case("basic-inlining", IPAK_BasicInlining) + .Case("inlining", IPAK_Inlining) + .Case("dynamic", IPAK_DynamicDispatch) + .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate) + .Default(None); + assert(K.hasValue() && "IPA Mode is invalid."); - return IPAMode.getValue(); + return K.getValue(); } bool -AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) { +AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind Param) { + if (!CXXMemberInliningMode.hasValue()) { + CXXMemberInliningMode = getOptionAsString("c++-inlining", "destructors"); + } + if (getIPAMode() < IPAK_Inlining) return false; - if (!CXXMemberInliningMode) { - StringRef ModeStr = getOptionAsString("c++-inlining", "destructors"); - - CXXMemberInliningMode = - llvm::StringSwitch>(ModeStr) - .Case("constructors", CIMK_Constructors) - .Case("destructors", CIMK_Destructors) - .Case("methods", CIMK_MemberFunctions) - .Case("none", CIMK_None) - .Default(None); + auto K = + llvm::StringSwitch>( + *CXXMemberInliningMode) + .Case("constructors", CIMK_Constructors) + .Case("destructors", CIMK_Destructors) + .Case("methods", CIMK_MemberFunctions) + .Case("none", CIMK_None) + .Default(None); - assert(CXXMemberInliningMode.hasValue() && - "Invalid c++ member function inlining mode."); - } + assert(K.hasValue() && "Invalid c++ member function inlining mode."); - return *CXXMemberInliningMode >= K; + return *K >= Param; } static StringRef toString(bool b) { return b ? "true" : "false"; } @@ -183,137 +179,6 @@ return V.getValue(); } -bool AnalyzerOptions::includeTemporaryDtorsInCFG() { - return getBooleanOption(IncludeTemporaryDtorsInCFG, - "cfg-temporary-dtors", - /* Default = */ true); -} - -bool AnalyzerOptions::includeImplicitDtorsInCFG() { - return getBooleanOption(IncludeImplicitDtorsInCFG, - "cfg-implicit-dtors", - /* Default = */ true); -} - -bool AnalyzerOptions::includeLifetimeInCFG() { - return getBooleanOption(IncludeLifetimeInCFG, "cfg-lifetime", - /* Default = */ false); -} - -bool AnalyzerOptions::includeLoopExitInCFG() { - return getBooleanOption(IncludeLoopExitInCFG, "cfg-loopexit", - /* Default = */ false); -} - -bool AnalyzerOptions::includeRichConstructorsInCFG() { - return getBooleanOption(IncludeRichConstructorsInCFG, - "cfg-rich-constructors", - /* Default = */ true); -} - -bool AnalyzerOptions::includeScopesInCFG() { - return getBooleanOption(IncludeScopesInCFG, - "cfg-scopes", - /* Default = */ false); -} - -bool AnalyzerOptions::mayInlineCXXStandardLibrary() { - return getBooleanOption(InlineCXXStandardLibrary, - "c++-stdlib-inlining", - /*Default=*/true); -} - -bool AnalyzerOptions::mayInlineTemplateFunctions() { - return getBooleanOption(InlineTemplateFunctions, - "c++-template-inlining", - /*Default=*/true); -} - -bool AnalyzerOptions::mayInlineCXXAllocator() { - return getBooleanOption(InlineCXXAllocator, - "c++-allocator-inlining", - /*Default=*/true); -} - -bool AnalyzerOptions::mayInlineCXXContainerMethods() { - return getBooleanOption(InlineCXXContainerMethods, - "c++-container-inlining", - /*Default=*/false); -} - -bool AnalyzerOptions::mayInlineCXXSharedPtrDtor() { - return getBooleanOption(InlineCXXSharedPtrDtor, - "c++-shared_ptr-inlining", - /*Default=*/false); -} - -bool AnalyzerOptions::mayInlineCXXTemporaryDtors() { - return getBooleanOption(InlineCXXTemporaryDtors, - "c++-temp-dtor-inlining", - /*Default=*/true); -} - -bool AnalyzerOptions::mayInlineObjCMethod() { - return getBooleanOption(ObjCInliningMode, - "objc-inlining", - /* Default = */ true); -} - -bool AnalyzerOptions::shouldSuppressNullReturnPaths() { - return getBooleanOption(SuppressNullReturnPaths, - "suppress-null-return-paths", - /* Default = */ true); -} - -bool AnalyzerOptions::shouldAvoidSuppressingNullArgumentPaths() { - return getBooleanOption(AvoidSuppressingNullArgumentPaths, - "avoid-suppressing-null-argument-paths", - /* Default = */ false); -} - -bool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() { - return getBooleanOption(SuppressInlinedDefensiveChecks, - "suppress-inlined-defensive-checks", - /* Default = */ true); -} - -bool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() { - return getBooleanOption(SuppressFromCXXStandardLibrary, - "suppress-c++-stdlib", - /* Default = */ true); -} - -bool AnalyzerOptions::shouldCrosscheckWithZ3() { - return getBooleanOption(CrosscheckWithZ3, - "crosscheck-with-z3", - /* Default = */ false); -} - -bool AnalyzerOptions::shouldReportIssuesInMainSourceFile() { - return getBooleanOption(ReportIssuesInMainSourceFile, - "report-in-main-source-file", - /* Default = */ false); -} - - -bool AnalyzerOptions::shouldWriteStableReportFilename() { - return getBooleanOption(StableReportFilename, - "stable-report-filename", - /* Default = */ false); -} - -bool AnalyzerOptions::shouldSerializeStats() { - return getBooleanOption(SerializeStats, - "serialize-stats", - /* Default = */ false); -} - -bool AnalyzerOptions::shouldElideConstructors() { - return getBooleanOption(ElideConstructors, - "elide-constructors", - /* Default = */ true); -} - int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal, const CheckerBase *C, bool SearchInParents) { @@ -361,123 +226,46 @@ return V.getValue(); } -unsigned AnalyzerOptions::getAlwaysInlineSize() { - if (!AlwaysInlineSize.hasValue()) - AlwaysInlineSize = getOptionAsInteger("ipa-always-inline-size", 3); - return AlwaysInlineSize.getValue(); -} - -unsigned AnalyzerOptions::getMaxInlinableSize() { - if (!MaxInlinableSize.hasValue()) { - int DefaultValue = 0; - UserModeKind HighLevelMode = getUserMode(); - switch (HighLevelMode) { - case UMK_Shallow: - DefaultValue = 4; - break; - case UMK_Deep: - DefaultValue = 100; - break; - } - - MaxInlinableSize = getOptionAsInteger("max-inlinable-size", DefaultValue); - } - return MaxInlinableSize.getValue(); -} - -unsigned AnalyzerOptions::getGraphTrimInterval() { - if (!GraphTrimInterval.hasValue()) - GraphTrimInterval = getOptionAsInteger("graph-trim-interval", 1000); - return GraphTrimInterval.getValue(); -} - -unsigned AnalyzerOptions::getMaxSymbolComplexity() { - if (!MaxSymbolComplexity.hasValue()) - MaxSymbolComplexity = getOptionAsInteger("max-symbol-complexity", 35); - return MaxSymbolComplexity.getValue(); -} - -unsigned AnalyzerOptions::getMaxTimesInlineLarge() { - if (!MaxTimesInlineLarge.hasValue()) - MaxTimesInlineLarge = getOptionAsInteger("max-times-inline-large", 32); - return MaxTimesInlineLarge.getValue(); -} - -unsigned AnalyzerOptions::getMinCFGSizeTreatFunctionsAsLarge() { - if (!MinCFGSizeTreatFunctionsAsLarge.hasValue()) - MinCFGSizeTreatFunctionsAsLarge = getOptionAsInteger( - "min-cfg-size-treat-functions-as-large", 14); - return MinCFGSizeTreatFunctionsAsLarge.getValue(); +static bool getOption(AnalyzerOptions &A, Optional &V, StringRef Name, + bool DefaultVal) { + return A.getBooleanOption(V, Name, DefaultVal); } -unsigned AnalyzerOptions::getMaxNodesPerTopLevelFunction() { - if (!MaxNodesPerTopLevelFunction.hasValue()) { - int DefaultValue = 0; - UserModeKind HighLevelMode = getUserMode(); - switch (HighLevelMode) { - case UMK_Shallow: - DefaultValue = 75000; - break; - case UMK_Deep: - DefaultValue = 225000; - break; - } - MaxNodesPerTopLevelFunction = getOptionAsInteger("max-nodes", DefaultValue); - } - return MaxNodesPerTopLevelFunction.getValue(); +static unsigned getOption(AnalyzerOptions &A, Optional &V, + StringRef Name, unsigned DefaultVal) { + return A.getOptionAsUInt(V, Name, DefaultVal); } -bool AnalyzerOptions::shouldSynthesizeBodies() { - return getBooleanOption("faux-bodies", true); +static StringRef getOption(AnalyzerOptions &A, Optional &V, + StringRef Name, StringRef DefaultVal) { + return A.getOptionAsString(V, Name, DefaultVal); } -bool AnalyzerOptions::shouldPrunePaths() { - return getBooleanOption("prune-paths", true); +#define ANALYZER_OPTION_GEN_FN(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL, \ + CREATE_FN) \ +TYPE AnalyzerOptions::CREATE_FN() { \ + return getOption(*this, NAME, CMDFLAG, DEFAULT_VAL); \ } -bool AnalyzerOptions::shouldConditionalizeStaticInitializers() { - return getBooleanOption("cfg-conditional-static-initializers", true); +#define ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE( \ + TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL, DEEP_VAL, CREATE_FN) \ +TYPE AnalyzerOptions::CREATE_FN() { \ + switch (getUserMode()) { \ + case UMK_Shallow: \ + return getOption(*this, NAME, CMDFLAG, SHALLOW_VAL); \ + case UMK_Deep: \ + return getOption(*this, NAME, CMDFLAG, DEEP_VAL); \ + } \ + \ + llvm_unreachable("Unknown usermode!"); \ + return {}; \ } -bool AnalyzerOptions::shouldInlineLambdas() { - if (!InlineLambdas.hasValue()) - InlineLambdas = getBooleanOption("inline-lambdas", /*Default=*/true); - return InlineLambdas.getValue(); -} +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def" -bool AnalyzerOptions::shouldWidenLoops() { - if (!WidenLoops.hasValue()) - WidenLoops = getBooleanOption("widen-loops", /*Default=*/false); - return WidenLoops.getValue(); -} +#undef ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE +#undef ANALYZER_OPTION_WITH_FN -bool AnalyzerOptions::shouldUnrollLoops() { - if (!UnrollLoops.hasValue()) - UnrollLoops = getBooleanOption("unroll-loops", /*Default=*/false); - return UnrollLoops.getValue(); -} - -bool AnalyzerOptions::shouldDisplayNotesAsEvents() { - if (!DisplayNotesAsEvents.hasValue()) - DisplayNotesAsEvents = - getBooleanOption("notes-as-events", /*Default=*/false); - return DisplayNotesAsEvents.getValue(); -} - -bool AnalyzerOptions::shouldAggressivelySimplifyBinaryOperation() { - if (!AggressiveBinaryOperationSimplification.hasValue()) - AggressiveBinaryOperationSimplification = - getBooleanOption("aggressive-binary-operation-simplification", - /*Default=*/false); - return AggressiveBinaryOperationSimplification.getValue(); -} - -bool AnalyzerOptions::shouldEagerlyAssume() { - if (!EagerlyAssumeBinOpBifurcation.hasValue()) - EagerlyAssumeBinOpBifurcation = - getBooleanOption("eagerly-assume", true); - return EagerlyAssumeBinOpBifurcation.getValue(); -} StringRef AnalyzerOptions::getCTUDir() { if (!CTUDir.hasValue()) { @@ -487,30 +275,3 @@ } return CTUDir.getValue(); } - -bool AnalyzerOptions::naiveCTUEnabled() { - if (!NaiveCTU.hasValue()) { - NaiveCTU = getBooleanOption("experimental-enable-naive-ctu-analysis", - /*Default=*/false); - } - return NaiveCTU.getValue(); -} - -unsigned AnalyzerOptions::getRegionStoreSmallStructLimit() { - if (!RegionStoreSmallStructLimit.hasValue()) - RegionStoreSmallStructLimit = - getOptionAsInteger("region-store-small-struct-limit", 2); - return RegionStoreSmallStructLimit.getValue(); -} - -StringRef AnalyzerOptions::getCTUIndexName() { - if (!CTUIndexName.hasValue()) - CTUIndexName = getOptionAsString("ctu-index-name", "externalFnMap.txt"); - return CTUIndexName.getValue(); -} - -StringRef AnalyzerOptions::getModelPath() { - if (!ModelPath.hasValue()) - ModelPath = getOptionAsString("model-path", ""); - return ModelPath.getValue(); -} Index: lib/StaticAnalyzer/Core/CoreEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/CoreEngine.cpp +++ lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -56,17 +56,17 @@ static std::unique_ptr generateWorkList(AnalyzerOptions &Opts, SubEngine &subengine) { switch (Opts.getExplorationStrategy()) { - case AnalyzerOptions::ExplorationStrategyKind::DFS: + case ExplorationStrategyKind::DFS: return WorkList::makeDFS(); - case AnalyzerOptions::ExplorationStrategyKind::BFS: + case ExplorationStrategyKind::BFS: return WorkList::makeBFS(); - case AnalyzerOptions::ExplorationStrategyKind::BFSBlockDFSContents: + case ExplorationStrategyKind::BFSBlockDFSContents: return WorkList::makeBFSBlockDFSContents(); - case AnalyzerOptions::ExplorationStrategyKind::UnexploredFirst: + case ExplorationStrategyKind::UnexploredFirst: return WorkList::makeUnexploredFirst(); - case AnalyzerOptions::ExplorationStrategyKind::UnexploredFirstQueue: + case ExplorationStrategyKind::UnexploredFirstQueue: return WorkList::makeUnexploredFirstPriorityQueue(); - case AnalyzerOptions::ExplorationStrategyKind::UnexploredFirstLocationQueue: + case ExplorationStrategyKind::UnexploredFirstLocationQueue: return WorkList::makeUnexploredFirstPriorityLocationQueue(); } }