Index: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h =================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ cfe/trunk/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,160 +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 shouldDisplayMacroExpansions - Optional DisplayMacroExpansions; - - /// \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. @@ -368,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. @@ -423,7 +297,6 @@ const ento::CheckerBase *C = nullptr, bool SearchInParents = false); - unsigned getOptionAsUInt(Optional &V, StringRef Name, unsigned DefaultVal, const ento::CheckerBase *C = nullptr, @@ -451,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. @@ -469,302 +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 macros related to the bugpath should be expanded and - /// included in the plist output. - /// - /// This is controlled by the 'expand-macros' option, which defaults to false - /// when unset. - bool shouldDisplayMacroExpansions(); - - /// 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(); - - /// 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. - /// - /// This is controlled by 'region-store-small-struct-limit' option. - /// To disable all small-struct-dependent behavior, set the option to "0". - unsigned getRegionStoreSmallStructLimit(); - - /// 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) - StringRef getModelPath(); }; using AnalyzerOptionsRef = IntrusiveRefCntPtr; Index: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def =================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def +++ cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -0,0 +1,467 @@ +//===-- 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", + "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_GEN_FN( + bool, IncludeLifetimeInCFG, "cfg-lifetime", + "Whether or not end-of-lifetime information should be included in the CFG.", + false, includeLifetimeInCFG) + +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_GEN_FN( + bool, InlineCXXSharedPtrDtor, "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) + +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_GEN_FN( + bool, SuppressNullReturnPaths, "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) + +ANALYZER_OPTION_GEN_FN( + bool, AvoidSuppressingNullArgumentPaths, + "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 " + "counter-heuristic to avoid false negatives.", + false, shouldAvoidSuppressingNullArgumentPaths) + +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_GEN_FN( + bool, SerializeStats, "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) + +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_GEN_FN( + bool, ConditionalizeStaticInitializers, + "cfg-conditional-static-initializers", + "Whether 'static' initializers should be in conditional logic in the CFG.", + true, shouldConditionalizeStaticInitializers) + +ANALYZER_OPTION_GEN_FN(bool, SynthesizeBodies, "faux-bodies", + "Whether the analyzer engine should synthesize fake " + "bodies for well-known functions.", + true, shouldSynthesizeBodies) + +ANALYZER_OPTION_GEN_FN( + bool, ElideConstructors, "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) + +ANALYZER_OPTION_GEN_FN( + bool, InlineLambdas, "inline-lambdas", + "Whether lambdas should be inlined. Otherwise a sink node will be " + "generated each time a LambdaExpr is visited.", + true, shouldInlineLambdas) + +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_GEN_FN( + bool, DisplayNotesAsEvents, "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) + +ANALYZER_OPTION_GEN_FN( + bool, AggressivelySimplifyBinaryOperation, + "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 " + "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.", + false, shouldAggressivelySimplifyBinaryOperation) + +ANALYZER_OPTION_GEN_FN( + bool, EagerlyAssume, "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 " + "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.", + true, shouldEagerlyAssume) + +ANALYZER_OPTION_GEN_FN( + bool, NaiveCTU, "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) + +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) + +//===----------------------------------------------------------------------===// +// Unsinged analyzer options. +//===----------------------------------------------------------------------===// + +ANALYZER_OPTION_GEN_FN( + 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) + +ANALYZER_OPTION_GEN_FN( + 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) + +ANALYZER_OPTION_GEN_FN( + 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) + +ANALYZER_OPTION_GEN_FN(unsigned, MaxSymbolComplexity, "max-symbol-complexity", + "The maximum complexity of symbolic constraint.", 35, + getMaxSymbolComplexity) + +ANALYZER_OPTION_GEN_FN(unsigned, MaxTimesInlineLarge, "max-times-inline-large", + "The maximum times a large function could be inlined.", + 32, getMaxTimesInlineLarge) + +ANALYZER_OPTION_GEN_FN_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) + +ANALYZER_OPTION_GEN_FN_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) + +ANALYZER_OPTION_GEN_FN( + 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) + +//===----------------------------------------------------------------------===// +// 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.", + "externalFnMap.txt", getCTUIndexName) + +ANALYZER_OPTION_GEN_FN( + 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", + "Controls which C++ member functions will be considered for inlining. " + "Value: \"constructors\", \"destructors\", \"methods\".", + "destructors") + +ANALYZER_OPTION_DEPENDS_ON_USER_MODE( + StringRef, IPAMode, "ipa", + "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", + "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: cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ cfe/trunk/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,130 +226,45 @@ 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(); -} - -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(); -} - -bool AnalyzerOptions::shouldSynthesizeBodies() { - return getBooleanOption("faux-bodies", true); +static bool getOption(AnalyzerOptions &A, Optional &V, StringRef Name, + bool DefaultVal) { + return A.getBooleanOption(V, Name, DefaultVal); } -bool AnalyzerOptions::shouldPrunePaths() { - return getBooleanOption("prune-paths", true); +static unsigned getOption(AnalyzerOptions &A, Optional &V, + StringRef Name, unsigned DefaultVal) { + return A.getOptionAsUInt(V, Name, DefaultVal); } -bool AnalyzerOptions::shouldConditionalizeStaticInitializers() { - return getBooleanOption("cfg-conditional-static-initializers", true); +static StringRef getOption(AnalyzerOptions &A, Optional &V, + StringRef Name, StringRef DefaultVal) { + return A.getOptionAsString(V, Name, DefaultVal); } -bool AnalyzerOptions::shouldInlineLambdas() { - if (!InlineLambdas.hasValue()) - InlineLambdas = getBooleanOption("inline-lambdas", /*Default=*/true); - return InlineLambdas.getValue(); +#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::shouldWidenLoops() { - if (!WidenLoops.hasValue()) - WidenLoops = getBooleanOption("widen-loops", /*Default=*/false); - return WidenLoops.getValue(); +#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::shouldUnrollLoops() { - if (!UnrollLoops.hasValue()) - UnrollLoops = getBooleanOption("unroll-loops", /*Default=*/false); - return UnrollLoops.getValue(); -} +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def" -bool AnalyzerOptions::shouldDisplayNotesAsEvents() { - if (!DisplayNotesAsEvents.hasValue()) - DisplayNotesAsEvents = - getBooleanOption("notes-as-events", /*Default=*/false); - return DisplayNotesAsEvents.getValue(); -} - -bool AnalyzerOptions::shouldDisplayMacroExpansions() { - if (!DisplayMacroExpansions.hasValue()) - DisplayMacroExpansions = - getBooleanOption("expand-macros", /*Default=*/false); - return DisplayMacroExpansions.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(); -} +#undef ANALYZER_OPTION_GEN_FN_DEPENDS_ON_USER_MODE +#undef ANALYZER_OPTION_WITH_FN StringRef AnalyzerOptions::getCTUDir() { if (!CTUDir.hasValue()) { @@ -494,30 +274,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: cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ cfe/trunk/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(); } llvm_unreachable("Unknown AnalyzerOptions::ExplorationStrategyKind");