Index: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h =================================================================== --- include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -116,6 +116,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; @@ -176,154 +194,11 @@ /// 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; +#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC) \ + Optional NAME; +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def" +#undef ANALYZER_OPTION /// A helper function that retrieves option for a given full-qualified /// checker name. @@ -359,7 +234,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. @@ -414,7 +289,6 @@ const ento::CheckerBase *C = nullptr, bool SearchInParents = false); - unsigned getOptionAsUInt(Optional &V, StringRef Name, unsigned DefaultVal, const ento::CheckerBase *C = nullptr, @@ -442,6 +316,15 @@ const ento::CheckerBase *C = nullptr, bool SearchInParents = false); + template + T getDefaultValForUserMode(T ShallowVal, T DeepVal); + +#define ANALYZER_OPTION_WITH_FN(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL, \ + CREATE_FN) \ + TYPE CREATE_FN(); +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def" +#undef ANALYZER_OPTION + /// 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. @@ -460,282 +343,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(); - - StringRef getModelPath(); }; using AnalyzerOptionsRef = IntrusiveRefCntPtr; Index: include/clang/StaticAnalyzer/Core/AnalyzerOptions.def =================================================================== --- /dev/null +++ include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -0,0 +1,352 @@ +//===-- 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. The options are listed +// in two formats, with two function-like macros: +// +// * ANALYZER_OPTION_WITH_FN: Register a new option, and generate a getter +// method for it in AnalyzerOptions. +// * ANALYZER_OPTION: Register a new option, but do not generate a method. +// +// If this file is included with ANALYZER_OPTION_WITH_FN predefined, entries +// that do not generate functions won't appear. If it is not defined, all +// entries are accessible through the ANALYZER_OPTION function-like macro. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H +#error This .def file is expected to be included in translation units where \ +"clang/StaticAnalyzer/Core/AnalyzerOptions.h" is already included, as it \ +contains types from that header! +#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. +#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC) +#endif + +#ifndef ANALYZER_OPTION_WITH_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, same type as TYPE. +/// 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_WITH_FN(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL, \ + CREATE_FN) \ + ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC) +#endif + +//===----------------------------------------------------------------------===// +// Analyzer options of a variety of types. +//===----------------------------------------------------------------------===// + +/// Controls the high-level analyzer mode, which influences the default +/// settings for some of the lower-level config options (such as IPAMode). +ANALYZER_OPTION(UserModeKind, UserMode, "mode", "") + +/// Controls which C++ member functions will be considered for inlining. +ANALYZER_OPTION(CXXInlineableMemberKind, CXXMemberInliningMode, "c++-inlining", + "") + +/// Controls the mode of inter-procedural analysis. +ANALYZER_OPTION(IPAKind, IPAMode, "ipa", "") + +ANALYZER_OPTION(ExplorationStrategyKind, ExplorationStrategy, + "exploration_strategy", "") + +//===----------------------------------------------------------------------===// +// Boolean analyzer options. +//===----------------------------------------------------------------------===// + +/// Returns whether or not implicit destructors for C++ objects should +/// be included in the CFG. +ANALYZER_OPTION_WITH_FN(bool, IncludeImplicitDtorsInCFG, "cfg-implicit-dtors", + "", true, includeImplicitDtorsInCFG) + +/// Returns whether or not the destructors for C++ temporary objects should +/// be included in the CFG. +ANALYZER_OPTION_WITH_FN(bool, IncludeTemporaryDtorsInCFG, "cfg-temporary-dtors", + "", true, includeTemporaryDtorsInCFG) + +/// Returns whether or not end-of-lifetime information should be included in +/// the CFG. +ANALYZER_OPTION_WITH_FN(bool, IncludeLifetimeInCFG, "cfg-lifetime", "", false, + includeLifetimeInCFG) + +/// Returns whether or not the end of the loop information should be included +/// in the CFG. +ANALYZER_OPTION_WITH_FN(bool, IncludeLoopExitInCFG, "cfg-loopexit", "", false, + includeLoopExitInCFG) + +/// Returns whether or not construction site information should be included +/// in the CFG C++ constructor elements. +ANALYZER_OPTION_WITH_FN(bool, IncludeRichConstructorsInCFG, + "cfg-rich-constructors", "", true, + includeRichConstructorsInCFG) + +/// Returns whether or not scope information should be included in the CFG. +ANALYZER_OPTION_WITH_FN(bool, IncludeScopesInCFG, "cfg-scopes", "", false, + includeScopesInCFG) + +/// Returns whether or not templated functions may be considered for inlining. +ANALYZER_OPTION_WITH_FN(bool, InlineTemplateFunctions, "c++-template-inlining", + "", true, mayInlineTemplateFunctions) + +/// Returns whether or not C++ standard library functions may be considered +/// for inlining. +ANALYZER_OPTION_WITH_FN(bool, InlineCXXStandardLibrary, "c++-stdlib-inlining", + "", true, mayInlineCXXStandardLibrary) + +/// Returns whether or not allocator call may be considered for inlining. +ANALYZER_OPTION_WITH_FN(bool, InlineCXXAllocator, "c++-allocator-inlining", "", + true, mayInlineCXXAllocator) + +/// 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". +ANALYZER_OPTION_WITH_FN(bool, InlineCXXSharedPtrDtor, "c++-shared_ptr-inlining", + "", false, 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. +ANALYZER_OPTION_WITH_FN(bool, InlineCXXTemporaryDtors, "c++-temp-dtor-inlining", + "", true, 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. +ANALYZER_OPTION_WITH_FN(bool, SuppressNullReturnPaths, + "suppress-null-return-paths", "", true, + 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. +ANALYZER_OPTION_WITH_FN(bool, AvoidSuppressingNullArgumentPaths, + "avoid-suppressing-null-argument-paths", "", false, + shouldAvoidSuppressingNullArgumentPaths) + +/// Returns whether or not diagnostics containing inlined defensive NULL +/// checks should be suppressed. +ANALYZER_OPTION_WITH_FN(bool, SuppressInlinedDefensiveChecks, + "suppress-inlined-defensive-checks", "", true, + shouldSuppressInlinedDefensiveChecks) + +/// Returns whether or not methods of C++ container objects may be considered +/// for inlining. +ANALYZER_OPTION_WITH_FN(bool, InlineCXXContainerMethods, + "c++-container-inlining", "", false, + mayInlineCXXContainerMethods) + +/// Returns whether or not diagnostics reported within the C++ standard +/// library should be suppressed. +ANALYZER_OPTION_WITH_FN(bool, SuppressFromCXXStandardLibrary, + "suppress-c++-stdlib", "", true, + shouldSuppressFromCXXStandardLibrary) + +/// Returns whether bug reports should be crosschecked with the Z3 +/// constraint manager backend. +ANALYZER_OPTION_WITH_FN(bool, CrosscheckWithZ3, "crosscheck-with-z3", "", false, + shouldCrosscheckWithZ3) + +/// Returns whether or not the diagnostic report should be always reported +/// in the main source file and not the headers. +ANALYZER_OPTION_WITH_FN(bool, ReportIssuesInMainSourceFile, + "report-in-main-source-file", "", false, + shouldReportIssuesInMainSourceFile) + +/// Returns whether or not the report filename should be random or not. +ANALYZER_OPTION_WITH_FN(bool, WriteStableReportFilename, + "stable-report-filename", "", false, + 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. +ANALYZER_OPTION_WITH_FN(bool, SerializeStats, "serialize-stats", "", false, + shouldSerializeStats) + +/// Returns true if ObjectiveC inlining is enabled, false otherwise. +ANALYZER_OPTION_WITH_FN(bool, InlineObjCMethod, "objc-inlining", "", true, + mayInlineObjCMethod) + +/// Returns whether irrelevant parts of a bug report path should be pruned +/// out of the final output. +ANALYZER_OPTION_WITH_FN(bool, PrunePaths, "prune-paths", "", true, + shouldPrunePaths) + +/// Returns true if 'static' initializers should be in conditional logic +/// in the CFG. +ANALYZER_OPTION_WITH_FN(bool, ConditionalizeStaticInitializers, + "cfg-conditional-static-initializers", "", true, + shouldConditionalizeStaticInitializers) + +/// Returns true if the analyzer engine should synthesize fake bodies +/// for well-known functions. +ANALYZER_OPTION_WITH_FN(bool, SynthesizeBodies, "faux-bodies", "", true, + shouldSynthesizeBodies) + +/// 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. +ANALYZER_OPTION_WITH_FN(bool, ElideConstructors, "elide-constructors", "", true, + shouldElideConstructors) + +/// Returns true if lambdas should be inlined. Otherwise a sink node will be +/// generated each time a LambdaExpr is visited. +ANALYZER_OPTION_WITH_FN(bool, InlineLambdas, "inline-lambdas", "", true, + shouldInlineLambdas) + +/// Returns true if the analysis should try to widen loops. +/// This is controlled by the '' config option. +ANALYZER_OPTION_WITH_FN(bool, WidenLoops, "widen-loops", "", false, + shouldWidenLoops) + +/// Returns true if the analysis should try to unroll loops with known bounds. +/// This is controlled by the '' config option. +ANALYZER_OPTION_WITH_FN(bool, UnrollLoops, "unroll-loops", "", false, + 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. +ANALYZER_OPTION_WITH_FN(bool, DisplayNotesAsEvents, "notes-as-events", "", + false, 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. +ANALYZER_OPTION_WITH_FN(bool, AggressivelySimplifyBinaryOperation, + "aggressive-binary-operation-simplification", "", false, + 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. +ANALYZER_OPTION_WITH_FN(bool, EagerlyAssume, "eagerly-assume", "", true, + shouldEagerlyAssume) + +/// Returns true when naive cross translation unit analysis is enabled. +/// This is an experimental feature to inline functions from another +/// translation units. +ANALYZER_OPTION_WITH_FN(bool, NaiveCTU, + "experimental-enable-naive-ctu-analysis", "", false, + naiveCTUEnabled) + +//===----------------------------------------------------------------------===// +// Unsinged analyzer options. +//===----------------------------------------------------------------------===// + +// Returns the size of the functions (in basic blocks), which should be +// considered to be small enough to always inline. +ANALYZER_OPTION_WITH_FN(unsigned, AlwaysInlineSize, "ipa-always-inline-size", + "", 3, getAlwaysInlineSize) + +/// Returns how often nodes in the ExplodedGraph should be recycled to save +/// memory. +/// +/// To disable node reclamation, set the option to "0". +ANALYZER_OPTION_WITH_FN(unsigned, GraphTrimInterval, "graph-trim-interval", "", + 1000, getGraphTrimInterval) + +/// Returns the number of basic blocks a function needs to have to be +/// considered large for the 'max-times-inline-large' config option. +ANALYZER_OPTION_WITH_FN(unsigned, MinCFGSizeTreatFunctionsAsLarge, + "min-cfg-size-treat-functions-as-large", "", 14, + getMinCFGSizeTreatFunctionsAsLarge) + +/// Returns the maximum complexity of symbolic constraint (35 by default). +ANALYZER_OPTION_WITH_FN(unsigned, MaxSymbolComplexity, "max-symbol-complexity", + "", 35, getMaxSymbolComplexity) + +/// Returns the maximum times a large function could be inlined. +ANALYZER_OPTION_WITH_FN(unsigned, MaxTimesInlineLarge, "max-times-inline-large", + "", 32, getMaxTimesInlineLarge) + +// Returns the bound on the number of basic blocks in an inlined function. +ANALYZER_OPTION_WITH_FN(unsigned, MaxInlinableSize, "max-inlinable-size", "", + getDefaultValForUserMode(/* ShallowVal */ 4, + /* DeepVal */ 100), + getMaxInlinableSize) + +/// Returns the maximum number of nodes the analyzer can generate while +/// exploring a top level function (for each exploded graph). 0 means no limit. +ANALYZER_OPTION_WITH_FN(unsigned, MaxNodesPerTopLevelFunction, "max-nodes", "", + getDefaultValForUserMode(/* ShallowVal */ 75000, + /* DeepVal */ 225000), + getMaxNodesPerTopLevelFunction) + +//===----------------------------------------------------------------------===// +// String analyzer options. +//===----------------------------------------------------------------------===// + +/// Returns the directory containing the CTU related files. +ANALYZER_OPTION(StringRef, CTUDir, "ctu-dir", "") + +/// Returns the name of the file containing the CTU index of functions. +ANALYZER_OPTION_WITH_FN(StringRef, CTUIndexName, "ctu-index-name", "", + "externalFnMap.txt", getCTUIndexName) + +/// TODO: Document this, used in lib/StaticAnalyzer/Frontend/ModelInjector.cpp. +ANALYZER_OPTION_WITH_FN(StringRef, ModelPath, "model-path", "", "", + getModelPath) + +#undef ANALYZER_OPTION_WITH_FN +#undef ANALYZER_OPTION Index: lib/StaticAnalyzer/Core/AnalyzerOptions.cpp =================================================================== --- lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -49,7 +49,7 @@ return Result; } -AnalyzerOptions::UserModeKind AnalyzerOptions::getUserMode() { +UserModeKind AnalyzerOptions::getUserMode() { if (!UserMode.hasValue()) { StringRef ModeStr = getOptionAsString("mode", "deep"); UserMode = llvm::StringSwitch>(ModeStr) @@ -61,7 +61,7 @@ return UserMode.getValue(); } -AnalyzerOptions::ExplorationStrategyKind +ExplorationStrategyKind AnalyzerOptions::getExplorationStrategy() { if (!ExplorationStrategy.hasValue()) { StringRef StratStr = getOptionAsString("exploration_strategy", @@ -182,137 +182,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) { @@ -348,6 +217,7 @@ SearchInParents) : StringRef( Config.insert(std::make_pair(Name, DefaultVal)).first->second); + } StringRef AnalyzerOptions::getOptionAsString(Optional &V, @@ -360,125 +230,43 @@ 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); +template +T AnalyzerOptions::getDefaultValForUserMode(T ShallowVal, T DeepVal) { + UserModeKind HighLevelMode = getUserMode(); + switch (HighLevelMode) { + case UMK_Shallow: + return ShallowVal; + case UMK_Deep: + return DeepVal; } - return MaxNodesPerTopLevelFunction.getValue(); -} - -bool AnalyzerOptions::shouldSynthesizeBodies() { - return getBooleanOption("faux-bodies", true); -} -bool AnalyzerOptions::shouldPrunePaths() { - return getBooleanOption("prune-paths", true); + return {}; } -bool AnalyzerOptions::shouldConditionalizeStaticInitializers() { - return getBooleanOption("cfg-conditional-static-initializers", true); +static bool getOption(AnalyzerOptions &A, Optional &V, StringRef Name, + bool DefaultVal) { + return A.getBooleanOption(V, Name, DefaultVal); } -bool AnalyzerOptions::shouldInlineLambdas() { - if (!InlineLambdas.hasValue()) - InlineLambdas = getBooleanOption("inline-lambdas", /*Default=*/true); - return InlineLambdas.getValue(); +static unsigned getOption(AnalyzerOptions &A, Optional &V, + StringRef Name, unsigned DefaultVal) { + return A.getOptionAsUInt(V, Name, DefaultVal); } -bool AnalyzerOptions::shouldWidenLoops() { - if (!WidenLoops.hasValue()) - WidenLoops = getBooleanOption("widen-loops", /*Default=*/false); - return WidenLoops.getValue(); +static StringRef getOption(AnalyzerOptions &A, Optional &V, + StringRef Name, StringRef DefaultVal) { + return A.getOptionAsString(V, Name, DefaultVal); } -bool AnalyzerOptions::shouldUnrollLoops() { - if (!UnrollLoops.hasValue()) - UnrollLoops = getBooleanOption("unroll-loops", /*Default=*/false); - return UnrollLoops.getValue(); +#define ANALYZER_OPTION_WITH_FN(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL, \ + CREATE_FN) \ +TYPE AnalyzerOptions::CREATE_FN() { \ + return getOption(*this, NAME, CMDFLAG, DEFAULT_VAL); \ } +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def" +#undef ANALYZER_OPTION -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()) { CTUDir = getOptionAsString("ctu-dir", ""); @@ -487,23 +275,3 @@ } return CTUDir.getValue(); } - -bool AnalyzerOptions::naiveCTUEnabled() { - if (!NaiveCTU.hasValue()) { - NaiveCTU = getBooleanOption("experimental-enable-naive-ctu-analysis", - /*Default=*/false); - } - return NaiveCTU.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(); } }