summaryrefslogtreecommitdiffstats
path: root/include/clang/StaticAnalyzer/Core
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/StaticAnalyzer/Core')
-rw-r--r--include/clang/StaticAnalyzer/Core/Analyses.def1
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.def377
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.h608
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h14
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerOptInfo.h44
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerRegistry.h9
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h21
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h5
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h21
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h29
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h54
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h27
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h41
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h22
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/RetainSummaryManager.h75
24 files changed, 712 insertions, 671 deletions
diff --git a/include/clang/StaticAnalyzer/Core/Analyses.def b/include/clang/StaticAnalyzer/Core/Analyses.def
index 281a2ac3a6..99e26c75e1 100644
--- a/include/clang/StaticAnalyzer/Core/Analyses.def
+++ b/include/clang/StaticAnalyzer/Core/Analyses.def
@@ -33,6 +33,7 @@ ANALYSIS_DIAGNOSTICS(HTML_SINGLE_FILE, "html-single-file", "Output analysis resu
ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer)
ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for multi-file bugs)", createPlistMultiFileDiagnosticConsumer)
ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer)
+ANALYSIS_DIAGNOSTICS(SARIF, "sarif", "Output analysis results in a SARIF file", createSarifDiagnosticConsumer)
ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer)
#ifndef ANALYSIS_PURGE
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
new file mode 100644
index 0000000000..8e5d8d3ad3
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
@@ -0,0 +1,377 @@
+//===-- 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.
+//
+//===----------------------------------------------------------------------===//
+
+#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 didnt 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 didnt 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
+/// 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
+
+//===----------------------------------------------------------------------===//
+// The "mode" option. Since some options depend on this, we list it on top of
+// this file in order to make sure that the generated field for it is
+// initialized before the rest.
+//===----------------------------------------------------------------------===//
+
+ANALYZER_OPTION(
+ StringRef, UserMode, "mode",
+ "(string) Controls the high-level analyzer mode, which influences the "
+ "default settings for some of the lower-level config options (such as "
+ "IPAMode). Value: \"deep\", \"shallow\".",
+ "deep")
+
+//===----------------------------------------------------------------------===//
+// Boolean analyzer options.
+//===----------------------------------------------------------------------===//
+
+ANALYZER_OPTION(bool, ShouldIncludeImplicitDtorsInCFG, "cfg-implicit-dtors",
+ "Whether or not implicit destructors for C++ objects "
+ "should be included in the CFG.",
+ true)
+
+ANALYZER_OPTION(bool, ShouldIncludeTemporaryDtorsInCFG, "cfg-temporary-dtors",
+ "Whether or not the destructors for C++ temporary "
+ "objects should be included in the CFG.",
+ true)
+
+ANALYZER_OPTION(
+ bool, ShouldIncludeLifetimeInCFG, "cfg-lifetime",
+ "Whether or not end-of-lifetime information should be included in the CFG.",
+ false)
+
+ANALYZER_OPTION(bool, ShouldIncludeLoopExitInCFG, "cfg-loopexit",
+ "Whether or not the end of the loop information should "
+ "be included in the CFG.",
+ false)
+
+ANALYZER_OPTION(bool, ShouldIncludeRichConstructorsInCFG,
+ "cfg-rich-constructors",
+ "Whether or not construction site information should be "
+ "included in the CFG C++ constructor elements.",
+ true)
+
+ANALYZER_OPTION(
+ bool, ShouldIncludeScopesInCFG, "cfg-scopes",
+ "Whether or not scope information should be included in the CFG.", false)
+
+ANALYZER_OPTION(
+ bool, MayInlineTemplateFunctions, "c++-template-inlining",
+ "Whether or not templated functions may be considered for inlining.", true)
+
+ANALYZER_OPTION(bool, MayInlineCXXStandardLibrary, "c++-stdlib-inlining",
+ "Whether or not C++ standard library functions may be "
+ "considered for inlining.",
+ true)
+
+ANALYZER_OPTION(bool, MayInlineCXXAllocator, "c++-allocator-inlining",
+ "Whether or not allocator call may be considered for inlining.",
+ true)
+
+ANALYZER_OPTION(
+ bool, MayInlineCXXSharedPtrDtor, "c++-shared_ptr-inlining",
+ "Whether or not the destructor of C++ 'shared_ptr' may be considered for "
+ "inlining. This covers std::shared_ptr, std::tr1::shared_ptr, and "
+ "boost::shared_ptr, and indeed any destructor named '~shared_ptr'.",
+ false)
+
+ANALYZER_OPTION(bool, MayInlineCXXTemporaryDtors, "c++-temp-dtor-inlining",
+ "Whether C++ temporary destructors should be inlined "
+ "during analysis. If temporary destructors are disabled "
+ "in the CFG via the 'cfg-temporary-dtors' option, "
+ "temporary destructors would not be inlined anyway.",
+ true)
+
+ANALYZER_OPTION(
+ bool, ShouldSuppressNullReturnPaths, "suppress-null-return-paths",
+ "Whether or not paths that go through null returns should be suppressed. "
+ "This is a heuristic for avoiding bug reports with paths that go through "
+ "inlined functions that are more defensive than their callers.",
+ true)
+
+ANALYZER_OPTION(
+ bool, ShouldAvoidSuppressingNullArgumentPaths,
+ "avoid-suppressing-null-argument-paths",
+ "Whether a bug report should not be suppressed if its path includes a call "
+ "with a null argument, even if that call has a null return. This option "
+ "has no effect when ShouldSuppressNullReturnPaths is false. This is a "
+ "counter-heuristic to avoid false negatives.",
+ false)
+
+ANALYZER_OPTION(bool, ShouldSuppressInlinedDefensiveChecks,
+ "suppress-inlined-defensive-checks",
+ "Whether or not diagnostics containing inlined "
+ "defensive NULL checks should be suppressed.",
+ true)
+
+ANALYZER_OPTION(bool, MayInlineCXXContainerMethods, "c++-container-inlining",
+ "Whether or not methods of C++ container objects may be "
+ "considered for inlining.",
+ false)
+
+ANALYZER_OPTION(bool, ShouldSuppressFromCXXStandardLibrary,
+ "suppress-c++-stdlib",
+ "Whether or not diagnostics reported within the C++ "
+ "standard library should be suppressed.",
+ true)
+
+ANALYZER_OPTION(bool, ShouldCrosscheckWithZ3, "crosscheck-with-z3",
+ "Whether bug reports should be crosschecked with the Z3 "
+ "constraint manager backend.",
+ false)
+
+ANALYZER_OPTION(bool, ShouldReportIssuesInMainSourceFile,
+ "report-in-main-source-file",
+ "Whether or not the diagnostic report should be always "
+ "reported in the main source file and not the headers.",
+ false)
+
+ANALYZER_OPTION(bool, ShouldWriteStableReportFilename, "stable-report-filename",
+ "Whether or not the report filename should be random or not.",
+ false)
+
+ANALYZER_OPTION(
+ bool, ShouldSerializeStats, "serialize-stats",
+ "Whether the analyzer should serialize statistics to plist output. "
+ "Statistics would be serialized in JSON format inside the main dictionary "
+ "under the statistics key. Available only if compiled in assert mode or "
+ "with LLVM statistics explicitly enabled.",
+ false)
+
+ANALYZER_OPTION(bool, MayInlineObjCMethod, "objc-inlining",
+ "Whether ObjectiveC inlining is enabled, false otherwise.",
+ true)
+
+ANALYZER_OPTION(bool, ShouldPrunePaths, "prune-paths",
+ "Whether irrelevant parts of a bug report path should "
+ "be pruned out of the final output.",
+ true)
+
+ANALYZER_OPTION(
+ bool, ShouldConditionalizeStaticInitializers,
+ "cfg-conditional-static-initializers",
+ "Whether 'static' initializers should be in conditional logic in the CFG.",
+ true)
+
+ANALYZER_OPTION(bool, ShouldSynthesizeBodies, "faux-bodies",
+ "Whether the analyzer engine should synthesize fake "
+ "bodies for well-known functions.",
+ true)
+
+ANALYZER_OPTION(
+ bool, ShouldElideConstructors, "elide-constructors",
+ "Whether elidable C++ copy-constructors and move-constructors should be "
+ "actually elided during analysis. Both behaviors are allowed by the C++ "
+ "standard, and the analyzer, like CodeGen, defaults to eliding. Starting "
+ "with C++17 some elisions become mandatory, and in these cases the option "
+ "will be ignored.",
+ true)
+
+ANALYZER_OPTION(
+ bool, ShouldInlineLambdas, "inline-lambdas",
+ "Whether lambdas should be inlined. Otherwise a sink node will be "
+ "generated each time a LambdaExpr is visited.",
+ true)
+
+ANALYZER_OPTION(bool, ShouldWidenLoops, "widen-loops",
+ "Whether the analysis should try to widen loops.", false)
+
+ANALYZER_OPTION(
+ bool, ShouldUnrollLoops, "unroll-loops",
+ "Whether the analysis should try to unroll loops with known bounds.", false)
+
+ANALYZER_OPTION(
+ bool, ShouldDisplayNotesAsEvents, "notes-as-events",
+ "Whether the bug reporter should transparently treat extra note diagnostic "
+ "pieces as event diagnostic pieces. Useful when the diagnostic consumer "
+ "doesn't support the extra note pieces.",
+ false)
+
+ANALYZER_OPTION(
+ bool, ShouldAggressivelySimplifyBinaryOperation,
+ "aggressive-binary-operation-simplification",
+ "Whether SValBuilder should rearrange comparisons and additive operations "
+ "of symbolic expressions which consist of a sum of a symbol and a concrete "
+ "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 <OP> B + m becomes A - B <OP> m - n, "
+ "where A and B symbolic, n and m are integers. <OP> 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)
+
+ANALYZER_OPTION(
+ bool, ShouldEagerlyAssume, "eagerly-assume",
+ "Whether we should eagerly assume evaluations of conditionals, thus, "
+ "bifurcating the path. This indicates how the engine should handle "
+ "expressions such as: 'x = (y != 0)'. When this is true then the "
+ "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)
+
+ANALYZER_OPTION(
+ bool, IsNaiveCTUEnabled, "experimental-enable-naive-ctu-analysis",
+ "Whether naive cross translation unit analysis is enabled. This is an "
+ "experimental feature to inline functions from another translation units.",
+ false)
+
+ANALYZER_OPTION(bool, ShouldDisplayMacroExpansions, "expand-macros",
+ "Whether macros related to the bugpath should be "
+ "expanded and included in the plist output.",
+ false)
+
+ANALYZER_OPTION(bool, DisplayCTUProgress, "display-ctu-progress",
+ "Whether to emit verbose output about "
+ "the analyzer's progress related to ctu.",
+ false)
+
+//===----------------------------------------------------------------------===//
+// Unsinged analyzer options.
+//===----------------------------------------------------------------------===//
+
+ANALYZER_OPTION(
+ unsigned, AlwaysInlineSize, "ipa-always-inline-size",
+ "The size of the functions (in basic blocks), which should be considered "
+ "to be small enough to always inline.",
+ 3)
+
+ANALYZER_OPTION(
+ unsigned, GraphTrimInterval, "graph-trim-interval",
+ "How often nodes in the ExplodedGraph should be recycled to save memory. "
+ "To disable node reclamation, set the option to 0.",
+ 1000)
+
+ANALYZER_OPTION(
+ unsigned, MinCFGSizeTreatFunctionsAsLarge,
+ "min-cfg-size-treat-functions-as-large",
+ "The number of basic blocks a function needs to have to be considered "
+ "large for the 'max-times-inline-large' config option.",
+ 14)
+
+ANALYZER_OPTION(unsigned, MaxSymbolComplexity, "max-symbol-complexity",
+ "The maximum complexity of symbolic constraint.", 35)
+
+ANALYZER_OPTION(unsigned, MaxTimesInlineLarge, "max-times-inline-large",
+ "The maximum times a large function could be inlined.", 32)
+
+ANALYZER_OPTION_DEPENDS_ON_USER_MODE(
+ unsigned, MaxInlinableSize, "max-inlinable-size",
+ "The bound on the number of basic blocks in an inlined function.",
+ /* SHALLOW_VAL */ 4, /* DEEP_VAL */ 100)
+
+ANALYZER_OPTION_DEPENDS_ON_USER_MODE(
+ unsigned, MaxNodesPerTopLevelFunction, "max-nodes",
+ "The maximum number of nodes the analyzer can generate while exploring a "
+ "top level function (for each exploded graph). 0 means no limit.",
+ /* SHALLOW_VAL */ 75000, /* DEEP_VAL */ 225000)
+
+ANALYZER_OPTION(
+ unsigned, RegionStoreSmallStructLimit, "region-store-small-struct-limit",
+ "The largest number of fields a struct can have and still be considered "
+ "small This is currently used to decide whether or not it is worth forcing "
+ "a LazyCompoundVal on bind. To disable all small-struct-dependent "
+ "behavior, set the option to 0.",
+ 2)
+
+//===----------------------------------------------------------------------===//
+// String analyzer options.
+//===----------------------------------------------------------------------===//
+
+ANALYZER_OPTION(StringRef, CTUDir, "ctu-dir",
+ "The directory containing the CTU related files.", "")
+
+ANALYZER_OPTION(StringRef, CTUIndexName, "ctu-index-name",
+ "the name of the file containing the CTU index of functions.",
+ "externalFnMap.txt")
+
+ANALYZER_OPTION(
+ StringRef, ModelPath, "model-path",
+ "The analyzer can inline an alternative implementation written in C at the "
+ "call site if the called function's body is not available. This is a path "
+ "where to look for those alternative implementations (called models).",
+ "")
+
+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_DEPENDS_ON_USER_MODE
+#undef ANALYZER_OPTION
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index 715cc2bf23..7745e459e1 100644
--- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -20,6 +20,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
#include <string>
#include <utility>
#include <vector>
@@ -85,7 +86,7 @@ enum CXXInlineableMemberKind {
// Uninitialized = 0,
/// A dummy mode in which no C++ inlining is enabled.
- CIMK_None = 1,
+ CIMK_None,
/// Refers to regular member function and operator calls.
CIMK_MemberFunctions,
@@ -102,8 +103,6 @@ enum CXXInlineableMemberKind {
/// Describes the different modes of inter-procedural analysis.
enum IPAKind {
- IPAK_NotSet = 0,
-
/// Perform only intra-procedural analysis.
IPAK_None = 1,
@@ -121,6 +120,46 @@ enum IPAKind {
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
+};
+
+/// Stores options for the analyzer from the command line.
+///
+/// Some options are frontend flags (e.g.: -analyzer-output), but some are
+/// analyzer configuration options, which are preceded by -analyzer-config
+/// (e.g.: -analyzer-config notes-as-events=true).
+///
+/// If you'd like to add a new frontend flag, add it to
+/// include/clang/Driver/CC1Options.td, add a new field to store the value of
+/// that flag in this class, and initialize it in
+/// lib/Frontend/CompilerInvocation.cpp.
+///
+/// If you'd like to add a new non-checker configuration, register it in
+/// include/clang/StaticAnalyzer/Core/AnalyzerOptions.def, and refer to the
+/// top of the file for documentation.
+///
+/// If you'd like to add a new checker option, call getChecker*Option()
+/// whenever.
+///
+/// Some of the options are controlled by raw frontend flags for no good reason,
+/// and should be eventually converted into -analyzer-config flags. New analyzer
+/// options should not be implemented as frontend flags. Frontend flags still
+/// make sense for things that do not affect the actual analysis.
class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
public:
using ConfigTable = llvm::StringMap<std::string>;
@@ -132,6 +171,7 @@ public:
std::vector<std::pair<std::string, bool>> CheckersControlList;
/// A key-value table of use-specified configuration values.
+ // TODO: This shouldn't be public.
ConfigTable Config;
AnalysisStores AnalysisStoreOpt = RegionStoreModel;
AnalysisConstraints AnalysisConstraintsOpt = RangeConstraintsModel;
@@ -159,6 +199,8 @@ public:
unsigned ShowCheckerHelp : 1;
unsigned ShowEnabledCheckerList : 1;
+ unsigned ShowConfigOptionsList : 1;
+ unsigned ShouldEmitErrorsOnInvalidConfigValue : 1;
unsigned AnalyzeAll : 1;
unsigned AnalyzerDisplayProgress : 1;
unsigned AnalyzeNestedBlocks : 1;
@@ -181,190 +223,51 @@ public:
/// The mode of function selection used during inlining.
AnalysisInliningMode InliningMode = NoRedundancy;
- enum class ExplorationStrategyKind {
- DFS,
- BFS,
- UnexploredFirst,
- UnexploredFirstQueue,
- BFSBlockDFSContents,
- NotSet
- };
-
-private:
- ExplorationStrategyKind ExplorationStrategy = ExplorationStrategyKind::NotSet;
-
- /// Describes the kinds for high-level analyzer mode.
- enum UserModeKind {
- UMK_NotSet = 0,
-
- /// Perform shallow but fast analyzes.
- UMK_Shallow = 1,
-
- /// Perform deep analyzes.
- UMK_Deep = 2
- };
-
- /// Controls the high-level analyzer mode, which influences the default
- /// settings for some of the lower-level config options (such as IPAMode).
- /// \sa getUserMode
- UserModeKind UserMode = UMK_NotSet;
-
- /// Controls the mode of inter-procedural analysis.
- IPAKind IPAMode = IPAK_NotSet;
-
- /// Controls which C++ member functions will be considered for inlining.
- CXXInlineableMemberKind CXXMemberInliningMode;
-
- /// \sa includeImplicitDtorsInCFG
- Optional<bool> IncludeImplicitDtorsInCFG;
-
- /// \sa includeTemporaryDtorsInCFG
- Optional<bool> IncludeTemporaryDtorsInCFG;
-
- /// \sa IncludeLifetimeInCFG
- Optional<bool> IncludeLifetimeInCFG;
-
- /// \sa IncludeLoopExitInCFG
- Optional<bool> IncludeLoopExitInCFG;
-
- /// \sa IncludeRichConstructorsInCFG
- Optional<bool> IncludeRichConstructorsInCFG;
-
- /// \sa mayInlineCXXStandardLibrary
- Optional<bool> InlineCXXStandardLibrary;
-
- /// \sa includeScopesInCFG
- Optional<bool> IncludeScopesInCFG;
-
- /// \sa mayInlineTemplateFunctions
- Optional<bool> InlineTemplateFunctions;
-
- /// \sa mayInlineCXXAllocator
- Optional<bool> InlineCXXAllocator;
-
- /// \sa mayInlineCXXContainerMethods
- Optional<bool> InlineCXXContainerMethods;
-
- /// \sa mayInlineCXXSharedPtrDtor
- Optional<bool> InlineCXXSharedPtrDtor;
-
- /// \sa mayInlineCXXTemporaryDtors
- Optional<bool> InlineCXXTemporaryDtors;
-
- /// \sa mayInlineObjCMethod
- Optional<bool> ObjCInliningMode;
-
- // Cache of the "ipa-always-inline-size" setting.
- // \sa getAlwaysInlineSize
- Optional<unsigned> AlwaysInlineSize;
+ // Create a field for each -analyzer-config option.
+#define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC, \
+ SHALLOW_VAL, DEEP_VAL) \
+ ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL)
- /// \sa shouldSuppressNullReturnPaths
- Optional<bool> SuppressNullReturnPaths;
+#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL) \
+ TYPE NAME;
- // \sa getMaxInlinableSize
- Optional<unsigned> MaxInlinableSize;
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def"
+#undef ANALYZER_OPTION
+#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE
- /// \sa shouldAvoidSuppressingNullArgumentPaths
- Optional<bool> AvoidSuppressingNullArgumentPaths;
+ // Create an array of all -analyzer-config command line options. Sort it in
+ // the constructor.
+ std::vector<StringRef> AnalyzerConfigCmdFlags = {
+#define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC, \
+ SHALLOW_VAL, DEEP_VAL) \
+ ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL)
- /// \sa shouldSuppressInlinedDefensiveChecks
- Optional<bool> SuppressInlinedDefensiveChecks;
+#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL) \
+ CMDFLAG,
- /// \sa shouldSuppressFromCXXStandardLibrary
- Optional<bool> SuppressFromCXXStandardLibrary;
-
- /// \sa shouldCrosscheckWithZ3
- Optional<bool> CrosscheckWithZ3;
-
- /// \sa reportIssuesInMainSourceFile
- Optional<bool> ReportIssuesInMainSourceFile;
-
- /// \sa StableReportFilename
- Optional<bool> StableReportFilename;
-
- Optional<bool> SerializeStats;
-
- /// \sa getGraphTrimInterval
- Optional<unsigned> GraphTrimInterval;
-
- /// \sa getMaxSymbolComplexity
- Optional<unsigned> MaxSymbolComplexity;
-
- /// \sa getMaxTimesInlineLarge
- Optional<unsigned> MaxTimesInlineLarge;
-
- /// \sa getMinCFGSizeTreatFunctionsAsLarge
- Optional<unsigned> MinCFGSizeTreatFunctionsAsLarge;
-
- /// \sa getMaxNodesPerTopLevelFunction
- Optional<unsigned> MaxNodesPerTopLevelFunction;
-
- /// \sa shouldInlineLambdas
- Optional<bool> InlineLambdas;
-
- /// \sa shouldWidenLoops
- Optional<bool> WidenLoops;
-
- /// \sa shouldUnrollLoops
- Optional<bool> UnrollLoops;
-
- /// \sa shouldDisplayNotesAsEvents
- Optional<bool> DisplayNotesAsEvents;
-
- /// \sa shouldAggressivelySimplifyBinaryOperation
- Optional<bool> AggressiveBinaryOperationSimplification;
-
- /// \sa shouldEagerlyAssume
- Optional<bool> EagerlyAssumeBinOpBifurcation;
-
- /// \sa getCTUDir
- Optional<StringRef> CTUDir;
-
- /// \sa getCTUIndexName
- Optional<StringRef> CTUIndexName;
-
- /// \sa naiveCTUEnabled
- Optional<bool> NaiveCTU;
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def"
+#undef ANALYZER_OPTION
+#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE
+ };
- /// \sa shouldElideConstructors
- Optional<bool> ElideConstructors;
+ bool isUnknownAnalyzerConfig(StringRef Name) const {
+ assert(std::is_sorted(AnalyzerConfigCmdFlags.begin(),
+ AnalyzerConfigCmdFlags.end()));
- /// A helper function that retrieves option for a given full-qualified
- /// checker name.
- /// Options for checkers can be specified via 'analyzer-config' command-line
- /// option.
- /// Example:
- /// @code-analyzer-config unix.Malloc:OptionName=CheckerOptionValue @endcode
- /// or @code-analyzer-config unix:OptionName=GroupOptionValue @endcode
- /// for groups of checkers.
- /// @param [in] CheckerName Full-qualified checker name, like
- /// alpha.unix.StreamChecker.
- /// @param [in] OptionName Name of the option to get.
- /// @param [in] Default Default value if no option is specified.
- /// @param [in] SearchInParents If set to true and the searched option was not
- /// specified for the given checker the options for the parent packages will
- /// be searched as well. The inner packages take precedence over the outer
- /// ones.
- /// @retval CheckerOptionValue An option for a checker if it was specified.
- /// @retval GroupOptionValue An option for group if it was specified and no
- /// checker-specific options were found. The closer group to checker,
- /// the more priority it has. For example, @c coregroup.subgroup has more
- /// priority than @c coregroup for @c coregroup.subgroup.CheckerName checker.
- /// @retval Default If nor checker option, nor group option was found.
- StringRef getCheckerOption(StringRef CheckerName, StringRef OptionName,
- StringRef Default,
- bool SearchInParents = false);
+ return !std::binary_search(AnalyzerConfigCmdFlags.begin(),
+ AnalyzerConfigCmdFlags.end(), Name);
+ }
-public:
AnalyzerOptions()
: DisableAllChecks(false), ShowCheckerHelp(false),
- ShowEnabledCheckerList(false), AnalyzeAll(false),
- AnalyzerDisplayProgress(false), AnalyzeNestedBlocks(false),
- eagerlyAssumeBinOpBifurcation(false), TrimGraph(false),
- visualizeExplodedGraphWithGraphViz(false),
- UnoptimizedCFG(false),
- PrintStats(false), NoRetryExhausted(false), CXXMemberInliningMode() {}
+ ShowEnabledCheckerList(false), ShowConfigOptionsList(false),
+ AnalyzeAll(false), AnalyzerDisplayProgress(false),
+ AnalyzeNestedBlocks(false), eagerlyAssumeBinOpBifurcation(false),
+ TrimGraph(false), visualizeExplodedGraphWithGraphViz(false),
+ UnoptimizedCFG(false), PrintStats(false), NoRetryExhausted(false) {
+ llvm::sort(AnalyzerConfigCmdFlags);
+ }
/// Interprets an option's string value as a boolean. The "true" string is
/// interpreted as true and the "false" string is interpreted as false.
@@ -373,34 +276,17 @@ public:
/// @param [in] Name Name for option to retrieve.
/// @param [in] DefaultVal Default value returned if no such option was
/// specified.
- /// @param [in] C The optional checker parameter that can be used to restrict
- /// the search to the options of this particular checker (and its parents
- /// depending on search mode).
+ /// @param [in] C The checker object the option belongs to. Checker options
+ /// are retrieved in the following format:
+ /// `-analyzer-config <package and checker name>:OptionName=Value.
/// @param [in] SearchInParents If set to true and the searched option was not
/// specified for the given checker the options for the parent packages will
/// be searched as well. The inner packages take precedence over the outer
/// ones.
- bool getBooleanOption(StringRef Name, bool DefaultVal,
- const ento::CheckerBase *C = nullptr,
- bool SearchInParents = false);
+ bool getCheckerBooleanOption(StringRef Name, bool DefaultVal,
+ const ento::CheckerBase *C,
+ bool SearchInParents = false) const;
- /// Variant that accepts a Optional value to cache the result.
- ///
- /// @param [in,out] V Return value storage, returned if parameter contains
- /// an existing valid option, else it is used to store a return value
- /// @param [in] Name Name for option to retrieve.
- /// @param [in] DefaultVal Default value returned if no such option was
- /// specified.
- /// @param [in] C The optional checker parameter that can be used to restrict
- /// the search to the options of this particular checker (and its parents
- /// depending on search mode).
- /// @param [in] SearchInParents If set to true and the searched option was not
- /// specified for the given checker the options for the parent packages will
- /// be searched as well. The inner packages take precedence over the outer
- /// ones.
- bool getBooleanOption(Optional<bool> &V, StringRef Name, bool DefaultVal,
- const ento::CheckerBase *C = nullptr,
- bool SearchInParents = false);
/// Interprets an option's string value as an integer value.
///
@@ -408,16 +294,16 @@ public:
/// @param [in] Name Name for option to retrieve.
/// @param [in] DefaultVal Default value returned if no such option was
/// specified.
- /// @param [in] C The optional checker parameter that can be used to restrict
- /// the search to the options of this particular checker (and its parents
- /// depending on search mode).
+ /// @param [in] C The checker object the option belongs to. Checker options
+ /// are retrieved in the following format:
+ /// `-analyzer-config <package and checker name>:OptionName=Value.
/// @param [in] SearchInParents If set to true and the searched option was not
/// specified for the given checker the options for the parent packages will
/// be searched as well. The inner packages take precedence over the outer
/// ones.
- int getOptionAsInteger(StringRef Name, int DefaultVal,
- const ento::CheckerBase *C = nullptr,
- bool SearchInParents = false);
+ int getCheckerIntegerOption(StringRef Name, int DefaultVal,
+ const ento::CheckerBase *C,
+ bool SearchInParents = false) const;
/// Query an option's string value.
///
@@ -425,26 +311,26 @@ public:
/// @param [in] Name Name for option to retrieve.
/// @param [in] DefaultVal Default value returned if no such option was
/// specified.
- /// @param [in] C The optional checker parameter that can be used to restrict
- /// the search to the options of this particular checker (and its parents
- /// depending on search mode).
+ /// @param [in] C The checker object the option belongs to. Checker options
+ /// are retrieved in the following format:
+ /// `-analyzer-config <package and checker name>:OptionName=Value.
/// @param [in] SearchInParents If set to true and the searched option was not
/// specified for the given checker the options for the parent packages will
/// be searched as well. The inner packages take precedence over the outer
/// ones.
- StringRef getOptionAsString(StringRef Name, StringRef DefaultVal,
- const ento::CheckerBase *C = nullptr,
- bool SearchInParents = false);
+ StringRef getCheckerStringOption(StringRef Name, StringRef DefaultVal,
+ const ento::CheckerBase *C,
+ bool SearchInParents = false) const;
/// Retrieves and sets the UserMode. This is a high-level option,
/// which is used to set other low-level options. It is not accessible
/// outside of AnalyzerOptions.
- UserModeKind getUserMode();
+ UserModeKind getUserMode() const;
- ExplorationStrategyKind getExplorationStrategy();
+ ExplorationStrategyKind getExplorationStrategy() const;
/// Returns the inter-procedural analysis mode.
- IPAKind getIPAMode();
+ IPAKind getIPAMode() const;
/// Returns the option controlling which C++ member functions will be
/// considered for inlining.
@@ -452,286 +338,28 @@ public:
/// This is controlled by the 'c++-inlining' config option.
///
/// \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 <OP> B + m becomes A - B <OP> m - n, where A and B symbolic,
- /// n and m are integers. <OP> 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();
+ bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K) const;
};
using AnalyzerOptionsRef = IntrusiveRefCntPtr<AnalyzerOptions>;
+//===----------------------------------------------------------------------===//
+// We'll use AnalyzerOptions in the frontend, but we can't link the frontend
+// with clangStaticAnalyzerCore, because clangStaticAnalyzerCore depends on
+// clangFrontend.
+//
+// For this reason, implement some methods in this header file.
+//===----------------------------------------------------------------------===//
+
+inline UserModeKind AnalyzerOptions::getUserMode() const {
+ auto K = llvm::StringSwitch<llvm::Optional<UserModeKind>>(UserMode)
+ .Case("shallow", UMK_Shallow)
+ .Case("deep", UMK_Deep)
+ .Default(None);
+ assert(K.hasValue() && "User mode is invalid.");
+ return K.getValue();
+}
+
} // namespace clang
#endif // LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index ee16522c0b..c023ed5641 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -345,12 +345,11 @@ public:
namespace bugreporter {
-/// Attempts to add visitors to trace a null or undefined value back to its
-/// point of origin, whether it is a symbol constrained to null or an explicit
-/// assignment.
+/// Attempts to add visitors to track expression value back to its point of
+/// origin.
///
/// \param N A node "downstream" from the evaluation of the statement.
-/// \param S The statement whose value is null or undefined.
+/// \param E The expression value which we are tracking
/// \param R The bug report to which visitors should be attached.
/// \param EnableNullFPSuppression Whether we should employ false positive
/// suppression (inlined defensive checks, returned null).
@@ -358,13 +357,10 @@ namespace bugreporter {
/// \return Whether or not the function was able to add visitors for this
/// statement. Note that returning \c true does not actually imply
/// that any visitors were added.
-bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R,
- bool EnableNullFPSuppression = true);
+bool trackExpressionValue(const ExplodedNode *N, const Expr *E, BugReport &R,
+ bool EnableNullFPSuppression = true);
const Expr *getDerefExpr(const Stmt *S);
-const Stmt *GetDenomExpr(const ExplodedNode *N);
-const Stmt *GetRetValExpr(const ExplodedNode *N);
-bool isDeclRefExprToReference(const Expr *E);
} // namespace bugreporter
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index 7fff42903b..e9c682d798 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -118,7 +118,7 @@ public:
/// Only runs visitors, no output generated.
None,
- /// Used for HTML and text output.
+ /// Used for HTML, SARIF, and text output.
Minimal,
/// Used for plist output, used for "arrows" generation.
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index 8484cfe4c9..786465cee8 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -558,6 +558,8 @@ struct ImplicitNullDerefEvent {
// dereference might happen later (for example pointer passed to a parameter
// that is marked with nonnull attribute.)
bool IsDirectDereference;
+
+ static int Tag;
};
/// A helper class which wraps a boolean value set to false by default.
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 463c842ec5..538ed19f7e 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -532,19 +532,19 @@ public:
template <typename EVENT>
void _registerListenerForEvent(CheckEventFunc checkfn) {
- EventInfo &info = Events[getTag<EVENT>()];
+ EventInfo &info = Events[&EVENT::Tag];
info.Checkers.push_back(checkfn);
}
template <typename EVENT>
void _registerDispatcherForEvent() {
- EventInfo &info = Events[getTag<EVENT>()];
+ EventInfo &info = Events[&EVENT::Tag];
info.HasDispatcher = true;
}
template <typename EVENT>
void _dispatchEvent(const EVENT &event) const {
- EventsTy::const_iterator I = Events.find(getTag<EVENT>());
+ EventsTy::const_iterator I = Events.find(&EVENT::Tag);
if (I == Events.end())
return;
const EventInfo &info = I->second;
diff --git a/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h b/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h
deleted file mode 100644
index 2d13bf34cd..0000000000
--- a/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//===--- CheckerOptInfo.h - Specifies which checkers to use -----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H
-#define LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H
-
-#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/StringRef.h"
-
-namespace clang {
-namespace ento {
-
-/// Represents a request to include or exclude a checker or package from a
-/// specific analysis run.
-///
-/// \sa CheckerRegistry::initializeManager
-class CheckerOptInfo {
- StringRef Name;
- bool Enable;
- bool Claimed;
-
-public:
- CheckerOptInfo(StringRef name, bool enable)
- : Name(name), Enable(enable), Claimed(false) { }
-
- StringRef getName() const { return Name; }
- bool isEnabled() const { return Enable; }
- bool isDisabled() const { return !isEnabled(); }
-
- bool isClaimed() const { return Claimed; }
- bool isUnclaimed() const { return !isClaimed(); }
- void claim() { Claimed = true; }
-};
-
-} // end namespace ento
-} // end namespace clang
-
-#endif
diff --git a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
index d580dda734..740754090d 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
@@ -73,8 +73,6 @@ class DiagnosticsEngine;
namespace ento {
-class CheckerOptInfo;
-
/// Manages a set of available checkers for running a static analysis.
/// The checkers are organized into packages by full name, where including
/// a package will recursively include all subpackages and checkers within it.
@@ -123,8 +121,8 @@ public:
/// all checkers specified by the given CheckerOptInfo list. The order of this
/// list is significant; later options can be used to reverse earlier ones.
/// This can be used to exclude certain checkers in an included package.
- void initializeManager(CheckerManager &mgr,
- SmallVectorImpl<CheckerOptInfo> &opts) const;
+ void initializeManager(CheckerManager &mgr, const AnalyzerOptions &Opts,
+ DiagnosticsEngine &diags) const;
/// Check if every option corresponds to a specific checker or package.
void validateCheckerOptions(const AnalyzerOptions &opts,
@@ -133,8 +131,7 @@ public:
/// Prints the name and description of all checkers in this registry.
/// This output is not intended to be machine-parseable.
void printHelp(raw_ostream &out, size_t maxNameChars = 30) const;
- void printList(raw_ostream &out,
- SmallVectorImpl<CheckerOptInfo> &opts) const;
+ void printList(raw_ostream &out, const AnalyzerOptions &opts) const;
private:
mutable CheckerInfoList Checkers;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 4c50eafbde..a53e8ee693 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -921,15 +921,30 @@ public:
return getOriginExpr()->getOperatorNew();
}
+ /// Number of non-placement arguments to the call. It is equal to 2 for
+ /// C++17 aligned operator new() calls that have alignment implicitly
+ /// passed as the second argument, and to 1 for other operator new() calls.
+ unsigned getNumImplicitArgs() const {
+ return getOriginExpr()->passAlignment() ? 2 : 1;
+ }
+
unsigned getNumArgs() const override {
- return getOriginExpr()->getNumPlacementArgs() + 1;
+ return getOriginExpr()->getNumPlacementArgs() + getNumImplicitArgs();
}
const Expr *getArgExpr(unsigned Index) const override {
// The first argument of an allocator call is the size of the allocation.
- if (Index == 0)
+ if (Index < getNumImplicitArgs())
return nullptr;
- return getOriginExpr()->getPlacementArg(Index - 1);
+ return getOriginExpr()->getPlacementArg(Index - getNumImplicitArgs());
+ }
+
+ /// Number of placement arguments to the operator new() call. For example,
+ /// standard std::nothrow operator new and standard placement new both have
+ /// 1 implicit argument (size) and 1 placement argument, while regular
+ /// operator new() has 1 implicit argument and 0 placement arguments.
+ const Expr *getPlacementArgExpr(unsigned Index) const {
+ return getOriginExpr()->getPlacementArg(Index);
}
Kind getKind() const override { return CE_CXXAllocator; }
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h
index 2f8ead0746..b0d514dc28 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h
@@ -36,10 +36,7 @@ using DynamicTypeMapImpl =
template <>
struct ProgramStateTrait<DynamicTypeMap>
: public ProgramStatePartialTrait<DynamicTypeMapImpl> {
- static void *GDMIndex() {
- static int index = 0;
- return &index;
- }
+ static void *GDMIndex();
};
/// Get dynamic type information for a region.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index cf4164dcd2..bf460df278 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -210,10 +210,14 @@ public:
return const_cast<ExplodedNode*>(this)->getFirstPred();
}
- const ExplodedNode *getFirstSucc() const {
+ ExplodedNode *getFirstSucc() {
return succ_empty() ? nullptr : *(succ_begin());
}
+ const ExplodedNode *getFirstSucc() const {
+ return const_cast<ExplodedNode*>(this)->getFirstSucc();
+ }
+
// Iterators over successor and predecessor vertices.
using succ_iterator = ExplodedNode * const *;
using const_succ_iterator = const ExplodedNode * const *;
@@ -243,8 +247,10 @@ public:
int64_t getID(ExplodedGraph *G) const;
/// The node is trivial if it has only one successor, only one predecessor,
+ /// it's predecessor has only one successor,
/// and its program state is the same as the program state of the previous
/// node.
+ /// Trivial nodes may be skipped while printing exploded graph.
bool isTrivial() const;
private:
@@ -460,7 +466,6 @@ public:
// GraphTraits
namespace llvm {
-
template <> struct GraphTraits<clang::ento::ExplodedGraph *> {
using GraphTy = clang::ento::ExplodedGraph *;
using NodeRef = clang::ento::ExplodedNode *;
@@ -471,17 +476,19 @@ namespace llvm {
return *G->roots_begin();
}
+ static bool predecessorOfTrivial(NodeRef N) {
+ return N->succ_size() == 1 && N->getFirstSucc()->isTrivial();
+ }
+
static ChildIteratorType child_begin(NodeRef N) {
- if (N->succ_size() == 1 && (*N->succ_begin())->isTrivial()) {
+ if (predecessorOfTrivial(N))
return child_begin(*N->succ_begin());
- }
return N->succ_begin();
}
static ChildIteratorType child_end(NodeRef N) {
- if (N->succ_size() == 1 && (*N->succ_begin())->isTrivial()) {
- return child_end(*N->succ_begin());
- }
+ if (predecessorOfTrivial(N))
+ return child_end(N->getFirstSucc());
return N->succ_end();
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 91e47b37b7..86b776afb8 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -832,7 +832,7 @@ struct ReplayWithoutInlining{};
template <>
struct ProgramStateTrait<ReplayWithoutInlining> :
public ProgramStatePartialTrait<const void*> {
- static void *GDMIndex() { static int index = 0; return &index; }
+ static void *GDMIndex();
};
} // namespace ento
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 0b0e32b8e3..bf01289a40 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -118,6 +118,10 @@ public:
const MemRegion *getBaseRegion() const;
+ /// Recursively retrieve the region of the most derived class instance of
+ /// regions of C++ base class instances.
+ const MemRegion *getMostDerivedObjectRegion() const;
+
/// Check if the region is a subregion of the given region.
/// Each region is a subregion of itself.
virtual bool isSubRegionOf(const MemRegion *R) const;
@@ -1077,7 +1081,7 @@ public:
void dump() const;
};
-/// ElementRegin is used to represent both array elements and casts.
+/// ElementRegion is used to represent both array elements and casts.
class ElementRegion : public TypedValueRegion {
friend class MemRegionManager;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 13f5b14378..f544204497 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -348,6 +348,8 @@ public:
/// a value of such type.
SVal getSValAsScalarOrLoc(const MemRegion *R) const;
+ using region_iterator = const MemRegion **;
+
/// Visits the symbols reachable from the given SVal using the provided
/// SymbolVisitor.
///
@@ -357,24 +359,14 @@ public:
/// \sa ScanReachableSymbols
bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const;
- /// Visits the symbols reachable from the SVals in the given range
- /// using the provided SymbolVisitor.
- bool scanReachableSymbols(const SVal *I, const SVal *E,
- SymbolVisitor &visitor) const;
-
/// Visits the symbols reachable from the regions in the given
/// MemRegions range using the provided SymbolVisitor.
- bool scanReachableSymbols(const MemRegion * const *I,
- const MemRegion * const *E,
+ bool scanReachableSymbols(llvm::iterator_range<region_iterator> Reachable,
SymbolVisitor &visitor) const;
template <typename CB> CB scanReachableSymbols(SVal val) const;
- template <typename CB> CB scanReachableSymbols(const SVal *beg,
- const SVal *end) const;
-
template <typename CB> CB
- scanReachableSymbols(const MemRegion * const *beg,
- const MemRegion * const *end) const;
+ scanReachableSymbols(llvm::iterator_range<region_iterator> Reachable) const;
/// Create a new state in which the statement is marked as tainted.
LLVM_NODISCARD ProgramStateRef
@@ -883,17 +875,10 @@ CB ProgramState::scanReachableSymbols(SVal val) const {
}
template <typename CB>
-CB ProgramState::scanReachableSymbols(const SVal *beg, const SVal *end) const {
- CB cb(this);
- scanReachableSymbols(beg, end, cb);
- return cb;
-}
-
-template <typename CB>
-CB ProgramState::scanReachableSymbols(const MemRegion * const *beg,
- const MemRegion * const *end) const {
+CB ProgramState::scanReachableSymbols(
+ llvm::iterator_range<region_iterator> Reachable) const {
CB cb(this);
- scanReachableSymbols(beg, end, cb);
+ scanReachableSymbols(Reachable, cb);
return cb;
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
index d2ba1f7c95..1b12a4edc2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -131,7 +131,7 @@ using ConstraintRangeTy = llvm::ImmutableMap<SymbolRef, RangeSet>;
template <>
struct ProgramStateTrait<ConstraintRange>
: public ProgramStatePartialTrait<ConstraintRangeTy> {
- static void *GDMIndex() { static int Index; return &Index; }
+ static void *GDMIndex();
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h
index 1a645cb870..8eaa9365be 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h
@@ -134,9 +134,9 @@ public:
// A value has been obtained, check if it is the only value
SMTExprRef NotExp = SMTConv::fromBinOp(
Solver, Exp, BO_NE,
- Ty->isBooleanType() ? Solver->fromBoolean(Value.getBoolValue())
- : Solver->fromAPSInt(Value),
- false);
+ Ty->isBooleanType() ? Solver->mkBoolean(Value.getBoolValue())
+ : Solver->mkBitvector(Value, Value.getBitWidth()),
+ /*isSigned=*/false);
Solver->addConstraint(NotExp);
@@ -198,7 +198,7 @@ public:
auto &CZFactory = State->get_context<ConstraintSMT>();
for (auto I = CZ.begin(), E = CZ.end(); I != E; ++I) {
- if (SymReaper.maybeDead(I->first))
+ if (SymReaper.isDead(I->first))
CZ = CZFactory.remove(CZ, *I);
}
@@ -218,6 +218,52 @@ public:
OS << nl;
}
+ bool canReasonAbout(SVal X) const override {
+ const TargetInfo &TI = getBasicVals().getContext().getTargetInfo();
+
+ Optional<nonloc::SymbolVal> SymVal = X.getAs<nonloc::SymbolVal>();
+ if (!SymVal)
+ return true;
+
+ const SymExpr *Sym = SymVal->getSymbol();
+ QualType Ty = Sym->getType();
+
+ // Complex types are not modeled
+ if (Ty->isComplexType() || Ty->isComplexIntegerType())
+ return false;
+
+ // Non-IEEE 754 floating-point types are not modeled
+ if ((Ty->isSpecificBuiltinType(BuiltinType::LongDouble) &&
+ (&TI.getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended() ||
+ &TI.getLongDoubleFormat() == &llvm::APFloat::PPCDoubleDouble())))
+ return false;
+
+ if (Ty->isRealFloatingType())
+ return Solver->isFPSupported();
+
+ if (isa<SymbolData>(Sym))
+ return true;
+
+ SValBuilder &SVB = getSValBuilder();
+
+ if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
+ return canReasonAbout(SVB.makeSymbolVal(SC->getOperand()));
+
+ if (const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) {
+ if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE))
+ return canReasonAbout(SVB.makeSymbolVal(SIE->getLHS()));
+
+ if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE))
+ return canReasonAbout(SVB.makeSymbolVal(ISE->getRHS()));
+
+ if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(BSE))
+ return canReasonAbout(SVB.makeSymbolVal(SSE->getLHS())) &&
+ canReasonAbout(SVB.makeSymbolVal(SSE->getRHS()));
+ }
+
+ llvm_unreachable("Unsupported expression to reason about!");
+ }
+
/// Dumps SMT formula
LLVM_DUMP_METHOD void dump() const { Solver->dump(); }
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
index 8be7d4c467..cdca2a0970 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
@@ -246,7 +246,7 @@ public:
// Logical operators
case BO_LAnd:
case BO_LOr:
- return fromBinOp(Solver, LHS, Op, RHS, false);
+ return fromBinOp(Solver, LHS, Op, RHS, /*isSigned=*/false);
default:;
}
@@ -294,14 +294,14 @@ public:
if (FromTy->isIntegralOrEnumerationType() && ToTy->isRealFloatingType()) {
SMTSortRef Sort = Solver->getFloatSort(ToBitWidth);
return FromTy->isSignedIntegerOrEnumerationType()
- ? Solver->mkFPtoSBV(Exp, Sort)
- : Solver->mkFPtoUBV(Exp, Sort);
+ ? Solver->mkSBVtoFP(Exp, Sort)
+ : Solver->mkUBVtoFP(Exp, Sort);
}
if (FromTy->isRealFloatingType() && ToTy->isIntegralOrEnumerationType())
return ToTy->isSignedIntegerOrEnumerationType()
- ? Solver->mkSBVtoFP(Exp, ToBitWidth)
- : Solver->mkUBVtoFP(Exp, ToBitWidth);
+ ? Solver->mkFPtoSBV(Exp, ToBitWidth)
+ : Solver->mkFPtoUBV(Exp, ToBitWidth);
llvm_unreachable("Unsupported explicit type cast!");
}
@@ -379,14 +379,14 @@ public:
getSymExpr(Solver, Ctx, SIE->getLHS(), &LTy, hasComparison);
llvm::APSInt NewRInt;
std::tie(NewRInt, RTy) = fixAPSInt(Ctx, SIE->getRHS());
- SMTExprRef RHS = Solver->fromAPSInt(NewRInt);
+ SMTExprRef RHS = Solver->mkBitvector(NewRInt, NewRInt.getBitWidth());
return getBinExpr(Solver, Ctx, LHS, LTy, Op, RHS, RTy, RetTy);
}
if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE)) {
llvm::APSInt NewLInt;
std::tie(NewLInt, LTy) = fixAPSInt(Ctx, ISE->getLHS());
- SMTExprRef LHS = Solver->fromAPSInt(NewLInt);
+ SMTExprRef LHS = Solver->mkBitvector(NewLInt, NewLInt.getBitWidth());
SMTExprRef RHS =
getSymExpr(Solver, Ctx, ISE->getRHS(), &RTy, hasComparison);
return getBinExpr(Solver, Ctx, LHS, LTy, Op, RHS, RTy, RetTy);
@@ -466,7 +466,7 @@ public:
llvm::APFloat Zero =
llvm::APFloat::getZero(Ctx.getFloatTypeSemantics(Ty));
return fromFloatBinOp(Solver, Exp, Assumption ? BO_EQ : BO_NE,
- Solver->fromAPFloat(Zero));
+ Solver->mkFloat(Zero));
}
if (Ty->isIntegralOrEnumerationType() || Ty->isAnyPointerType() ||
@@ -477,8 +477,10 @@ public:
if (Ty->isBooleanType())
return Assumption ? fromUnOp(Solver, UO_LNot, Exp) : Exp;
- return fromBinOp(Solver, Exp, Assumption ? BO_EQ : BO_NE,
- Solver->fromInt("0", Ctx.getTypeSize(Ty)), isSigned);
+ return fromBinOp(
+ Solver, Exp, Assumption ? BO_EQ : BO_NE,
+ Solver->mkBitvector(llvm::APSInt("0"), Ctx.getTypeSize(Ty)),
+ isSigned);
}
llvm_unreachable("Unsupported type for zero value!");
@@ -493,7 +495,8 @@ public:
QualType FromTy;
llvm::APSInt NewFromInt;
std::tie(NewFromInt, FromTy) = fixAPSInt(Ctx, From);
- SMTExprRef FromExp = Solver->fromAPSInt(NewFromInt);
+ SMTExprRef FromExp =
+ Solver->mkBitvector(NewFromInt, NewFromInt.getBitWidth());
// Convert symbol
QualType SymTy;
@@ -507,7 +510,7 @@ public:
QualType ToTy;
llvm::APSInt NewToInt;
std::tie(NewToInt, ToTy) = fixAPSInt(Ctx, To);
- SMTExprRef ToExp = Solver->fromAPSInt(NewToInt);
+ SMTExprRef ToExp = Solver->mkBitvector(NewToInt, NewToInt.getBitWidth());
assert(FromTy == ToTy && "Range values have different types!");
// Construct two (in)equalities, and a logical and/or
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h
index 71bfb400fc..2abe5fc987 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h
@@ -226,23 +226,23 @@ public:
/// operation
virtual SMTExprRef mkFPtoFP(const SMTExprRef &From, const SMTSortRef &To) = 0;
- /// Creates a floating-point conversion from floatint-point to signed
- /// bitvector operation
- virtual SMTExprRef mkFPtoSBV(const SMTExprRef &From,
- const SMTSortRef &To) = 0;
-
- /// Creates a floating-point conversion from floatint-point to unsigned
- /// bitvector operation
- virtual SMTExprRef mkFPtoUBV(const SMTExprRef &From,
- const SMTSortRef &To) = 0;
-
/// Creates a floating-point conversion from signed bitvector to
/// floatint-point operation
- virtual SMTExprRef mkSBVtoFP(const SMTExprRef &From, unsigned ToWidth) = 0;
+ virtual SMTExprRef mkSBVtoFP(const SMTExprRef &From,
+ const SMTSortRef &To) = 0;
/// Creates a floating-point conversion from unsigned bitvector to
/// floatint-point operation
- virtual SMTExprRef mkUBVtoFP(const SMTExprRef &From, unsigned ToWidth) = 0;
+ virtual SMTExprRef mkUBVtoFP(const SMTExprRef &From,
+ const SMTSortRef &To) = 0;
+
+ /// Creates a floating-point conversion from floatint-point to signed
+ /// bitvector operation
+ virtual SMTExprRef mkFPtoSBV(const SMTExprRef &From, unsigned ToWidth) = 0;
+
+ /// Creates a floating-point conversion from floatint-point to unsigned
+ /// bitvector operation
+ virtual SMTExprRef mkFPtoUBV(const SMTExprRef &From, unsigned ToWidth) = 0;
/// Creates a new symbol, given a name and a sort
virtual SMTExprRef mkSymbol(const char *Name, SMTSortRef Sort) = 0;
@@ -273,18 +273,6 @@ public:
virtual bool getInterpretation(const SMTExprRef &Exp,
llvm::APFloat &Float) = 0;
- /// Construct an SMTExprRef value from a boolean.
- virtual SMTExprRef fromBoolean(const bool Bool) = 0;
-
- /// Construct an SMTExprRef value from a finite APFloat.
- virtual SMTExprRef fromAPFloat(const llvm::APFloat &Float) = 0;
-
- /// Construct an SMTExprRef value from an APSInt.
- virtual SMTExprRef fromAPSInt(const llvm::APSInt &Int) = 0;
-
- /// Construct an SMTExprRef value from an integer.
- virtual SMTExprRef fromInt(const char *Int, uint64_t BitWidth) = 0;
-
/// Check if the constraints are satisfiable
virtual Optional<bool> check() const = 0;
@@ -295,7 +283,10 @@ public:
virtual void pop(unsigned NumStates = 1) = 0;
/// Reset the solver and remove all constraints.
- virtual void reset() const = 0;
+ virtual void reset() = 0;
+
+ /// Checks if the solver supports floating-points.
+ virtual bool isFPSupported() = 0;
virtual void print(raw_ostream &OS) const = 0;
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index 4ab7161459..f49f761c77 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -260,12 +260,12 @@ public:
public:
virtual ~BindingsHandler();
+ /// \return whether the iteration should continue.
virtual bool HandleBinding(StoreManager& SMgr, Store store,
const MemRegion *region, SVal val) = 0;
};
- class FindUniqueBinding :
- public BindingsHandler {
+ class FindUniqueBinding : public BindingsHandler {
SymbolRef Sym;
const MemRegion* Binding = nullptr;
bool First = true;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index b014c63709..d02a8abd11 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -558,7 +558,6 @@ class SymbolReaper {
SymbolMapTy TheLiving;
SymbolSetTy MetadataInUse;
- SymbolSetTy TheDead;
RegionSetTy RegionRoots;
@@ -603,21 +602,6 @@ public:
/// symbol marking has occurred, i.e. in the MarkLiveSymbols callback.
void markInUse(SymbolRef sym);
- /// If a symbol is known to be live, marks the symbol as live.
- ///
- /// Otherwise, if the symbol cannot be proven live, it is marked as dead.
- /// Returns true if the symbol is dead, false if live.
- bool maybeDead(SymbolRef sym);
-
- using dead_iterator = SymbolSetTy::const_iterator;
-
- dead_iterator dead_begin() const { return TheDead.begin(); }
- dead_iterator dead_end() const { return TheDead.end(); }
-
- bool hasDeadSymbols() const {
- return !TheDead.empty();
- }
-
using region_iterator = RegionSetTy::const_iterator;
region_iterator region_begin() const { return RegionRoots.begin(); }
@@ -626,9 +610,9 @@ public:
/// Returns whether or not a symbol has been confirmed dead.
///
/// This should only be called once all marking of dead symbols has completed.
- /// (For checkers, this means only in the evalDeadSymbols callback.)
- bool isDead(SymbolRef sym) const {
- return TheDead.count(sym);
+ /// (For checkers, this means only in the checkDeadSymbols callback.)
+ bool isDead(SymbolRef sym) {
+ return !isLive(sym);
}
void markLive(const MemRegion *region);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
index ce19b7131d..8218fb1eea 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
@@ -34,10 +34,7 @@ using TaintMapImpl = llvm::ImmutableMap<SymbolRef, TaintTagType>;
template<> struct ProgramStateTrait<TaintMap>
: public ProgramStatePartialTrait<TaintMapImpl> {
- static void *GDMIndex() {
- static int index = 0;
- return &index;
- }
+ static void *GDMIndex();
};
/// The GDM component mapping derived symbols' parent symbols to their
@@ -49,10 +46,7 @@ using DerivedSymTaintImpl = llvm::ImmutableMap<SymbolRef, TaintedSubRegions>;
template<> struct ProgramStateTrait<DerivedSymTaint>
: public ProgramStatePartialTrait<DerivedSymTaintImpl> {
- static void *GDMIndex() {
- static int index;
- return &index;
- }
+ static void *GDMIndex();
};
class TaintManager {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
index 07edd35ff9..ef3c2694b2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
@@ -85,6 +85,7 @@ public:
static std::unique_ptr<WorkList> makeBFSBlockDFSContents();
static std::unique_ptr<WorkList> makeUnexploredFirst();
static std::unique_ptr<WorkList> makeUnexploredFirstPriorityQueue();
+ static std::unique_ptr<WorkList> makeUnexploredFirstPriorityLocationQueue();
};
} // end ento namespace
diff --git a/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h b/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h
index fc506ae52e..de16a1781a 100644
--- a/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h
+++ b/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h
@@ -56,7 +56,7 @@ enum ArgEffect {
/// The argument has its reference count decreased by 1. This is as
/// if a -release message has been sent to the argument. This differs
- /// in behavior from DecRef when GC is enabled.
+ /// in behavior from DecRef when ARC is enabled.
DecRefMsg,
/// The argument has its reference count decreased by 1 to model
@@ -65,7 +65,7 @@ enum ArgEffect {
/// The argument has its reference count increased by 1. This is as
/// if a -retain message has been sent to the argument. This differs
- /// in behavior from IncRef when GC is enabled.
+ /// in behavior from IncRef when ARC is enabled.
IncRefMsg,
/// The argument has its reference count increased by 1. This is as
@@ -139,7 +139,7 @@ public:
OwnedWhenTrackedReceiver,
// Treat this function as returning a non-tracked symbol even if
// the function has been inlined. This is used where the call
- // site summary is more presise than the summary indirectly produced
+ // site summary is more precise than the summary indirectly produced
// by inlining the function
NoRetHard
};
@@ -369,8 +369,12 @@ public:
/// This is only meaningful if the summary applies to an ObjCMessageExpr*.
ArgEffect getReceiverEffect() const { return Receiver; }
+ /// \return the effect on the "this" receiver of the method call.
ArgEffect getThisEffect() const { return This; }
+ /// Set the effect of the method on "this".
+ void setThisEffect(ArgEffect e) { This = e; }
+
bool isNoop() const {
return Ret == RetEffect::MakeNoRet() && Receiver == DoNothing
&& DefaultArgEffect == MayEscape && This == DoNothing
@@ -465,6 +469,8 @@ public:
}
};
+class RetainSummaryTemplate;
+
class RetainSummaryManager {
typedef llvm::DenseMap<const FunctionDecl*, const RetainSummary *>
FuncSummariesTy;
@@ -479,7 +485,10 @@ class RetainSummaryManager {
/// Records whether or not the analyzed code runs in ARC mode.
const bool ARCEnabled;
- /// Track sublcasses of OSObject
+ /// Track Objective-C and CoreFoundation objects.
+ const bool TrackObjCAndCFObjects;
+
+ /// Track sublcasses of OSObject.
const bool TrackOSObjects;
/// FuncSummaries - A map from FunctionDecls to summaries.
@@ -530,6 +539,8 @@ class RetainSummaryManager {
/// Decrement the reference count on OS object.
const RetainSummary *getOSSummaryReleaseRule(const FunctionDecl *FD);
+ /// Free the OS object.
+ const RetainSummary *getOSSummaryFreeRule(const FunctionDecl *FD);
enum UnaryFuncKind { cfretain, cfrelease, cfautorelease, cfmakecollectable };
@@ -620,13 +631,36 @@ class RetainSummaryManager {
const RetainSummary * generateSummary(const FunctionDecl *FD,
bool &AllowAnnotations);
+ /// Return a summary for OSObject, or nullptr if not found.
+ const RetainSummary *getSummaryForOSObject(const FunctionDecl *FD,
+ StringRef FName, QualType RetTy);
+
+ /// Return a summary for Objective-C or CF object, or nullptr if not found.
+ const RetainSummary *getSummaryForObjCOrCFObject(
+ const FunctionDecl *FD,
+ StringRef FName,
+ QualType RetTy,
+ const FunctionType *FT,
+ bool &AllowAnnotations);
+
+ /// Apply the annotation of {@code pd} in function {@code FD}
+ /// to the resulting summary stored in out-parameter {@code Template}.
+ /// \return whether an annotation was applied.
+ bool applyFunctionParamAnnotationEffect(const ParmVarDecl *pd,
+ unsigned parm_idx,
+ const FunctionDecl *FD,
+ ArgEffects::Factory &AF,
+ RetainSummaryTemplate &Template);
+
public:
RetainSummaryManager(ASTContext &ctx,
bool usesARC,
- bool trackOSObject)
+ bool trackObjCAndCFObjects,
+ bool trackOSObjects)
: Ctx(ctx),
ARCEnabled(usesARC),
- TrackOSObjects(trackOSObject),
+ TrackObjCAndCFObjects(trackObjCAndCFObjects),
+ TrackOSObjects(trackOSObjects),
AF(BPAlloc), ScratchArgs(AF.getEmptyMap()),
ObjCAllocRetE(usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC)
: RetEffect::MakeOwned(RetEffect::ObjC)),
@@ -636,9 +670,19 @@ public:
InitializeMethodSummaries();
}
- bool canEval(const CallExpr *CE,
- const FunctionDecl *FD,
- bool &hasTrustedImplementationAnnotation);
+ enum class BehaviorSummary {
+ // Function does not return.
+ NoOp,
+
+ // Function returns the first argument.
+ Identity,
+
+ // Function either returns zero, or the input parameter.
+ IdentityOrZero
+ };
+
+ Optional<BehaviorSummary> canEval(const CallExpr *CE, const FunctionDecl *FD,
+ bool &hasTrustedImplementationAnnotation);
bool isTrustedReferenceCountImplementation(const FunctionDecl *FD);
@@ -693,6 +737,7 @@ public:
void updateSummaryFromAnnotations(const RetainSummary *&Summ,
const FunctionDecl *FD);
+
void updateSummaryForCall(const RetainSummary *&Summ,
const CallEvent &Call);
@@ -700,9 +745,21 @@ public:
RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
+ /// \return True if the declaration has an attribute {@code T},
+ /// AND we are tracking that attribute. False otherwise.
+ template <class T>
+ bool hasEnabledAttr(const Decl *D) {
+ return isAttrEnabled<T>() && D->hasAttr<T>();
+ }
+
+ /// Check whether we are tracking properties specified by the attributes.
+ template <class T>
+ bool isAttrEnabled();
+
friend class RetainSummaryTemplate;
};
+
// Used to avoid allocating long-term (BPAlloc'd) memory for default retain
// summaries. If a function or method looks like it has a default summary, but
// it has annotations, the annotations are added to the stack-based template