summaryrefslogtreecommitdiff
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/AnalyzerOptions.h236
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h246
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h181
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugType.h40
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h296
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h24
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h294
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerRegistry.h22
-rw-r--r--include/clang/StaticAnalyzer/Core/IssueHash.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h30
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h79
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h296
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h42
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h21
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h41
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h174
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h8
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h28
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h39
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h125
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h264
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h29
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h274
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h185
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h142
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h216
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h77
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SMTContext.h31
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SMTExpr.h62
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h996
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SMTSort.h91
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h64
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h232
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h5
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h73
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h25
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h39
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h140
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h31
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h11
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h18
46 files changed, 3738 insertions, 1515 deletions
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index ce50cc582d1e0..9d292cfddb0c8 100644
--- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -1,4 +1,4 @@
-//===--- AnalyzerOptions.h - Analysis Engine Options ------------*- C++ -*-===//
+//===- AnalyzerOptions.h - Analysis Engine Options --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -19,18 +19,18 @@
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
#include <string>
+#include <utility>
#include <vector>
namespace clang {
-class ASTConsumer;
-class DiagnosticsEngine;
-class Preprocessor;
-class LangOptions;
namespace ento {
+
class CheckerBase;
-}
+
+} // namespace ento
/// Analysis - Set of available source code analyses.
enum Analyses {
@@ -76,7 +76,7 @@ enum AnalysisInliningMode {
NumInliningModes
};
-/// \brief Describes the different kinds of C++ member functions which can be
+/// Describes the different kinds of C++ member functions which can be
/// considered for inlining by the analyzer.
///
/// These options are cumulative; enabling one kind of member function will
@@ -100,7 +100,7 @@ enum CXXInlineableMemberKind {
CIMK_Destructors
};
-/// \brief Describes the different modes of inter-procedural analysis.
+/// Describes the different modes of inter-procedural analysis.
enum IPAKind {
IPAK_NotSet = 0,
@@ -123,28 +123,31 @@ enum IPAKind {
class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
public:
- typedef llvm::StringMap<std::string> ConfigTable;
+ using ConfigTable = llvm::StringMap<std::string>;
static std::vector<StringRef>
getRegisteredCheckers(bool IncludeExperimental = false);
- /// \brief Pair of checker name and enable/disable.
- std::vector<std::pair<std::string, bool> > CheckersControlList;
+ /// Pair of checker name and enable/disable.
+ std::vector<std::pair<std::string, bool>> CheckersControlList;
- /// \brief A key-value table of use-specified configuration values.
+ /// A key-value table of use-specified configuration values.
ConfigTable Config;
- AnalysisStores AnalysisStoreOpt;
- AnalysisConstraints AnalysisConstraintsOpt;
- AnalysisDiagClients AnalysisDiagOpt;
- AnalysisPurgeMode AnalysisPurgeOpt;
+ AnalysisStores AnalysisStoreOpt = RegionStoreModel;
+ AnalysisConstraints AnalysisConstraintsOpt = RangeConstraintsModel;
+ AnalysisDiagClients AnalysisDiagOpt = PD_HTML;
+ AnalysisPurgeMode AnalysisPurgeOpt = PurgeStmt;
std::string AnalyzeSpecificFunction;
+
+ /// Store full compiler invocation for reproducible instructions in the
+ /// generated report.
+ std::string FullCompilerInvocation;
- /// \brief The maximum number of times the analyzer visits a block.
+ /// The maximum number of times the analyzer visits a block.
unsigned maxBlockVisitOnPath;
-
- /// \brief Disable all analyzer checks.
+ /// Disable all analyzer checks.
///
/// This flag allows one to disable analyzer checks on the code processed by
/// the given analysis consumer. Note, the code will get parsed and the
@@ -157,7 +160,7 @@ public:
unsigned AnalyzerDisplayProgress : 1;
unsigned AnalyzeNestedBlocks : 1;
- /// \brief The flag regulates if we should eagerly assume evaluations of
+ /// The flag regulates if we should eagerly assume evaluations of
/// conditionals, thus, bifurcating the path.
///
/// This flag indicates how the engine should handle expressions such as: 'x =
@@ -174,22 +177,36 @@ public:
unsigned UnoptimizedCFG : 1;
unsigned PrintStats : 1;
- /// \brief Do not re-analyze paths leading to exhausted nodes with a different
+ /// Do not re-analyze paths leading to exhausted nodes with a different
/// strategy. We get better code coverage when retry is enabled.
unsigned NoRetryExhausted : 1;
- /// \brief The inlining stack depth limit.
- unsigned InlineMaxStackDepth;
+ /// The inlining stack depth limit.
+ // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls).
+ unsigned InlineMaxStackDepth = 5;
- /// \brief The mode of function selection used during inlining.
- AnalysisInliningMode InliningMode;
+ /// The mode of function selection used during inlining.
+ AnalysisInliningMode InliningMode = NoRedundancy;
+
+ enum class ExplorationStrategyKind {
+ DFS,
+ BFS,
+ UnexploredFirst,
+ UnexploredFirstQueue,
+ BFSBlockDFSContents,
+ NotSet
+ };
private:
- /// \brief Describes the kinds for high-level analyzer mode.
+ 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
};
@@ -197,10 +214,10 @@ private:
/// 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;
+ UserModeKind UserMode = UMK_NotSet;
/// Controls the mode of inter-procedural analysis.
- IPAKind IPAMode;
+ IPAKind IPAMode = IPAK_NotSet;
/// Controls which C++ member functions will be considered for inlining.
CXXInlineableMemberKind CXXMemberInliningMode;
@@ -217,9 +234,15 @@ private:
/// \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;
@@ -232,6 +255,9 @@ private:
/// \sa mayInlineCXXSharedPtrDtor
Optional<bool> InlineCXXSharedPtrDtor;
+ /// \sa mayInlineCXXTemporaryDtors
+ Optional<bool> InlineCXXTemporaryDtors;
+
/// \sa mayInlineObjCMethod
Optional<bool> ObjCInliningMode;
@@ -254,15 +280,23 @@ private:
/// \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;
@@ -284,6 +318,22 @@ private:
/// \sa shouldDisplayNotesAsEvents
Optional<bool> DisplayNotesAsEvents;
+ /// \sa shouldAggressivelySimplifyBinaryOperation
+ Optional<bool> AggressiveBinaryOperationSimplification;
+
+ /// \sa getCTUDir
+ Optional<StringRef> CTUDir;
+
+ /// \sa getCTUIndexName
+ Optional<StringRef> CTUIndexName;
+
+ /// \sa naiveCTUEnabled
+ Optional<bool> NaiveCTU;
+
+ /// \sa shouldElideConstructors
+ Optional<bool> ElideConstructors;
+
+
/// A helper function that retrieves option for a given full-qualified
/// checker name.
/// Options for checkers can be specified via 'analyzer-config' command-line
@@ -311,6 +361,15 @@ private:
bool SearchInParents = false);
public:
+ AnalyzerOptions()
+ : DisableAllChecks(false), ShowCheckerHelp(false),
+ ShowEnabledCheckerList(false), AnalyzeAll(false),
+ AnalyzerDisplayProgress(false), AnalyzeNestedBlocks(false),
+ eagerlyAssumeBinOpBifurcation(false), TrimGraph(false),
+ visualizeExplodedGraphWithGraphViz(false),
+ visualizeExplodedGraphWithUbiGraph(false), UnoptimizedCFG(false),
+ PrintStats(false), NoRetryExhausted(false), CXXMemberInliningMode() {}
+
/// Interprets an option's string value as a boolean. The "true" string is
/// interpreted as true and the "false" string is interpreted as false.
///
@@ -320,7 +379,7 @@ public:
/// 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
- /// dependening on search mode).
+ /// 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
@@ -338,7 +397,7 @@ public:
/// 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
- /// dependening on search mode).
+ /// 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
@@ -355,7 +414,7 @@ public:
/// 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
- /// dependening on search mode).
+ /// 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
@@ -372,7 +431,7 @@ public:
/// 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
- /// dependening on search mode).
+ /// 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
@@ -381,12 +440,14 @@ public:
const ento::CheckerBase *C = nullptr,
bool SearchInParents = false);
- /// \brief Retrieves and sets the UserMode. This is a high-level 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.
UserModeKind getUserMode();
- /// \brief Returns the inter-procedural analysis mode.
+ ExplorationStrategyKind getExplorationStrategy();
+
+ /// Returns the inter-procedural analysis mode.
IPAKind getIPAMode();
/// Returns the option controlling which C++ member functions will be
@@ -428,6 +489,19 @@ public:
/// 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.
///
@@ -464,6 +538,17 @@ public:
/// 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.
///
@@ -499,6 +584,13 @@ public:
/// 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.
///
@@ -512,6 +604,14 @@ public:
/// 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.
///
@@ -546,6 +646,11 @@ public:
/// 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.
@@ -585,36 +690,41 @@ public:
/// to false when unset.
bool shouldDisplayNotesAsEvents();
-public:
- AnalyzerOptions() :
- AnalysisStoreOpt(RegionStoreModel),
- AnalysisConstraintsOpt(RangeConstraintsModel),
- AnalysisDiagOpt(PD_HTML),
- AnalysisPurgeOpt(PurgeStmt),
- DisableAllChecks(0),
- ShowCheckerHelp(0),
- ShowEnabledCheckerList(0),
- AnalyzeAll(0),
- AnalyzerDisplayProgress(0),
- AnalyzeNestedBlocks(0),
- eagerlyAssumeBinOpBifurcation(0),
- TrimGraph(0),
- visualizeExplodedGraphWithGraphViz(0),
- visualizeExplodedGraphWithUbiGraph(0),
- UnoptimizedCFG(0),
- PrintStats(0),
- NoRetryExhausted(0),
- // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls).
- InlineMaxStackDepth(5),
- InliningMode(NoRedundancy),
- UserMode(UMK_NotSet),
- IPAMode(IPAK_NotSet),
- CXXMemberInliningMode() {}
-
+ /// 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 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();
};
-typedef IntrusiveRefCntPtr<AnalyzerOptions> AnalyzerOptionsRef;
+using AnalyzerOptionsRef = IntrusiveRefCntPtr<AnalyzerOptions>;
-}
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index cd1355d03b639..111e1d1e8e20a 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -1,4 +1,4 @@
-//===--- BugReporter.h - Generate PathDiagnostics --------------*- C++ -*-===//
+//===- BugReporter.h - Generate PathDiagnostics -----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,78 +15,101 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
+#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
-#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableSet.h"
+#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/ilist.h"
#include "llvm/ADT/ilist_node.h"
+#include "llvm/ADT/iterator_range.h"
+#include <cassert>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
namespace clang {
+class AnalyzerOptions;
class ASTContext;
+class Decl;
class DiagnosticsEngine;
+class LocationContext;
+class SourceManager;
class Stmt;
-class ParentMap;
namespace ento {
-class PathDiagnostic;
-class ExplodedNode;
+class BugType;
+class CheckerBase;
class ExplodedGraph;
-class BugReport;
-class BugReporter;
-class BugReporterContext;
+class ExplodedNode;
class ExprEngine;
-class BugType;
+class MemRegion;
+class SValBuilder;
//===----------------------------------------------------------------------===//
// Interface for individual bug reports.
//===----------------------------------------------------------------------===//
+/// A mapping from diagnostic consumers to the diagnostics they should
+/// consume.
+using DiagnosticForConsumerMapTy =
+ llvm::DenseMap<PathDiagnosticConsumer *, std::unique_ptr<PathDiagnostic>>;
+
/// This class provides an interface through which checkers can create
/// individual bug reports.
class BugReport : public llvm::ilist_node<BugReport> {
public:
class NodeResolver {
virtual void anchor();
+
public:
- virtual ~NodeResolver() {}
+ virtual ~NodeResolver() = default;
+
virtual const ExplodedNode*
getOriginalNode(const ExplodedNode *N) = 0;
};
- typedef const SourceRange *ranges_iterator;
- typedef SmallVector<std::unique_ptr<BugReporterVisitor>, 8> VisitorList;
- typedef VisitorList::iterator visitor_iterator;
- typedef SmallVector<StringRef, 2> ExtraTextList;
- typedef SmallVector<std::shared_ptr<PathDiagnosticNotePiece>, 4> NoteList;
+ using ranges_iterator = const SourceRange *;
+ using VisitorList = SmallVector<std::unique_ptr<BugReporterVisitor>, 8>;
+ using visitor_iterator = VisitorList::iterator;
+ using ExtraTextList = SmallVector<StringRef, 2>;
+ using NoteList = SmallVector<std::shared_ptr<PathDiagnosticNotePiece>, 4>;
protected:
- friend class BugReporter;
friend class BugReportEquivClass;
+ friend class BugReporter;
BugType& BT;
- const Decl *DeclWithIssue;
+ const Decl *DeclWithIssue = nullptr;
std::string ShortDescription;
std::string Description;
PathDiagnosticLocation Location;
PathDiagnosticLocation UniqueingLocation;
const Decl *UniqueingDecl;
- const ExplodedNode *ErrorNode;
+ const ExplodedNode *ErrorNode = nullptr;
SmallVector<SourceRange, 4> Ranges;
ExtraTextList ExtraText;
NoteList Notes;
- typedef llvm::DenseSet<SymbolRef> Symbols;
- typedef llvm::DenseSet<const MemRegion *> Regions;
+ using Symbols = llvm::DenseSet<SymbolRef>;
+ using Regions = llvm::DenseSet<const MemRegion *>;
/// A (stack of) a set of symbols that are registered with this
/// report as being "interesting", and thus used to help decide which
@@ -113,20 +136,16 @@ protected:
/// Used for ensuring the visitors are only added once.
llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
- /// Used for clients to tell if the report's configuration has changed
- /// since the last time they checked.
- unsigned ConfigurationChangeToken;
-
/// When set, this flag disables all callstack pruning from a diagnostic
/// path. This is useful for some reports that want maximum fidelty
/// when reporting an issue.
- bool DoNotPrunePath;
+ bool DoNotPrunePath = false;
/// Used to track unique reasons why a bug report might be invalid.
///
/// \sa markInvalid
/// \sa removeInvalidation
- typedef std::pair<const void *, const void *> InvalidationRecord;
+ using InvalidationRecord = std::pair<const void *, const void *>;
/// If non-empty, this bug report is likely a false positive and should not be
/// shown to the user.
@@ -146,20 +165,17 @@ private:
public:
BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode)
- : BT(bt), DeclWithIssue(nullptr), Description(desc), ErrorNode(errornode),
- ConfigurationChangeToken(0), DoNotPrunePath(false) {}
+ : BT(bt), Description(desc), ErrorNode(errornode) {}
BugReport(BugType& bt, StringRef shortDesc, StringRef desc,
const ExplodedNode *errornode)
- : BT(bt), DeclWithIssue(nullptr), ShortDescription(shortDesc),
- Description(desc), ErrorNode(errornode), ConfigurationChangeToken(0),
- DoNotPrunePath(false) {}
+ : BT(bt), ShortDescription(shortDesc), Description(desc),
+ ErrorNode(errornode) {}
BugReport(BugType &bt, StringRef desc, PathDiagnosticLocation l)
- : BT(bt), DeclWithIssue(nullptr), Description(desc), Location(l),
- ErrorNode(nullptr), ConfigurationChangeToken(0), DoNotPrunePath(false) {}
+ : BT(bt), Description(desc), Location(l) {}
- /// \brief Create a BugReport with a custom uniqueing location.
+ /// Create a BugReport with a custom uniqueing location.
///
/// The reports that have the same report location, description, bug type, and
/// ranges are uniqued - only one of the equivalent reports will be presented
@@ -168,18 +184,15 @@ public:
/// the allocation site, rather then the location where the bug is reported.
BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode,
PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique)
- : BT(bt), DeclWithIssue(nullptr), Description(desc),
- UniqueingLocation(LocationToUnique),
- UniqueingDecl(DeclToUnique),
- ErrorNode(errornode), ConfigurationChangeToken(0),
- DoNotPrunePath(false) {}
+ : BT(bt), Description(desc), UniqueingLocation(LocationToUnique),
+ UniqueingDecl(DeclToUnique), ErrorNode(errornode) {}
virtual ~BugReport();
const BugType& getBugType() const { return BT; }
BugType& getBugType() { return BT; }
- /// \brief True when the report has an execution path associated with it.
+ /// True when the report has an execution path associated with it.
///
/// A report is said to be path-sensitive if it was thrown against a
/// particular exploded node in the path-sensitive analysis graph.
@@ -218,10 +231,6 @@ public:
bool isInteresting(SVal V);
bool isInteresting(const LocationContext *LC);
- unsigned getConfigurationChangeToken() const {
- return ConfigurationChangeToken;
- }
-
/// Returns whether or not this report should be considered valid.
///
/// Invalid reports are those that have been classified as likely false
@@ -242,13 +251,6 @@ public:
void markInvalid(const void *Tag, const void *Data) {
Invalidations.insert(std::make_pair(Tag, Data));
}
-
- /// Reverses the effects of a previous invalidation.
- ///
- /// \sa markInvalid
- void removeInvalidation(const void *Tag, const void *Data) {
- Invalidations.erase(std::make_pair(Tag, Data));
- }
/// Return the canonical declaration, be it a method or class, where
/// this issue semantically occurred.
@@ -286,7 +288,7 @@ public:
return Notes;
}
- /// \brief This allows for addition of meta data to the diagnostic.
+ /// This allows for addition of meta data to the diagnostic.
///
/// Currently, only the HTMLDiagnosticClient knows how to display it.
void addExtraText(StringRef S) {
@@ -297,26 +299,26 @@ public:
return ExtraText;
}
- /// \brief Return the "definitive" location of the reported bug.
+ /// Return the "definitive" location of the reported bug.
///
/// While a bug can span an entire path, usually there is a specific
/// location that can be used to identify where the key issue occurred.
/// This location is used by clients rendering diagnostics.
virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const;
- /// \brief Get the location on which the report should be uniqued.
+ /// Get the location on which the report should be uniqued.
PathDiagnosticLocation getUniqueingLocation() const {
return UniqueingLocation;
}
- /// \brief Get the declaration containing the uniqueing location.
+ /// Get the declaration containing the uniqueing location.
const Decl *getUniqueingDecl() const {
return UniqueingDecl;
}
const Stmt *getStmt() const;
- /// \brief Add a range to a bug report.
+ /// Add a range to a bug report.
///
/// Ranges are used to highlight regions of interest in the source code.
/// They should be at the same source code line as the BugReport location.
@@ -329,10 +331,10 @@ public:
Ranges.push_back(R);
}
- /// \brief Get the SourceRanges associated with the report.
+ /// Get the SourceRanges associated with the report.
virtual llvm::iterator_range<ranges_iterator> getRanges();
- /// \brief Add custom or predefined bug report visitors to this report.
+ /// Add custom or predefined bug report visitors to this report.
///
/// The visitors should be used when the default trace is not sufficient.
/// For example, they allow constructing a more elaborate trace.
@@ -341,6 +343,9 @@ public:
/// registerVarDeclsLastStore().
void addVisitor(std::unique_ptr<BugReporterVisitor> visitor);
+ /// Remove all visitors attached to this bug report.
+ void clearVisitors();
+
/// Iterators through the custom diagnostic visitors.
visitor_iterator visitor_begin() { return Callbacks.begin(); }
visitor_iterator visitor_end() { return Callbacks.end(); }
@@ -356,10 +361,11 @@ public:
//===----------------------------------------------------------------------===//
class BugReportEquivClass : public llvm::FoldingSetNode {
+ friend class BugReporter;
+
/// List of *owned* BugReport objects.
llvm::ilist<BugReport> Reports;
- friend class BugReporter;
void AddReport(std::unique_ptr<BugReport> R) {
Reports.push_back(R.release());
}
@@ -373,8 +379,8 @@ public:
Reports.front().Profile(ID);
}
- typedef llvm::ilist<BugReport>::iterator iterator;
- typedef llvm::ilist<BugReport>::const_iterator const_iterator;
+ using iterator = llvm::ilist<BugReport>::iterator;
+ using const_iterator = llvm::ilist<BugReport>::const_iterator;
iterator begin() { return Reports.begin(); }
iterator end() { return Reports.end(); }
@@ -390,22 +396,26 @@ public:
class BugReporterData {
public:
virtual ~BugReporterData();
+
virtual DiagnosticsEngine& getDiagnostic() = 0;
virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0;
virtual ASTContext &getASTContext() = 0;
- virtual SourceManager& getSourceManager() = 0;
- virtual AnalyzerOptions& getAnalyzerOptions() = 0;
+ virtual SourceManager &getSourceManager() = 0;
+ virtual AnalyzerOptions &getAnalyzerOptions() = 0;
};
/// BugReporter is a utility class for generating PathDiagnostics for analysis.
/// It collects the BugReports and BugTypes and knows how to generate
/// and flush the corresponding diagnostics.
+///
+/// The base class is used for generating path-insensitive
class BugReporter {
public:
enum Kind { BaseBRKind, GRBugReporterKind };
private:
- typedef llvm::ImmutableSet<BugType*> BugTypesTy;
+ using BugTypesTy = llvm::ImmutableSet<BugType *>;
+
BugTypesTy::Factory F;
BugTypesTy BugTypes;
@@ -415,27 +425,28 @@ private:
/// Generate and flush the diagnostics for the given bug report.
void FlushReport(BugReportEquivClass& EQ);
- /// Generate and flush the diagnostics for the given bug report
- /// and PathDiagnosticConsumer.
- void FlushReport(BugReport *exampleReport,
- PathDiagnosticConsumer &PD,
- ArrayRef<BugReport*> BugReports);
+ /// Generate the diagnostics for the given bug report.
+ std::unique_ptr<DiagnosticForConsumerMapTy>
+ generateDiagnosticForConsumerMap(BugReport *exampleReport,
+ ArrayRef<PathDiagnosticConsumer *> consumers,
+ ArrayRef<BugReport *> bugReports);
/// The set of bug reports tracked by the BugReporter.
llvm::FoldingSet<BugReportEquivClass> EQClasses;
+
/// A vector of BugReports for tracking the allocated pointers and cleanup.
std::vector<BugReportEquivClass *> EQClassesVector;
protected:
- BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
- D(d) {}
+ BugReporter(BugReporterData& d, Kind k)
+ : BugTypes(F.getEmptySet()), kind(k), D(d) {}
public:
- BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind),
- D(d) {}
+ BugReporter(BugReporterData& d)
+ : BugTypes(F.getEmptySet()), kind(BaseBRKind), D(d) {}
virtual ~BugReporter();
- /// \brief Generate and flush diagnostics for all bug reports.
+ /// Generate and flush diagnostics for all bug reports.
void FlushReports();
Kind getKind() const { return kind; }
@@ -448,33 +459,31 @@ public:
return D.getPathDiagnosticConsumers();
}
- /// \brief Iterator over the set of BugTypes tracked by the BugReporter.
- typedef BugTypesTy::iterator iterator;
+ /// Iterator over the set of BugTypes tracked by the BugReporter.
+ using iterator = BugTypesTy::iterator;
iterator begin() { return BugTypes.begin(); }
iterator end() { return BugTypes.end(); }
- /// \brief Iterator over the set of BugReports tracked by the BugReporter.
- typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator;
+ /// Iterator over the set of BugReports tracked by the BugReporter.
+ using EQClasses_iterator = llvm::FoldingSet<BugReportEquivClass>::iterator;
EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
EQClasses_iterator EQClasses_end() { return EQClasses.end(); }
ASTContext &getContext() { return D.getASTContext(); }
- SourceManager& getSourceManager() { return D.getSourceManager(); }
+ SourceManager &getSourceManager() { return D.getSourceManager(); }
- AnalyzerOptions& getAnalyzerOptions() { return D.getAnalyzerOptions(); }
+ AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); }
- virtual bool generatePathDiagnostic(PathDiagnostic& pathDiagnostic,
- PathDiagnosticConsumer &PC,
- ArrayRef<BugReport *> &bugReports) {
- return true;
+ virtual std::unique_ptr<DiagnosticForConsumerMapTy>
+ generatePathDiagnostics(ArrayRef<PathDiagnosticConsumer *> consumers,
+ ArrayRef<BugReport *> &bugReports) {
+ return {};
}
- bool RemoveUnneededCalls(PathPieces &pieces, BugReport *R);
-
void Register(BugType *BT);
- /// \brief Add the given report to the set of reports tracked by BugReporter.
+ /// Add the given report to the set of reports tracked by BugReporter.
///
/// The reports are usually generated by the checkers. Further, they are
/// folded based on the profile value, which is done to coalesce similar
@@ -494,25 +503,22 @@ public:
private:
llvm::StringMap<BugType *> StrBugTypes;
- /// \brief Returns a BugType that is associated with the given name and
+ /// Returns a BugType that is associated with the given name and
/// category.
BugType *getBugTypeForName(CheckName CheckName, StringRef name,
StringRef category);
};
-// FIXME: Get rid of GRBugReporter. It's the wrong abstraction.
+/// GRBugReporter is used for generating path-sensitive reports.
class GRBugReporter : public BugReporter {
ExprEngine& Eng;
+
public:
GRBugReporter(BugReporterData& d, ExprEngine& eng)
- : BugReporter(d, GRBugReporterKind), Eng(eng) {}
+ : BugReporter(d, GRBugReporterKind), Eng(eng) {}
~GRBugReporter() override;
- /// getEngine - Return the analysis engine used to analyze a given
- /// function or method.
- ExprEngine &getEngine() { return Eng; }
-
/// getGraph - Get the exploded graph created by the analysis engine
/// for the analyzed method or function.
ExplodedGraph &getGraph();
@@ -521,16 +527,14 @@ public:
/// engine.
ProgramStateManager &getStateManager();
- /// Generates a path corresponding to one of the given bug reports.
- ///
- /// Which report is used for path generation is not specified. The
- /// bug reporter will try to pick the shortest path, but this is not
- /// guaranteed.
+ /// \p bugReports A set of bug reports within a *single* equivalence class
///
- /// \return True if the report was valid and a path was generated,
- /// false if the reports should be considered invalid.
- bool generatePathDiagnostic(PathDiagnostic &PD, PathDiagnosticConsumer &PC,
- ArrayRef<BugReport*> &bugReports) override;
+ /// \return A mapping from consumers to the corresponding diagnostics.
+ /// Iterates through the bug reports within a single equivalence class,
+ /// stops at a first non-invalidated report.
+ std::unique_ptr<DiagnosticForConsumerMapTy>
+ generatePathDiagnostics(ArrayRef<PathDiagnosticConsumer *> consumers,
+ ArrayRef<BugReport *> &bugReports) override;
/// classof - Used by isa<>, cast<>, and dyn_cast<>.
static bool classof(const BugReporter* R) {
@@ -538,13 +542,29 @@ public:
}
};
+
+class NodeMapClosure : public BugReport::NodeResolver {
+ InterExplodedGraphMap &M;
+
+public:
+ NodeMapClosure(InterExplodedGraphMap &m) : M(m) {}
+
+ const ExplodedNode *getOriginalNode(const ExplodedNode *N) override {
+ return M.lookup(N);
+ }
+};
+
class BugReporterContext {
- virtual void anchor();
GRBugReporter &BR;
+ NodeMapClosure NMC;
+
+ virtual void anchor();
+
public:
- BugReporterContext(GRBugReporter& br) : BR(br) {}
+ BugReporterContext(GRBugReporter &br, InterExplodedGraphMap &Backmap)
+ : BR(br), NMC(Backmap) {}
- virtual ~BugReporterContext() {}
+ virtual ~BugReporterContext() = default;
GRBugReporter& getBugReporter() { return BR; }
@@ -554,7 +574,7 @@ public:
return BR.getStateManager();
}
- SValBuilder& getSValBuilder() {
+ SValBuilder &getSValBuilder() {
return getStateManager().getSValBuilder();
}
@@ -566,11 +586,15 @@ public:
return BR.getSourceManager();
}
- virtual BugReport::NodeResolver& getNodeResolver() = 0;
+ AnalyzerOptions &getAnalyzerOptions() {
+ return BR.getAnalyzerOptions();
+ }
+
+ NodeMapClosure& getNodeResolver() { return NMC; }
};
-} // end GR namespace
+} // namespace ento
-} // end clang namespace
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index 2043896fd26fe..92118b0fbee25 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -1,4 +1,4 @@
-//===--- BugReporterVisitors.h - Generate PathDiagnostics -------*- C++ -*-===//
+//===- BugReporterVisitors.h - Generate PathDiagnostics ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,11 +15,21 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
+#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include <memory>
namespace clang {
+
+class BinaryOperator;
class CFGBlock;
+class DeclRefExpr;
+class Expr;
+class Stmt;
namespace ento {
@@ -29,13 +39,7 @@ class ExplodedNode;
class MemRegion;
class PathDiagnosticPiece;
-/// \brief BugReporterVisitors are used to add custom diagnostics along a path.
-///
-/// Custom visitors should subclass the BugReporterVisitorImpl class for a
-/// default implementation of the clone() method.
-/// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
-/// default implementation of clone() will NOT do the right thing, and you
-/// will have to provide your own implementation.)
+/// BugReporterVisitors are used to add custom diagnostics along a path.
class BugReporterVisitor : public llvm::FoldingSetNode {
public:
BugReporterVisitor() = default;
@@ -43,19 +47,13 @@ public:
BugReporterVisitor(BugReporterVisitor &&) {}
virtual ~BugReporterVisitor();
- /// \brief Returns a copy of this BugReporter.
- ///
- /// Custom BugReporterVisitors should not override this method directly.
- /// Instead, they should inherit from BugReporterVisitorImpl and provide
- /// a protected or public copy constructor.
- ///
- /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
- /// default implementation of clone() will NOT do the right thing, and you
- /// will have to provide your own implementation.)
- virtual std::unique_ptr<BugReporterVisitor> clone() const = 0;
-
- /// \brief Return a diagnostic piece which should be associated with the
+ /// Return a diagnostic piece which should be associated with the
/// given node.
+ /// Note that this function does *not* get run on the very last node
+ /// of the report, as the PathDiagnosticPiece associated with the
+ /// last node should be unique.
+ /// Use {@code getEndPath} to customize the note associated with the report
+ /// end instead.
///
/// The last parameter can be used to register a new visitor with the given
/// BugReport while processing a node.
@@ -63,43 +61,32 @@ public:
VisitNode(const ExplodedNode *Succ, const ExplodedNode *Pred,
BugReporterContext &BRC, BugReport &BR) = 0;
- /// \brief Provide custom definition for the final diagnostic piece on the
+ /// Last function called on the visitor, no further calls to VisitNode
+ /// would follow.
+ virtual void finalizeVisitor(BugReporterContext &BRC,
+ const ExplodedNode *EndPathNode,
+ BugReport &BR);
+
+ /// Provide custom definition for the final diagnostic piece on the
/// path - the piece, which is displayed before the path is expanded.
///
- /// If returns NULL the default implementation will be used.
- /// Also note that at most one visitor of a BugReport should generate a
- /// non-NULL end of path diagnostic piece.
- virtual std::unique_ptr<PathDiagnosticPiece>
+ /// NOTE that this function can be implemented on at most one used visitor,
+ /// and otherwise it crahes at runtime.
+ virtual std::shared_ptr<PathDiagnosticPiece>
getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR);
virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
- /// \brief Generates the default final diagnostic piece.
- static std::unique_ptr<PathDiagnosticPiece>
+ /// Generates the default final diagnostic piece.
+ static std::shared_ptr<PathDiagnosticPiece>
getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N,
BugReport &BR);
};
-/// This class provides a convenience implementation for clone() using the
-/// Curiously-Recurring Template Pattern. If you are implementing a custom
-/// BugReporterVisitor, subclass BugReporterVisitorImpl and provide a public
-/// or protected copy constructor.
-///
-/// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the
-/// default implementation of clone() will NOT do the right thing, and you
-/// will have to provide your own implementation.)
-template <class DERIVED>
-class BugReporterVisitorImpl : public BugReporterVisitor {
- std::unique_ptr<BugReporterVisitor> clone() const override {
- return llvm::make_unique<DERIVED>(*static_cast<const DERIVED *>(this));
- }
-};
-
-class FindLastStoreBRVisitor final
- : public BugReporterVisitorImpl<FindLastStoreBRVisitor> {
+class FindLastStoreBRVisitor final : public BugReporterVisitor {
const MemRegion *R;
SVal V;
- bool Satisfied;
+ bool Satisfied = false;
/// If the visitor is tracking the value directly responsible for the
/// bug, we are going to employ false positive suppression.
@@ -113,10 +100,7 @@ public:
FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R,
bool InEnableNullFPSuppression)
- : R(R),
- V(V),
- Satisfied(false),
- EnableNullFPSuppression(InEnableNullFPSuppression) {}
+ : R(R), V(V), EnableNullFPSuppression(InEnableNullFPSuppression) {}
void Profile(llvm::FoldingSetNodeID &ID) const override;
@@ -126,22 +110,20 @@ public:
BugReport &BR) override;
};
-class TrackConstraintBRVisitor final
- : public BugReporterVisitorImpl<TrackConstraintBRVisitor> {
+class TrackConstraintBRVisitor final : public BugReporterVisitor {
DefinedSVal Constraint;
bool Assumption;
- bool IsSatisfied;
+ bool IsSatisfied = false;
bool IsZeroCheck;
/// We should start tracking from the last node along the path in which the
/// value is constrained.
- bool IsTrackingTurnedOn;
+ bool IsTrackingTurnedOn = false;
public:
TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
- : Constraint(constraint), Assumption(assumption), IsSatisfied(false),
- IsZeroCheck(!Assumption && Constraint.getAs<Loc>()),
- IsTrackingTurnedOn(false) {}
+ : Constraint(constraint), Assumption(assumption),
+ IsZeroCheck(!Assumption && Constraint.getAs<Loc>()) {}
void Profile(llvm::FoldingSetNodeID &ID) const override;
@@ -157,15 +139,12 @@ public:
private:
/// Checks if the constraint is valid in the current state.
bool isUnderconstrained(const ExplodedNode *N) const;
-
};
/// \class NilReceiverBRVisitor
-/// \brief Prints path notes when a message is sent to a nil receiver.
-class NilReceiverBRVisitor final
- : public BugReporterVisitorImpl<NilReceiverBRVisitor> {
+/// Prints path notes when a message is sent to a nil receiver.
+class NilReceiverBRVisitor final : public BugReporterVisitor {
public:
-
void Profile(llvm::FoldingSetNodeID &ID) const override {
static int x = 0;
ID.AddPointer(&x);
@@ -182,9 +161,7 @@ public:
};
/// Visitor that tries to report interesting diagnostics from conditions.
-class ConditionBRVisitor final
- : public BugReporterVisitorImpl<ConditionBRVisitor> {
-
+class ConditionBRVisitor final : public BugReporterVisitor {
// FIXME: constexpr initialization isn't supported by MSVC2013.
static const char *const GenericTrueMessage;
static const char *const GenericFalseMessage;
@@ -243,11 +220,11 @@ public:
static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece);
};
-/// \brief Suppress reports that might lead to known false positives.
+/// Suppress reports that might lead to known false positives.
///
/// Currently this suppresses reports based on locations of bugs.
class LikelyFalsePositiveSuppressionBRVisitor final
- : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> {
+ : public BugReporterVisitor {
public:
static void *getTag() {
static int Tag = 0;
@@ -265,19 +242,16 @@ public:
return nullptr;
}
- std::unique_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
- const ExplodedNode *N,
- BugReport &BR) override;
+ void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N,
+ BugReport &BR) override;
};
-/// \brief When a region containing undefined value or '0' value is passed
+/// When a region containing undefined value or '0' value is passed
/// as an argument in a call, marks the call as interesting.
///
/// As a result, BugReporter will not prune the path through the function even
/// if the region's contents are not modified/accessed by the call.
-class UndefOrNullArgVisitor final
- : public BugReporterVisitorImpl<UndefOrNullArgVisitor> {
-
+class UndefOrNullArgVisitor final : public BugReporterVisitor {
/// The interesting memory region this visitor is tracking.
const MemRegion *R;
@@ -296,21 +270,20 @@ public:
BugReport &BR) override;
};
-class SuppressInlineDefensiveChecksVisitor final
- : public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor> {
+class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor {
/// The symbolic value for which we are tracking constraints.
/// This value is constrained to null in the end of path.
DefinedSVal V;
/// Track if we found the node where the constraint was first added.
- bool IsSatisfied;
+ bool IsSatisfied = false;
/// Since the visitors can be registered on nodes previous to the last
/// node in the BugReport, but the path traversal always starts with the last
/// node, the visitor invariant (that we start with a node in which V is null)
/// might not hold when node visitation starts. We are going to start tracking
/// from the last node in which the value is null.
- bool IsTrackingTurnedOn;
+ bool IsTrackingTurnedOn = false;
public:
SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N);
@@ -327,13 +300,11 @@ public:
BugReport &BR) override;
};
-class CXXSelfAssignmentBRVisitor final
- : public BugReporterVisitorImpl<CXXSelfAssignmentBRVisitor> {
-
- bool Satisfied;
+class CXXSelfAssignmentBRVisitor final : public BugReporterVisitor {
+ bool Satisfied = false;
public:
- CXXSelfAssignmentBRVisitor() : Satisfied(false) {}
+ CXXSelfAssignmentBRVisitor() = default;
void Profile(llvm::FoldingSetNodeID &ID) const override {}
@@ -343,6 +314,44 @@ public:
BugReport &BR) override;
};
+/// The bug visitor prints a diagnostic message at the location where a given
+/// variable was tainted.
+class TaintBugVisitor final : public BugReporterVisitor {
+private:
+ const SVal V;
+
+public:
+ TaintBugVisitor(const SVal V) : V(V) {}
+ void Profile(llvm::FoldingSetNodeID &ID) const override { ID.Add(V); }
+
+ std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) override;
+};
+
+/// The bug visitor will walk all the nodes in a path and collect all the
+/// constraints. When it reaches the root node, will create a refutation
+/// manager and check if the constraints are satisfiable
+class FalsePositiveRefutationBRVisitor final : public BugReporterVisitor {
+private:
+ /// Holds the constraints in a given path
+ ConstraintRangeTy Constraints;
+
+public:
+ FalsePositiveRefutationBRVisitor();
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override;
+
+ std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) override;
+
+ void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
+ BugReport &BR) override;
+};
+
namespace bugreporter {
/// Attempts to add visitors to trace a null or undefined value back to its
@@ -370,10 +379,10 @@ const Stmt *GetDenomExpr(const ExplodedNode *N);
const Stmt *GetRetValExpr(const ExplodedNode *N);
bool isDeclRefExprToReference(const Expr *E);
+} // namespace bugreporter
-} // end namespace clang
-} // end namespace ento
-} // end namespace bugreporter
+} // namespace ento
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
index 18fa85c9657f6..c723f31aec266 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
@@ -1,4 +1,4 @@
-//===--- BugType.h - Bug Information Desciption ----------------*- C++ -*-===//
+//===--- BugType.h - Bug Information Description ---------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -32,27 +32,39 @@ private:
const CheckName Check;
const std::string Name;
const std::string Category;
- bool SuppressonSink;
+ const CheckerBase *Checker;
+ bool SuppressOnSink;
virtual void anchor();
+
public:
- BugType(class CheckName check, StringRef name, StringRef cat)
- : Check(check), Name(name), Category(cat), SuppressonSink(false) {}
- BugType(const CheckerBase *checker, StringRef name, StringRef cat)
- : Check(checker->getCheckName()), Name(name), Category(cat),
- SuppressonSink(false) {}
- virtual ~BugType() {}
-
- // FIXME: Should these be made strings as well?
+ BugType(CheckName Check, StringRef Name, StringRef Cat)
+ : Check(Check), Name(Name), Category(Cat), Checker(nullptr),
+ SuppressOnSink(false) {}
+ BugType(const CheckerBase *Checker, StringRef Name, StringRef Cat)
+ : Check(Checker->getCheckName()), Name(Name), Category(Cat),
+ Checker(Checker), SuppressOnSink(false) {}
+ virtual ~BugType() = default;
+
StringRef getName() const { return Name; }
StringRef getCategory() const { return Category; }
- StringRef getCheckName() const { return Check.getName(); }
+ StringRef getCheckName() const {
+ // FIXME: This is a workaround to ensure that the correct check name is used
+ // The check names are set after the constructors are run.
+ // In case the BugType object is initialized in the checker's ctor
+ // the Check field will be empty. To circumvent this problem we use
+ // CheckerBase whenever it is possible.
+ StringRef CheckName =
+ Checker ? Checker->getCheckName().getName() : Check.getName();
+ assert(!CheckName.empty() && "Check name is not set properly.");
+ return CheckName;
+ }
/// isSuppressOnSink - Returns true if bug reports associated with this bug
/// type should be suppressed if the end node of the report is post-dominated
/// by a sink node.
- bool isSuppressOnSink() const { return SuppressonSink; }
- void setSuppressOnSink(bool x) { SuppressonSink = x; }
+ bool isSuppressOnSink() const { return SuppressOnSink; }
+ void setSuppressOnSink(bool x) { SuppressOnSink = x; }
virtual void FlushReports(BugReporter& BR);
};
@@ -74,7 +86,7 @@ public:
StringRef getDescription() const { return desc; }
};
-} // end GR namespace
+} // end ento namespace
} // end clang namespace
#endif
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index f31ab2cd81cd2..b18d3c9b3031c 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -1,4 +1,4 @@
-//===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- C++ -*-===//
+//===- PathDiagnostic.h - Path-Specific Diagnostic Handling -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -14,37 +14,49 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
-#include "clang/Analysis/ProgramPoint.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+#include <cassert>
#include <deque>
#include <iterator>
#include <list>
+#include <map>
+#include <memory>
+#include <set>
#include <string>
+#include <utility>
#include <vector>
namespace clang {
-class ConditionalOperator;
+
class AnalysisDeclContext;
class BinaryOperator;
-class CompoundStmt;
+class CallEnter;
+class CallExitEnd;
+class CallExpr;
+class ConditionalOperator;
class Decl;
+class Expr;
class LocationContext;
class MemberExpr;
-class ParentMap;
class ProgramPoint;
class SourceManager;
-class Stmt;
-class CallExpr;
namespace ento {
class ExplodedNode;
class SymExpr;
-typedef const SymExpr* SymbolRef;
+
+using SymbolRef = const SymExpr *;
//===----------------------------------------------------------------------===//
// High-level interface for handlers of path-sensitive diagnostics.
@@ -58,15 +70,15 @@ public:
public:
PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {}
- typedef std::vector<std::pair<StringRef, StringRef> > ConsumerFiles;
+ using ConsumerFiles = std::vector<std::pair<StringRef, StringRef>>;
- /// \brief A vector of <consumer,file> pairs.
+ /// A vector of <consumer,file> pairs.
ConsumerFiles files;
- /// \brief A precomputed hash tag used for uniquing PDFileEntry objects.
+ /// A precomputed hash tag used for uniquing PDFileEntry objects.
const llvm::FoldingSetNodeID NodeID;
- /// \brief Used for profiling in the FoldingSet.
+ /// Used for profiling in the FoldingSet.
void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; }
};
@@ -88,8 +100,9 @@ public:
private:
virtual void anchor();
+
public:
- PathDiagnosticConsumer() : flushed(false) {}
+ PathDiagnosticConsumer() = default;
virtual ~PathDiagnosticConsumer();
void FlushDiagnostics(FilesMade *FilesMade);
@@ -101,7 +114,17 @@ public:
void HandlePathDiagnostic(std::unique_ptr<PathDiagnostic> D);
- enum PathGenerationScheme { None, Minimal, Extensive, AlternateExtensive };
+ enum PathGenerationScheme {
+ /// Only runs visitors, no output generated.
+ None,
+
+ /// Used for HTML and text output.
+ Minimal,
+
+ /// Used for plist output, used for "arrows" generation.
+ Extensive,
+ };
+
virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
virtual bool supportsLogicalOpControlFlow() const { return false; }
@@ -110,7 +133,7 @@ public:
virtual bool supportsCrossFileDiagnostics() const { return false; }
protected:
- bool flushed;
+ bool flushed = false;
llvm::FoldingSet<PathDiagnostic> Diags;
};
@@ -120,31 +143,28 @@ protected:
class PathDiagnosticRange : public SourceRange {
public:
- bool isPoint;
+ bool isPoint = false;
PathDiagnosticRange(SourceRange R, bool isP = false)
- : SourceRange(R), isPoint(isP) {}
-
- PathDiagnosticRange() : isPoint(false) {}
+ : SourceRange(R), isPoint(isP) {}
+ PathDiagnosticRange() = default;
};
-typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*>
- LocationOrAnalysisDeclContext;
+using LocationOrAnalysisDeclContext =
+ llvm::PointerUnion<const LocationContext *, AnalysisDeclContext *>;
class PathDiagnosticLocation {
private:
- enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
- const Stmt *S;
- const Decl *D;
- const SourceManager *SM;
+ enum Kind { RangeK, SingleLocK, StmtK, DeclK } K = SingleLocK;
+
+ const Stmt *S = nullptr;
+ const Decl *D = nullptr;
+ const SourceManager *SM = nullptr;
FullSourceLoc Loc;
PathDiagnosticRange Range;
- PathDiagnosticLocation(SourceLocation L, const SourceManager &sm,
- Kind kind)
- : K(kind), S(nullptr), D(nullptr), SM(&sm),
- Loc(genLocation(L)), Range(genRange()) {
- }
+ PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, Kind kind)
+ : K(kind), SM(&sm), Loc(genLocation(L)), Range(genRange()) {}
FullSourceLoc genLocation(
SourceLocation L = SourceLocation(),
@@ -155,18 +175,15 @@ private:
public:
/// Create an invalid location.
- PathDiagnosticLocation()
- : K(SingleLocK), S(nullptr), D(nullptr), SM(nullptr) {}
+ PathDiagnosticLocation() = default;
/// Create a location corresponding to the given statement.
PathDiagnosticLocation(const Stmt *s,
const SourceManager &sm,
LocationOrAnalysisDeclContext lac)
- : K(s->getLocStart().isValid() ? StmtK : SingleLocK),
- S(K == StmtK ? s : nullptr),
- D(nullptr), SM(&sm),
- Loc(genLocation(SourceLocation(), lac)),
- Range(genRange(lac)) {
+ : K(s->getLocStart().isValid() ? StmtK : SingleLocK),
+ S(K == StmtK ? s : nullptr), SM(&sm),
+ Loc(genLocation(SourceLocation(), lac)), Range(genRange(lac)) {
assert(K == SingleLocK || S);
assert(K == SingleLocK || Loc.isValid());
assert(K == SingleLocK || Range.isValid());
@@ -174,8 +191,7 @@ public:
/// Create a location corresponding to the given declaration.
PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
- : K(DeclK), S(nullptr), D(d), SM(&sm),
- Loc(genLocation()), Range(genRange()) {
+ : K(DeclK), D(d), SM(&sm), Loc(genLocation()), Range(genRange()) {
assert(D);
assert(Loc.isValid());
assert(Range.isValid());
@@ -185,8 +201,7 @@ public:
///
/// This should only be used if there are no more appropriate constructors.
PathDiagnosticLocation(SourceLocation loc, const SourceManager &sm)
- : K(SingleLocK), S(nullptr), D(nullptr), SM(&sm), Loc(loc, sm),
- Range(genRange()) {
+ : SM(&sm), Loc(loc, sm), Range(genRange()) {
assert(Loc.isValid());
assert(Range.isValid());
}
@@ -201,6 +216,15 @@ public:
static PathDiagnosticLocation createBegin(const Decl *D,
const SourceManager &SM);
+ /// Create a location for the beginning of the declaration.
+ /// The third argument is ignored, useful for generic treatment
+ /// of statements and declarations.
+ static PathDiagnosticLocation
+ createBegin(const Decl *D, const SourceManager &SM,
+ const LocationOrAnalysisDeclContext LAC) {
+ return createBegin(D, SM);
+ }
+
/// Create a location for the beginning of the statement.
static PathDiagnosticLocation createBegin(const Stmt *S,
const SourceManager &SM,
@@ -248,7 +272,7 @@ public:
const SourceManager &SM);
/// Create a location corresponding to the given valid ExplodedNode.
- static PathDiagnosticLocation create(const ProgramPoint& P,
+ static PathDiagnosticLocation create(const ProgramPoint &P,
const SourceManager &SMng);
/// Create a location corresponding to the next valid ExplodedNode as end
@@ -281,6 +305,12 @@ public:
}
const Stmt *asStmt() const { assert(isValid()); return S; }
+ const Stmt *getStmtOrNull() const {
+ if (!isValid())
+ return nullptr;
+ return asStmt();
+ }
+
const Decl *asDecl() const { assert(isValid()); return D; }
bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
@@ -297,21 +327,22 @@ public:
void dump() const;
- /// \brief Given an exploded node, retrieve the statement that should be used
+ /// Given an exploded node, retrieve the statement that should be used
/// for the diagnostic location.
static const Stmt *getStmt(const ExplodedNode *N);
- /// \brief Retrieve the statement corresponding to the successor node.
+ /// Retrieve the statement corresponding to the successor node.
static const Stmt *getNextStmt(const ExplodedNode *N);
};
class PathDiagnosticLocationPair {
private:
PathDiagnosticLocation Start, End;
+
public:
PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
const PathDiagnosticLocation &end)
- : Start(start), End(end) {}
+ : Start(start), End(end) {}
const PathDiagnosticLocation &getStart() const { return Start; }
const PathDiagnosticLocation &getEnd() const { return End; }
@@ -344,9 +375,9 @@ private:
const Kind kind;
const DisplayHint Hint;
- /// \brief In the containing bug report, this piece is the last piece from
+ /// In the containing bug report, this piece is the last piece from
/// the main source file.
- bool LastInMainSourceFile;
+ bool LastInMainSourceFile = false;
/// A constant string that can be used to tag the PathDiagnosticPiece,
/// typically with the identification of the creator. The actual pointer
@@ -356,16 +387,14 @@ private:
std::vector<SourceRange> ranges;
- PathDiagnosticPiece() = delete;
- PathDiagnosticPiece(const PathDiagnosticPiece &P) = delete;
- void operator=(const PathDiagnosticPiece &P) = delete;
-
protected:
PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
-
PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
public:
+ PathDiagnosticPiece() = delete;
+ PathDiagnosticPiece(const PathDiagnosticPiece &) = delete;
+ PathDiagnosticPiece &operator=(const PathDiagnosticPiece &) = delete;
virtual ~PathDiagnosticPiece();
StringRef getString() const { return str; }
@@ -420,8 +449,8 @@ public:
class PathPieces : public std::list<std::shared_ptr<PathDiagnosticPiece>> {
void flattenTo(PathPieces &Primary, PathPieces &Current,
bool ShouldFlattenMacros) const;
-public:
+public:
PathPieces flatten(bool ShouldFlattenMacros) const {
PathPieces Result;
flattenTo(Result, Result, ShouldFlattenMacros);
@@ -434,12 +463,13 @@ public:
class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
private:
PathDiagnosticLocation Pos;
+
public:
PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
StringRef s,
PathDiagnosticPiece::Kind k,
bool addPosRange = true)
- : PathDiagnosticPiece(s, k), Pos(pos) {
+ : PathDiagnosticPiece(s, k), Pos(pos) {
assert(Pos.isValid() && Pos.asLocation().isValid() &&
"PathDiagnosticSpotPiece's must have a valid location.");
if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
@@ -456,7 +486,7 @@ public:
}
};
-/// \brief Interface for classes constructing Stack hints.
+/// Interface for classes constructing Stack hints.
///
/// If a PathDiagnosticEvent occurs in a different frame than the final
/// diagnostic the hints can be used to summarize the effect of the call.
@@ -464,11 +494,11 @@ class StackHintGenerator {
public:
virtual ~StackHintGenerator() = 0;
- /// \brief Construct the Diagnostic message for the given ExplodedNode.
+ /// Construct the Diagnostic message for the given ExplodedNode.
virtual std::string getMessage(const ExplodedNode *N) = 0;
};
-/// \brief Constructs a Stack hint for the given symbol.
+/// Constructs a Stack hint for the given symbol.
///
/// The class knows how to construct the stack hint message based on
/// traversing the CallExpr associated with the call and checking if the given
@@ -481,18 +511,20 @@ private:
public:
StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
- ~StackHintGeneratorForSymbol() override {}
+ ~StackHintGeneratorForSymbol() override = default;
- /// \brief Search the call expression for the symbol Sym and dispatch the
+ /// Search the call expression for the symbol Sym and dispatch the
/// 'getMessageForX()' methods to construct a specific message.
std::string getMessage(const ExplodedNode *N) override;
/// Produces the message of the following form:
/// 'Msg via Nth parameter'
virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
+
virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
return Msg;
}
+
virtual std::string getMessageForSymbolNotFound() {
return Msg;
}
@@ -511,9 +543,8 @@ public:
PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
StringRef s, bool addPosRange = true,
StackHintGenerator *stackHint = nullptr)
- : PathDiagnosticSpotPiece(pos, s, Event, addPosRange),
- CallStackHint(stackHint) {}
-
+ : PathDiagnosticSpotPiece(pos, s, Event, addPosRange),
+ CallStackHint(stackHint) {}
~PathDiagnosticEventPiece() override;
/// Mark the diagnostic piece as being potentially prunable. This
@@ -537,30 +568,19 @@ public:
std::string getCallStackMessage(const ExplodedNode *N) {
if (CallStackHint)
return CallStackHint->getMessage(N);
- return "";
+ return {};
}
void dump() const override;
- static inline bool classof(const PathDiagnosticPiece *P) {
+ static bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == Event;
}
};
class PathDiagnosticCallPiece : public PathDiagnosticPiece {
- PathDiagnosticCallPiece(const Decl *callerD,
- const PathDiagnosticLocation &callReturnPos)
- : PathDiagnosticPiece(Call), Caller(callerD), Callee(nullptr),
- NoExit(false), IsCalleeAnAutosynthesizedPropertyAccessor(false),
- callReturn(callReturnPos) {}
-
- PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
- : PathDiagnosticPiece(Call), Caller(caller), Callee(nullptr),
- NoExit(true), IsCalleeAnAutosynthesizedPropertyAccessor(false),
- path(oldPath) {}
-
const Decl *Caller;
- const Decl *Callee;
+ const Decl *Callee = nullptr;
// Flag signifying that this diagnostic has only call enter and no matching
// call exit.
@@ -568,12 +588,20 @@ class PathDiagnosticCallPiece : public PathDiagnosticPiece {
// Flag signifying that the callee function is an Objective-C autosynthesized
// property getter or setter.
- bool IsCalleeAnAutosynthesizedPropertyAccessor;
+ bool IsCalleeAnAutosynthesizedPropertyAccessor = false;
// The custom string, which should appear after the call Return Diagnostic.
// TODO: Should we allow multiple diagnostics?
std::string CallStackMessage;
+ PathDiagnosticCallPiece(const Decl *callerD,
+ const PathDiagnosticLocation &callReturnPos)
+ : PathDiagnosticPiece(Call), Caller(callerD), NoExit(false),
+ callReturn(callReturnPos) {}
+ PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
+ : PathDiagnosticPiece(Call), Caller(caller), NoExit(true),
+ path(oldPath) {}
+
public:
PathDiagnosticLocation callEnter;
PathDiagnosticLocation callEnterWithin;
@@ -588,13 +616,9 @@ public:
void setCallee(const CallEnter &CE, const SourceManager &SM);
bool hasCallStackMessage() { return !CallStackMessage.empty(); }
- void setCallStackMessage(StringRef st) {
- CallStackMessage = st;
- }
+ void setCallStackMessage(StringRef st) { CallStackMessage = st; }
- PathDiagnosticLocation getLocation() const override {
- return callEnter;
- }
+ PathDiagnosticLocation getLocation() const override { return callEnter; }
std::shared_ptr<PathDiagnosticEventPiece> getCallEnterEvent() const;
std::shared_ptr<PathDiagnosticEventPiece>
@@ -604,8 +628,8 @@ public:
void flattenLocations() override {
callEnter.flatten();
callReturn.flatten();
- for (PathPieces::iterator I = path.begin(),
- E = path.end(); I != E; ++I) (*I)->flattenLocations();
+ for (const auto &I : path)
+ I->flattenLocations();
}
static std::shared_ptr<PathDiagnosticCallPiece>
@@ -619,28 +643,29 @@ public:
void Profile(llvm::FoldingSetNodeID &ID) const override;
- static inline bool classof(const PathDiagnosticPiece *P) {
+ static bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == Call;
}
};
class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
std::vector<PathDiagnosticLocationPair> LPairs;
+
public:
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
const PathDiagnosticLocation &endPos,
StringRef s)
- : PathDiagnosticPiece(s, ControlFlow) {
- LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
- }
+ : PathDiagnosticPiece(s, ControlFlow) {
+ LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
+ }
PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
const PathDiagnosticLocation &endPos)
- : PathDiagnosticPiece(ControlFlow) {
- LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
- }
+ : PathDiagnosticPiece(ControlFlow) {
+ LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
+ }
- ~PathDiagnosticControlFlowPiece() override;
+ ~PathDiagnosticControlFlowPiece() override;
PathDiagnosticLocation getStartLocation() const {
assert(!LPairs.empty() &&
@@ -668,20 +693,23 @@ public:
return getStartLocation();
}
- typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
+ using iterator = std::vector<PathDiagnosticLocationPair>::iterator;
+
iterator begin() { return LPairs.begin(); }
- iterator end() { return LPairs.end(); }
+ iterator end() { return LPairs.end(); }
void flattenLocations() override {
- for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
+ for (auto &I : *this)
+ I.flatten();
}
- typedef std::vector<PathDiagnosticLocationPair>::const_iterator
- const_iterator;
+ using const_iterator =
+ std::vector<PathDiagnosticLocationPair>::const_iterator;
+
const_iterator begin() const { return LPairs.begin(); }
- const_iterator end() const { return LPairs.end(); }
+ const_iterator end() const { return LPairs.end(); }
- static inline bool classof(const PathDiagnosticPiece *P) {
+ static bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == ControlFlow;
}
@@ -693,8 +721,7 @@ public:
class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
public:
PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
- : PathDiagnosticSpotPiece(pos, "", Macro) {}
-
+ : PathDiagnosticSpotPiece(pos, "", Macro) {}
~PathDiagnosticMacroPiece() override;
PathPieces subPieces;
@@ -703,11 +730,11 @@ public:
void flattenLocations() override {
PathDiagnosticSpotPiece::flattenLocations();
- for (PathPieces::iterator I = subPieces.begin(),
- E = subPieces.end(); I != E; ++I) (*I)->flattenLocations();
+ for (const auto &I : subPieces)
+ I->flattenLocations();
}
- static inline bool classof(const PathDiagnosticPiece *P) {
+ static bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == Macro;
}
@@ -721,10 +748,9 @@ public:
PathDiagnosticNotePiece(const PathDiagnosticLocation &Pos, StringRef S,
bool AddPosRange = true)
: PathDiagnosticSpotPiece(Pos, S, Note, AddPosRange) {}
-
~PathDiagnosticNotePiece() override;
- static inline bool classof(const PathDiagnosticPiece *P) {
+ static bool classof(const PathDiagnosticPiece *P) {
return P->getKind() == Note;
}
@@ -733,6 +759,9 @@ public:
void Profile(llvm::FoldingSetNodeID &ID) const override;
};
+/// File IDs mapped to sets of line numbers.
+using FilesToLineNumsMap = std::map<unsigned, std::set<unsigned>>;
+
/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
/// each which represent the pieces of the path.
@@ -745,24 +774,27 @@ class PathDiagnostic : public llvm::FoldingSetNode {
std::string Category;
std::deque<std::string> OtherDesc;
- /// \brief Loc The location of the path diagnostic report.
+ /// Loc The location of the path diagnostic report.
PathDiagnosticLocation Loc;
PathPieces pathImpl;
SmallVector<PathPieces *, 3> pathStack;
- /// \brief Important bug uniqueing location.
+ /// Important bug uniqueing location.
/// The location info is useful to differentiate between bugs.
PathDiagnosticLocation UniqueingLoc;
const Decl *UniqueingDecl;
- PathDiagnostic() = delete;
+ /// Lines executed in the path.
+ std::unique_ptr<FilesToLineNumsMap> ExecutedLines;
+
public:
+ PathDiagnostic() = delete;
PathDiagnostic(StringRef CheckName, const Decl *DeclWithIssue,
StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
StringRef category, PathDiagnosticLocation LocationToUnique,
- const Decl *DeclToUnique);
-
+ const Decl *DeclToUnique,
+ std::unique_ptr<FilesToLineNumsMap> ExecutedLines);
~PathDiagnostic();
const PathPieces &path;
@@ -788,7 +820,7 @@ public:
bool isWithinCall() const { return !pathStack.empty(); }
- void setEndOfPath(std::unique_ptr<PathDiagnosticPiece> EndPiece) {
+ void setEndOfPath(std::shared_ptr<PathDiagnosticPiece> EndPiece) {
assert(!Loc.isValid() && "End location already set!");
Loc = EndPiece->getLocation();
assert(Loc.isValid() && "Invalid location for end-of-path piece");
@@ -801,21 +833,17 @@ public:
VerboseDesc += S;
}
- void resetPath() {
- pathStack.clear();
- pathImpl.clear();
- Loc = PathDiagnosticLocation();
- }
-
- /// \brief If the last piece of the report point to the header file, resets
+ /// If the last piece of the report point to the header file, resets
/// the location of the report to be the last location in the main source
/// file.
void resetDiagnosticLocationToMainFile();
StringRef getVerboseDescription() const { return VerboseDesc; }
+
StringRef getShortDescription() const {
return ShortDesc.empty() ? VerboseDesc : ShortDesc;
}
+
StringRef getCheckName() const { return CheckName; }
StringRef getBugType() const { return BugType; }
StringRef getCategory() const { return Category; }
@@ -825,30 +853,38 @@ public:
/// where the bug manifests.
const Decl *getDeclWithIssue() const { return DeclWithIssue; }
- typedef std::deque<std::string>::const_iterator meta_iterator;
+ using meta_iterator = std::deque<std::string>::const_iterator;
+
meta_iterator meta_begin() const { return OtherDesc.begin(); }
meta_iterator meta_end() const { return OtherDesc.end(); }
void addMeta(StringRef s) { OtherDesc.push_back(s); }
+ using filesmap_iterator = FilesToLineNumsMap::const_iterator;
+
+ filesmap_iterator executedLines_begin() const {
+ return ExecutedLines->begin();
+ }
+
+ filesmap_iterator executedLines_end() const { return ExecutedLines->end(); }
+
PathDiagnosticLocation getLocation() const {
- assert(Loc.isValid() && "No report location set yet!");
return Loc;
}
- /// \brief Get the location on which the report should be uniqued.
+ /// Get the location on which the report should be uniqued.
PathDiagnosticLocation getUniqueingLoc() const {
return UniqueingLoc;
}
- /// \brief Get the declaration containing the uniqueing location.
+ /// Get the declaration containing the uniqueing location.
const Decl *getUniqueingDecl() const {
return UniqueingDecl;
}
void flattenLocations() {
Loc.flatten();
- for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end();
- I != E; ++I) (*I)->flattenLocations();
+ for (const auto &I : pathImpl)
+ I->flattenLocations();
}
/// Profiles the diagnostic, independent of the path it references.
@@ -864,8 +900,8 @@ public:
void FullProfile(llvm::FoldingSetNodeID &ID) const;
};
-} // end GR namespace
+} // namespace ento
-} //end clang namespace
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index f9477762c7585..45b7a61139ea7 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -254,9 +254,9 @@ public:
class EndFunction {
template <typename CHECKER>
- static void _checkEndFunction(void *checker,
+ static void _checkEndFunction(void *checker, const ReturnStmt *RS,
CheckerContext &C) {
- ((const CHECKER *)checker)->checkEndFunction(C);
+ ((const CHECKER *)checker)->checkEndFunction(RS, C);
}
public:
@@ -283,6 +283,22 @@ public:
}
};
+class NewAllocator {
+ template <typename CHECKER>
+ static void _checkNewAllocator(void *checker, const CXXNewExpr *NE,
+ SVal Target, CheckerContext &C) {
+ ((const CHECKER *)checker)->checkNewAllocator(NE, Target, C);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForNewAllocator(
+ CheckerManager::CheckNewAllocatorFunc(checker,
+ _checkNewAllocator<CHECKER>));
+ }
+};
+
class LiveSymbols {
template <typename CHECKER>
static void _checkLiveSymbols(void *checker, ProgramStateRef state,
@@ -532,7 +548,7 @@ public:
}
};
-/// \brief We dereferenced a location that may be null.
+/// We dereferenced a location that may be null.
struct ImplicitNullDerefEvent {
SVal Location;
bool IsLoad;
@@ -544,7 +560,7 @@ struct ImplicitNullDerefEvent {
bool IsDirectDereference;
};
-/// \brief A helper class which wraps a boolean value set to false by default.
+/// A helper class which wraps a boolean value set to false by default.
///
/// This class should behave exactly like 'bool' except that it doesn't need to
/// be explicitly initialized.
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 88cb08a4b647c..33a794061a384 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -1,4 +1,4 @@
-//===--- CheckerManager.h - Static Analyzer Checker Manager -----*- C++ -*-===//
+//===- CheckerManager.h - Static Analyzer Checker Manager -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -16,51 +16,62 @@
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
-#include <utility>
+#include "llvm/ADT/StringRef.h"
#include <vector>
namespace clang {
- class Decl;
- class Stmt;
- class CallExpr;
+
+class AnalyzerOptions;
+class CallExpr;
+class CXXNewExpr;
+class Decl;
+class LocationContext;
+class Stmt;
+class TranslationUnitDecl;
namespace ento {
- class CheckerBase;
- class CheckerRegistry;
- class ExprEngine;
- class AnalysisManager;
- class BugReporter;
- class CheckerContext;
- class ObjCMethodCall;
- class SVal;
- class ExplodedNode;
- class ExplodedNodeSet;
- class ExplodedGraph;
- class ProgramState;
- class NodeBuilder;
- struct NodeBuilderContext;
- class MemRegion;
- class SymbolReaper;
+
+class AnalysisManager;
+class BugReporter;
+class CallEvent;
+class CheckerBase;
+class CheckerContext;
+class CheckerRegistry;
+class ExplodedGraph;
+class ExplodedNode;
+class ExplodedNodeSet;
+class ExprEngine;
+class MemRegion;
+struct NodeBuilderContext;
+class ObjCMethodCall;
+class RegionAndSymbolInvalidationTraits;
+class SVal;
+class SymbolReaper;
template <typename T> class CheckerFn;
template <typename RET, typename... Ps>
class CheckerFn<RET(Ps...)> {
- typedef RET (*Func)(void *, Ps...);
+ using Func = RET (*)(void *, Ps...);
+
Func Fn;
+
public:
CheckerBase *Checker;
- CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { }
+
+ CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) {}
+
RET operator()(Ps... ps) const {
return Fn(Checker, ps...);
}
};
-/// \brief Describes the different reasons a pointer escapes
+/// Describes the different reasons a pointer escapes
/// during analysis.
enum PointerEscapeKind {
/// A pointer escapes due to binding its value to a location
@@ -85,12 +96,15 @@ enum PointerEscapeKind {
// name strings have a lifetime that keeps them alive at least until the path
// diagnostics have been processed.
class CheckName {
- StringRef Name;
friend class ::clang::ento::CheckerRegistry;
+
+ StringRef Name;
+
explicit CheckName(StringRef Name) : Name(Name) {}
public:
CheckName() = default;
+
StringRef getName() const { return Name; }
};
@@ -121,40 +135,27 @@ public:
const LangOptions &getLangOpts() const { return LangOpts; }
AnalyzerOptions &getAnalyzerOptions() { return AOptions; }
- typedef CheckerBase *CheckerRef;
- typedef const void *CheckerTag;
- typedef CheckerFn<void ()> CheckerDtor;
+ using CheckerRef = CheckerBase *;
+ using CheckerTag = const void *;
+ using CheckerDtor = CheckerFn<void ()>;
//===----------------------------------------------------------------------===//
// registerChecker
//===----------------------------------------------------------------------===//
- /// \brief Used to register checkers.
+ /// Used to register checkers.
+ /// All arguments are automatically passed through to the checker
+ /// constructor.
///
/// \returns a pointer to the checker object.
- template <typename CHECKER>
- CHECKER *registerChecker() {
+ template <typename CHECKER, typename... AT>
+ CHECKER *registerChecker(AT... Args) {
CheckerTag tag = getTag<CHECKER>();
CheckerRef &ref = CheckerTags[tag];
if (ref)
return static_cast<CHECKER *>(ref); // already registered.
- CHECKER *checker = new CHECKER();
- checker->Name = CurrentCheckName;
- CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>));
- CHECKER::_register(checker, *this);
- ref = checker;
- return checker;
- }
-
- template <typename CHECKER>
- CHECKER *registerChecker(AnalyzerOptions &AOpts) {
- CheckerTag tag = getTag<CHECKER>();
- CheckerRef &ref = CheckerTags[tag];
- if (ref)
- return static_cast<CHECKER *>(ref); // already registered.
-
- CHECKER *checker = new CHECKER(AOpts);
+ CHECKER *checker = new CHECKER(Args...);
checker->Name = CurrentCheckName;
CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>));
CHECKER::_register(checker, *this);
@@ -166,11 +167,11 @@ public:
// Functions for running checkers for AST traversing..
//===----------------------------------------------------------------------===//
- /// \brief Run checkers handling Decls.
+ /// Run checkers handling Decls.
void runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr,
BugReporter &BR);
- /// \brief Run checkers handling Decls containing a Stmt body.
+ /// Run checkers handling Decls containing a Stmt body.
void runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR);
@@ -178,7 +179,7 @@ public:
// Functions for running checkers for path-sensitive checking.
//===----------------------------------------------------------------------===//
- /// \brief Run checkers for pre-visiting Stmts.
+ /// Run checkers for pre-visiting Stmts.
///
/// The notification is performed for every explored CFGElement, which does
/// not include the control flow statements such as IfStmt.
@@ -191,7 +192,7 @@ public:
runCheckersForStmt(/*isPreVisit=*/true, Dst, Src, S, Eng);
}
- /// \brief Run checkers for post-visiting Stmts.
+ /// Run checkers for post-visiting Stmts.
///
/// The notification is performed for every explored CFGElement, which does
/// not include the control flow statements such as IfStmt.
@@ -205,13 +206,13 @@ public:
runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng, wasInlined);
}
- /// \brief Run checkers for visiting Stmts.
+ /// Run checkers for visiting Stmts.
void runCheckersForStmt(bool isPreVisit,
ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
const Stmt *S, ExprEngine &Eng,
bool wasInlined = false);
- /// \brief Run checkers for pre-visiting obj-c messages.
+ /// Run checkers for pre-visiting obj-c messages.
void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const ObjCMethodCall &msg,
@@ -219,7 +220,7 @@ public:
runCheckersForObjCMessage(ObjCMessageVisitKind::Pre, Dst, Src, msg, Eng);
}
- /// \brief Run checkers for post-visiting obj-c messages.
+ /// Run checkers for post-visiting obj-c messages.
void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const ObjCMethodCall &msg,
@@ -229,7 +230,7 @@ public:
wasInlined);
}
- /// \brief Run checkers for visiting an obj-c message to nil.
+ /// Run checkers for visiting an obj-c message to nil.
void runCheckersForObjCMessageNil(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const ObjCMethodCall &msg,
@@ -238,21 +239,20 @@ public:
Eng);
}
-
- /// \brief Run checkers for visiting obj-c messages.
+ /// Run checkers for visiting obj-c messages.
void runCheckersForObjCMessage(ObjCMessageVisitKind visitKind,
ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const ObjCMethodCall &msg, ExprEngine &Eng,
bool wasInlined = false);
- /// \brief Run checkers for pre-visiting obj-c messages.
+ /// Run checkers for pre-visiting obj-c messages.
void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
const CallEvent &Call, ExprEngine &Eng) {
runCheckersForCallEvent(/*isPreVisit=*/true, Dst, Src, Call, Eng);
}
- /// \brief Run checkers for post-visiting obj-c messages.
+ /// Run checkers for post-visiting obj-c messages.
void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
const CallEvent &Call, ExprEngine &Eng,
bool wasInlined = false) {
@@ -260,13 +260,13 @@ public:
wasInlined);
}
- /// \brief Run checkers for visiting obj-c messages.
+ /// Run checkers for visiting obj-c messages.
void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const CallEvent &Call, ExprEngine &Eng,
bool wasInlined = false);
- /// \brief Run checkers for load/store of a location.
+ /// Run checkers for load/store of a location.
void runCheckersForLocation(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location,
@@ -275,35 +275,43 @@ public:
const Stmt *BoundEx,
ExprEngine &Eng);
- /// \brief Run checkers for binding of a value to a location.
+ /// Run checkers for binding of a value to a location.
void runCheckersForBind(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location, SVal val,
const Stmt *S, ExprEngine &Eng,
const ProgramPoint &PP);
- /// \brief Run checkers for end of analysis.
+ /// Run checkers for end of analysis.
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
ExprEngine &Eng);
- /// \brief Run checkers on beginning of function.
+ /// Run checkers on beginning of function.
void runCheckersForBeginFunction(ExplodedNodeSet &Dst,
const BlockEdge &L,
ExplodedNode *Pred,
ExprEngine &Eng);
- /// \brief Run checkers on end of function.
+ /// Run checkers on end of function.
void runCheckersForEndFunction(NodeBuilderContext &BC,
ExplodedNodeSet &Dst,
ExplodedNode *Pred,
- ExprEngine &Eng);
+ ExprEngine &Eng,
+ const ReturnStmt *RS);
- /// \brief Run checkers for branch condition.
+ /// Run checkers for branch condition.
void runCheckersForBranchCondition(const Stmt *condition,
ExplodedNodeSet &Dst, ExplodedNode *Pred,
ExprEngine &Eng);
- /// \brief Run checkers for live symbols.
+ /// Run checkers between C++ operator new and constructor calls.
+ void runCheckersForNewAllocator(const CXXNewExpr *NE, SVal Target,
+ ExplodedNodeSet &Dst,
+ ExplodedNode *Pred,
+ ExprEngine &Eng,
+ bool wasInlined = false);
+
+ /// Run checkers for live symbols.
///
/// Allows modifying SymbolReaper object. For example, checkers can explicitly
/// register symbols of interest as live. These symbols will not be marked
@@ -311,7 +319,7 @@ public:
void runCheckersForLiveSymbols(ProgramStateRef state,
SymbolReaper &SymReaper);
- /// \brief Run checkers for dead symbols.
+ /// Run checkers for dead symbols.
///
/// Notifies checkers when symbols become dead. For example, this allows
/// checkers to aggressively clean up/reduce the checker state and produce
@@ -322,7 +330,7 @@ public:
ExprEngine &Eng,
ProgramPoint::Kind K);
- /// \brief Run checkers for region changes.
+ /// Run checkers for region changes.
///
/// This corresponds to the check::RegionChanges callback.
/// \param state The current program state.
@@ -341,7 +349,7 @@ public:
const LocationContext *LCtx,
const CallEvent *Call);
- /// \brief Run checkers when pointers escape.
+ /// Run checkers when pointers escape.
///
/// This notifies the checkers about pointer escape, which occurs whenever
/// the analyzer cannot track the symbol any more. For example, as a
@@ -361,25 +369,25 @@ public:
const InvalidatedSymbols &Escaped,
const CallEvent *Call,
PointerEscapeKind Kind,
- RegionAndSymbolInvalidationTraits *ITraits);
+ RegionAndSymbolInvalidationTraits *ITraits);
- /// \brief Run checkers for handling assumptions on symbolic values.
+ /// Run checkers for handling assumptions on symbolic values.
ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state,
SVal Cond, bool Assumption);
- /// \brief Run checkers for evaluating a call.
+ /// Run checkers for evaluating a call.
///
/// Warning: Currently, the CallEvent MUST come from a CallExpr!
void runCheckersForEvalCall(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const CallEvent &CE, ExprEngine &Eng);
- /// \brief Run checkers for the entire Translation Unit.
+ /// Run checkers for the entire Translation Unit.
void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU,
AnalysisManager &mgr,
BugReporter &BR);
- /// \brief Run checkers for debug-printing a ProgramState.
+ /// Run checkers for debug-printing a ProgramState.
///
/// Unlike most other callbacks, any checker can simply implement the virtual
/// method CheckerBase::printState if it has custom data to print.
@@ -397,10 +405,11 @@ public:
// Functions used by the registration mechanism, checkers should not touch
// these directly.
- typedef CheckerFn<void (const Decl *, AnalysisManager&, BugReporter &)>
- CheckDeclFunc;
+ using CheckDeclFunc =
+ CheckerFn<void (const Decl *, AnalysisManager&, BugReporter &)>;
+
+ using HandlesDeclFunc = bool (*)(const Decl *D);
- typedef bool (*HandlesDeclFunc)(const Decl *D);
void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn);
void _registerForBody(CheckDeclFunc checkfn);
@@ -409,67 +418,67 @@ public:
// Internal registration functions for path-sensitive checking.
//===----------------------------------------------------------------------===//
- typedef CheckerFn<void (const Stmt *, CheckerContext &)> CheckStmtFunc;
+ using CheckStmtFunc = CheckerFn<void (const Stmt *, CheckerContext &)>;
- typedef CheckerFn<void (const ObjCMethodCall &, CheckerContext &)>
- CheckObjCMessageFunc;
+ using CheckObjCMessageFunc =
+ CheckerFn<void (const ObjCMethodCall &, CheckerContext &)>;
- typedef CheckerFn<void (const CallEvent &, CheckerContext &)>
- CheckCallFunc;
+ using CheckCallFunc =
+ CheckerFn<void (const CallEvent &, CheckerContext &)>;
- typedef CheckerFn<void (const SVal &location, bool isLoad,
- const Stmt *S,
- CheckerContext &)>
- CheckLocationFunc;
+ using CheckLocationFunc =
+ CheckerFn<void (const SVal &location, bool isLoad, const Stmt *S,
+ CheckerContext &)>;
- typedef CheckerFn<void (const SVal &location, const SVal &val,
- const Stmt *S, CheckerContext &)>
- CheckBindFunc;
+ using CheckBindFunc =
+ CheckerFn<void (const SVal &location, const SVal &val, const Stmt *S,
+ CheckerContext &)>;
- typedef CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>
- CheckEndAnalysisFunc;
+ using CheckEndAnalysisFunc =
+ CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>;
- typedef CheckerFn<void (CheckerContext &)>
- CheckBeginFunctionFunc;
+ using CheckBeginFunctionFunc = CheckerFn<void (CheckerContext &)>;
- typedef CheckerFn<void (CheckerContext &)>
- CheckEndFunctionFunc;
+ using CheckEndFunctionFunc =
+ CheckerFn<void (const ReturnStmt *, CheckerContext &)>;
- typedef CheckerFn<void (const Stmt *, CheckerContext &)>
- CheckBranchConditionFunc;
+ using CheckBranchConditionFunc =
+ CheckerFn<void (const Stmt *, CheckerContext &)>;
+
+ using CheckNewAllocatorFunc =
+ CheckerFn<void (const CXXNewExpr *, SVal, CheckerContext &)>;
- typedef CheckerFn<void (SymbolReaper &, CheckerContext &)>
- CheckDeadSymbolsFunc;
+ using CheckDeadSymbolsFunc =
+ CheckerFn<void (SymbolReaper &, CheckerContext &)>;
- typedef CheckerFn<void (ProgramStateRef,SymbolReaper &)> CheckLiveSymbolsFunc;
+ using CheckLiveSymbolsFunc = CheckerFn<void (ProgramStateRef,SymbolReaper &)>;
- typedef CheckerFn<ProgramStateRef (ProgramStateRef,
- const InvalidatedSymbols *symbols,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const LocationContext *LCtx,
- const CallEvent *Call)>
- CheckRegionChangesFunc;
+ using CheckRegionChangesFunc =
+ CheckerFn<ProgramStateRef (ProgramStateRef,
+ const InvalidatedSymbols *symbols,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const LocationContext *LCtx,
+ const CallEvent *Call)>;
- typedef CheckerFn<ProgramStateRef (ProgramStateRef,
- const InvalidatedSymbols &Escaped,
- const CallEvent *Call,
- PointerEscapeKind Kind,
- RegionAndSymbolInvalidationTraits *ITraits)>
- CheckPointerEscapeFunc;
+ using CheckPointerEscapeFunc =
+ CheckerFn<ProgramStateRef (ProgramStateRef,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call, PointerEscapeKind Kind,
+ RegionAndSymbolInvalidationTraits *ITraits)>;
- typedef CheckerFn<ProgramStateRef (ProgramStateRef,
- const SVal &cond, bool assumption)>
- EvalAssumeFunc;
+ using EvalAssumeFunc =
+ CheckerFn<ProgramStateRef (ProgramStateRef, const SVal &cond,
+ bool assumption)>;
- typedef CheckerFn<bool (const CallExpr *, CheckerContext &)>
- EvalCallFunc;
+ using EvalCallFunc = CheckerFn<bool (const CallExpr *, CheckerContext &)>;
- typedef CheckerFn<void (const TranslationUnitDecl *,
- AnalysisManager&, BugReporter &)>
- CheckEndOfTranslationUnit;
+ using CheckEndOfTranslationUnit =
+ CheckerFn<void (const TranslationUnitDecl *, AnalysisManager &,
+ BugReporter &)>;
+
+ using HandlesStmtFunc = bool (*)(const Stmt *D);
- typedef bool (*HandlesStmtFunc)(const Stmt *D);
void _registerForPreStmt(CheckStmtFunc checkfn,
HandlesStmtFunc isForStmtFn);
void _registerForPostStmt(CheckStmtFunc checkfn,
@@ -489,11 +498,13 @@ public:
void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn);
- void _registerForBeginFunction(CheckEndFunctionFunc checkfn);
+ void _registerForBeginFunction(CheckBeginFunctionFunc checkfn);
void _registerForEndFunction(CheckEndFunctionFunc checkfn);
void _registerForBranchCondition(CheckBranchConditionFunc checkfn);
+ void _registerForNewAllocator(CheckNewAllocatorFunc checkfn);
+
void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn);
void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn);
@@ -514,8 +525,8 @@ public:
// Internal registration functions for events.
//===----------------------------------------------------------------------===//
- typedef void *EventTag;
- typedef CheckerFn<void (const void *event)> CheckEventFunc;
+ using EventTag = void *;
+ using CheckEventFunc = CheckerFn<void (const void *event)>;
template <typename EVENT>
void _registerListenerForEvent(CheckEventFunc checkfn) {
@@ -535,8 +546,8 @@ public:
if (I == Events.end())
return;
const EventInfo &info = I->second;
- for (unsigned i = 0, e = info.Checkers.size(); i != e; ++i)
- info.Checkers[i](&event);
+ for (const auto Checker : info.Checkers)
+ Checker(&event);
}
//===----------------------------------------------------------------------===//
@@ -562,8 +573,8 @@ private:
std::vector<CheckDeclFunc> BodyCheckers;
- typedef SmallVector<CheckDeclFunc, 4> CachedDeclCheckers;
- typedef llvm::DenseMap<unsigned, CachedDeclCheckers> CachedDeclCheckersMapTy;
+ using CachedDeclCheckers = SmallVector<CheckDeclFunc, 4>;
+ using CachedDeclCheckersMapTy = llvm::DenseMap<unsigned, CachedDeclCheckers>;
CachedDeclCheckersMapTy CachedDeclCheckersMap;
struct StmtCheckerInfo {
@@ -573,8 +584,8 @@ private:
};
std::vector<StmtCheckerInfo> StmtCheckers;
- typedef SmallVector<CheckStmtFunc, 4> CachedStmtCheckers;
- typedef llvm::DenseMap<unsigned, CachedStmtCheckers> CachedStmtCheckersMapTy;
+ using CachedStmtCheckers = SmallVector<CheckStmtFunc, 4>;
+ using CachedStmtCheckersMapTy = llvm::DenseMap<unsigned, CachedStmtCheckers>;
CachedStmtCheckersMapTy CachedStmtCheckersMap;
const CachedStmtCheckers &getCachedStmtCheckersFor(const Stmt *S,
@@ -603,6 +614,8 @@ private:
std::vector<CheckBranchConditionFunc> BranchConditionCheckers;
+ std::vector<CheckNewAllocatorFunc> NewAllocatorCheckers;
+
std::vector<CheckLiveSymbolsFunc> LiveSymbolsCheckers;
std::vector<CheckDeadSymbolsFunc> DeadSymbolsCheckers;
@@ -619,16 +632,17 @@ private:
struct EventInfo {
SmallVector<CheckEventFunc, 4> Checkers;
- bool HasDispatcher;
- EventInfo() : HasDispatcher(false) { }
+ bool HasDispatcher = false;
+
+ EventInfo() = default;
};
- typedef llvm::DenseMap<EventTag, EventInfo> EventsTy;
+ using EventsTy = llvm::DenseMap<EventTag, EventInfo>;
EventsTy Events;
};
-} // end ento namespace
+} // namespace ento
-} // end clang namespace
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H
diff --git a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
index 3b26ed3e1a09a..912a601b61c49 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
@@ -1,4 +1,4 @@
-//===--- CheckerRegistry.h - Maintains all available checkers ---*- C++ -*-===//
+//===- CheckerRegistry.h - Maintains all available checkers -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,6 +12,9 @@
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include <cstddef>
#include <vector>
// FIXME: move this information to an HTML file in docs/.
@@ -64,8 +67,9 @@
#endif
namespace clang {
-class DiagnosticsEngine;
+
class AnalyzerOptions;
+class DiagnosticsEngine;
namespace ento {
@@ -81,17 +85,18 @@ class CheckerRegistry {
public:
/// Initialization functions perform any necessary setup for a checker.
/// They should include a call to CheckerManager::registerChecker.
- typedef void (*InitializationFunction)(CheckerManager &);
+ using InitializationFunction = void (*)(CheckerManager &);
+
struct CheckerInfo {
InitializationFunction Initialize;
StringRef FullName;
StringRef Desc;
CheckerInfo(InitializationFunction fn, StringRef name, StringRef desc)
- : Initialize(fn), FullName(name), Desc(desc) {}
+ : Initialize(fn), FullName(name), Desc(desc) {}
};
- typedef std::vector<CheckerInfo> CheckerInfoList;
+ using CheckerInfoList = std::vector<CheckerInfo>;
private:
template <typename T>
@@ -136,7 +141,8 @@ private:
mutable llvm::StringMap<size_t> Packages;
};
-} // end namespace ento
-} // end namespace clang
+} // namespace ento
-#endif
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H
diff --git a/include/clang/StaticAnalyzer/Core/IssueHash.h b/include/clang/StaticAnalyzer/Core/IssueHash.h
index b3c4f1465594e..8cb6631fae747 100644
--- a/include/clang/StaticAnalyzer/Core/IssueHash.h
+++ b/include/clang/StaticAnalyzer/Core/IssueHash.h
@@ -17,7 +17,7 @@ class SourceManager;
class FullSourceLoc;
class LangOptions;
-/// \brief Get an MD5 hash to help identify bugs.
+/// Get an MD5 hash to help identify bugs.
///
/// This function returns a hash that helps identify bugs within a source file.
/// This identification can be utilized to diff diagnostic results on different
@@ -41,7 +41,7 @@ llvm::SmallString<32> GetIssueHash(const SourceManager &SM,
llvm::StringRef BugType, const Decl *D,
const LangOptions &LangOpts);
-/// \brief Get the string representation of issue hash. See GetIssueHash() for
+/// Get the string representation of issue hash. See GetIssueHash() for
/// more information.
std::string GetIssueString(const SourceManager &SM, FullSourceLoc &IssueLoc,
llvm::StringRef CheckerName, llvm::StringRef BugType,
diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
index ce512fd301ee7..2e81aa38c8de3 100644
--- a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
+++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
@@ -1,4 +1,4 @@
-//===--- PathDiagnosticClients.h - Path Diagnostic Clients ------*- C++ -*-===//
+//===--- PathDiagnosticConsumers.h - Path Diagnostic Clients ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
index cc8a9b8ef0719..93edfcef2d5aa 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
@@ -16,7 +16,7 @@
namespace clang {
namespace ento {
-/// \brief A record of the "type" of an APSInt, used for conversions.
+/// A record of the "type" of an APSInt, used for conversions.
class APSIntType {
uint32_t BitWidth;
bool IsUnsigned;
@@ -31,7 +31,7 @@ public:
uint32_t getBitWidth() const { return BitWidth; }
bool isUnsigned() const { return IsUnsigned; }
- /// \brief Convert a given APSInt, in place, to match this type.
+ /// Convert a given APSInt, in place, to match this type.
///
/// This behaves like a C cast: converting 255u8 (0xFF) to s16 gives
/// 255 (0x00FF), and converting -1s8 (0xFF) to u16 gives 65535 (0xFFFF).
@@ -93,7 +93,7 @@ public:
return BitWidth == Other.BitWidth && IsUnsigned == Other.IsUnsigned;
}
- /// \brief Provide an ordering for finding a common conversion type.
+ /// Provide an ordering for finding a common conversion type.
///
/// Unsigned integers are considered to be better conversion types than
/// signed integers of the same width.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index 15b930bc3f1eb..02b335761e708 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -126,6 +126,36 @@ public:
AnalysisDeclContext *getAnalysisDeclContext(const Decl *D) {
return AnaCtxMgr.getContext(D);
}
+
+ static bool isInCodeFile(SourceLocation SL, const SourceManager &SM) {
+ if (SM.isInMainFile(SL))
+ return true;
+
+ // Support the "unified sources" compilation method (eg. WebKit) that
+ // involves producing non-header files that include other non-header files.
+ // We should be included directly from a UnifiedSource* file
+ // and we shouldn't be a header - which is a very safe defensive check.
+ SourceLocation IL = SM.getIncludeLoc(SM.getFileID(SL));
+ if (!IL.isValid() || !SM.isInMainFile(IL))
+ return false;
+ // Should rather be "file name starts with", but the current .getFilename
+ // includes the full path.
+ if (SM.getFilename(IL).contains("UnifiedSource")) {
+ // It might be great to reuse FrontendOptions::getInputKindForExtension()
+ // but for now it doesn't discriminate between code and header files.
+ return llvm::StringSwitch<bool>(SM.getFilename(SL).rsplit('.').second)
+ .Cases("c", "m", "mm", "C", "cc", "cp", true)
+ .Cases("cpp", "CPP", "c++", "cxx", "cppm", true)
+ .Default(false);
+ }
+
+ return false;
+ }
+
+ bool isInCodeFile(SourceLocation SL) {
+ const SourceManager &SM = getASTContext().getSourceManager();
+ return isInCodeFile(SL, SM);
+ }
};
} // enAnaCtxMgrspace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index 4aa87443e4c22..0bbc6500d6ec3 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -1,4 +1,4 @@
-//=== BasicValueFactory.h - Basic values for Path Sens analysis --*- C++ -*---//
+//==- BasicValueFactory.h - Basic values for Path Sens analysis --*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
@@ -17,12 +17,26 @@
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BASICVALUEFACTORY_H
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Allocator.h"
+#include <cassert>
+#include <cstdint>
+#include <utility>
namespace clang {
+
+class CXXBaseSpecifier;
+class DeclaratorDecl;
+
namespace ento {
class CompoundValData : public llvm::FoldingSetNode {
@@ -34,7 +48,8 @@ public:
assert(NonLoc::isCompoundType(t));
}
- typedef llvm::ImmutableList<SVal>::iterator iterator;
+ using iterator = llvm::ImmutableList<SVal>::iterator;
+
iterator begin() const { return L.begin(); }
iterator end() const { return L.end(); }
@@ -47,6 +62,7 @@ public:
class LazyCompoundValData : public llvm::FoldingSetNode {
StoreRef store;
const TypedValueRegion *region;
+
public:
LazyCompoundValData(const StoreRef &st, const TypedValueRegion *r)
: store(st), region(r) {
@@ -63,16 +79,17 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); }
};
-class PointerToMemberData: public llvm::FoldingSetNode {
+class PointerToMemberData : public llvm::FoldingSetNode {
const DeclaratorDecl *D;
llvm::ImmutableList<const CXXBaseSpecifier *> L;
public:
PointerToMemberData(const DeclaratorDecl *D,
llvm::ImmutableList<const CXXBaseSpecifier *> L)
- : D(D), L(L) {}
+ : D(D), L(L) {}
+
+ using iterator = llvm::ImmutableList<const CXXBaseSpecifier *>::iterator;
- typedef llvm::ImmutableList<const CXXBaseSpecifier *>::iterator iterator;
iterator begin() const { return L.begin(); }
iterator end() const { return L.end(); }
@@ -81,24 +98,25 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, D, L); }
const DeclaratorDecl *getDeclaratorDecl() const {return D;}
+
llvm::ImmutableList<const CXXBaseSpecifier *> getCXXBaseList() const {
return L;
}
};
class BasicValueFactory {
- typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
- APSIntSetTy;
+ using APSIntSetTy =
+ llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt>>;
ASTContext &Ctx;
llvm::BumpPtrAllocator& BPAlloc;
- APSIntSetTy APSIntSet;
- void * PersistentSVals;
- void * PersistentSValPairs;
+ APSIntSetTy APSIntSet;
+ void *PersistentSVals = nullptr;
+ void *PersistentSValPairs = nullptr;
llvm::ImmutableList<SVal>::Factory SValListFactory;
- llvm::ImmutableList<const CXXBaseSpecifier*>::Factory CXXBaseListFactory;
+ llvm::ImmutableList<const CXXBaseSpecifier *>::Factory CXXBaseListFactory;
llvm::FoldingSet<CompoundValData> CompoundValDataSet;
llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet;
llvm::FoldingSet<PointerToMemberData> PointerToMemberDataSet;
@@ -109,9 +127,8 @@ class BasicValueFactory {
public:
BasicValueFactory(ASTContext &ctx, llvm::BumpPtrAllocator &Alloc)
- : Ctx(ctx), BPAlloc(Alloc), PersistentSVals(nullptr),
- PersistentSValPairs(nullptr), SValListFactory(Alloc),
- CXXBaseListFactory(Alloc) {}
+ : Ctx(ctx), BPAlloc(Alloc), SValListFactory(Alloc),
+ CXXBaseListFactory(Alloc) {}
~BasicValueFactory();
@@ -147,57 +164,57 @@ public:
return getValue(TargetType.convert(From));
}
- const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) {
+ const llvm::APSInt &getIntValue(uint64_t X, bool isUnsigned) {
QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy;
return getValue(X, T);
}
- inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) {
+ const llvm::APSInt &getMaxValue(const llvm::APSInt &v) {
return getValue(APSIntType(v).getMaxValue());
}
- inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) {
+ const llvm::APSInt &getMinValue(const llvm::APSInt &v) {
return getValue(APSIntType(v).getMinValue());
}
- inline const llvm::APSInt& getMaxValue(QualType T) {
+ const llvm::APSInt &getMaxValue(QualType T) {
return getValue(getAPSIntType(T).getMaxValue());
}
- inline const llvm::APSInt& getMinValue(QualType T) {
+ const llvm::APSInt &getMinValue(QualType T) {
return getValue(getAPSIntType(T).getMinValue());
}
- inline const llvm::APSInt& Add1(const llvm::APSInt& V) {
+ const llvm::APSInt &Add1(const llvm::APSInt &V) {
llvm::APSInt X = V;
++X;
return getValue(X);
}
- inline const llvm::APSInt& Sub1(const llvm::APSInt& V) {
+ const llvm::APSInt &Sub1(const llvm::APSInt &V) {
llvm::APSInt X = V;
--X;
return getValue(X);
}
- inline const llvm::APSInt& getZeroWithTypeSize(QualType T) {
+ const llvm::APSInt &getZeroWithTypeSize(QualType T) {
assert(T->isScalarType());
return getValue(0, Ctx.getTypeSize(T), true);
}
- inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) {
+ const llvm::APSInt &getZeroWithPtrWidth(bool isUnsigned = true) {
return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
}
- inline const llvm::APSInt &getIntWithPtrWidth(uint64_t X, bool isUnsigned) {
+ const llvm::APSInt &getIntWithPtrWidth(uint64_t X, bool isUnsigned) {
return getValue(X, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
}
- inline const llvm::APSInt& getTruthValue(bool b, QualType T) {
- return getValue(b ? 1 : 0, Ctx.getTypeSize(T), false);
+ const llvm::APSInt &getTruthValue(bool b, QualType T) {
+ return getValue(b ? 1 : 0, Ctx.getIntWidth(T), true);
}
- inline const llvm::APSInt& getTruthValue(bool b) {
+ const llvm::APSInt &getTruthValue(bool b) {
return getTruthValue(b, Ctx.getLogicalOperationType());
}
@@ -229,7 +246,7 @@ public:
return CXXBaseListFactory.add(CBS, L);
}
- const clang::ento::PointerToMemberData *accumCXXBase(
+ const PointerToMemberData *accumCXXBase(
llvm::iterator_range<CastExpr::path_const_iterator> PathRange,
const nonloc::PointerToMember &PTM);
@@ -246,8 +263,8 @@ public:
const SVal* getPersistentSVal(SVal X);
};
-} // end GR namespace
+} // namespace ento
-} // end clang namespace
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_BASICVALUEFACTORY_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h
index 1d779e6cb6ec0..b94dadff23427 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h
@@ -25,7 +25,7 @@ class StackFrameContext;
namespace ento {
/// \class BlockCounter
-/// \brief An abstract data type used to count the number of times a given
+/// An abstract data type used to count the number of times a given
/// block has been visited along a path analyzed by CoreEngine.
class BlockCounter {
void *Data;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 9fec217aca725..9c667f912e9fd 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -1,4 +1,4 @@
-//===- CallEvent.h - Wrapper for all function and method calls ----*- C++ -*--//
+//===- CallEvent.h - Wrapper for all function and method calls --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -16,19 +16,42 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLEVENT_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLEVENT_H
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cassert>
+#include <limits>
#include <utility>
namespace clang {
+
+class LocationContext;
class ProgramPoint;
class ProgramPointTag;
+class StackFrameContext;
namespace ento {
@@ -48,31 +71,31 @@ enum CallEventKind {
};
class CallEvent;
-class CallEventManager;
/// This class represents a description of a function call using the number of
/// arguments and the name of the function.
class CallDescription {
friend CallEvent;
- mutable IdentifierInfo *II;
- mutable bool IsLookupDone;
+
+ mutable IdentifierInfo *II = nullptr;
+ mutable bool IsLookupDone = false;
StringRef FuncName;
unsigned RequiredArgs;
public:
- const static unsigned NoArgRequirement = ~0;
- /// \brief Constructs a CallDescription object.
+ const static unsigned NoArgRequirement = std::numeric_limits<unsigned>::max();
+
+ /// Constructs a CallDescription object.
///
/// @param FuncName The name of the function that will be matched.
///
/// @param RequiredArgs The number of arguments that is expected to match a
- /// call. Omit this parameter to match every occurance of call with a given
+ /// call. Omit this parameter to match every occurrence of call with a given
/// name regardless the number of arguments.
CallDescription(StringRef FuncName, unsigned RequiredArgs = NoArgRequirement)
- : II(nullptr), IsLookupDone(false), FuncName(FuncName),
- RequiredArgs(RequiredArgs) {}
+ : FuncName(FuncName), RequiredArgs(RequiredArgs) {}
- /// \brief Get the name of the function that this object matches.
+ /// Get the name of the function that this object matches.
StringRef getFunctionName() const { return FuncName; }
};
@@ -95,7 +118,7 @@ public:
};
/// \class RuntimeDefinition
-/// \brief Defines the runtime definition of the called function.
+/// Defines the runtime definition of the called function.
///
/// Encapsulates the information we have about which Decl will be used
/// when the call is executed on the given path. When dealing with dynamic
@@ -104,21 +127,22 @@ public:
class RuntimeDefinition {
/// The Declaration of the function which could be called at runtime.
/// NULL if not available.
- const Decl *D;
+ const Decl *D = nullptr;
/// The region representing an object (ObjC/C++) on which the method is
/// called. With dynamic dispatch, the method definition depends on the
/// runtime type of this object. NULL when the DynamicTypeInfo is
/// precise.
- const MemRegion *R;
+ const MemRegion *R = nullptr;
public:
- RuntimeDefinition(): D(nullptr), R(nullptr) {}
- RuntimeDefinition(const Decl *InD): D(InD), R(nullptr) {}
+ RuntimeDefinition() = default;
+ RuntimeDefinition(const Decl *InD): D(InD) {}
RuntimeDefinition(const Decl *InD, const MemRegion *InR): D(InD), R(InR) {}
+
const Decl *getDecl() { return D; }
- /// \brief Check if the definition we have is precise.
+ /// Check if the definition we have is precise.
/// If not, it is possible that the call dispatches to another definition at
/// execution time.
bool mayHaveOtherDefinitions() { return R != nullptr; }
@@ -128,7 +152,7 @@ public:
const MemRegion *getDispatchRegion() { return R; }
};
-/// \brief Represents an abstract call to a function or method along a
+/// Represents an abstract call to a function or method along a
/// particular path.
///
/// CallEvents are created through the factory methods of CallEventManager.
@@ -139,15 +163,13 @@ public:
/// Use the "Data" and "Location" fields instead.
class CallEvent {
public:
- typedef CallEventKind Kind;
+ using Kind = CallEventKind;
private:
ProgramStateRef State;
const LocationContext *LCtx;
llvm::PointerUnion<const Expr *, const Decl *> Origin;
- void operator=(const CallEvent &) = delete;
-
protected:
// This is user data for subclasses.
const void *Data;
@@ -158,9 +180,10 @@ protected:
SourceLocation Location;
private:
- mutable unsigned RefCount;
-
template <typename T> friend struct llvm::IntrusiveRefCntPtrInfo;
+
+ mutable unsigned RefCount = 0;
+
void Retain() const { ++RefCount; }
void Release() const;
@@ -168,72 +191,72 @@ protected:
friend class CallEventManager;
CallEvent(const Expr *E, ProgramStateRef state, const LocationContext *lctx)
- : State(std::move(state)), LCtx(lctx), Origin(E), RefCount(0) {}
+ : State(std::move(state)), LCtx(lctx), Origin(E) {}
CallEvent(const Decl *D, ProgramStateRef state, const LocationContext *lctx)
- : State(std::move(state)), LCtx(lctx), Origin(D), RefCount(0) {}
+ : State(std::move(state)), LCtx(lctx), Origin(D) {}
// DO NOT MAKE PUBLIC
CallEvent(const CallEvent &Original)
- : State(Original.State), LCtx(Original.LCtx), Origin(Original.Origin),
- Data(Original.Data), Location(Original.Location), RefCount(0) {}
+ : State(Original.State), LCtx(Original.LCtx), Origin(Original.Origin),
+ Data(Original.Data), Location(Original.Location) {}
/// Copies this CallEvent, with vtable intact, into a new block of memory.
virtual void cloneTo(void *Dest) const = 0;
- /// \brief Get the value of arbitrary expressions at this point in the path.
+ /// Get the value of arbitrary expressions at this point in the path.
SVal getSVal(const Stmt *S) const {
return getState()->getSVal(S, getLocationContext());
}
+ using ValueList = SmallVectorImpl<SVal>;
- typedef SmallVectorImpl<SVal> ValueList;
-
- /// \brief Used to specify non-argument regions that will be invalidated as a
+ /// Used to specify non-argument regions that will be invalidated as a
/// result of this call.
virtual void getExtraInvalidatedValues(ValueList &Values,
RegionAndSymbolInvalidationTraits *ETraits) const {}
public:
- virtual ~CallEvent() {}
+ CallEvent &operator=(const CallEvent &) = delete;
+ virtual ~CallEvent() = default;
- /// \brief Returns the kind of call this is.
+ /// Returns the kind of call this is.
virtual Kind getKind() const = 0;
- /// \brief Returns the declaration of the function or method that will be
+ /// Returns the declaration of the function or method that will be
/// called. May be null.
virtual const Decl *getDecl() const {
return Origin.dyn_cast<const Decl *>();
}
- /// \brief The state in which the call is being evaluated.
+ /// The state in which the call is being evaluated.
const ProgramStateRef &getState() const {
return State;
}
- /// \brief The context in which the call is being evaluated.
+ /// The context in which the call is being evaluated.
const LocationContext *getLocationContext() const {
return LCtx;
}
- /// \brief Returns the definition of the function or method that will be
+ /// Returns the definition of the function or method that will be
/// called.
virtual RuntimeDefinition getRuntimeDefinition() const = 0;
- /// \brief Returns the expression whose value will be the result of this call.
+ /// Returns the expression whose value will be the result of this call.
/// May be null.
const Expr *getOriginExpr() const {
return Origin.dyn_cast<const Expr *>();
}
- /// \brief Returns the number of arguments (explicit and implicit).
+ /// Returns the number of arguments (explicit and implicit).
///
/// Note that this may be greater than the number of parameters in the
/// callee's declaration, and that it may include arguments not written in
/// the source.
virtual unsigned getNumArgs() const = 0;
- /// \brief Returns true if the callee is known to be from a system header.
+ /// Returns true if the callee is known to be from a system header.
bool isInSystemHeader() const {
const Decl *D = getDecl();
if (!D)
@@ -248,57 +271,57 @@ public:
// Special case for implicitly-declared global operator new/delete.
// These should be considered system functions.
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (const auto *FD = dyn_cast<FunctionDecl>(D))
return FD->isOverloadedOperator() && FD->isImplicit() && FD->isGlobal();
return false;
}
- /// \brief Returns true if the CallEvent is a call to a function that matches
+ /// Returns true if the CallEvent is a call to a function that matches
/// the CallDescription.
///
/// Note that this function is not intended to be used to match Obj-C method
/// calls.
bool isCalled(const CallDescription &CD) const;
- /// \brief Returns a source range for the entire call, suitable for
+ /// Returns a source range for the entire call, suitable for
/// outputting in diagnostics.
virtual SourceRange getSourceRange() const {
return getOriginExpr()->getSourceRange();
}
- /// \brief Returns the value of a given argument at the time of the call.
+ /// Returns the value of a given argument at the time of the call.
virtual SVal getArgSVal(unsigned Index) const;
- /// \brief Returns the expression associated with a given argument.
+ /// Returns the expression associated with a given argument.
/// May be null if this expression does not appear in the source.
virtual const Expr *getArgExpr(unsigned Index) const { return nullptr; }
- /// \brief Returns the source range for errors associated with this argument.
+ /// Returns the source range for errors associated with this argument.
///
/// May be invalid if the argument is not written in the source.
virtual SourceRange getArgSourceRange(unsigned Index) const;
- /// \brief Returns the result type, adjusted for references.
+ /// Returns the result type, adjusted for references.
QualType getResultType() const;
- /// \brief Returns the return value of the call.
+ /// Returns the return value of the call.
///
/// This should only be called if the CallEvent was created using a state in
/// which the return value has already been bound to the origin expression.
SVal getReturnValue() const;
- /// \brief Returns true if the type of any of the non-null arguments satisfies
+ /// Returns true if the type of any of the non-null arguments satisfies
/// the condition.
bool hasNonNullArgumentsWithType(bool (*Condition)(QualType)) const;
- /// \brief Returns true if any of the arguments appear to represent callbacks.
+ /// Returns true if any of the arguments appear to represent callbacks.
bool hasNonZeroCallbackArg() const;
- /// \brief Returns true if any of the arguments is void*.
+ /// Returns true if any of the arguments is void*.
bool hasVoidPointerToNonConstArg() const;
- /// \brief Returns true if any of the arguments are known to escape to long-
+ /// Returns true if any of the arguments are known to escape to long-
/// term storage, even if this method will not modify them.
// NOTE: The exact semantics of this are still being defined!
// We don't really want a list of hardcoded exceptions in the long run,
@@ -307,7 +330,7 @@ public:
return hasNonZeroCallbackArg();
}
- /// \brief Returns true if the callee is an externally-visible function in the
+ /// Returns true if the callee is an externally-visible function in the
/// top-level namespace, such as \c malloc.
///
/// You can use this call to determine that a particular function really is
@@ -325,7 +348,7 @@ public:
// precise callbacks.
bool isGlobalCFunction(StringRef SpecificName = StringRef()) const;
- /// \brief Returns the name of the callee, if its name is a simple identifier.
+ /// Returns the name of the callee, if its name is a simple identifier.
///
/// Note that this will fail for Objective-C methods, blocks, and C++
/// overloaded operators. The former is named by a Selector rather than a
@@ -333,25 +356,25 @@ public:
// FIXME: Move this down to AnyFunctionCall once checkers have more
// precise callbacks.
const IdentifierInfo *getCalleeIdentifier() const {
- const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getDecl());
+ const auto *ND = dyn_cast_or_null<NamedDecl>(getDecl());
if (!ND)
return nullptr;
return ND->getIdentifier();
}
- /// \brief Returns an appropriate ProgramPoint for this call.
+ /// Returns an appropriate ProgramPoint for this call.
ProgramPoint getProgramPoint(bool IsPreVisit = false,
const ProgramPointTag *Tag = nullptr) const;
- /// \brief Returns a new state with all argument regions invalidated.
+ /// Returns a new state with all argument regions invalidated.
///
/// This accepts an alternate state in case some processing has already
/// occurred.
ProgramStateRef invalidateRegions(unsigned BlockCount,
ProgramStateRef Orig = nullptr) const;
- typedef std::pair<Loc, SVal> FrameBindingTy;
- typedef SmallVectorImpl<FrameBindingTy> BindingsTy;
+ using FrameBindingTy = std::pair<Loc, SVal>;
+ using BindingsTy = SmallVectorImpl<FrameBindingTy>;
/// Populates the given SmallVector with the bindings in the callee's stack
/// frame at the start of this call.
@@ -367,16 +390,16 @@ public:
return cloneWithState<CallEvent>(NewState);
}
- /// \brief Returns true if this is a statement is a function or method call
+ /// Returns true if this is a statement is a function or method call
/// of some kind.
static bool isCallStmt(const Stmt *S);
- /// \brief Returns the result type of a function or method declaration.
+ /// Returns the result type of a function or method declaration.
///
/// This will return a null QualType if the result type cannot be determined.
static QualType getDeclaredResultType(const Decl *D);
- /// \brief Returns true if the given decl is known to be variadic.
+ /// Returns true if the given decl is known to be variadic.
///
/// \p D must not be null.
static bool isVariadic(const Decl *D);
@@ -393,10 +416,10 @@ public:
/// Remember that the number of formal parameters may not match the number
/// of arguments for all calls. However, the first parameter will always
/// correspond with the argument value returned by \c getArgSVal(0).
- virtual ArrayRef<ParmVarDecl*> parameters() const = 0;
+ virtual ArrayRef<ParmVarDecl *> parameters() const = 0;
- typedef llvm::mapped_iterator<ArrayRef<ParmVarDecl*>::iterator, GetTypeFn>
- param_type_iterator;
+ using param_type_iterator =
+ llvm::mapped_iterator<ArrayRef<ParmVarDecl *>::iterator, GetTypeFn>;
/// Returns an iterator over the types of the call's formal parameters.
///
@@ -416,18 +439,17 @@ public:
void dump() const;
};
-
-/// \brief Represents a call to any sort of function that might have a
+/// Represents a call to any sort of function that might have a
/// FunctionDecl.
class AnyFunctionCall : public CallEvent {
protected:
AnyFunctionCall(const Expr *E, ProgramStateRef St,
const LocationContext *LCtx)
- : CallEvent(E, St, LCtx) {}
+ : CallEvent(E, St, LCtx) {}
AnyFunctionCall(const Decl *D, ProgramStateRef St,
const LocationContext *LCtx)
- : CallEvent(D, St, LCtx) {}
- AnyFunctionCall(const AnyFunctionCall &Other) : CallEvent(Other) {}
+ : CallEvent(D, St, LCtx) {}
+ AnyFunctionCall(const AnyFunctionCall &Other) = default;
public:
// This function is overridden by subclasses, but they must return
@@ -451,7 +473,7 @@ public:
}
};
-/// \brief Represents a C function or static C++ member function call.
+/// Represents a C function or static C++ member function call.
///
/// Example: \c fun()
class SimpleFunctionCall : public AnyFunctionCall {
@@ -460,9 +482,9 @@ class SimpleFunctionCall : public AnyFunctionCall {
protected:
SimpleFunctionCall(const CallExpr *CE, ProgramStateRef St,
const LocationContext *LCtx)
- : AnyFunctionCall(CE, St, LCtx) {}
- SimpleFunctionCall(const SimpleFunctionCall &Other)
- : AnyFunctionCall(Other) {}
+ : AnyFunctionCall(CE, St, LCtx) {}
+ SimpleFunctionCall(const SimpleFunctionCall &Other) = default;
+
void cloneTo(void *Dest) const override {
new (Dest) SimpleFunctionCall(*this);
}
@@ -487,7 +509,7 @@ public:
}
};
-/// \brief Represents a call to a block.
+/// Represents a call to a block.
///
/// Example: <tt>^{ /* ... */ }()</tt>
class BlockCall : public CallEvent {
@@ -496,9 +518,9 @@ class BlockCall : public CallEvent {
protected:
BlockCall(const CallExpr *CE, ProgramStateRef St,
const LocationContext *LCtx)
- : CallEvent(CE, St, LCtx) {}
+ : CallEvent(CE, St, LCtx) {}
+ BlockCall(const BlockCall &Other) = default;
- BlockCall(const BlockCall &Other) : CallEvent(Other) {}
void cloneTo(void *Dest) const override { new (Dest) BlockCall(*this); }
void getExtraInvalidatedValues(ValueList &Values,
@@ -515,7 +537,7 @@ public:
return getOriginExpr()->getArg(Index);
}
- /// \brief Returns the region associated with this instance of the block.
+ /// Returns the region associated with this instance of the block.
///
/// This may be NULL if the block's origin is unknown.
const BlockDataRegion *getBlockRegion() const;
@@ -535,7 +557,7 @@ public:
return BD->isConversionFromLambda();
}
- /// \brief For a block converted from a C++ lambda, returns the block
+ /// For a block converted from a C++ lambda, returns the block
/// VarRegion for the variable holding the captured C++ lambda record.
const VarRegion *getRegionStoringCapturedLambda() const {
assert(isConversionFromLambda());
@@ -594,28 +616,26 @@ public:
}
};
-/// \brief Represents a non-static C++ member function call, no matter how
+/// Represents a non-static C++ member function call, no matter how
/// it is written.
class CXXInstanceCall : public AnyFunctionCall {
protected:
- void getExtraInvalidatedValues(ValueList &Values,
- RegionAndSymbolInvalidationTraits *ETraits) const override;
-
CXXInstanceCall(const CallExpr *CE, ProgramStateRef St,
const LocationContext *LCtx)
- : AnyFunctionCall(CE, St, LCtx) {}
+ : AnyFunctionCall(CE, St, LCtx) {}
CXXInstanceCall(const FunctionDecl *D, ProgramStateRef St,
const LocationContext *LCtx)
- : AnyFunctionCall(D, St, LCtx) {}
-
+ : AnyFunctionCall(D, St, LCtx) {}
+ CXXInstanceCall(const CXXInstanceCall &Other) = default;
- CXXInstanceCall(const CXXInstanceCall &Other) : AnyFunctionCall(Other) {}
+ void getExtraInvalidatedValues(ValueList &Values,
+ RegionAndSymbolInvalidationTraits *ETraits) const override;
public:
- /// \brief Returns the expression representing the implicit 'this' object.
+ /// Returns the expression representing the implicit 'this' object.
virtual const Expr *getCXXThisExpr() const { return nullptr; }
- /// \brief Returns the value of the implicit 'this' object.
+ /// Returns the value of the implicit 'this' object.
virtual SVal getCXXThisVal() const;
const FunctionDecl *getDecl() const override;
@@ -631,7 +651,7 @@ public:
}
};
-/// \brief Represents a non-static C++ member function call.
+/// Represents a non-static C++ member function call.
///
/// Example: \c obj.fun()
class CXXMemberCall : public CXXInstanceCall {
@@ -640,9 +660,9 @@ class CXXMemberCall : public CXXInstanceCall {
protected:
CXXMemberCall(const CXXMemberCallExpr *CE, ProgramStateRef St,
const LocationContext *LCtx)
- : CXXInstanceCall(CE, St, LCtx) {}
+ : CXXInstanceCall(CE, St, LCtx) {}
+ CXXMemberCall(const CXXMemberCall &Other) = default;
- CXXMemberCall(const CXXMemberCall &Other) : CXXInstanceCall(Other) {}
void cloneTo(void *Dest) const override { new (Dest) CXXMemberCall(*this); }
public:
@@ -671,7 +691,7 @@ public:
}
};
-/// \brief Represents a C++ overloaded operator call where the operator is
+/// Represents a C++ overloaded operator call where the operator is
/// implemented as a non-static member function.
///
/// Example: <tt>iter + 1</tt>
@@ -681,10 +701,9 @@ class CXXMemberOperatorCall : public CXXInstanceCall {
protected:
CXXMemberOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St,
const LocationContext *LCtx)
- : CXXInstanceCall(CE, St, LCtx) {}
+ : CXXInstanceCall(CE, St, LCtx) {}
+ CXXMemberOperatorCall(const CXXMemberOperatorCall &Other) = default;
- CXXMemberOperatorCall(const CXXMemberOperatorCall &Other)
- : CXXInstanceCall(Other) {}
void cloneTo(void *Dest) const override {
new (Dest) CXXMemberOperatorCall(*this);
}
@@ -697,6 +716,7 @@ public:
unsigned getNumArgs() const override {
return getOriginExpr()->getNumArgs() - 1;
}
+
const Expr *getArgExpr(unsigned Index) const override {
return getOriginExpr()->getArg(Index + 1);
}
@@ -710,7 +730,7 @@ public:
}
};
-/// \brief Represents an implicit call to a C++ destructor.
+/// Represents an implicit call to a C++ destructor.
///
/// This can occur at the end of a scope (for automatic objects), at the end
/// of a full-expression (for temporaries), or as part of a delete.
@@ -718,7 +738,7 @@ class CXXDestructorCall : public CXXInstanceCall {
friend class CallEventManager;
protected:
- typedef llvm::PointerIntPair<const MemRegion *, 1, bool> DtorDataTy;
+ using DtorDataTy = llvm::PointerIntPair<const MemRegion *, 1, bool>;
/// Creates an implicit destructor.
///
@@ -730,12 +750,13 @@ protected:
CXXDestructorCall(const CXXDestructorDecl *DD, const Stmt *Trigger,
const MemRegion *Target, bool IsBaseDestructor,
ProgramStateRef St, const LocationContext *LCtx)
- : CXXInstanceCall(DD, St, LCtx) {
+ : CXXInstanceCall(DD, St, LCtx) {
Data = DtorDataTy(Target, IsBaseDestructor).getOpaqueValue();
Location = Trigger->getLocEnd();
}
- CXXDestructorCall(const CXXDestructorCall &Other) : CXXInstanceCall(Other) {}
+ CXXDestructorCall(const CXXDestructorCall &Other) = default;
+
void cloneTo(void *Dest) const override {new (Dest) CXXDestructorCall(*this);}
public:
@@ -744,7 +765,7 @@ public:
RuntimeDefinition getRuntimeDefinition() const override;
- /// \brief Returns the value of the implicit 'this' object.
+ /// Returns the value of the implicit 'this' object.
SVal getCXXThisVal() const override;
/// Returns true if this is a call to a base class destructor.
@@ -759,7 +780,7 @@ public:
}
};
-/// \brief Represents a call to a C++ constructor.
+/// Represents a call to a C++ constructor.
///
/// Example: \c T(1)
class CXXConstructorCall : public AnyFunctionCall {
@@ -775,11 +796,12 @@ protected:
/// \param LCtx The location context at this point in the program.
CXXConstructorCall(const CXXConstructExpr *CE, const MemRegion *Target,
ProgramStateRef St, const LocationContext *LCtx)
- : AnyFunctionCall(CE, St, LCtx) {
+ : AnyFunctionCall(CE, St, LCtx) {
Data = Target;
}
- CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){}
+ CXXConstructorCall(const CXXConstructorCall &Other) = default;
+
void cloneTo(void *Dest) const override { new (Dest) CXXConstructorCall(*this); }
void getExtraInvalidatedValues(ValueList &Values,
@@ -800,7 +822,7 @@ public:
return getOriginExpr()->getArg(Index);
}
- /// \brief Returns the value of the implicit 'this' object.
+ /// Returns the value of the implicit 'this' object.
SVal getCXXThisVal() const;
void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
@@ -813,7 +835,7 @@ public:
}
};
-/// \brief Represents the memory allocation call in a C++ new-expression.
+/// Represents the memory allocation call in a C++ new-expression.
///
/// This is a call to "operator new".
class CXXAllocatorCall : public AnyFunctionCall {
@@ -822,9 +844,9 @@ class CXXAllocatorCall : public AnyFunctionCall {
protected:
CXXAllocatorCall(const CXXNewExpr *E, ProgramStateRef St,
const LocationContext *LCtx)
- : AnyFunctionCall(E, St, LCtx) {}
+ : AnyFunctionCall(E, St, LCtx) {}
+ CXXAllocatorCall(const CXXAllocatorCall &Other) = default;
- CXXAllocatorCall(const CXXAllocatorCall &Other) : AnyFunctionCall(Other) {}
void cloneTo(void *Dest) const override { new (Dest) CXXAllocatorCall(*this); }
public:
@@ -854,7 +876,7 @@ public:
}
};
-/// \brief Represents the ways an Objective-C message send can occur.
+/// Represents the ways an Objective-C message send can occur.
//
// Note to maintainers: OCM_Message should always be last, since it does not
// need to fit in the Data field's low bits.
@@ -864,7 +886,7 @@ enum ObjCMessageKind {
OCM_Message
};
-/// \brief Represents any expression that calls an Objective-C method.
+/// Represents any expression that calls an Objective-C method.
///
/// This includes all of the kinds listed in ObjCMessageKind.
class ObjCMethodCall : public CallEvent {
@@ -875,11 +897,12 @@ class ObjCMethodCall : public CallEvent {
protected:
ObjCMethodCall(const ObjCMessageExpr *Msg, ProgramStateRef St,
const LocationContext *LCtx)
- : CallEvent(Msg, St, LCtx) {
+ : CallEvent(Msg, St, LCtx) {
Data = nullptr;
}
- ObjCMethodCall(const ObjCMethodCall &Other) : CallEvent(Other) {}
+ ObjCMethodCall(const ObjCMethodCall &Other) = default;
+
void cloneTo(void *Dest) const override { new (Dest) ObjCMethodCall(*this); }
void getExtraInvalidatedValues(ValueList &Values,
@@ -893,12 +916,15 @@ public:
virtual const ObjCMessageExpr *getOriginExpr() const {
return cast<ObjCMessageExpr>(CallEvent::getOriginExpr());
}
+
const ObjCMethodDecl *getDecl() const override {
return getOriginExpr()->getMethodDecl();
}
+
unsigned getNumArgs() const override {
return getOriginExpr()->getNumArgs();
}
+
const Expr *getArgExpr(unsigned Index) const override {
return getOriginExpr()->getArg(Index);
}
@@ -906,22 +932,24 @@ public:
bool isInstanceMessage() const {
return getOriginExpr()->isInstanceMessage();
}
+
ObjCMethodFamily getMethodFamily() const {
return getOriginExpr()->getMethodFamily();
}
+
Selector getSelector() const {
return getOriginExpr()->getSelector();
}
SourceRange getSourceRange() const override;
- /// \brief Returns the value of the receiver at the time of this call.
+ /// Returns the value of the receiver at the time of this call.
SVal getReceiverSVal() const;
- /// \brief Return the value of 'self' if available.
+ /// Return the value of 'self' if available.
SVal getSelfSVal() const;
- /// \brief Get the interface for the receiver.
+ /// Get the interface for the receiver.
///
/// This works whether this is an instance message or a class message.
/// However, it currently just uses the static type of the receiver.
@@ -929,7 +957,7 @@ public:
return getOriginExpr()->getReceiverInterface();
}
- /// \brief Checks if the receiver refers to 'self' or 'super'.
+ /// Checks if the receiver refers to 'self' or 'super'.
bool isReceiverSelfOrSuper() const;
/// Returns how the message was written in the source (property access,
@@ -971,8 +999,7 @@ public:
}
};
-
-/// \brief Manages the lifetime of CallEvent objects.
+/// Manages the lifetime of CallEvent objects.
///
/// CallEventManager provides a way to create arbitrary CallEvents "on the
/// stack" as if they were value objects by keeping a cache of CallEvent-sized
@@ -984,7 +1011,8 @@ class CallEventManager {
llvm::BumpPtrAllocator &Alloc;
SmallVector<void *, 8> Cache;
- typedef SimpleFunctionCall CallEventTemplateTy;
+
+ using CallEventTemplateTy = SimpleFunctionCall;
void reclaim(const void *Memory) {
Cache.push_back(const_cast<void *>(Memory));
@@ -1032,11 +1060,9 @@ class CallEventManager {
public:
CallEventManager(llvm::BumpPtrAllocator &alloc) : Alloc(alloc) {}
-
CallEventRef<>
getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State);
-
CallEventRef<>
getSimpleCall(const CallExpr *E, ProgramStateRef State,
const LocationContext *LCtx);
@@ -1067,7 +1093,6 @@ public:
}
};
-
template <typename T>
CallEventRef<T> CallEvent::cloneWithState(ProgramStateRef NewState) const {
assert(isa<T>(*this) && "Cloning to unrelated type");
@@ -1099,19 +1124,22 @@ inline void CallEvent::Release() const {
this->~CallEvent();
}
-} // end namespace ento
-} // end namespace clang
+} // namespace ento
+
+} // namespace clang
namespace llvm {
- // Support isa<>, cast<>, and dyn_cast<> for CallEventRef.
- template<class T> struct simplify_type< clang::ento::CallEventRef<T> > {
- typedef const T *SimpleType;
- static SimpleType
- getSimplifiedValue(clang::ento::CallEventRef<T> Val) {
- return Val.get();
- }
- };
-}
+// Support isa<>, cast<>, and dyn_cast<> for CallEventRef.
+template<class T> struct simplify_type< clang::ento::CallEventRef<T>> {
+ using SimpleType = const T *;
+
+ static SimpleType
+ getSimplifiedValue(clang::ento::CallEventRef<T> Val) {
+ return Val.get();
+ }
+};
+
+} // namespace llvm
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLEVENT_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index 78d38a3d598dc..f3a0ca7b66081 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -111,17 +111,17 @@ public:
return Eng.getStoreManager();
}
- /// \brief Returns the previous node in the exploded graph, which includes
+ /// Returns the previous node in the exploded graph, which includes
/// the state of the program before the checker ran. Note, checkers should
/// not retain the node in their state since the nodes might get invalidated.
ExplodedNode *getPredecessor() { return Pred; }
const ProgramStateRef &getState() const { return Pred->getState(); }
- /// \brief Check if the checker changed the state of the execution; ex: added
+ /// Check if the checker changed the state of the execution; ex: added
/// a new transition or a bug report.
bool isDifferent() { return Changed; }
- /// \brief Returns the number of times the current block has been visited
+ /// Returns the number of times the current block has been visited
/// along the analyzed path.
unsigned blockCount() const {
return NB.getContext().blockCount();
@@ -174,12 +174,12 @@ public:
return Pred->getLocationContext()->getAnalysisDeclContext();
}
- /// \brief Get the blockID.
+ /// Get the blockID.
unsigned getBlockID() const {
return NB.getContext().getBlock()->getBlockID();
}
- /// \brief If the given node corresponds to a PostStore program point,
+ /// If the given node corresponds to a PostStore program point,
/// retrieve the location region as it was uttered in the code.
///
/// This utility can be useful for generating extensive diagnostics, for
@@ -191,19 +191,19 @@ public:
return nullptr;
}
- /// \brief Get the value of arbitrary expressions at this point in the path.
+ /// Get the value of arbitrary expressions at this point in the path.
SVal getSVal(const Stmt *S) const {
- return getState()->getSVal(S, getLocationContext());
+ return Pred->getSVal(S);
}
- /// \brief Returns true if the value of \p E is greater than or equal to \p
+ /// Returns true if the value of \p E is greater than or equal to \p
/// Val under unsigned comparison
bool isGreaterOrEqual(const Expr *E, unsigned long long Val);
/// Returns true if the value of \p E is negative.
bool isNegative(const Expr *E);
- /// \brief Generates a new transition in the program state graph
+ /// Generates a new transition in the program state graph
/// (ExplodedGraph). Uses the default CheckerContext predecessor node.
///
/// @param State The state of the generated node. If not specified, the state
@@ -217,7 +217,7 @@ public:
return addTransitionImpl(State ? State : getState(), false, nullptr, Tag);
}
- /// \brief Generates a new transition with the given predecessor.
+ /// Generates a new transition with the given predecessor.
/// Allows checkers to generate a chain of nodes.
///
/// @param State The state of the generated node.
@@ -230,7 +230,7 @@ public:
return addTransitionImpl(State, false, Pred, Tag);
}
- /// \brief Generate a sink node. Generating a sink stops exploration of the
+ /// Generate a sink node. Generating a sink stops exploration of the
/// given path. To create a sink node for the purpose of reporting an error,
/// checkers should use generateErrorNode() instead.
ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred,
@@ -238,7 +238,7 @@ public:
return addTransitionImpl(State ? State : getState(), true, Pred, Tag);
}
- /// \brief Generate a transition to a node that will be used to report
+ /// Generate a transition to a node that will be used to report
/// an error. This node will be a sink. That is, it will stop exploration of
/// the given path.
///
@@ -251,7 +251,7 @@ public:
(Tag ? Tag : Location.getTag()));
}
- /// \brief Generate a transition to a node that will be used to report
+ /// Generate a transition to a node that will be used to report
/// an error. This node will not be a sink. That is, exploration will
/// continue along this path.
///
@@ -264,23 +264,23 @@ public:
return addTransition(State, (Tag ? Tag : Location.getTag()));
}
- /// \brief Emit the diagnostics report.
+ /// Emit the diagnostics report.
void emitReport(std::unique_ptr<BugReport> R) {
Changed = true;
Eng.getBugReporter().emitReport(std::move(R));
}
- /// \brief Returns the word that should be used to refer to the declaration
+ /// Returns the word that should be used to refer to the declaration
/// in the report.
StringRef getDeclDescription(const Decl *D);
- /// \brief Get the declaration of the called function (path-sensitive).
+ /// Get the declaration of the called function (path-sensitive).
const FunctionDecl *getCalleeDecl(const CallExpr *CE) const;
- /// \brief Get the name of the called function (path-sensitive).
+ /// Get the name of the called function (path-sensitive).
StringRef getCalleeName(const FunctionDecl *FunDecl) const;
- /// \brief Get the identifier of the called function (path-sensitive).
+ /// Get the identifier of the called function (path-sensitive).
const IdentifierInfo *getCalleeIdentifier(const CallExpr *CE) const {
const FunctionDecl *FunDecl = getCalleeDecl(CE);
if (FunDecl)
@@ -289,13 +289,13 @@ public:
return nullptr;
}
- /// \brief Get the name of the called function (path-sensitive).
+ /// Get the name of the called function (path-sensitive).
StringRef getCalleeName(const CallExpr *CE) const {
const FunctionDecl *FunDecl = getCalleeDecl(CE);
return getCalleeName(FunDecl);
}
- /// \brief Returns true if the callee is an externally-visible function in the
+ /// Returns true if the callee is an externally-visible function in the
/// top-level namespace, such as \c malloc.
///
/// If a name is provided, the function must additionally match the given
@@ -308,7 +308,7 @@ public:
static bool isCLibraryFunction(const FunctionDecl *FD,
StringRef Name = StringRef());
- /// \brief Depending on wither the location corresponds to a macro, return
+ /// Depending on wither the location corresponds to a macro, return
/// either the macro name or the token spelling.
///
/// This could be useful when checkers' logic depends on whether a function
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
index 8dda6367c2e00..7f34a7a5b19dd 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
@@ -21,6 +21,8 @@ namespace clang {
class Expr;
class VarDecl;
+class QualType;
+class AttributedType;
namespace ento {
@@ -42,6 +44,25 @@ template <class T> bool containsStmt(const Stmt *S) {
std::pair<const clang::VarDecl *, const clang::Expr *>
parseAssignment(const Stmt *S);
+// Do not reorder! The getMostNullable method relies on the order.
+// Optimization: Most pointers expected to be unspecified. When a symbol has an
+// unspecified or nonnull type non of the rules would indicate any problem for
+// that symbol. For this reason only nullable and contradicted nullability are
+// stored for a symbol. When a symbol is already contradicted, it can not be
+// casted back to nullable.
+enum class Nullability : char {
+ Contradicted, // Tracked nullability is contradicted by an explicit cast. Do
+ // not report any nullability related issue for this symbol.
+ // This nullability is propagated aggressively to avoid false
+ // positive results. See the comment on getMostNullable method.
+ Nullable,
+ Unspecified,
+ Nonnull
+};
+
+/// Get nullability annotation for a given type.
+Nullability getNullabilityAnnotation(QualType Type);
+
} // end GR namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index c01600d5c969e..d4f8fbaa43df3 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -1,4 +1,4 @@
-//== ConstraintManager.h - Constraints on symbolic values.-------*- C++ -*--==//
+//===- ConstraintManager.h - Constraints on symbolic values. ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -14,28 +14,44 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H
+#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/Support/SaveAndRestore.h"
+#include <memory>
+#include <utility>
namespace llvm {
+
class APSInt;
-}
+
+} // namespace llvm
namespace clang {
namespace ento {
+class ProgramStateManager;
class SubEngine;
+class SymbolReaper;
class ConditionTruthVal {
Optional<bool> Val;
+
public:
/// Construct a ConditionTruthVal indicating the constraint is constrained
/// to either true or false, depending on the boolean value provided.
ConditionTruthVal(bool constraint) : Val(constraint) {}
/// Construct a ConstraintVal indicating the constraint is underconstrained.
- ConditionTruthVal() {}
+ ConditionTruthVal() = default;
+
+ /// \return Stored value, assuming that the value is known.
+ /// Crashes otherwise.
+ bool getValue() const {
+ return *Val;
+ }
/// Return true if the constraint is perfectly constrained to 'true'.
bool isConstrainedTrue() const {
@@ -61,14 +77,14 @@ public:
class ConstraintManager {
public:
- ConstraintManager() : NotifyAssumeClients(true) {}
-
+ ConstraintManager() = default;
virtual ~ConstraintManager();
+
virtual ProgramStateRef assume(ProgramStateRef state,
DefinedSVal Cond,
bool Assumption) = 0;
- typedef std::pair<ProgramStateRef, ProgramStateRef> ProgramStatePair;
+ using ProgramStatePair = std::pair<ProgramStateRef, ProgramStateRef>;
/// Returns a pair of states (StTrue, StFalse) where the given condition is
/// assumed to be true or false, respectively.
@@ -129,7 +145,7 @@ public:
return ProgramStatePair(StInRange, StOutOfRange);
}
- /// \brief If a symbol is perfectly constrained to a constant, attempt
+ /// If a symbol is perfectly constrained to a constant, attempt
/// to return the concrete value.
///
/// Note that a ConstraintManager is not obligated to return a concretized
@@ -166,7 +182,7 @@ protected:
///
/// Note that this flag allows the ConstraintManager to be re-entrant,
/// but not thread-safe.
- bool NotifyAssumeClients;
+ bool NotifyAssumeClients = true;
/// canReasonAbout - Not all ConstraintManagers can accurately reason about
/// all SVal values. This method returns true if the ConstraintManager can
@@ -187,8 +203,7 @@ CreateRangeConstraintManager(ProgramStateManager &statemgr,
std::unique_ptr<ConstraintManager>
CreateZ3ConstraintManager(ProgramStateManager &statemgr, SubEngine *subengine);
-} // end GR namespace
+} // namespace ento
+} // namespace clang
-} // end clang namespace
-
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 7472a7147fca6..5755818cd9716 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -1,4 +1,4 @@
-//==- CoreEngine.h - Path-Sensitive Dataflow Engine ----------------*- C++ -*-//
+//===- CoreEngine.h - Path-Sensitive Dataflow Engine ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,21 +15,33 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
-#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Casting.h"
+#include <cassert>
#include <memory>
+#include <utility>
+#include <vector>
namespace clang {
-class ProgramPointTag;
-
+class AnalyzerOptions;
+class CXXBindTemporaryExpr;
+class Expr;
+class LabelDecl;
+
namespace ento {
-class NodeBuilder;
+class FunctionSummariesTy;
+class SubEngine;
//===----------------------------------------------------------------------===//
/// CoreEngine - Implements the core logic of the graph-reachability
@@ -41,23 +53,23 @@ class NodeBuilder;
/// at the statement and block-level. The analyses themselves must implement
/// any transfer function logic and the sub-expression level (if any).
class CoreEngine {
- friend struct NodeBuilderContext;
- friend class NodeBuilder;
- friend class ExprEngine;
friend class CommonNodeBuilder;
+ friend class EndOfFunctionNodeBuilder;
+ friend class ExprEngine;
friend class IndirectGotoNodeBuilder;
+ friend class NodeBuilder;
+ friend struct NodeBuilderContext;
friend class SwitchNodeBuilder;
- friend class EndOfFunctionNodeBuilder;
+
public:
- typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> >
- BlocksExhausted;
+ using BlocksExhausted =
+ std::vector<std::pair<BlockEdge, const ExplodedNode *>>;
- typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> >
- BlocksAborted;
+ using BlocksAborted =
+ std::vector<std::pair<const CFGBlock *, const ExplodedNode *>>;
private:
-
- SubEngine& SubEng;
+ SubEngine &SubEng;
/// G - The simulation graph. Each node is a (location,state) pair.
mutable ExplodedGraph G;
@@ -106,17 +118,17 @@ private:
ExplodedNode *Pred);
private:
- CoreEngine(const CoreEngine &) = delete;
- void operator=(const CoreEngine &) = delete;
-
ExplodedNode *generateCallExitBeginNode(ExplodedNode *N,
const ReturnStmt *RS);
public:
/// Construct a CoreEngine object to analyze the provided CFG.
- CoreEngine(SubEngine &subengine, FunctionSummariesTy *FS)
- : SubEng(subengine), WList(WorkList::makeDFS()),
- BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {}
+ CoreEngine(SubEngine &subengine,
+ FunctionSummariesTy *FS,
+ AnalyzerOptions &Opts);
+
+ CoreEngine(const CoreEngine &) = delete;
+ CoreEngine &operator=(const CoreEngine &) = delete;
/// getGraph - Returns the exploded graph.
ExplodedGraph &getGraph() { return G; }
@@ -125,6 +137,7 @@ public:
/// steps. Returns true if there is still simulation state on the worklist.
bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
ProgramStateRef InitState);
+
/// Returns true if there is still simulation state on the worklist.
bool ExecuteWorkListWithInitialState(const LocationContext *L,
unsigned Steps,
@@ -154,28 +167,31 @@ public:
BlocksExhausted::const_iterator blocks_exhausted_begin() const {
return blocksExhausted.begin();
}
+
BlocksExhausted::const_iterator blocks_exhausted_end() const {
return blocksExhausted.end();
}
+
BlocksAborted::const_iterator blocks_aborted_begin() const {
return blocksAborted.begin();
}
+
BlocksAborted::const_iterator blocks_aborted_end() const {
return blocksAborted.end();
}
- /// \brief Enqueue the given set of nodes onto the work list.
+ /// Enqueue the given set of nodes onto the work list.
void enqueue(ExplodedNodeSet &Set);
- /// \brief Enqueue nodes that were created as a result of processing
+ /// Enqueue nodes that were created as a result of processing
/// a statement onto the work list.
void enqueue(ExplodedNodeSet &Set, const CFGBlock *Block, unsigned Idx);
- /// \brief enqueue the nodes corresponding to the end of function onto the
+ /// enqueue the nodes corresponding to the end of function onto the
/// end of path / work list.
void enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS);
- /// \brief Enqueue a single node created as a result of statement processing.
+ /// Enqueue a single node created as a result of statement processing.
void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx);
};
@@ -184,23 +200,24 @@ struct NodeBuilderContext {
const CoreEngine &Eng;
const CFGBlock *Block;
const LocationContext *LC;
+
NodeBuilderContext(const CoreEngine &E, const CFGBlock *B, ExplodedNode *N)
- : Eng(E), Block(B), LC(N->getLocationContext()) { assert(B); }
+ : Eng(E), Block(B), LC(N->getLocationContext()) { assert(B); }
- /// \brief Return the CFGBlock associated with this builder.
+ /// Return the CFGBlock associated with this builder.
const CFGBlock *getBlock() const { return Block; }
- /// \brief Returns the number of times the current basic block has been
+ /// Returns the number of times the current basic block has been
/// visited on the exploded graph path.
unsigned blockCount() const {
return Eng.WList->getBlockCounter().getNumVisited(
- LC->getCurrentStackFrame(),
+ LC->getStackFrame(),
Block->getBlockID());
}
};
/// \class NodeBuilder
-/// \brief This is the simplest builder which generates nodes in the
+/// This is the simplest builder which generates nodes in the
/// ExplodedGraph.
///
/// The main benefit of the builder is that it automatically tracks the
@@ -210,29 +227,29 @@ struct NodeBuilderContext {
/// constructed nodes) but did not have any outgoing transitions added.
class NodeBuilder {
virtual void anchor();
+
protected:
const NodeBuilderContext &C;
/// Specifies if the builder results have been finalized. For example, if it
/// is set to false, autotransitions are yet to be generated.
bool Finalized;
- bool HasGeneratedNodes;
- /// \brief The frontier set - a set of nodes which need to be propagated after
+
+ bool HasGeneratedNodes = false;
+
+ /// The frontier set - a set of nodes which need to be propagated after
/// the builder dies.
ExplodedNodeSet &Frontier;
- /// Checkes if the results are ready.
+ /// Checks if the results are ready.
virtual bool checkResults() {
- if (!Finalized)
- return false;
- return true;
+ return Finalized;
}
bool hasNoSinksInFrontier() {
- for (iterator I = Frontier.begin(), E = Frontier.end(); I != E; ++I) {
- if ((*I)->isSink())
+ for (const auto I : Frontier)
+ if (I->isSink())
return false;
- }
return true;
}
@@ -247,27 +264,27 @@ protected:
public:
NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
const NodeBuilderContext &Ctx, bool F = true)
- : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) {
+ : C(Ctx), Finalized(F), Frontier(DstSet) {
Frontier.Add(SrcNode);
}
NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
const NodeBuilderContext &Ctx, bool F = true)
- : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) {
+ : C(Ctx), Finalized(F), Frontier(DstSet) {
Frontier.insert(SrcSet);
assert(hasNoSinksInFrontier());
}
- virtual ~NodeBuilder() {}
+ virtual ~NodeBuilder() = default;
- /// \brief Generates a node in the ExplodedGraph.
+ /// Generates a node in the ExplodedGraph.
ExplodedNode *generateNode(const ProgramPoint &PP,
ProgramStateRef State,
ExplodedNode *Pred) {
return generateNodeImpl(PP, State, Pred, false);
}
- /// \brief Generates a sink in the ExplodedGraph.
+ /// Generates a sink in the ExplodedGraph.
///
/// When a node is marked as sink, the exploration from the node is stopped -
/// the node becomes the last node on the path and certain kinds of bugs are
@@ -284,14 +301,16 @@ public:
return Frontier;
}
- typedef ExplodedNodeSet::iterator iterator;
- /// \brief Iterators through the results frontier.
- inline iterator begin() {
+ using iterator = ExplodedNodeSet::iterator;
+
+ /// Iterators through the results frontier.
+ iterator begin() {
finalizeResults();
assert(checkResults());
return Frontier.begin();
}
- inline iterator end() {
+
+ iterator end() {
finalizeResults();
return Frontier.end();
}
@@ -300,18 +319,20 @@ public:
bool hasGeneratedNodes() { return HasGeneratedNodes; }
void takeNodes(const ExplodedNodeSet &S) {
- for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I )
- Frontier.erase(*I);
+ for (const auto I : S)
+ Frontier.erase(I);
}
+
void takeNodes(ExplodedNode *N) { Frontier.erase(N); }
void addNodes(const ExplodedNodeSet &S) { Frontier.insert(S); }
void addNodes(ExplodedNode *N) { Frontier.Add(N); }
};
/// \class NodeBuilderWithSinks
-/// \brief This node builder keeps track of the generated sink nodes.
+/// This node builder keeps track of the generated sink nodes.
class NodeBuilderWithSinks: public NodeBuilder {
void anchor() override;
+
protected:
SmallVector<ExplodedNode*, 2> sinksGenerated;
ProgramPoint &Location;
@@ -319,7 +340,7 @@ protected:
public:
NodeBuilderWithSinks(ExplodedNode *Pred, ExplodedNodeSet &DstSet,
const NodeBuilderContext &Ctx, ProgramPoint &L)
- : NodeBuilder(Pred, DstSet, Ctx), Location(L) {}
+ : NodeBuilder(Pred, DstSet, Ctx), Location(L) {}
ExplodedNode *generateNode(ProgramStateRef State,
ExplodedNode *Pred,
@@ -343,20 +364,20 @@ public:
};
/// \class StmtNodeBuilder
-/// \brief This builder class is useful for generating nodes that resulted from
+/// This builder class is useful for generating nodes that resulted from
/// visiting a statement. The main difference from its parent NodeBuilder is
/// that it creates a statement specific ProgramPoint.
class StmtNodeBuilder: public NodeBuilder {
NodeBuilder *EnclosingBldr;
-public:
- /// \brief Constructs a StmtNodeBuilder. If the builder is going to process
+public:
+ /// Constructs a StmtNodeBuilder. If the builder is going to process
/// nodes currently owned by another builder(with larger scope), use
/// Enclosing builder to transfer ownership.
StmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
const NodeBuilderContext &Ctx,
NodeBuilder *Enclosing = nullptr)
- : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) {
+ : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) {
if (EnclosingBldr)
EnclosingBldr->takeNodes(SrcNode);
}
@@ -364,11 +385,10 @@ public:
StmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
const NodeBuilderContext &Ctx,
NodeBuilder *Enclosing = nullptr)
- : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) {
+ : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) {
if (EnclosingBldr)
- for (ExplodedNodeSet::iterator I = SrcSet.begin(),
- E = SrcSet.end(); I != E; ++I )
- EnclosingBldr->takeNodes(*I);
+ for (const auto I : SrcSet)
+ EnclosingBldr->takeNodes(I);
}
~StmtNodeBuilder() override;
@@ -397,22 +417,23 @@ public:
}
};
-/// \brief BranchNodeBuilder is responsible for constructing the nodes
+/// BranchNodeBuilder is responsible for constructing the nodes
/// corresponding to the two branches of the if statement - true and false.
class BranchNodeBuilder: public NodeBuilder {
- void anchor() override;
const CFGBlock *DstT;
const CFGBlock *DstF;
bool InFeasibleTrue;
bool InFeasibleFalse;
+ void anchor() override;
+
public:
BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
const NodeBuilderContext &C,
const CFGBlock *dstT, const CFGBlock *dstF)
- : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF),
- InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
+ : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF),
+ InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
// The branch node builder does not generate autotransitions.
// If there are no successors it means that both branches are infeasible.
takeNodes(SrcNode);
@@ -421,8 +442,8 @@ public:
BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
const NodeBuilderContext &C,
const CFGBlock *dstT, const CFGBlock *dstF)
- : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF),
- InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
+ : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF),
+ InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
takeNodes(SrcSet);
}
@@ -455,15 +476,16 @@ class IndirectGotoNodeBuilder {
public:
IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
const Expr *e, const CFGBlock *dispatch, CoreEngine* eng)
- : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
+ : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
class iterator {
+ friend class IndirectGotoNodeBuilder;
+
CFGBlock::const_succ_iterator I;
- friend class IndirectGotoNodeBuilder;
iterator(CFGBlock::const_succ_iterator i) : I(i) {}
- public:
+ public:
iterator &operator++() { ++I; return *this; }
bool operator!=(const iterator &X) const { return I != X.I; }
@@ -501,12 +523,13 @@ class SwitchNodeBuilder {
public:
SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
const Expr *condition, CoreEngine* eng)
- : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
+ : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
class iterator {
+ friend class SwitchNodeBuilder;
+
CFGBlock::const_succ_reverse_iterator I;
- friend class SwitchNodeBuilder;
iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {}
public:
@@ -545,7 +568,8 @@ public:
}
};
-} // end ento namespace
-} // end clang namespace
+} // namespace ento
+
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
index e13c6410c7be9..092e23ce73c8b 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
@@ -14,7 +14,7 @@
namespace clang {
namespace ento {
-/// \brief Stores the currently inferred strictest bound on the runtime type
+/// Stores the currently inferred strictest bound on the runtime type
/// of a region in a given state along the analysis path.
class DynamicTypeInfo {
private:
@@ -27,13 +27,13 @@ public:
DynamicTypeInfo(QualType WithType, bool CanBeSub = true)
: T(WithType), CanBeASubClass(CanBeSub) {}
- /// \brief Return false if no dynamic type info is available.
+ /// Return false if no dynamic type info is available.
bool isValid() const { return !T.isNull(); }
- /// \brief Returns the currently inferred upper bound on the runtime type.
+ /// Returns the currently inferred upper bound on the runtime type.
QualType getType() const { return T; }
- /// \brief Returns false if the type information is precise (the type T is
+ /// Returns false if the type information is precise (the type T is
/// the only type in the lattice), true otherwise.
bool canBeASubClass() const { return CanBeASubClass; }
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h
index 555191d997099..2f8ead0746cac 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h
@@ -1,4 +1,4 @@
-//== DynamicTypeMap.h - Dynamic type map ----------------------- -*- C++ -*--=//
+//===- DynamicTypeMap.h - Dynamic type map ----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -13,19 +13,26 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/ImmutableMap.h"
+#include "clang/AST/Type.h"
namespace clang {
namespace ento {
+class MemRegion;
+
/// The GDM component containing the dynamic type info. This is a map from a
/// symbol to its most likely type.
struct DynamicTypeMap {};
-typedef llvm::ImmutableMap<const MemRegion *, DynamicTypeInfo>
- DynamicTypeMapImpl;
+
+using DynamicTypeMapImpl =
+ llvm::ImmutableMap<const MemRegion *, DynamicTypeInfo>;
+
template <>
struct ProgramStateTrait<DynamicTypeMap>
: public ProgramStatePartialTrait<DynamicTypeMapImpl> {
@@ -35,15 +42,15 @@ struct ProgramStateTrait<DynamicTypeMap>
}
};
-/// \brief Get dynamic type information for a region.
+/// Get dynamic type information for a region.
DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State,
const MemRegion *Reg);
-/// \brief Set dynamic type information of the region; return the new state.
+/// Set dynamic type information of the region; return the new state.
ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *Reg,
DynamicTypeInfo NewTy);
-/// \brief Set dynamic type information of the region; return the new state.
+/// Set dynamic type information of the region; return the new state.
inline ProgramStateRef setDynamicTypeInfo(ProgramStateRef State,
const MemRegion *Reg, QualType NewTy,
bool CanBeSubClassed = true) {
@@ -51,7 +58,10 @@ inline ProgramStateRef setDynamicTypeInfo(ProgramStateRef State,
DynamicTypeInfo(NewTy, CanBeSubClassed));
}
-} // ento
-} // clang
+void printDynamicTypeInfo(ProgramStateRef State, raw_ostream &Out,
+ const char *NL, const char *Sep);
+
+} // namespace ento
+} // namespace clang
#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index c63ed4a013aa6..d49aa81bc9585 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -1,4 +1,4 @@
-//== Environment.h - Map from Stmt* to Locations/Values ---------*- C++ -*--==//
+//===- Environment.h - Map from Stmt* to Locations/Values -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,16 +15,17 @@
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H
#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/ImmutableMap.h"
+#include <utility>
namespace clang {
-class LiveVariables;
+class Stmt;
namespace ento {
-class EnvironmentManager;
class SValBuilder;
class SymbolReaper;
@@ -32,7 +33,7 @@ class SymbolReaper;
/// This allows the environment to manage context-sensitive bindings,
/// which is essentially for modeling recursive function analysis, among
/// other things.
-class EnvironmentEntry : public std::pair<const Stmt*,
+class EnvironmentEntry : public std::pair<const Stmt *,
const StackFrameContext *> {
public:
EnvironmentEntry(const Stmt *s, const LocationContext *L);
@@ -57,19 +58,17 @@ class Environment {
private:
friend class EnvironmentManager;
- // Type definitions.
- typedef llvm::ImmutableMap<EnvironmentEntry, SVal> BindingsTy;
+ using BindingsTy = llvm::ImmutableMap<EnvironmentEntry, SVal>;
- // Data.
BindingsTy ExprBindings;
- Environment(BindingsTy eb)
- : ExprBindings(eb) {}
+ Environment(BindingsTy eb) : ExprBindings(eb) {}
SVal lookupExpr(const EnvironmentEntry &E) const;
public:
- typedef BindingsTy::iterator iterator;
+ using iterator = BindingsTy::iterator;
+
iterator begin() const { return ExprBindings.begin(); }
iterator end() const { return ExprBindings.end(); }
@@ -92,21 +91,19 @@ public:
bool operator==(const Environment& RHS) const {
return ExprBindings == RHS.ExprBindings;
}
-
- void print(raw_ostream &Out, const char *NL, const char *Sep) const;
-
-private:
- void printAux(raw_ostream &Out, bool printLocations,
- const char *NL, const char *Sep) const;
+
+ void print(raw_ostream &Out, const char *NL, const char *Sep,
+ const LocationContext *WithLC = nullptr) const;
};
class EnvironmentManager {
private:
- typedef Environment::BindingsTy::Factory FactoryTy;
+ using FactoryTy = Environment::BindingsTy::Factory;
+
FactoryTy F;
public:
- EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {}
+ EnvironmentManager(llvm::BumpPtrAllocator &Allocator) : F(Allocator) {}
Environment getInitialEnvironment() {
return Environment(F.getEmptyMap());
@@ -121,8 +118,8 @@ public:
ProgramStateRef state);
};
-} // end GR namespace
+} // namespace ento
-} // end clang namespace
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ENVIRONMENT_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index dcea5e461d27c..c12198db6598d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -1,4 +1,4 @@
-//=-- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -*- C++ -*-------==//
+//===- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -19,17 +19,25 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H
-#include "clang/AST/Decl.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Analysis/Support/BumpVector.h"
+#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include <cassert>
+#include <cstdint>
#include <memory>
#include <utility>
#include <vector>
@@ -37,6 +45,10 @@
namespace clang {
class CFG;
+class Decl;
+class Expr;
+class ParentMap;
+class Stmt;
namespace ento {
@@ -52,13 +64,13 @@ class ExplodedGraph;
// successors to it at any time after creating it.
class ExplodedNode : public llvm::FoldingSetNode {
- friend class ExplodedGraph;
- friend class CoreEngine;
- friend class NodeBuilder;
friend class BranchNodeBuilder;
+ friend class CoreEngine;
+ friend class EndOfFunctionNodeBuilder;
+ friend class ExplodedGraph;
friend class IndirectGotoNodeBuilder;
+ friend class NodeBuilder;
friend class SwitchNodeBuilder;
- friend class EndOfFunctionNodeBuilder;
/// Efficiently stores a list of ExplodedNodes, or an optional flag.
///
@@ -135,7 +147,7 @@ public:
}
const StackFrameContext *getStackFrame() const {
- return getLocationContext()->getCurrentStackFrame();
+ return getLocation().getStackFrame();
}
const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); }
@@ -156,6 +168,11 @@ public:
return Location.getAs<T>();
}
+ /// Get the value of an arbitrary expression at this node.
+ SVal getSVal(const Stmt *S) const {
+ return getState()->getSVal(S, getLocationContext());
+ }
+
static void Profile(llvm::FoldingSetNodeID &ID,
const ProgramPoint &Loc,
const ProgramStateRef &state,
@@ -198,10 +215,10 @@ public:
}
// Iterators over successor and predecessor vertices.
- typedef ExplodedNode* const * succ_iterator;
- typedef const ExplodedNode* const * const_succ_iterator;
- typedef ExplodedNode* const * pred_iterator;
- typedef const ExplodedNode* const * const_pred_iterator;
+ using succ_iterator = ExplodedNode * const *;
+ using const_succ_iterator = const ExplodedNode * const *;
+ using pred_iterator = ExplodedNode * const *;
+ using const_pred_iterator = const ExplodedNode * const *;
pred_iterator pred_begin() { return Preds.begin(); }
pred_iterator pred_end() { return Preds.end(); }
@@ -226,10 +243,10 @@ public:
// For debugging.
public:
-
class Auditor {
public:
virtual ~Auditor();
+
virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst) = 0;
};
@@ -240,15 +257,15 @@ private:
void replacePredecessor(ExplodedNode *node) { Preds.replaceNode(node); }
};
-typedef llvm::DenseMap<const ExplodedNode *, const ExplodedNode *>
- InterExplodedGraphMap;
+using InterExplodedGraphMap =
+ llvm::DenseMap<const ExplodedNode *, const ExplodedNode *>;
class ExplodedGraph {
protected:
friend class CoreEngine;
// Type definitions.
- typedef std::vector<ExplodedNode *> NodeVector;
+ using NodeVector = std::vector<ExplodedNode *>;
/// The roots of the simulation graph. Usually there will be only
/// one, but clients are free to establish multiple subgraphs within a single
@@ -268,7 +285,7 @@ protected:
BumpVectorContext BVC;
/// NumNodes - The number of nodes in the graph.
- unsigned NumNodes;
+ unsigned NumNodes = 0;
/// A list of recently allocated nodes that can potentially be recycled.
NodeVector ChangedNodes;
@@ -279,14 +296,16 @@ protected:
/// Determines how often nodes are reclaimed.
///
/// If this is 0, nodes will never be reclaimed.
- unsigned ReclaimNodeInterval;
+ unsigned ReclaimNodeInterval = 0;
/// Counter to determine when to reclaim nodes.
unsigned ReclaimCounter;
public:
+ ExplodedGraph();
+ ~ExplodedGraph();
- /// \brief Retrieve the node associated with a (Location,State) pair,
+ /// Retrieve the node associated with a (Location,State) pair,
/// where the 'Location' is a ProgramPoint in the CFG. If no node for
/// this pair exists, it is created. IsNew is set to true if
/// the node was freshly created.
@@ -294,7 +313,7 @@ public:
bool IsSink = false,
bool* IsNew = nullptr);
- /// \brief Create a node for a (Location, State) pair,
+ /// Create a node for a (Location, State) pair,
/// but don't store it for deduplication later. This
/// is useful when copying an already completed
/// ExplodedGraph for further processing.
@@ -318,10 +337,6 @@ public:
return V;
}
- ExplodedGraph();
-
- ~ExplodedGraph();
-
unsigned num_roots() const { return Roots.size(); }
unsigned num_eops() const { return EndNodes.size(); }
@@ -331,14 +346,14 @@ public:
void reserve(unsigned NodeCount) { Nodes.reserve(NodeCount); }
// Iterators.
- typedef ExplodedNode NodeTy;
- typedef llvm::FoldingSet<ExplodedNode> AllNodesTy;
- typedef NodeVector::iterator roots_iterator;
- typedef NodeVector::const_iterator const_roots_iterator;
- typedef NodeVector::iterator eop_iterator;
- typedef NodeVector::const_iterator const_eop_iterator;
- typedef AllNodesTy::iterator node_iterator;
- typedef AllNodesTy::const_iterator const_node_iterator;
+ using NodeTy = ExplodedNode;
+ using AllNodesTy = llvm::FoldingSet<ExplodedNode>;
+ using roots_iterator = NodeVector::iterator;
+ using const_roots_iterator = NodeVector::const_iterator;
+ using eop_iterator = NodeVector::iterator;
+ using const_eop_iterator = NodeVector::const_iterator;
+ using node_iterator = AllNodesTy::iterator;
+ using const_node_iterator = AllNodesTy::const_iterator;
node_iterator nodes_begin() { return Nodes.begin(); }
@@ -367,7 +382,7 @@ public:
llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); }
BumpVectorContext &getNodeAllocator() { return BVC; }
- typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> NodeMap;
+ using NodeMap = llvm::DenseMap<const ExplodedNode *, ExplodedNode *>;
/// Creates a trimmed version of the graph that only contains paths leading
/// to the given nodes.
@@ -394,7 +409,7 @@ public:
/// was called.
void reclaimRecentlyAllocatedNodes();
- /// \brief Returns true if nodes for the given expression kind are always
+ /// Returns true if nodes for the given expression kind are always
/// kept around.
static bool isInterestingLValueExpr(const Expr *Ex);
@@ -404,29 +419,30 @@ private:
};
class ExplodedNodeSet {
- typedef llvm::SmallSetVector<ExplodedNode*, 4> ImplTy;
+ using ImplTy = llvm::SmallSetVector<ExplodedNode *, 4>;
ImplTy Impl;
public:
ExplodedNodeSet(ExplodedNode *N) {
- assert (N && !static_cast<ExplodedNode*>(N)->isSink());
+ assert(N && !static_cast<ExplodedNode*>(N)->isSink());
Impl.insert(N);
}
- ExplodedNodeSet() {}
+ ExplodedNodeSet() = default;
- inline void Add(ExplodedNode *N) {
+ void Add(ExplodedNode *N) {
if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N);
}
- typedef ImplTy::iterator iterator;
- typedef ImplTy::const_iterator const_iterator;
+ using iterator = ImplTy::iterator;
+ using const_iterator = ImplTy::const_iterator;
unsigned size() const { return Impl.size(); }
bool empty() const { return Impl.empty(); }
bool erase(ExplodedNode *N) { return Impl.remove(N); }
void clear() { Impl.clear(); }
+
void insert(const ExplodedNodeSet &S) {
assert(&S != this);
if (empty())
@@ -435,24 +451,25 @@ public:
Impl.insert(S.begin(), S.end());
}
- inline iterator begin() { return Impl.begin(); }
- inline iterator end() { return Impl.end(); }
+ iterator begin() { return Impl.begin(); }
+ iterator end() { return Impl.end(); }
- inline const_iterator begin() const { return Impl.begin(); }
- inline const_iterator end() const { return Impl.end(); }
+ const_iterator begin() const { return Impl.begin(); }
+ const_iterator end() const { return Impl.end(); }
};
-} // end GR namespace
+} // namespace ento
-} // end clang namespace
+} // namespace clang
// GraphTraits
namespace llvm {
+
template<> struct GraphTraits<clang::ento::ExplodedNode*> {
- typedef clang::ento::ExplodedNode *NodeRef;
- typedef clang::ento::ExplodedNode::succ_iterator ChildIteratorType;
- typedef llvm::df_iterator<NodeRef> nodes_iterator;
+ using NodeRef = clang::ento::ExplodedNode *;
+ using ChildIteratorType = clang::ento::ExplodedNode::succ_iterator;
+ using nodes_iterator = llvm::df_iterator<NodeRef>;
static NodeRef getEntryNode(NodeRef N) { return N; }
@@ -466,9 +483,9 @@ namespace llvm {
};
template<> struct GraphTraits<const clang::ento::ExplodedNode*> {
- typedef const clang::ento::ExplodedNode *NodeRef;
- typedef clang::ento::ExplodedNode::const_succ_iterator ChildIteratorType;
- typedef llvm::df_iterator<NodeRef> nodes_iterator;
+ using NodeRef = const clang::ento::ExplodedNode *;
+ using ChildIteratorType = clang::ento::ExplodedNode::const_succ_iterator;
+ using nodes_iterator = llvm::df_iterator<NodeRef>;
static NodeRef getEntryNode(NodeRef N) { return N; }
@@ -481,6 +498,6 @@ namespace llvm {
static nodes_iterator nodes_end(NodeRef N) { return df_end(N); }
};
-} // end llvm namespace
+} // namespace llvm
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 712cd6361e118..25849e94c8ff1 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -1,4 +1,4 @@
-//===-- ExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-=//
+//===- ExprEngine.h - Path-Sensitive Expression-Level Dataflow --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -18,32 +18,68 @@
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
+#include "llvm/ADT/ArrayRef.h"
+#include <cassert>
+#include <utility>
namespace clang {
class AnalysisDeclContextManager;
+class AnalyzerOptions;
+class ASTContext;
+class ConstructionContext;
+class CXXBindTemporaryExpr;
class CXXCatchStmt;
class CXXConstructExpr;
class CXXDeleteExpr;
class CXXNewExpr;
-class CXXTemporaryObjectExpr;
class CXXThisExpr;
+class Decl;
+class DeclStmt;
+class GCCAsmStmt;
+class LambdaExpr;
+class LocationContext;
class MaterializeTemporaryExpr;
+class MSAsmStmt;
+class NamedDecl;
class ObjCAtSynchronizedStmt;
class ObjCForCollectionStmt;
+class ObjCIvarRefExpr;
+class ObjCMessageExpr;
+class ReturnStmt;
+class Stmt;
+
+namespace cross_tu {
+
+class CrossTranslationUnitContext;
+
+} // namespace cross_tu
namespace ento {
-class AnalysisManager;
+class BasicValueFactory;
class CallEvent;
-class CXXConstructorCall;
+class CheckerManager;
+class ConstraintManager;
+class CXXTempObjectRegion;
+class MemRegion;
+class RegionAndSymbolInvalidationTraits;
+class SymbolManager;
class ExprEngine : public SubEngine {
public:
@@ -51,11 +87,35 @@ public:
enum InliningModes {
/// Follow the default settings for inlining callees.
Inline_Regular = 0,
+
/// Do minimal inlining of callees.
Inline_Minimal = 0x1
};
+ /// Hints for figuring out of a call should be inlined during evalCall().
+ struct EvalCallOptions {
+ /// This call is a constructor or a destructor for which we do not currently
+ /// compute the this-region correctly.
+ bool IsCtorOrDtorWithImproperlyModeledTargetRegion = false;
+
+ /// This call is a constructor or a destructor for a single element within
+ /// an array, a part of array construction or destruction.
+ bool IsArrayCtorOrDtor = false;
+
+ /// This call is a constructor or a destructor of a temporary value.
+ bool IsTemporaryCtorOrDtor = false;
+
+ /// This call is a constructor for a temporary that is lifetime-extended
+ /// by binding it to a reference-type field within an aggregate,
+ /// for example 'A { const C &c; }; A a = { C() };'
+ bool IsTemporaryLifetimeExtendedViaAggregate = false;
+
+ EvalCallOptions() {}
+ };
+
private:
+ cross_tu::CrossTranslationUnitContext &CTU;
+
AnalysisManager &AMgr;
AnalysisDeclContextManager &AnalysisDeclContexts;
@@ -63,19 +123,19 @@ private:
CoreEngine Engine;
/// G - the simulation graph.
- ExplodedGraph& G;
+ ExplodedGraph &G;
/// StateMgr - Object that manages the data for all created states.
ProgramStateManager StateMgr;
/// SymMgr - Object that manages the symbol information.
- SymbolManager& SymMgr;
+ SymbolManager &SymMgr;
/// svalBuilder - SValBuilder object that creates SVals from expressions.
SValBuilder &svalBuilder;
- unsigned int currStmtIdx;
- const NodeBuilderContext *currBldrCtx;
+ unsigned int currStmtIdx = 0;
+ const NodeBuilderContext *currBldrCtx = nullptr;
/// Helper object to determine if an Objective-C message expression
/// implicitly never returns.
@@ -97,10 +157,9 @@ private:
InliningModes HowToInline;
public:
- ExprEngine(AnalysisManager &mgr, bool gcEnabled,
- SetOfConstDecls *VisitedCalleesIn,
- FunctionSummariesTy *FS,
- InliningModes HowToInlineIn);
+ ExprEngine(cross_tu::CrossTranslationUnitContext &CTU, AnalysisManager &mgr,
+ bool gcEnabled, SetOfConstDecls *VisitedCalleesIn,
+ FunctionSummariesTy *FS, InliningModes HowToInlineIn);
~ExprEngine() override;
@@ -130,7 +189,12 @@ public:
SValBuilder &getSValBuilder() { return svalBuilder; }
- BugReporter& getBugReporter() { return BR; }
+ BugReporter &getBugReporter() { return BR; }
+
+ cross_tu::CrossTranslationUnitContext *
+ getCrossTranslationUnitContext() override {
+ return &CTU;
+ }
const NodeBuilderContext &getBuilderContext() {
assert(currBldrCtx);
@@ -150,16 +214,16 @@ public:
/// Visualize a trimmed ExplodedGraph that only contains paths to the given
/// nodes.
- void ViewGraph(ArrayRef<const ExplodedNode*> Nodes);
+ void ViewGraph(ArrayRef<const ExplodedNode *> Nodes);
/// getInitialState - Return the initial state used for the root vertex
/// in the ExplodedGraph.
ProgramStateRef getInitialState(const LocationContext *InitLoc) override;
- ExplodedGraph& getGraph() { return G; }
- const ExplodedGraph& getGraph() const { return G; }
+ ExplodedGraph &getGraph() { return G; }
+ const ExplodedGraph &getGraph() const { return G; }
- /// \brief Run the analyzer's garbage collection - remove dead symbols and
+ /// Run the analyzer's garbage collection - remove dead symbols and
/// bindings from the state.
///
/// Checkers can participate in this process with two callbacks:
@@ -194,7 +258,7 @@ public:
void processCFGElement(const CFGElement E, ExplodedNode *Pred,
unsigned StmtIdx, NodeBuilderContext *Ctx) override;
- void ProcessStmt(const CFGStmt S, ExplodedNode *Pred);
+ void ProcessStmt(const Stmt *S, ExplodedNode *Pred);
void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred);
@@ -299,25 +363,26 @@ public:
const CallEvent *Call) override;
/// printState - Called by ProgramStateManager to print checker-specific data.
- void printState(raw_ostream &Out, ProgramStateRef State,
- const char *NL, const char *Sep) override;
+ void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
+ const char *Sep,
+ const LocationContext *LCtx = nullptr) override;
- ProgramStateManager& getStateManager() override { return StateMgr; }
+ ProgramStateManager &getStateManager() override { return StateMgr; }
- StoreManager& getStoreManager() { return StateMgr.getStoreManager(); }
+ StoreManager &getStoreManager() { return StateMgr.getStoreManager(); }
- ConstraintManager& getConstraintManager() {
+ ConstraintManager &getConstraintManager() {
return StateMgr.getConstraintManager();
}
// FIXME: Remove when we migrate over to just using SValBuilder.
- BasicValueFactory& getBasicVals() {
+ BasicValueFactory &getBasicVals() {
return StateMgr.getBasicVals();
}
// FIXME: Remove when we migrate over to just using ValueManager.
- SymbolManager& getSymbolManager() { return SymMgr; }
- const SymbolManager& getSymbolManager() const { return SymMgr; }
+ SymbolManager &getSymbolManager() { return SymMgr; }
+ const SymbolManager &getSymbolManager() const { return SymMgr; }
// Functions for external checking of whether we have unfinished work
bool wasBlocksExhausted() const { return Engine.wasBlocksExhausted(); }
@@ -363,7 +428,7 @@ public:
/// VisitCast - Transfer function logic for all casts (implicit and explicit).
void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred,
- ExplodedNodeSet &Dst);
+ ExplodedNodeSet &Dst);
/// VisitCompoundLiteralExpr - Transfer function logic for compound literals.
void VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
@@ -390,9 +455,9 @@ public:
/// VisitMemberExpr - Transfer function for member expressions.
void VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
- ExplodedNodeSet &Dst);
+ ExplodedNodeSet &Dst);
- /// VisitMemberExpr - Transfer function for builtin atomic expressions
+ /// VisitAtomicExpr - Transfer function for builtin atomic expressions
void VisitAtomicExpr(const AtomicExpr *E, ExplodedNode *Pred,
ExplodedNodeSet &Dst);
@@ -422,7 +487,7 @@ public:
/// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof.
void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
- ExplodedNode *Pred, ExplodedNodeSet &Dst);
+ ExplodedNode *Pred, ExplodedNodeSet &Dst);
/// VisitUnaryOperator - Transfer function logic for unary operators.
void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode *Pred,
@@ -448,7 +513,8 @@ public:
void VisitCXXDestructor(QualType ObjectType, const MemRegion *Dest,
const Stmt *S, bool IsBaseDtor,
- ExplodedNode *Pred, ExplodedNodeSet &Dst);
+ ExplodedNode *Pred, ExplodedNodeSet &Dst,
+ const EvalCallOptions &Options);
void VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
ExplodedNode *Pred,
@@ -471,7 +537,7 @@ public:
void evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
const Expr *Ex);
- std::pair<const ProgramPointTag *, const ProgramPointTag*>
+ static std::pair<const ProgramPointTag *, const ProgramPointTag *>
geteagerlyAssumeBinOpBifurcationTags();
SVal evalMinus(SVal X) {
@@ -499,7 +565,6 @@ public:
StmtNodeBuilder &Bldr);
public:
-
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
NonLoc L, NonLoc R, QualType T) {
return svalBuilder.evalBinOpNN(state, op, L, R, T);
@@ -539,6 +604,11 @@ protected:
const CallEvent *Call,
RegionAndSymbolInvalidationTraits &ITraits) override;
+ /// A simple wrapper when you only need to notify checkers of pointer-escape
+ /// of a single value.
+ ProgramStateRef escapeValue(ProgramStateRef State, SVal V,
+ PointerEscapeKind K) const;
+
public:
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
@@ -561,7 +631,13 @@ public:
ExplodedNode *Pred, ProgramStateRef St, SVal TargetLV, SVal Val,
const ProgramPointTag *tag = nullptr);
- /// \brief Create a new state in which the call return value is binded to the
+ /// Return the CFG element corresponding to the worklist element
+ /// that is currently being processed by ExprEngine.
+ CFGElement getCurrentCFGElement() {
+ return (*currBldrCtx->getBlock())[currStmtIdx];
+ }
+
+ /// Create a new state in which the call return value is binded to the
/// call origin expression.
ProgramStateRef bindReturnValue(const CallEvent &Call,
const LocationContext *LCtx,
@@ -572,9 +648,11 @@ public:
void evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
const CallEvent &Call);
- /// \brief Default implementation of call evaluation.
+ /// Default implementation of call evaluation.
void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred,
- const CallEvent &Call);
+ const CallEvent &Call,
+ const EvalCallOptions &CallOpts = {});
+
private:
void evalLoadCommon(ExplodedNodeSet &Dst,
const Expr *NodeEx, /* Eventually will be a CFGStmt */
@@ -598,19 +676,33 @@ private:
void examineStackFrames(const Decl *D, const LocationContext *LCtx,
bool &IsRecursive, unsigned &StackDepth);
+ enum CallInlinePolicy {
+ CIP_Allowed,
+ CIP_DisallowedOnce,
+ CIP_DisallowedAlways
+ };
+
+ /// See if a particular call should be inlined, by only looking
+ /// at the call event and the current state of analysis.
+ CallInlinePolicy mayInlineCallKind(const CallEvent &Call,
+ const ExplodedNode *Pred,
+ AnalyzerOptions &Opts,
+ const EvalCallOptions &CallOpts);
+
/// Checks our policies and decides weither the given call should be inlined.
bool shouldInlineCall(const CallEvent &Call, const Decl *D,
- const ExplodedNode *Pred);
+ const ExplodedNode *Pred,
+ const EvalCallOptions &CallOpts = {});
bool inlineCall(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr,
ExplodedNode *Pred, ProgramStateRef State);
- /// \brief Conservatively evaluate call by invalidating regions and binding
+ /// Conservatively evaluate call by invalidating regions and binding
/// a conjured return value.
void conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
ExplodedNode *Pred, ProgramStateRef State);
- /// \brief Either inline or process the call conservatively (or both), based
+ /// Either inline or process the call conservatively (or both), based
/// on DynamicDispatchBifurcation data.
void BifurcateCall(const MemRegion *BifurReg,
const CallEvent &Call, const Decl *D, NodeBuilder &Bldr,
@@ -634,6 +726,17 @@ private:
const Expr *InitWithAdjustments,
const Expr *Result = nullptr);
+ /// Returns a region representing the first element of a (possibly
+ /// multi-dimensional) array, for the purposes of element construction or
+ /// destruction.
+ ///
+ /// On return, \p Ty will be set to the base type of the array.
+ ///
+ /// If the type is not an array type at all, the original value is returned.
+ /// Otherwise the "IsArray" flag is set.
+ static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue,
+ QualType &Ty, bool &IsArray);
+
/// For a DeclStmt or CXXInitCtorInitializer, walk backward in the current CFG
/// block to find the constructor expression that directly constructed into
/// the storage for this statement. Returns null if the constructor for this
@@ -641,20 +744,69 @@ private:
/// constructing into an existing region.
const CXXConstructExpr *findDirectConstructorForCurrentCFGElement();
- /// For a CXXConstructExpr, walk forward in the current CFG block to find the
- /// CFGElement for the DeclStmt or CXXInitCtorInitializer for which is
- /// directly constructed by this constructor. Returns None if the current
- /// constructor expression did not directly construct into an existing
- /// region.
- Optional<CFGElement> findElementDirectlyInitializedByCurrentConstructor();
-
- /// For a given constructor, look forward in the current CFG block to
- /// determine the region into which an object will be constructed by \p CE.
- /// Returns either a field or local variable region if the object will be
- /// directly constructed in an existing region or a temporary object region
- /// if not.
- const MemRegion *getRegionForConstructedObject(const CXXConstructExpr *CE,
- ExplodedNode *Pred);
+ /// Update the program state with all the path-sensitive information
+ /// that's necessary to perform construction of an object with a given
+ /// syntactic construction context. If the construction context is unavailable
+ /// or unusable for any reason, a dummy temporary region is returned, and the
+ /// IsConstructorWithImproperlyModeledTargetRegion flag is set in \p CallOpts.
+ /// Returns the updated program state and the new object's this-region.
+ std::pair<ProgramStateRef, SVal> prepareForObjectConstruction(
+ const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
+ const ConstructionContext *CC, EvalCallOptions &CallOpts);
+
+ /// Store the location of a C++ object corresponding to a statement
+ /// until the statement is actually encountered. For example, if a DeclStmt
+ /// has CXXConstructExpr as its initializer, the object would be considered
+ /// to be "under construction" between CXXConstructExpr and DeclStmt.
+ /// This allows, among other things, to keep bindings to variable's fields
+ /// made within the constructor alive until its declaration actually
+ /// goes into scope.
+ static ProgramStateRef addObjectUnderConstruction(
+ ProgramStateRef State,
+ llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P,
+ const LocationContext *LC, SVal V);
+
+ /// Mark the object sa fully constructed, cleaning up the state trait
+ /// that tracks objects under construction.
+ static ProgramStateRef finishObjectConstruction(
+ ProgramStateRef State,
+ llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P,
+ const LocationContext *LC);
+
+ /// If the given statement corresponds to an object under construction,
+ /// being part of its construciton context, retrieve that object's location.
+ static Optional<SVal> getObjectUnderConstruction(
+ ProgramStateRef State,
+ llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P,
+ const LocationContext *LC);
+
+ /// If the given expression corresponds to a temporary that was used for
+ /// passing into an elidable copy/move constructor and that constructor
+ /// was actually elided, track that we also need to elide the destructor.
+ static ProgramStateRef elideDestructor(ProgramStateRef State,
+ const CXXBindTemporaryExpr *BTE,
+ const LocationContext *LC);
+
+ /// Stop tracking the destructor that corresponds to an elided constructor.
+ static ProgramStateRef
+ cleanupElidedDestructor(ProgramStateRef State,
+ const CXXBindTemporaryExpr *BTE,
+ const LocationContext *LC);
+
+ /// Returns true if the given expression corresponds to a temporary that
+ /// was constructed for passing into an elidable copy/move constructor
+ /// and that constructor was actually elided.
+ static bool isDestructorElided(ProgramStateRef State,
+ const CXXBindTemporaryExpr *BTE,
+ const LocationContext *LC);
+
+ /// Check if all objects under construction have been fully constructed
+ /// for the given context range (including FromLC, not including ToLC).
+ /// This is useful for assertions. Also checks if elided destructors
+ /// were cleaned up.
+ static bool areAllObjectsFullyConstructed(ProgramStateRef State,
+ const LocationContext *FromLC,
+ const LocationContext *ToLC);
};
/// Traits for storing the call processing policy inside GDM.
@@ -668,8 +820,8 @@ struct ProgramStateTrait<ReplayWithoutInlining> :
static void *GDMIndex() { static int index = 0; return &index; }
};
-} // end ento namespace
+} // namespace ento
-} // end clang namespace
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPRENGINE_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
index ce81c98c206b2..b70faa10f0b2c 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
@@ -1,4 +1,4 @@
-//== FunctionSummary.h - Stores summaries of functions. ------------*- C++ -*-//
+//===- FunctionSummary.h - Stores summaries of functions. -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -18,15 +18,18 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallBitVector.h"
+#include <cassert>
#include <deque>
+#include <utility>
namespace clang {
-
namespace ento {
-typedef std::deque<Decl*> SetOfDecls;
-typedef llvm::DenseSet<const Decl*> SetOfConstDecls;
+
+using SetOfDecls = std::deque<Decl *>;
+using SetOfConstDecls = llvm::DenseSet<const Decl *>;
class FunctionSummariesTy {
class FunctionSummary {
@@ -47,13 +50,12 @@ class FunctionSummariesTy {
/// The number of times the function has been inlined.
unsigned TimesInlined : 32;
- FunctionSummary() :
- TotalBasicBlocks(0),
- InlineChecked(0),
- TimesInlined(0) {}
+ FunctionSummary()
+ : TotalBasicBlocks(0), InlineChecked(0), MayInline(0),
+ TimesInlined(0) {}
};
- typedef llvm::DenseMap<const Decl *, FunctionSummary> MapTy;
+ using MapTy = llvm::DenseMap<const Decl *, FunctionSummary>;
MapTy Map;
public:
@@ -62,7 +64,8 @@ public:
if (I != Map.end())
return I;
- typedef std::pair<const Decl *, FunctionSummary> KVPair;
+ using KVPair = std::pair<const Decl *, FunctionSummary>;
+
I = Map.insert(KVPair(D, FunctionSummary())).first;
assert(I != Map.end());
return I;
@@ -132,9 +135,9 @@ public:
unsigned getTotalNumBasicBlocks();
unsigned getTotalNumVisitedBasicBlocks();
-
};
-}} // end clang ento namespaces
+} // namespace ento
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_FUNCTIONSUMMARY_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h b/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
index 3168733e4258e..f494c5d6dab82 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
@@ -22,7 +22,7 @@
namespace clang {
namespace ento {
-/// \brief Get the states that result from widening the loop.
+/// Get the states that result from widening the loop.
///
/// Widen the loop by invalidating anything that might be modified
/// by the loop body in any iteration.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 8ab6656230888..f3846eba6b963 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -1,4 +1,4 @@
-//== MemRegion.h - Abstract memory regions for static analysis --*- C++ -*--==//
+//==- MemRegion.h - Abstract memory regions for static analysis -*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
@@ -19,24 +19,39 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "llvm/Support/Allocator.h"
-#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Casting.h"
+#include <cassert>
+#include <cstdint>
+#include <limits>
#include <string>
+#include <utility>
namespace clang {
+class AnalysisDeclContext;
+class CXXRecordDecl;
+class Decl;
class LocationContext;
class StackFrameContext;
namespace ento {
class CodeTextRegion;
+class MemRegion;
class MemRegionManager;
class MemSpaceRegion;
class SValBuilder;
@@ -46,7 +61,7 @@ class VarRegion;
/// Represent a region's offset within the top level base region.
class RegionOffset {
/// The base region.
- const MemRegion *R;
+ const MemRegion *R = nullptr;
/// The bit offset within the base region. Can be negative.
int64_t Offset;
@@ -54,9 +69,9 @@ class RegionOffset {
public:
// We're using a const instead of an enumeration due to the size required;
// Visual Studio will only create enumerations of size int, not long long.
- static const int64_t Symbolic = INT64_MAX;
+ static const int64_t Symbolic = std::numeric_limits<int64_t>::max();
- RegionOffset() : R(nullptr) {}
+ RegionOffset() = default;
RegionOffset(const MemRegion *r, int64_t off) : R(r), Offset(off) {}
const MemRegion *getRegion() const { return R; }
@@ -86,6 +101,7 @@ public:
private:
const Kind kind;
+ mutable Optional<RegionOffset> cachedOffset;
protected:
MemRegion(Kind k) : kind(k) {}
@@ -103,11 +119,12 @@ public:
const MemRegion *getBaseRegion() 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;
const MemRegion *StripCasts(bool StripBaseCasts = true) const;
- /// \brief If this is a symbolic region, returns the region. Otherwise,
+ /// If this is a symbolic region, returns the region. Otherwise,
/// goes up the base chain looking for the first symbolic base region.
const SymbolicRegion *getSymbolicBase() const;
@@ -122,24 +139,24 @@ public:
/// Compute the offset within the top level memory object.
RegionOffset getAsOffset() const;
- /// \brief Get a string representation of a region for debug use.
+ /// Get a string representation of a region for debug use.
std::string getString() const;
virtual void dumpToStream(raw_ostream &os) const;
void dump() const;
- /// \brief Returns true if this region can be printed in a user-friendly way.
+ /// Returns true if this region can be printed in a user-friendly way.
virtual bool canPrintPretty() const;
- /// \brief Print the region for use in diagnostics.
+ /// Print the region for use in diagnostics.
virtual void printPretty(raw_ostream &os) const;
- /// \brief Returns true if this region's textual representation can be used
+ /// Returns true if this region's textual representation can be used
/// as part of a larger expression.
virtual bool canPrintPrettyAsExpr() const;
- /// \brief Print the region as expression.
+ /// Print the region as expression.
///
/// When this region represents a subexpression, the method is for printing
/// an expression containing it.
@@ -151,7 +168,6 @@ public:
virtual bool isBoundable() const { return false; }
-
/// Get descriptive name for memory region. The name is obtained from
/// the variable/field declaration retrieved from the memory region.
/// Regions that point to an element of an array are returned as: "arr[0]".
@@ -162,7 +178,6 @@ public:
/// \returns variable name for memory region
std::string getDescriptiveName(bool UseQuotes = true) const;
-
/// Retrieve source range from memory region. The range retrieval
/// is based on the decl obtained from the memory region.
/// For a VarRegion the range of the base region is returned.
@@ -171,7 +186,7 @@ public:
/// The client is responsible for checking if the returned range is valid.
///
/// \returns source range for declaration retrieved from memory region
- clang::SourceRange sourceRange() const;
+ SourceRange sourceRange() const;
};
/// MemSpaceRegion - A memory region that represents a "memory space";
@@ -229,7 +244,7 @@ public:
}
};
-/// \brief The region of the static variables within the current CodeTextRegion
+/// The region of the static variables within the current CodeTextRegion
/// scope.
///
/// Currently, only the static locals are placed there, so we know that these
@@ -240,7 +255,7 @@ class StaticGlobalSpaceRegion : public GlobalsSpaceRegion {
const CodeTextRegion *CR;
StaticGlobalSpaceRegion(MemRegionManager *mgr, const CodeTextRegion *cr)
- : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) {
+ : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) {
assert(cr);
}
@@ -256,14 +271,14 @@ public:
}
};
-/// \brief The region for all the non-static global variables.
+/// The region for all the non-static global variables.
///
/// This class is further split into subclasses for efficient implementation of
/// invalidating a set of related global values as is done in
/// RegionStoreManager::invalidateRegions (instead of finding all the dependent
/// globals, we invalidate the whole parent region).
class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion {
- virtual void anchor() override;
+ void anchor() override;
protected:
NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k)
@@ -272,7 +287,6 @@ protected:
}
public:
-
static bool classof(const MemRegion *R) {
Kind k = R->getKind();
return k >= BEGIN_NON_STATIC_GLOBAL_MEMSPACES &&
@@ -280,16 +294,15 @@ public:
}
};
-/// \brief The region containing globals which are defined in system/external
+/// The region containing globals which are defined in system/external
/// headers and are considered modifiable by system calls (ex: errno).
class GlobalSystemSpaceRegion : public NonStaticGlobalSpaceRegion {
friend class MemRegionManager;
GlobalSystemSpaceRegion(MemRegionManager *mgr)
- : NonStaticGlobalSpaceRegion(mgr, GlobalSystemSpaceRegionKind) {}
+ : NonStaticGlobalSpaceRegion(mgr, GlobalSystemSpaceRegionKind) {}
public:
-
void dumpToStream(raw_ostream &os) const override;
static bool classof(const MemRegion *R) {
@@ -297,7 +310,7 @@ public:
}
};
-/// \brief The region containing globals which are considered not to be modified
+/// The region containing globals which are considered not to be modified
/// or point to data which could be modified as a result of a function call
/// (system or internal). Ex: Const global scalars would be modeled as part of
/// this region. This region also includes most system globals since they have
@@ -306,10 +319,9 @@ class GlobalImmutableSpaceRegion : public NonStaticGlobalSpaceRegion {
friend class MemRegionManager;
GlobalImmutableSpaceRegion(MemRegionManager *mgr)
- : NonStaticGlobalSpaceRegion(mgr, GlobalImmutableSpaceRegionKind) {}
+ : NonStaticGlobalSpaceRegion(mgr, GlobalImmutableSpaceRegionKind) {}
public:
-
void dumpToStream(raw_ostream &os) const override;
static bool classof(const MemRegion *R) {
@@ -317,17 +329,16 @@ public:
}
};
-/// \brief The region containing globals which can be modified by calls to
+/// The region containing globals which can be modified by calls to
/// "internally" defined functions - (for now just) functions other then system
/// calls.
class GlobalInternalSpaceRegion : public NonStaticGlobalSpaceRegion {
friend class MemRegionManager;
GlobalInternalSpaceRegion(MemRegionManager *mgr)
- : NonStaticGlobalSpaceRegion(mgr, GlobalInternalSpaceRegionKind) {}
+ : NonStaticGlobalSpaceRegion(mgr, GlobalInternalSpaceRegionKind) {}
public:
-
void dumpToStream(raw_ostream &os) const override;
static bool classof(const MemRegion *R) {
@@ -339,9 +350,9 @@ class HeapSpaceRegion : public MemSpaceRegion {
friend class MemRegionManager;
HeapSpaceRegion(MemRegionManager *mgr)
- : MemSpaceRegion(mgr, HeapSpaceRegionKind) {}
-public:
+ : MemSpaceRegion(mgr, HeapSpaceRegionKind) {}
+public:
void dumpToStream(raw_ostream &os) const override;
static bool classof(const MemRegion *R) {
@@ -351,11 +362,11 @@ public:
class UnknownSpaceRegion : public MemSpaceRegion {
friend class MemRegionManager;
+
UnknownSpaceRegion(MemRegionManager *mgr)
: MemSpaceRegion(mgr, UnknownSpaceRegionKind) {}
public:
-
void dumpToStream(raw_ostream &os) const override;
static bool classof(const MemRegion *R) {
@@ -370,7 +381,7 @@ class StackSpaceRegion : public MemSpaceRegion {
protected:
StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc)
- : MemSpaceRegion(mgr, k), SFC(sfc) {
+ : MemSpaceRegion(mgr, k), SFC(sfc) {
assert(classof(this));
assert(sfc);
}
@@ -388,10 +399,11 @@ public:
class StackLocalsSpaceRegion : public StackSpaceRegion {
friend class MemRegionManager;
+
StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
- : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {}
-public:
+ : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {}
+public:
void dumpToStream(raw_ostream &os) const override;
static bool classof(const MemRegion *R) {
@@ -402,10 +414,11 @@ public:
class StackArgumentsSpaceRegion : public StackSpaceRegion {
private:
friend class MemRegionManager;
+
StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
- : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {}
-public:
+ : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {}
+public:
void dumpToStream(raw_ostream &os) const override;
static bool classof(const MemRegion *R) {
@@ -413,7 +426,6 @@ public:
}
};
-
/// SubRegion - A region that subsets another larger region. Most regions
/// are subclasses of SubRegion.
class SubRegion : public MemRegion {
@@ -421,6 +433,7 @@ class SubRegion : public MemRegion {
protected:
const MemRegion* superRegion;
+
SubRegion(const MemRegion *sReg, Kind k) : MemRegion(k), superRegion(sReg) {
assert(classof(this));
assert(sReg);
@@ -454,8 +467,10 @@ public:
class AllocaRegion : public SubRegion {
friend class MemRegionManager;
- unsigned Cnt; // Block counter. Used to distinguish different pieces of
- // memory allocated by alloca at the same call site.
+ // Block counter. Used to distinguish different pieces of memory allocated by
+ // alloca at the same call site.
+ unsigned Cnt;
+
const Expr *Ex;
AllocaRegion(const Expr *ex, unsigned cnt, const MemSpaceRegion *superRegion)
@@ -467,7 +482,6 @@ class AllocaRegion : public SubRegion {
unsigned Cnt, const MemRegion *superRegion);
public:
-
const Expr *getExpr() const { return Ex; }
bool isBoundable() const override { return true; }
@@ -485,7 +499,7 @@ public:
/// TypedRegion - An abstract class representing regions that are typed.
class TypedRegion : public SubRegion {
- virtual void anchor() override;
+ void anchor() override;
protected:
TypedRegion(const MemRegion *sReg, Kind k) : SubRegion(sReg, k) {
@@ -509,7 +523,7 @@ public:
/// TypedValueRegion - An abstract class representing regions having a typed value.
class TypedValueRegion : public TypedRegion {
- virtual void anchor() override;
+ void anchor() override;
protected:
TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) {
@@ -541,9 +555,8 @@ public:
}
};
-
class CodeTextRegion : public TypedRegion {
- virtual void anchor() override;
+ void anchor() override;
protected:
CodeTextRegion(const MemSpaceRegion *sreg, Kind k) : TypedRegion(sreg, k) {
@@ -566,7 +579,7 @@ class FunctionCodeRegion : public CodeTextRegion {
const NamedDecl *FD;
FunctionCodeRegion(const NamedDecl *fd, const CodeSpaceRegion* sreg)
- : CodeTextRegion(sreg, FunctionCodeRegionKind), FD(fd) {
+ : CodeTextRegion(sreg, FunctionCodeRegionKind), FD(fd) {
assert(isa<ObjCMethodDecl>(fd) || isa<FunctionDecl>(fd));
}
@@ -576,7 +589,7 @@ class FunctionCodeRegion : public CodeTextRegion {
public:
QualType getLocationType() const override {
const ASTContext &Ctx = getContext();
- if (const FunctionDecl *D = dyn_cast<FunctionDecl>(FD)) {
+ if (const auto *D = dyn_cast<FunctionDecl>(FD)) {
return Ctx.getPointerType(D->getType());
}
@@ -585,7 +598,7 @@ public:
// TODO: We might want to return a different type here (ex: id (*ty)(...))
// depending on how it is used.
- return QualType();
+ return {};
}
const NamedDecl *getDecl() const {
@@ -601,7 +614,6 @@ public:
}
};
-
/// BlockCodeRegion - A region that represents code texts of blocks (closures).
/// Blocks are represented with two kinds of regions. BlockCodeRegions
/// represent the "code", while BlockDataRegions represent instances of blocks,
@@ -657,15 +669,15 @@ class BlockDataRegion : public TypedRegion {
friend class MemRegionManager;
const BlockCodeRegion *BC;
- const LocationContext *LC; // Can be null */
+ const LocationContext *LC; // Can be null
unsigned BlockCount;
- void *ReferencedVars;
- void *OriginalVars;
+ void *ReferencedVars = nullptr;
+ void *OriginalVars = nullptr;
BlockDataRegion(const BlockCodeRegion *bc, const LocationContext *lc,
unsigned count, const MemSpaceRegion *sreg)
: TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
- BlockCount(count), ReferencedVars(nullptr), OriginalVars(nullptr) {
+ BlockCount(count) {
assert(bc);
assert(lc);
assert(isa<GlobalImmutableSpaceRegion>(sreg) ||
@@ -679,7 +691,7 @@ class BlockDataRegion : public TypedRegion {
public:
const BlockCodeRegion *getCodeRegion() const { return BC; }
-
+
const BlockDecl *getDecl() const { return BC->getDecl(); }
QualType getLocationType() const override { return BC->getLocationType(); }
@@ -687,14 +699,16 @@ public:
class referenced_vars_iterator {
const MemRegion * const *R;
const MemRegion * const *OriginalR;
+
public:
explicit referenced_vars_iterator(const MemRegion * const *r,
const MemRegion * const *originalR)
- : R(r), OriginalR(originalR) {}
+ : R(r), OriginalR(originalR) {}
const VarRegion *getCapturedRegion() const {
return cast<VarRegion>(*R);
}
+
const VarRegion *getOriginalRegion() const {
return cast<VarRegion>(*OriginalR);
}
@@ -703,10 +717,12 @@ public:
assert((R == nullptr) == (I.R == nullptr));
return I.R == R;
}
+
bool operator!=(const referenced_vars_iterator &I) const {
assert((R == nullptr) == (I.R == nullptr));
return I.R != R;
}
+
referenced_vars_iterator &operator++() {
++R;
++OriginalR;
@@ -728,6 +744,7 @@ public:
static bool classof(const MemRegion* R) {
return R->getKind() == BlockDataRegionKind;
}
+
private:
void LazyInitializeReferencedVars();
std::pair<const VarRegion *, const VarRegion *>
@@ -754,9 +771,7 @@ class SymbolicRegion : public SubRegion {
}
public:
- SymbolRef getSymbol() const {
- return sym;
- }
+ SymbolRef getSymbol() const { return sym; }
bool isBoundable() const override { return true; }
@@ -779,24 +794,21 @@ public:
class StringRegion : public TypedValueRegion {
friend class MemRegionManager;
- const StringLiteral* Str;
+ const StringLiteral *Str;
StringRegion(const StringLiteral *str, const GlobalInternalSpaceRegion *sreg)
: TypedValueRegion(sreg, StringRegionKind), Str(str) {
assert(str);
}
- static void ProfileRegion(llvm::FoldingSetNodeID& ID,
- const StringLiteral* Str,
- const MemRegion* superRegion);
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const StringLiteral *Str,
+ const MemRegion *superRegion);
public:
+ const StringLiteral *getStringLiteral() const { return Str; }
- const StringLiteral* getStringLiteral() const { return Str; }
-
- QualType getValueType() const override {
- return Str->getType();
- }
+ QualType getValueType() const override { return Str->getType(); }
DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override;
@@ -817,7 +829,7 @@ public:
class ObjCStringRegion : public TypedValueRegion {
friend class MemRegionManager;
- const ObjCStringLiteral* Str;
+ const ObjCStringLiteral *Str;
ObjCStringRegion(const ObjCStringLiteral *str,
const GlobalInternalSpaceRegion *sreg)
@@ -825,17 +837,14 @@ class ObjCStringRegion : public TypedValueRegion {
assert(str);
}
- static void ProfileRegion(llvm::FoldingSetNodeID& ID,
- const ObjCStringLiteral* Str,
- const MemRegion* superRegion);
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const ObjCStringLiteral *Str,
+ const MemRegion *superRegion);
public:
-
- const ObjCStringLiteral* getObjCStringLiteral() const { return Str; }
+ const ObjCStringLiteral *getObjCStringLiteral() const { return Str; }
- QualType getValueType() const override {
- return Str->getType();
- }
+ QualType getValueType() const override { return Str->getType(); }
bool isBoundable() const override { return false; }
@@ -869,10 +878,9 @@ class CompoundLiteralRegion : public TypedValueRegion {
static void ProfileRegion(llvm::FoldingSetNodeID& ID,
const CompoundLiteralExpr *CL,
const MemRegion* superRegion);
+
public:
- QualType getValueType() const override {
- return CL->getType();
- }
+ QualType getValueType() const override { return CL->getType(); }
bool isBoundable() const override { return !CL->isFileScope(); }
@@ -943,13 +951,13 @@ public:
void dumpToStream(raw_ostream &os) const override;
- static bool classof(const MemRegion* R) {
- return R->getKind() == VarRegionKind;
- }
-
bool canPrintPrettyAsExpr() const override;
void printPrettyAsExpr(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == VarRegionKind;
+ }
};
/// CXXThisRegion - Represents the region for the implicit 'this' parameter
@@ -961,7 +969,10 @@ class CXXThisRegion : public TypedValueRegion {
CXXThisRegion(const PointerType *thisPointerTy,
const StackArgumentsSpaceRegion *sReg)
: TypedValueRegion(sReg, CXXThisRegionKind),
- ThisPointerTy(thisPointerTy) {}
+ ThisPointerTy(thisPointerTy) {
+ assert(ThisPointerTy->getPointeeType()->getAsCXXRecordDecl() &&
+ "Invalid region type!");
+ }
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
const PointerType *PT,
@@ -988,7 +999,7 @@ class FieldRegion : public DeclRegion {
friend class MemRegionManager;
FieldRegion(const FieldDecl *fd, const SubRegion* sReg)
- : DeclRegion(fd, sReg, FieldRegionKind) {}
+ : DeclRegion(fd, sReg, FieldRegionKind) {}
static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD,
const MemRegion* superRegion) {
@@ -1005,16 +1016,16 @@ public:
DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override;
- static bool classof(const MemRegion* R) {
- return R->getKind() == FieldRegionKind;
- }
-
void dumpToStream(raw_ostream &os) const override;
bool canPrintPretty() const override;
void printPretty(raw_ostream &os) const override;
bool canPrintPrettyAsExpr() const override;
void printPrettyAsExpr(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == FieldRegionKind;
+ }
};
class ObjCIvarRegion : public DeclRegion {
@@ -1038,12 +1049,11 @@ public:
return R->getKind() == ObjCIvarRegionKind;
}
};
+
//===----------------------------------------------------------------------===//
// Auxiliary data classes for use with MemRegions.
//===----------------------------------------------------------------------===//
-class ElementRegion;
-
class RegionRawOffset {
friend class ElementRegion;
@@ -1051,7 +1061,7 @@ class RegionRawOffset {
CharUnits Offset;
RegionRawOffset(const MemRegion* reg, CharUnits offset = CharUnits::Zero())
- : Region(reg), Offset(offset) {}
+ : Region(reg), Offset(offset) {}
public:
// FIXME: Eventually support symbolic offsets.
@@ -1062,7 +1072,7 @@ public:
void dump() const;
};
-/// \brief ElementRegin is used to represent both array elements and casts.
+/// ElementRegin is used to represent both array elements and casts.
class ElementRegion : public TypedValueRegion {
friend class MemRegionManager;
@@ -1070,27 +1080,25 @@ class ElementRegion : public TypedValueRegion {
NonLoc Index;
ElementRegion(QualType elementType, NonLoc Idx, const SubRegion *sReg)
- : TypedValueRegion(sReg, ElementRegionKind),
- ElementType(elementType), Index(Idx) {
+ : TypedValueRegion(sReg, ElementRegionKind), ElementType(elementType),
+ Index(Idx) {
assert((!Idx.getAs<nonloc::ConcreteInt>() ||
Idx.castAs<nonloc::ConcreteInt>().getValue().isSigned()) &&
"The index must be signed");
+ assert(!elementType.isNull() && !elementType->isVoidType() &&
+ "Invalid region type!");
}
static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType,
SVal Idx, const MemRegion* superRegion);
public:
-
NonLoc getIndex() const { return Index; }
- QualType getValueType() const override {
- return ElementType;
- }
+ QualType getValueType() const override { return ElementType; }
+
+ QualType getElementType() const { return ElementType; }
- QualType getElementType() const {
- return ElementType;
- }
/// Compute the offset within the array. The array might also be a subobject.
RegionRawOffset getAsArrayOffset() const;
@@ -1122,9 +1130,7 @@ class CXXTempObjectRegion : public TypedValueRegion {
public:
const Expr *getExpr() const { return Ex; }
- QualType getValueType() const override {
- return Ex->getType();
- }
+ QualType getValueType() const override { return Ex->getType(); }
void dumpToStream(raw_ostream &os) const override;
@@ -1161,18 +1167,18 @@ public:
void Profile(llvm::FoldingSetNodeID &ID) const override;
- static bool classof(const MemRegion *region) {
- return region->getKind() == CXXBaseObjectRegionKind;
- }
-
bool canPrintPrettyAsExpr() const override;
void printPrettyAsExpr(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion *region) {
+ return region->getKind() == CXXBaseObjectRegionKind;
+ }
};
template<typename RegionTy>
const RegionTy* MemRegion::getAs() const {
- if (const RegionTy* RT = dyn_cast<RegionTy>(this))
+ if (const auto *RT = dyn_cast<RegionTy>(this))
return RT;
return nullptr;
@@ -1187,11 +1193,10 @@ class MemRegionManager {
llvm::BumpPtrAllocator& A;
llvm::FoldingSet<MemRegion> Regions;
- GlobalInternalSpaceRegion *InternalGlobals;
- GlobalSystemSpaceRegion *SystemGlobals;
- GlobalImmutableSpaceRegion *ImmutableGlobals;
+ GlobalInternalSpaceRegion *InternalGlobals = nullptr;
+ GlobalSystemSpaceRegion *SystemGlobals = nullptr;
+ GlobalImmutableSpaceRegion *ImmutableGlobals = nullptr;
-
llvm::DenseMap<const StackFrameContext *, StackLocalsSpaceRegion *>
StackLocalsSpaceRegions;
llvm::DenseMap<const StackFrameContext *, StackArgumentsSpaceRegion *>
@@ -1199,16 +1204,12 @@ class MemRegionManager {
llvm::DenseMap<const CodeTextRegion *, StaticGlobalSpaceRegion *>
StaticsGlobalSpaceRegions;
- HeapSpaceRegion *heap;
- UnknownSpaceRegion *unknown;
- CodeSpaceRegion *code;
+ HeapSpaceRegion *heap = nullptr;
+ UnknownSpaceRegion *unknown = nullptr;
+ CodeSpaceRegion *code = nullptr;
public:
- MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator &a)
- : C(c), A(a), InternalGlobals(nullptr), SystemGlobals(nullptr),
- ImmutableGlobals(nullptr), heap(nullptr), unknown(nullptr),
- code(nullptr) {}
-
+ MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator &a) : C(c), A(a) {}
~MemRegionManager();
ASTContext &getContext() { return C; }
@@ -1256,13 +1257,13 @@ public:
const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy,
const LocationContext *LC);
- /// \brief Retrieve or create a "symbolic" memory region.
+ /// Retrieve or create a "symbolic" memory region.
const SymbolicRegion* getSymbolicRegion(SymbolRef Sym);
- /// \brief Return a unique symbolic region belonging to heap memory space.
+ /// Return a unique symbolic region belonging to heap memory space.
const SymbolicRegion *getSymbolicHeapRegion(SymbolRef sym);
- const StringRegion *getStringRegion(const StringLiteral* Str);
+ const StringRegion *getStringRegion(const StringLiteral *Str);
const ObjCStringRegion *getObjCStringRegion(const ObjCStringLiteral *Str);
@@ -1381,24 +1382,28 @@ inline ASTContext &MemRegion::getContext() const {
/// Information about invalidation for a particular region/symbol.
class RegionAndSymbolInvalidationTraits {
- typedef unsigned char StorageTypeForKinds;
+ using StorageTypeForKinds = unsigned char;
+
llvm::DenseMap<const MemRegion *, StorageTypeForKinds> MRTraitsMap;
llvm::DenseMap<SymbolRef, StorageTypeForKinds> SymTraitsMap;
- typedef llvm::DenseMap<const MemRegion *, StorageTypeForKinds>::const_iterator
- const_region_iterator;
- typedef llvm::DenseMap<SymbolRef, StorageTypeForKinds>::const_iterator
- const_symbol_iterator;
+ using const_region_iterator =
+ llvm::DenseMap<const MemRegion *, StorageTypeForKinds>::const_iterator;
+ using const_symbol_iterator =
+ llvm::DenseMap<SymbolRef, StorageTypeForKinds>::const_iterator;
public:
- /// \brief Describes different invalidation traits.
+ /// Describes different invalidation traits.
enum InvalidationKinds {
/// Tells that a region's contents is not changed.
TK_PreserveContents = 0x1,
+
/// Suppress pointer-escaping of a region.
TK_SuppressEscape = 0x2,
+
// Do not invalidate super region.
TK_DoNotInvalidateSuperRegion = 0x4,
+
/// When applied to a MemSpaceRegion, indicates the entire memory space
/// should be invalidated.
TK_EntireMemSpace = 0x8
@@ -1416,8 +1421,7 @@ public:
//===----------------------------------------------------------------------===//
// Pretty-printing regions.
//===----------------------------------------------------------------------===//
-inline raw_ostream &operator<<(raw_ostream &os,
- const clang::ento::MemRegion *R) {
+inline raw_ostream &operator<<(raw_ostream &os, const MemRegion *R) {
R->dumpToStream(os);
return os;
}
@@ -1426,4 +1430,4 @@ inline raw_ostream &operator<<(raw_ostream &os,
} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_MEMREGION_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index dd2564b0a3c3e..17ab7379fdba9 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -177,20 +177,20 @@ public:
///
/// This returns a new state with the added constraint on \p cond.
/// If no new state is feasible, NULL is returned.
- ProgramStateRef assume(DefinedOrUnknownSVal cond, bool assumption) const;
+ LLVM_NODISCARD ProgramStateRef assume(DefinedOrUnknownSVal cond,
+ bool assumption) const;
/// Assumes both "true" and "false" for \p cond, and returns both
/// corresponding states (respectively).
///
/// This is more efficient than calling assume() twice. Note that one (but not
/// both) of the returned states may be NULL.
- std::pair<ProgramStateRef, ProgramStateRef>
+ LLVM_NODISCARD std::pair<ProgramStateRef, ProgramStateRef>
assume(DefinedOrUnknownSVal cond) const;
- ProgramStateRef assumeInBound(DefinedOrUnknownSVal idx,
- DefinedOrUnknownSVal upperBound,
- bool assumption,
- QualType IndexType = QualType()) const;
+ LLVM_NODISCARD ProgramStateRef
+ assumeInBound(DefinedOrUnknownSVal idx, DefinedOrUnknownSVal upperBound,
+ bool assumption, QualType IndexType = QualType()) const;
/// Assumes that the value of \p Val is bounded with [\p From; \p To]
/// (if \p assumption is "true") or it is fully out of this range
@@ -198,24 +198,31 @@ public:
///
/// This returns a new state with the added constraint on \p cond.
/// If no new state is feasible, NULL is returned.
- ProgramStateRef assumeInclusiveRange(DefinedOrUnknownSVal Val,
- const llvm::APSInt &From,
- const llvm::APSInt &To,
- bool assumption) const;
+ LLVM_NODISCARD ProgramStateRef assumeInclusiveRange(DefinedOrUnknownSVal Val,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool assumption) const;
/// Assumes given range both "true" and "false" for \p Val, and returns both
/// corresponding states (respectively).
///
/// This is more efficient than calling assume() twice. Note that one (but not
/// both) of the returned states may be NULL.
- std::pair<ProgramStateRef, ProgramStateRef>
+ LLVM_NODISCARD std::pair<ProgramStateRef, ProgramStateRef>
assumeInclusiveRange(DefinedOrUnknownSVal Val, const llvm::APSInt &From,
const llvm::APSInt &To) const;
- /// \brief Check if the given SVal is constrained to zero or is a zero
+ /// Check if the given SVal is not constrained to zero and is not
+ /// a zero constant.
+ ConditionTruthVal isNonNull(SVal V) const;
+
+ /// Check if the given SVal is constrained to zero or is a zero
/// constant.
ConditionTruthVal isNull(SVal V) const;
+ /// \return Whether values \p Lhs and \p Rhs are equal.
+ ConditionTruthVal areEqual(SVal Lhs, SVal Rhs) const;
+
/// Utility method for getting regions.
const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const;
@@ -225,21 +232,34 @@ public:
/// Create a new state by binding the value 'V' to the statement 'S' in the
/// state's environment.
- ProgramStateRef BindExpr(const Stmt *S, const LocationContext *LCtx,
- SVal V, bool Invalidate = true) const;
-
- ProgramStateRef bindLoc(Loc location,
- SVal V,
- const LocationContext *LCtx,
- bool notifyChanges = true) const;
-
- ProgramStateRef bindLoc(SVal location, SVal V, const LocationContext *LCtx) const;
-
- ProgramStateRef bindDefault(SVal loc, SVal V, const LocationContext *LCtx) const;
-
- ProgramStateRef killBinding(Loc LV) const;
-
- /// \brief Returns the state with bindings for the given regions
+ LLVM_NODISCARD ProgramStateRef BindExpr(const Stmt *S,
+ const LocationContext *LCtx, SVal V,
+ bool Invalidate = true) const;
+
+ LLVM_NODISCARD ProgramStateRef bindLoc(Loc location, SVal V,
+ const LocationContext *LCtx,
+ bool notifyChanges = true) const;
+
+ LLVM_NODISCARD ProgramStateRef bindLoc(SVal location, SVal V,
+ const LocationContext *LCtx) const;
+
+ /// Initializes the region of memory represented by \p loc with an initial
+ /// value. Once initialized, all values loaded from any sub-regions of that
+ /// region will be equal to \p V, unless overwritten later by the program.
+ /// This method should not be used on regions that are already initialized.
+ /// If you need to indicate that memory contents have suddenly become unknown
+ /// within a certain region of memory, consider invalidateRegions().
+ LLVM_NODISCARD ProgramStateRef
+ bindDefaultInitial(SVal loc, SVal V, const LocationContext *LCtx) const;
+
+ /// Performs C++ zero-initialization procedure on the region of memory
+ /// represented by \p loc.
+ LLVM_NODISCARD ProgramStateRef
+ bindDefaultZero(SVal loc, const LocationContext *LCtx) const;
+
+ LLVM_NODISCARD ProgramStateRef killBinding(Loc LV) const;
+
+ /// Returns the state with bindings for the given regions
/// cleared from the store.
///
/// Optionally invalidates global regions as well.
@@ -257,14 +277,14 @@ public:
/// the call and should be considered directly invalidated.
/// \param ITraits information about special handling for a particular
/// region/symbol.
- ProgramStateRef
+ LLVM_NODISCARD ProgramStateRef
invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E,
unsigned BlockCount, const LocationContext *LCtx,
bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr,
const CallEvent *Call = nullptr,
RegionAndSymbolInvalidationTraits *ITraits = nullptr) const;
- ProgramStateRef
+ LLVM_NODISCARD ProgramStateRef
invalidateRegions(ArrayRef<SVal> Regions, const Expr *E,
unsigned BlockCount, const LocationContext *LCtx,
bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr,
@@ -273,8 +293,15 @@ public:
/// enterStackFrame - Returns the state for entry to the given stack frame,
/// preserving the current state.
- ProgramStateRef enterStackFrame(const CallEvent &Call,
- const StackFrameContext *CalleeCtx) const;
+ LLVM_NODISCARD ProgramStateRef enterStackFrame(
+ const CallEvent &Call, const StackFrameContext *CalleeCtx) const;
+
+ /// Get the lvalue for a base class object reference.
+ Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const;
+
+ /// Get the lvalue for a base class object reference.
+ Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super,
+ bool IsVirtual) const;
/// Get the lvalue for a variable reference.
Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
@@ -299,24 +326,24 @@ public:
SVal getSValAsScalarOrLoc(const Stmt *Ex, const LocationContext *LCtx) const;
- /// \brief Return the value bound to the specified location.
+ /// Return the value bound to the specified location.
/// Returns UnknownVal() if none found.
SVal getSVal(Loc LV, QualType T = QualType()) const;
/// Returns the "raw" SVal bound to LV before any value simplfication.
SVal getRawSVal(Loc LV, QualType T= QualType()) const;
- /// \brief Return the value bound to the specified location.
+ /// Return the value bound to the specified location.
/// Returns UnknownVal() if none found.
SVal getSVal(const MemRegion* R, QualType T = QualType()) const;
- /// \brief Return the value bound to the specified location, assuming
+ /// Return the value bound to the specified location, assuming
/// that the value is a scalar integer or an enumeration or a pointer.
/// Returns UnknownVal() if none found or the region is not known to hold
/// a value of such type.
SVal getSValAsScalarOrLoc(const MemRegion *R) const;
- /// \brief Visits the symbols reachable from the given SVal using the provided
+ /// Visits the symbols reachable from the given SVal using the provided
/// SymbolVisitor.
///
/// This is a convenience API. Consider using ScanReachableSymbols class
@@ -325,12 +352,12 @@ public:
/// \sa ScanReachableSymbols
bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const;
- /// \brief Visits the symbols reachable from the SVals in the given range
+ /// 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;
- /// \brief Visits the symbols reachable from the regions in the given
+ /// 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,
@@ -345,27 +372,29 @@ public:
const MemRegion * const *end) const;
/// Create a new state in which the statement is marked as tainted.
- ProgramStateRef addTaint(const Stmt *S, const LocationContext *LCtx,
- TaintTagType Kind = TaintTagGeneric) const;
+ LLVM_NODISCARD ProgramStateRef
+ addTaint(const Stmt *S, const LocationContext *LCtx,
+ TaintTagType Kind = TaintTagGeneric) const;
/// Create a new state in which the value is marked as tainted.
- ProgramStateRef addTaint(SVal V, TaintTagType Kind = TaintTagGeneric) const;
+ LLVM_NODISCARD ProgramStateRef
+ addTaint(SVal V, TaintTagType Kind = TaintTagGeneric) const;
/// Create a new state in which the symbol is marked as tainted.
- ProgramStateRef addTaint(SymbolRef S,
+ LLVM_NODISCARD ProgramStateRef addTaint(SymbolRef S,
TaintTagType Kind = TaintTagGeneric) const;
/// Create a new state in which the region symbol is marked as tainted.
- ProgramStateRef addTaint(const MemRegion *R,
- TaintTagType Kind = TaintTagGeneric) const;
+ LLVM_NODISCARD ProgramStateRef
+ addTaint(const MemRegion *R, TaintTagType Kind = TaintTagGeneric) const;
/// Create a new state in a which a sub-region of a given symbol is tainted.
/// This might be necessary when referring to regions that can not have an
/// individual symbol, e.g. if they are represented by the default binding of
/// a LazyCompoundVal.
- ProgramStateRef addPartialTaint(SymbolRef ParentSym,
- const SubRegion *SubRegion,
- TaintTagType Kind = TaintTagGeneric) const;
+ LLVM_NODISCARD ProgramStateRef
+ addPartialTaint(SymbolRef ParentSym, const SubRegion *SubRegion,
+ TaintTagType Kind = TaintTagGeneric) const;
/// Check if the statement is tainted in the current state.
bool isTainted(const Stmt *S, const LocationContext *LCtx,
@@ -380,8 +409,9 @@ public:
void *const* FindGDM(void *K) const;
- template<typename T>
- ProgramStateRef add(typename ProgramStateTrait<T>::key_type K) const;
+ template <typename T>
+ LLVM_NODISCARD ProgramStateRef
+ add(typename ProgramStateTrait<T>::key_type K) const;
template <typename T>
typename ProgramStateTrait<T>::data_type
@@ -399,27 +429,31 @@ public:
template <typename T>
typename ProgramStateTrait<T>::context_type get_context() const;
+ template <typename T>
+ LLVM_NODISCARD ProgramStateRef
+ remove(typename ProgramStateTrait<T>::key_type K) const;
- template<typename T>
- ProgramStateRef remove(typename ProgramStateTrait<T>::key_type K) const;
-
- template<typename T>
- ProgramStateRef remove(typename ProgramStateTrait<T>::key_type K,
- typename ProgramStateTrait<T>::context_type C) const;
template <typename T>
- ProgramStateRef remove() const;
+ LLVM_NODISCARD ProgramStateRef
+ remove(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::context_type C) const;
- template<typename T>
- ProgramStateRef set(typename ProgramStateTrait<T>::data_type D) const;
+ template <typename T> LLVM_NODISCARD ProgramStateRef remove() const;
- template<typename T>
- ProgramStateRef set(typename ProgramStateTrait<T>::key_type K,
- typename ProgramStateTrait<T>::value_type E) const;
+ template <typename T>
+ LLVM_NODISCARD ProgramStateRef
+ set(typename ProgramStateTrait<T>::data_type D) const;
- template<typename T>
- ProgramStateRef set(typename ProgramStateTrait<T>::key_type K,
- typename ProgramStateTrait<T>::value_type E,
- typename ProgramStateTrait<T>::context_type C) const;
+ template <typename T>
+ LLVM_NODISCARD ProgramStateRef
+ set(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type E) const;
+
+ template <typename T>
+ LLVM_NODISCARD ProgramStateRef
+ set(typename ProgramStateTrait<T>::key_type K,
+ typename ProgramStateTrait<T>::value_type E,
+ typename ProgramStateTrait<T>::context_type C) const;
template<typename T>
bool contains(typename ProgramStateTrait<T>::key_type key) const {
@@ -428,9 +462,10 @@ public:
}
// Pretty-printing.
- void print(raw_ostream &Out, const char *nl = "\n",
- const char *sep = "") const;
- void printDOT(raw_ostream &Out) const;
+ void print(raw_ostream &Out, const char *nl = "\n", const char *sep = "",
+ const LocationContext *CurrentLC = nullptr) const;
+ void printDOT(raw_ostream &Out,
+ const LocationContext *CurrentLC = nullptr) const;
void printTaint(raw_ostream &Out, const char *nl = "\n",
const char *sep = "") const;
@@ -705,6 +740,22 @@ inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V, const LocationCont
return this;
}
+inline Loc ProgramState::getLValue(const CXXBaseSpecifier &BaseSpec,
+ const SubRegion *Super) const {
+ const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl();
+ return loc::MemRegionVal(
+ getStateManager().getRegionManager().getCXXBaseObjectRegion(
+ Base, Super, BaseSpec.isVirtual()));
+}
+
+inline Loc ProgramState::getLValue(const CXXRecordDecl *BaseClass,
+ const SubRegion *Super,
+ bool IsVirtual) const {
+ return loc::MemRegionVal(
+ getStateManager().getRegionManager().getCXXBaseObjectRegion(
+ BaseClass, Super, IsVirtual));
+}
+
inline Loc ProgramState::getLValue(const VarDecl *VD,
const LocationContext *LC) const {
return getStateManager().StoreMgr->getLValueVar(VD, LC);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
index a04fa90059555..5555b292534c5 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
@@ -14,33 +14,28 @@
//
//===----------------------------------------------------------------------===//
-
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/ImmutableSet.h"
#include "llvm/Support/Allocator.h"
-#include "llvm/Support/DataTypes.h"
-
-namespace llvm {
- template <typename K, typename D, typename I> class ImmutableMap;
- template <typename K, typename I> class ImmutableSet;
- template <typename T> class ImmutableList;
- template <typename T> class ImmutableListImpl;
-}
+#include <cstdint>
namespace clang {
-
namespace ento {
+
template <typename T> struct ProgramStatePartialTrait;
/// Declares a program state trait for type \p Type called \p Name, and
- /// introduce a typedef named \c NameTy.
+ /// introduce a type named \c NameTy.
/// The macro should not be used inside namespaces, or for traits that must
/// be accessible from more than one translation unit.
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type) \
namespace { \
class Name {}; \
- typedef Type Name ## Ty; \
+ using Name ## Ty = Type; \
} \
namespace clang { \
namespace ento { \
@@ -52,28 +47,30 @@ namespace ento {
} \
}
-
// Partial-specialization for ImmutableMap.
-
template <typename Key, typename Data, typename Info>
- struct ProgramStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > {
- typedef llvm::ImmutableMap<Key,Data,Info> data_type;
- typedef typename data_type::Factory& context_type;
- typedef Key key_type;
- typedef Data value_type;
- typedef const value_type* lookup_type;
-
- static inline data_type MakeData(void *const* p) {
- return p ? data_type((typename data_type::TreeTy*) *p)
+ struct ProgramStatePartialTrait<llvm::ImmutableMap<Key, Data, Info>> {
+ using data_type = llvm::ImmutableMap<Key, Data, Info>;
+ using context_type = typename data_type::Factory &;
+ using key_type = Key;
+ using value_type = Data;
+ using lookup_type = const value_type *;
+
+ static data_type MakeData(void *const *p) {
+ return p ? data_type((typename data_type::TreeTy *) *p)
: data_type(nullptr);
}
- static inline void *MakeVoidPtr(data_type B) {
+
+ static void *MakeVoidPtr(data_type B) {
return B.getRoot();
}
+
static lookup_type Lookup(data_type B, key_type K) {
return B.lookup(K);
}
- static data_type Set(data_type B, key_type K, value_type E,context_type F){
+
+ static data_type Set(data_type B, key_type K, value_type E,
+ context_type F) {
return F.add(B, K, E);
}
@@ -85,8 +82,8 @@ namespace ento {
return B.contains(K);
}
- static inline context_type MakeContext(void *p) {
- return *((typename data_type::Factory*) p);
+ static context_type MakeContext(void *p) {
+ return *((typename data_type::Factory *) p);
}
static void *CreateContext(llvm::BumpPtrAllocator& Alloc) {
@@ -94,7 +91,7 @@ namespace ento {
}
static void DeleteContext(void *Ctx) {
- delete (typename data_type::Factory*) Ctx;
+ delete (typename data_type::Factory *) Ctx;
}
};
@@ -107,21 +104,19 @@ namespace ento {
/// can deal with.
#define CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value) llvm::ImmutableMap<Key, Value>
-
// Partial-specialization for ImmutableSet.
-
template <typename Key, typename Info>
- struct ProgramStatePartialTrait< llvm::ImmutableSet<Key,Info> > {
- typedef llvm::ImmutableSet<Key,Info> data_type;
- typedef typename data_type::Factory& context_type;
- typedef Key key_type;
+ struct ProgramStatePartialTrait<llvm::ImmutableSet<Key, Info>> {
+ using data_type = llvm::ImmutableSet<Key, Info>;
+ using context_type = typename data_type::Factory &;
+ using key_type = Key;
- static inline data_type MakeData(void *const* p) {
- return p ? data_type((typename data_type::TreeTy*) *p)
+ static data_type MakeData(void *const *p) {
+ return p ? data_type((typename data_type::TreeTy *) *p)
: data_type(nullptr);
}
- static inline void *MakeVoidPtr(data_type B) {
+ static void *MakeVoidPtr(data_type B) {
return B.getRoot();
}
@@ -137,27 +132,25 @@ namespace ento {
return B.contains(K);
}
- static inline context_type MakeContext(void *p) {
- return *((typename data_type::Factory*) p);
+ static context_type MakeContext(void *p) {
+ return *((typename data_type::Factory *) p);
}
- static void *CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ static void *CreateContext(llvm::BumpPtrAllocator &Alloc) {
return new typename data_type::Factory(Alloc);
}
static void DeleteContext(void *Ctx) {
- delete (typename data_type::Factory*) Ctx;
+ delete (typename data_type::Factory *) Ctx;
}
};
-
// Partial-specialization for ImmutableList.
-
template <typename T>
- struct ProgramStatePartialTrait< llvm::ImmutableList<T> > {
- typedef llvm::ImmutableList<T> data_type;
- typedef T key_type;
- typedef typename data_type::Factory& context_type;
+ struct ProgramStatePartialTrait<llvm::ImmutableList<T>> {
+ using data_type = llvm::ImmutableList<T>;
+ using key_type = T;
+ using context_type = typename data_type::Factory &;
static data_type Add(data_type L, key_type K, context_type F) {
return F.add(K, L);
@@ -167,83 +160,84 @@ namespace ento {
return L.contains(K);
}
- static inline data_type MakeData(void *const* p) {
- return p ? data_type((const llvm::ImmutableListImpl<T>*) *p)
+ static data_type MakeData(void *const *p) {
+ return p ? data_type((const llvm::ImmutableListImpl<T> *) *p)
: data_type(nullptr);
}
- static inline void *MakeVoidPtr(data_type D) {
+ static void *MakeVoidPtr(data_type D) {
return const_cast<llvm::ImmutableListImpl<T> *>(D.getInternalPointer());
}
- static inline context_type MakeContext(void *p) {
- return *((typename data_type::Factory*) p);
+ static context_type MakeContext(void *p) {
+ return *((typename data_type::Factory *) p);
}
- static void *CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ static void *CreateContext(llvm::BumpPtrAllocator &Alloc) {
return new typename data_type::Factory(Alloc);
}
static void DeleteContext(void *Ctx) {
- delete (typename data_type::Factory*) Ctx;
+ delete (typename data_type::Factory *) Ctx;
}
};
-
// Partial specialization for bool.
template <> struct ProgramStatePartialTrait<bool> {
- typedef bool data_type;
+ using data_type = bool;
- static inline data_type MakeData(void *const* p) {
+ static data_type MakeData(void *const *p) {
return p ? (data_type) (uintptr_t) *p
: data_type();
}
- static inline void *MakeVoidPtr(data_type d) {
- return (void*) (uintptr_t) d;
+
+ static void *MakeVoidPtr(data_type d) {
+ return (void *) (uintptr_t) d;
}
};
// Partial specialization for unsigned.
template <> struct ProgramStatePartialTrait<unsigned> {
- typedef unsigned data_type;
+ using data_type = unsigned;
- static inline data_type MakeData(void *const* p) {
+ static data_type MakeData(void *const *p) {
return p ? (data_type) (uintptr_t) *p
: data_type();
}
- static inline void *MakeVoidPtr(data_type d) {
- return (void*) (uintptr_t) d;
+
+ static void *MakeVoidPtr(data_type d) {
+ return (void *) (uintptr_t) d;
}
};
// Partial specialization for void*.
- template <> struct ProgramStatePartialTrait<void*> {
- typedef void *data_type;
+ template <> struct ProgramStatePartialTrait<void *> {
+ using data_type = void *;
- static inline data_type MakeData(void *const* p) {
+ static data_type MakeData(void *const *p) {
return p ? *p
: data_type();
}
- static inline void *MakeVoidPtr(data_type d) {
+
+ static void *MakeVoidPtr(data_type d) {
return d;
}
};
// Partial specialization for const void *.
template <> struct ProgramStatePartialTrait<const void *> {
- typedef const void *data_type;
+ using data_type = const void *;
- static inline data_type MakeData(void * const *p) {
+ static data_type MakeData(void *const *p) {
return p ? *p : data_type();
}
- static inline void *MakeVoidPtr(data_type d) {
+ static void *MakeVoidPtr(data_type d) {
return const_cast<void *>(d);
}
};
-} // end ento namespace
-
-} // end clang namespace
+} // namespace ento
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
new file mode 100644
index 0000000000000..d2ba1f7c9529a
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h
@@ -0,0 +1,216 @@
+//== RangedConstraintManager.h ----------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Ranged constraint manager, built on SimpleConstraintManager.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CORE_RANGEDCONSTRAINTMANAGER_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CORE_RANGEDCONSTRAINTMANAGER_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h"
+
+namespace clang {
+
+namespace ento {
+
+/// A Range represents the closed range [from, to]. The caller must
+/// guarantee that from <= to. Note that Range is immutable, so as not
+/// to subvert RangeSet's immutability.
+class Range : public std::pair<const llvm::APSInt *, const llvm::APSInt *> {
+public:
+ Range(const llvm::APSInt &from, const llvm::APSInt &to)
+ : std::pair<const llvm::APSInt *, const llvm::APSInt *>(&from, &to) {
+ assert(from <= to);
+ }
+ bool Includes(const llvm::APSInt &v) const {
+ return *first <= v && v <= *second;
+ }
+ const llvm::APSInt &From() const { return *first; }
+ const llvm::APSInt &To() const { return *second; }
+ const llvm::APSInt *getConcreteValue() const {
+ return &From() == &To() ? &From() : nullptr;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(&From());
+ ID.AddPointer(&To());
+ }
+};
+
+class RangeTrait : public llvm::ImutContainerInfo<Range> {
+public:
+ // When comparing if one Range is less than another, we should compare
+ // the actual APSInt values instead of their pointers. This keeps the order
+ // consistent (instead of comparing by pointer values) and can potentially
+ // be used to speed up some of the operations in RangeSet.
+ static inline bool isLess(key_type_ref lhs, key_type_ref rhs) {
+ return *lhs.first < *rhs.first ||
+ (!(*rhs.first < *lhs.first) && *lhs.second < *rhs.second);
+ }
+};
+
+/// RangeSet contains a set of ranges. If the set is empty, then
+/// there the value of a symbol is overly constrained and there are no
+/// possible values for that symbol.
+class RangeSet {
+ typedef llvm::ImmutableSet<Range, RangeTrait> PrimRangeSet;
+ PrimRangeSet ranges; // no need to make const, since it is an
+ // ImmutableSet - this allows default operator=
+ // to work.
+public:
+ typedef PrimRangeSet::Factory Factory;
+ typedef PrimRangeSet::iterator iterator;
+
+ RangeSet(PrimRangeSet RS) : ranges(RS) {}
+
+ /// Create a new set with all ranges of this set and RS.
+ /// Possible intersections are not checked here.
+ RangeSet addRange(Factory &F, const RangeSet &RS) {
+ PrimRangeSet Ranges(RS.ranges);
+ for (const auto &range : ranges)
+ Ranges = F.add(Ranges, range);
+ return RangeSet(Ranges);
+ }
+
+ iterator begin() const { return ranges.begin(); }
+ iterator end() const { return ranges.end(); }
+
+ bool isEmpty() const { return ranges.isEmpty(); }
+
+ /// Construct a new RangeSet representing '{ [from, to] }'.
+ RangeSet(Factory &F, const llvm::APSInt &from, const llvm::APSInt &to)
+ : ranges(F.add(F.getEmptySet(), Range(from, to))) {}
+
+ /// Profile - Generates a hash profile of this RangeSet for use
+ /// by FoldingSet.
+ void Profile(llvm::FoldingSetNodeID &ID) const { ranges.Profile(ID); }
+
+ /// getConcreteValue - If a symbol is contrained to equal a specific integer
+ /// constant then this method returns that value. Otherwise, it returns
+ /// NULL.
+ const llvm::APSInt *getConcreteValue() const {
+ return ranges.isSingleton() ? ranges.begin()->getConcreteValue() : nullptr;
+ }
+
+private:
+ void IntersectInRange(BasicValueFactory &BV, Factory &F,
+ const llvm::APSInt &Lower, const llvm::APSInt &Upper,
+ PrimRangeSet &newRanges, PrimRangeSet::iterator &i,
+ PrimRangeSet::iterator &e) const;
+
+ const llvm::APSInt &getMinValue() const;
+
+ bool pin(llvm::APSInt &Lower, llvm::APSInt &Upper) const;
+
+public:
+ RangeSet Intersect(BasicValueFactory &BV, Factory &F, llvm::APSInt Lower,
+ llvm::APSInt Upper) const;
+
+ RangeSet Negate(BasicValueFactory &BV, Factory &F) const;
+
+ void print(raw_ostream &os) const;
+
+ bool operator==(const RangeSet &other) const {
+ return ranges == other.ranges;
+ }
+};
+
+
+class ConstraintRange {};
+using ConstraintRangeTy = llvm::ImmutableMap<SymbolRef, RangeSet>;
+
+template <>
+struct ProgramStateTrait<ConstraintRange>
+ : public ProgramStatePartialTrait<ConstraintRangeTy> {
+ static void *GDMIndex() { static int Index; return &Index; }
+};
+
+
+class RangedConstraintManager : public SimpleConstraintManager {
+public:
+ RangedConstraintManager(SubEngine *SE, SValBuilder &SB)
+ : SimpleConstraintManager(SE, SB) {}
+
+ ~RangedConstraintManager() override;
+
+ //===------------------------------------------------------------------===//
+ // Implementation for interface from SimpleConstraintManager.
+ //===------------------------------------------------------------------===//
+
+ ProgramStateRef assumeSym(ProgramStateRef State, SymbolRef Sym,
+ bool Assumption) override;
+
+ ProgramStateRef assumeSymInclusiveRange(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool InRange) override;
+
+ ProgramStateRef assumeSymUnsupported(ProgramStateRef State, SymbolRef Sym,
+ bool Assumption) override;
+
+protected:
+ /// Assume a constraint between a symbolic expression and a concrete integer.
+ virtual ProgramStateRef assumeSymRel(ProgramStateRef State, SymbolRef Sym,
+ BinaryOperator::Opcode op,
+ const llvm::APSInt &Int);
+
+ //===------------------------------------------------------------------===//
+ // Interface that subclasses must implement.
+ //===------------------------------------------------------------------===//
+
+ // Each of these is of the form "$Sym+Adj <> V", where "<>" is the comparison
+ // operation for the method being invoked.
+
+ virtual ProgramStateRef assumeSymNE(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) = 0;
+
+ virtual ProgramStateRef assumeSymEQ(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) = 0;
+
+ virtual ProgramStateRef assumeSymLT(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) = 0;
+
+ virtual ProgramStateRef assumeSymGT(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) = 0;
+
+ virtual ProgramStateRef assumeSymLE(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) = 0;
+
+ virtual ProgramStateRef assumeSymGE(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) = 0;
+
+ virtual ProgramStateRef assumeSymWithinInclusiveRange(
+ ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
+ const llvm::APSInt &To, const llvm::APSInt &Adjustment) = 0;
+
+ virtual ProgramStateRef assumeSymOutsideInclusiveRange(
+ ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From,
+ const llvm::APSInt &To, const llvm::APSInt &Adjustment) = 0;
+
+ //===------------------------------------------------------------------===//
+ // Internal implementation.
+ //===------------------------------------------------------------------===//
+private:
+ static void computeAdjustment(SymbolRef &Sym, llvm::APSInt &Adjustment);
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h
new file mode 100644
index 0000000000000..19d3d5973e0fd
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h
@@ -0,0 +1,77 @@
+//== SMTConstraintManager.h -------------------------------------*- 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 a SMT generic API, which will be the base class for
+// every SMT solver specific class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONSTRAINTMANAGER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONSTRAINTMANAGER_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h"
+
+namespace clang {
+namespace ento {
+
+class SMTConstraintManager : public clang::ento::SimpleConstraintManager {
+ SMTSolverRef &Solver;
+
+public:
+ SMTConstraintManager(clang::ento::SubEngine *SE, clang::ento::SValBuilder &SB,
+ SMTSolverRef &S)
+ : SimpleConstraintManager(SE, SB), Solver(S) {}
+ virtual ~SMTConstraintManager() = default;
+
+ //===------------------------------------------------------------------===//
+ // Implementation for interface from SimpleConstraintManager.
+ //===------------------------------------------------------------------===//
+
+ ProgramStateRef assumeSym(ProgramStateRef state, SymbolRef Sym,
+ bool Assumption) override;
+
+ ProgramStateRef assumeSymInclusiveRange(ProgramStateRef State, SymbolRef Sym,
+ const llvm::APSInt &From,
+ const llvm::APSInt &To,
+ bool InRange) override;
+
+ ProgramStateRef assumeSymUnsupported(ProgramStateRef State, SymbolRef Sym,
+ bool Assumption) override;
+
+ //===------------------------------------------------------------------===//
+ // Implementation for interface from ConstraintManager.
+ //===------------------------------------------------------------------===//
+
+ ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym) override;
+
+ const llvm::APSInt *getSymVal(ProgramStateRef State,
+ SymbolRef Sym) const override;
+
+ /// Dumps SMT formula
+ LLVM_DUMP_METHOD void dump() const { Solver->dump(); }
+
+protected:
+ // Check whether a new model is satisfiable, and update the program state.
+ virtual ProgramStateRef assumeExpr(ProgramStateRef State, SymbolRef Sym,
+ const SMTExprRef &Exp) = 0;
+
+ /// Given a program state, construct the logical conjunction and add it to
+ /// the solver
+ virtual void addStateConstraints(ProgramStateRef State) const = 0;
+
+ // Generate and check a Z3 model, using the given constraint.
+ ConditionTruthVal checkModel(ProgramStateRef State,
+ const SMTExprRef &Exp) const;
+}; // end class SMTConstraintManager
+
+} // namespace ento
+} // namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTContext.h
new file mode 100644
index 0000000000000..45c9df4ef4019
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTContext.h
@@ -0,0 +1,31 @@
+//== SMTContext.h -----------------------------------------------*- 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 a SMT generic Context API, which will be the base class
+// for every SMT solver context specific class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONTEXT_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONTEXT_H
+
+namespace clang {
+namespace ento {
+
+/// Generic base class for SMT contexts
+class SMTContext {
+public:
+ SMTContext() = default;
+ virtual ~SMTContext() = default;
+};
+
+} // namespace ento
+} // namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTExpr.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTExpr.h
new file mode 100644
index 0000000000000..9dedf96cfaf83
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTExpr.h
@@ -0,0 +1,62 @@
+//== SMTExpr.h --------------------------------------------------*- 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 a SMT generic Expr API, which will be the base class
+// for every SMT solver expr specific class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTEXPR_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTEXPR_H
+
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/FoldingSet.h"
+
+namespace clang {
+namespace ento {
+
+/// Generic base class for SMT exprs
+class SMTExpr {
+public:
+ SMTExpr() = default;
+ virtual ~SMTExpr() = default;
+
+ bool operator<(const SMTExpr &Other) const {
+ llvm::FoldingSetNodeID ID1, ID2;
+ Profile(ID1);
+ Other.Profile(ID2);
+ return ID1 < ID2;
+ }
+
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const {
+ static int Tag = 0;
+ ID.AddPointer(&Tag);
+ }
+
+ friend bool operator==(SMTExpr const &LHS, SMTExpr const &RHS) {
+ return LHS.equal_to(RHS);
+ }
+
+ virtual void print(raw_ostream &OS) const = 0;
+
+ LLVM_DUMP_METHOD void dump() const { print(llvm::errs()); }
+
+protected:
+ /// Query the SMT solver and returns true if two sorts are equal (same kind
+ /// and bit width). This does not check if the two sorts are the same objects.
+ virtual bool equal_to(SMTExpr const &other) const = 0;
+};
+
+/// Shared pointer for SMTExprs, used by SMTSolver API.
+using SMTExprRef = std::shared_ptr<SMTExpr>;
+
+} // namespace ento
+} // namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h
new file mode 100644
index 0000000000000..a43ca486901bc
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h
@@ -0,0 +1,996 @@
+//== SMTSolver.h ------------------------------------------------*- 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 a SMT generic Solver API, which will be the base class
+// for every SMT solver specific class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTSOLVER_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTSOLVER_H
+
+#include "clang/AST/Expr.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SMTExpr.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SMTSort.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+
+namespace clang {
+namespace ento {
+
+/// Generic base class for SMT Solvers
+///
+/// This class is responsible for wrapping all sorts and expression generation,
+/// through the mk* methods. It also provides methods to create SMT expressions
+/// straight from clang's AST, through the from* methods.
+class SMTSolver {
+public:
+ SMTSolver() = default;
+ virtual ~SMTSolver() = default;
+
+ LLVM_DUMP_METHOD void dump() const { print(llvm::errs()); }
+
+ // Returns an appropriate floating-point sort for the given bitwidth.
+ SMTSortRef getFloatSort(unsigned BitWidth) {
+ switch (BitWidth) {
+ case 16:
+ return getFloat16Sort();
+ case 32:
+ return getFloat32Sort();
+ case 64:
+ return getFloat64Sort();
+ case 128:
+ return getFloat128Sort();
+ default:;
+ }
+ llvm_unreachable("Unsupported floating-point bitwidth!");
+ }
+
+ // Returns an appropriate sort, given a QualType and it's bit width.
+ SMTSortRef mkSort(const QualType &Ty, unsigned BitWidth) {
+ if (Ty->isBooleanType())
+ return getBoolSort();
+
+ if (Ty->isRealFloatingType())
+ return getFloatSort(BitWidth);
+
+ return getBitvectorSort(BitWidth);
+ }
+
+ /// Constructs an SMTExprRef from an unary operator.
+ SMTExprRef fromUnOp(const UnaryOperator::Opcode Op, const SMTExprRef &Exp) {
+ switch (Op) {
+ case UO_Minus:
+ return mkBVNeg(Exp);
+
+ case UO_Not:
+ return mkBVNot(Exp);
+
+ case UO_LNot:
+ return mkNot(Exp);
+
+ default:;
+ }
+ llvm_unreachable("Unimplemented opcode");
+ }
+
+ /// Constructs an SMTExprRef from a floating-point unary operator.
+ SMTExprRef fromFloatUnOp(const UnaryOperator::Opcode Op,
+ const SMTExprRef &Exp) {
+ switch (Op) {
+ case UO_Minus:
+ return mkFPNeg(Exp);
+
+ case UO_LNot:
+ return fromUnOp(Op, Exp);
+
+ default:;
+ }
+ llvm_unreachable("Unimplemented opcode");
+ }
+
+ /// Construct an SMTExprRef from a n-ary binary operator.
+ SMTExprRef fromNBinOp(const BinaryOperator::Opcode Op,
+ const std::vector<SMTExprRef> &ASTs) {
+ assert(!ASTs.empty());
+
+ if (Op != BO_LAnd && Op != BO_LOr)
+ llvm_unreachable("Unimplemented opcode");
+
+ SMTExprRef res = ASTs.front();
+ for (std::size_t i = 1; i < ASTs.size(); ++i)
+ res = (Op == BO_LAnd) ? mkAnd(res, ASTs[i]) : mkOr(res, ASTs[i]);
+ return res;
+ }
+
+ /// Construct an SMTExprRef from a binary operator.
+ SMTExprRef fromBinOp(const SMTExprRef &LHS, const BinaryOperator::Opcode Op,
+ const SMTExprRef &RHS, bool isSigned) {
+ assert(*getSort(LHS) == *getSort(RHS) && "AST's must have the same sort!");
+
+ switch (Op) {
+ // Multiplicative operators
+ case BO_Mul:
+ return mkBVMul(LHS, RHS);
+
+ case BO_Div:
+ return isSigned ? mkBVSDiv(LHS, RHS) : mkBVUDiv(LHS, RHS);
+
+ case BO_Rem:
+ return isSigned ? mkBVSRem(LHS, RHS) : mkBVURem(LHS, RHS);
+
+ // Additive operators
+ case BO_Add:
+ return mkBVAdd(LHS, RHS);
+
+ case BO_Sub:
+ return mkBVSub(LHS, RHS);
+
+ // Bitwise shift operators
+ case BO_Shl:
+ return mkBVShl(LHS, RHS);
+
+ case BO_Shr:
+ return isSigned ? mkBVAshr(LHS, RHS) : mkBVLshr(LHS, RHS);
+
+ // Relational operators
+ case BO_LT:
+ return isSigned ? mkBVSlt(LHS, RHS) : mkBVUlt(LHS, RHS);
+
+ case BO_GT:
+ return isSigned ? mkBVSgt(LHS, RHS) : mkBVUgt(LHS, RHS);
+
+ case BO_LE:
+ return isSigned ? mkBVSle(LHS, RHS) : mkBVUle(LHS, RHS);
+
+ case BO_GE:
+ return isSigned ? mkBVSge(LHS, RHS) : mkBVUge(LHS, RHS);
+
+ // Equality operators
+ case BO_EQ:
+ return mkEqual(LHS, RHS);
+
+ case BO_NE:
+ return fromUnOp(UO_LNot, fromBinOp(LHS, BO_EQ, RHS, isSigned));
+
+ // Bitwise operators
+ case BO_And:
+ return mkBVAnd(LHS, RHS);
+
+ case BO_Xor:
+ return mkBVXor(LHS, RHS);
+
+ case BO_Or:
+ return mkBVOr(LHS, RHS);
+
+ // Logical operators
+ case BO_LAnd:
+ return mkAnd(LHS, RHS);
+
+ case BO_LOr:
+ return mkOr(LHS, RHS);
+
+ default:;
+ }
+ llvm_unreachable("Unimplemented opcode");
+ }
+
+ /// Construct an SMTExprRef from a special floating-point binary operator.
+ SMTExprRef fromFloatSpecialBinOp(const SMTExprRef &LHS,
+ const BinaryOperator::Opcode Op,
+ const llvm::APFloat::fltCategory &RHS) {
+ switch (Op) {
+ // Equality operators
+ case BO_EQ:
+ switch (RHS) {
+ case llvm::APFloat::fcInfinity:
+ return mkFPIsInfinite(LHS);
+
+ case llvm::APFloat::fcNaN:
+ return mkFPIsNaN(LHS);
+
+ case llvm::APFloat::fcNormal:
+ return mkFPIsNormal(LHS);
+
+ case llvm::APFloat::fcZero:
+ return mkFPIsZero(LHS);
+ }
+ break;
+
+ case BO_NE:
+ return fromFloatUnOp(UO_LNot, fromFloatSpecialBinOp(LHS, BO_EQ, RHS));
+
+ default:;
+ }
+
+ llvm_unreachable("Unimplemented opcode");
+ }
+
+ /// Construct an SMTExprRef from a floating-point binary operator.
+ SMTExprRef fromFloatBinOp(const SMTExprRef &LHS,
+ const BinaryOperator::Opcode Op,
+ const SMTExprRef &RHS) {
+ assert(*getSort(LHS) == *getSort(RHS) && "AST's must have the same sort!");
+
+ switch (Op) {
+ // Multiplicative operators
+ case BO_Mul:
+ return mkFPMul(LHS, RHS);
+
+ case BO_Div:
+ return mkFPDiv(LHS, RHS);
+
+ case BO_Rem:
+ return mkFPRem(LHS, RHS);
+
+ // Additive operators
+ case BO_Add:
+ return mkFPAdd(LHS, RHS);
+
+ case BO_Sub:
+ return mkFPSub(LHS, RHS);
+
+ // Relational operators
+ case BO_LT:
+ return mkFPLt(LHS, RHS);
+
+ case BO_GT:
+ return mkFPGt(LHS, RHS);
+
+ case BO_LE:
+ return mkFPLe(LHS, RHS);
+
+ case BO_GE:
+ return mkFPGe(LHS, RHS);
+
+ // Equality operators
+ case BO_EQ:
+ return mkFPEqual(LHS, RHS);
+
+ case BO_NE:
+ return fromFloatUnOp(UO_LNot, fromFloatBinOp(LHS, BO_EQ, RHS));
+
+ // Logical operators
+ case BO_LAnd:
+ case BO_LOr:
+ return fromBinOp(LHS, Op, RHS, false);
+
+ default:;
+ }
+
+ llvm_unreachable("Unimplemented opcode");
+ }
+
+ /// Construct an SMTExprRef from a QualType FromTy to a QualType ToTy, and
+ /// their bit widths.
+ SMTExprRef fromCast(const SMTExprRef &Exp, QualType ToTy, uint64_t ToBitWidth,
+ QualType FromTy, uint64_t FromBitWidth) {
+ if ((FromTy->isIntegralOrEnumerationType() &&
+ ToTy->isIntegralOrEnumerationType()) ||
+ (FromTy->isAnyPointerType() ^ ToTy->isAnyPointerType()) ||
+ (FromTy->isBlockPointerType() ^ ToTy->isBlockPointerType()) ||
+ (FromTy->isReferenceType() ^ ToTy->isReferenceType())) {
+
+ if (FromTy->isBooleanType()) {
+ assert(ToBitWidth > 0 && "BitWidth must be positive!");
+ return mkIte(Exp, mkBitvector(llvm::APSInt("1"), ToBitWidth),
+ mkBitvector(llvm::APSInt("0"), ToBitWidth));
+ }
+
+ if (ToBitWidth > FromBitWidth)
+ return FromTy->isSignedIntegerOrEnumerationType()
+ ? mkBVSignExt(ToBitWidth - FromBitWidth, Exp)
+ : mkBVZeroExt(ToBitWidth - FromBitWidth, Exp);
+
+ if (ToBitWidth < FromBitWidth)
+ return mkBVExtract(ToBitWidth - 1, 0, Exp);
+
+ // Both are bitvectors with the same width, ignore the type cast
+ return Exp;
+ }
+
+ if (FromTy->isRealFloatingType() && ToTy->isRealFloatingType()) {
+ if (ToBitWidth != FromBitWidth)
+ return mkFPtoFP(Exp, getFloatSort(ToBitWidth));
+
+ return Exp;
+ }
+
+ if (FromTy->isIntegralOrEnumerationType() && ToTy->isRealFloatingType()) {
+ SMTSortRef Sort = getFloatSort(ToBitWidth);
+ return FromTy->isSignedIntegerOrEnumerationType() ? mkFPtoSBV(Exp, Sort)
+ : mkFPtoUBV(Exp, Sort);
+ }
+
+ if (FromTy->isRealFloatingType() && ToTy->isIntegralOrEnumerationType())
+ return ToTy->isSignedIntegerOrEnumerationType()
+ ? mkSBVtoFP(Exp, ToBitWidth)
+ : mkUBVtoFP(Exp, ToBitWidth);
+
+ llvm_unreachable("Unsupported explicit type cast!");
+ }
+
+ // Callback function for doCast parameter on APSInt type.
+ llvm::APSInt castAPSInt(const llvm::APSInt &V, QualType ToTy,
+ uint64_t ToWidth, QualType FromTy,
+ uint64_t FromWidth) {
+ APSIntType TargetType(ToWidth, !ToTy->isSignedIntegerOrEnumerationType());
+ return TargetType.convert(V);
+ }
+
+ // Generate an SMTExprRef that represents the given symbolic expression.
+ // Sets the hasComparison parameter if the expression has a comparison
+ // operator.
+ // Sets the RetTy parameter to the final return type after promotions and
+ // casts.
+ SMTExprRef getExpr(ASTContext &Ctx, SymbolRef Sym, QualType *RetTy = nullptr,
+ bool *hasComparison = nullptr) {
+ if (hasComparison) {
+ *hasComparison = false;
+ }
+
+ return getSymExpr(Ctx, Sym, RetTy, hasComparison);
+ }
+
+ // Generate an SMTExprRef that compares the expression to zero.
+ SMTExprRef getZeroExpr(ASTContext &Ctx, const SMTExprRef &Exp, QualType Ty,
+ bool Assumption) {
+
+ if (Ty->isRealFloatingType()) {
+ llvm::APFloat Zero =
+ llvm::APFloat::getZero(Ctx.getFloatTypeSemantics(Ty));
+ return fromFloatBinOp(Exp, Assumption ? BO_EQ : BO_NE, fromAPFloat(Zero));
+ }
+
+ if (Ty->isIntegralOrEnumerationType() || Ty->isAnyPointerType() ||
+ Ty->isBlockPointerType() || Ty->isReferenceType()) {
+
+ // Skip explicit comparison for boolean types
+ bool isSigned = Ty->isSignedIntegerOrEnumerationType();
+ if (Ty->isBooleanType())
+ return Assumption ? fromUnOp(UO_LNot, Exp) : Exp;
+
+ return fromBinOp(Exp, Assumption ? BO_EQ : BO_NE,
+ fromInt("0", Ctx.getTypeSize(Ty)), isSigned);
+ }
+
+ llvm_unreachable("Unsupported type for zero value!");
+ }
+
+ // Recursive implementation to unpack and generate symbolic expression.
+ // Sets the hasComparison and RetTy parameters. See getExpr().
+ SMTExprRef getSymExpr(ASTContext &Ctx, SymbolRef Sym, QualType *RetTy,
+ bool *hasComparison) {
+ if (const SymbolData *SD = dyn_cast<SymbolData>(Sym)) {
+ if (RetTy)
+ *RetTy = Sym->getType();
+
+ return fromData(SD->getSymbolID(), Sym->getType(),
+ Ctx.getTypeSize(Sym->getType()));
+ }
+
+ if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) {
+ if (RetTy)
+ *RetTy = Sym->getType();
+
+ QualType FromTy;
+ SMTExprRef Exp =
+ getSymExpr(Ctx, SC->getOperand(), &FromTy, hasComparison);
+ // Casting an expression with a comparison invalidates it. Note that this
+ // must occur after the recursive call above.
+ // e.g. (signed char) (x > 0)
+ if (hasComparison)
+ *hasComparison = false;
+ return getCastExpr(Ctx, Exp, FromTy, Sym->getType());
+ }
+
+ if (const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) {
+ SMTExprRef Exp = getSymBinExpr(Ctx, BSE, hasComparison, RetTy);
+ // Set the hasComparison parameter, in post-order traversal order.
+ if (hasComparison)
+ *hasComparison = BinaryOperator::isComparisonOp(BSE->getOpcode());
+ return Exp;
+ }
+
+ llvm_unreachable("Unsupported SymbolRef type!");
+ }
+
+ // Wrapper to generate SMTExprRef from SymbolCast data.
+ SMTExprRef getCastExpr(ASTContext &Ctx, const SMTExprRef &Exp,
+ QualType FromTy, QualType ToTy) {
+ return fromCast(Exp, ToTy, Ctx.getTypeSize(ToTy), FromTy,
+ Ctx.getTypeSize(FromTy));
+ }
+
+ // Wrapper to generate SMTExprRef from BinarySymExpr.
+ // Sets the hasComparison and RetTy parameters. See getSMTExprRef().
+ SMTExprRef getSymBinExpr(ASTContext &Ctx, const BinarySymExpr *BSE,
+ bool *hasComparison, QualType *RetTy) {
+ QualType LTy, RTy;
+ BinaryOperator::Opcode Op = BSE->getOpcode();
+
+ if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE)) {
+ SMTExprRef LHS = getSymExpr(Ctx, SIE->getLHS(), &LTy, hasComparison);
+ llvm::APSInt NewRInt;
+ std::tie(NewRInt, RTy) = fixAPSInt(Ctx, SIE->getRHS());
+ SMTExprRef RHS = fromAPSInt(NewRInt);
+ return getBinExpr(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 = fromAPSInt(NewLInt);
+ SMTExprRef RHS = getSymExpr(Ctx, ISE->getRHS(), &RTy, hasComparison);
+ return getBinExpr(Ctx, LHS, LTy, Op, RHS, RTy, RetTy);
+ }
+
+ if (const SymSymExpr *SSM = dyn_cast<SymSymExpr>(BSE)) {
+ SMTExprRef LHS = getSymExpr(Ctx, SSM->getLHS(), &LTy, hasComparison);
+ SMTExprRef RHS = getSymExpr(Ctx, SSM->getRHS(), &RTy, hasComparison);
+ return getBinExpr(Ctx, LHS, LTy, Op, RHS, RTy, RetTy);
+ }
+
+ llvm_unreachable("Unsupported BinarySymExpr type!");
+ }
+
+ // Wrapper to generate SMTExprRef from unpacked binary symbolic expression.
+ // Sets the RetTy parameter. See getSMTExprRef().
+ SMTExprRef getBinExpr(ASTContext &Ctx, const SMTExprRef &LHS, QualType LTy,
+ BinaryOperator::Opcode Op, const SMTExprRef &RHS,
+ QualType RTy, QualType *RetTy) {
+ SMTExprRef NewLHS = LHS;
+ SMTExprRef NewRHS = RHS;
+ doTypeConversion(Ctx, NewLHS, NewRHS, LTy, RTy);
+
+ // Update the return type parameter if the output type has changed.
+ if (RetTy) {
+ // A boolean result can be represented as an integer type in C/C++, but at
+ // this point we only care about the SMT sorts. Set it as a boolean type
+ // to avoid subsequent SMT errors.
+ if (BinaryOperator::isComparisonOp(Op) ||
+ BinaryOperator::isLogicalOp(Op)) {
+ *RetTy = Ctx.BoolTy;
+ } else {
+ *RetTy = LTy;
+ }
+
+ // If the two operands are pointers and the operation is a subtraction,
+ // the result is of type ptrdiff_t, which is signed
+ if (LTy->isAnyPointerType() && RTy->isAnyPointerType() && Op == BO_Sub) {
+ *RetTy = Ctx.getPointerDiffType();
+ }
+ }
+
+ return LTy->isRealFloatingType()
+ ? fromFloatBinOp(NewLHS, Op, NewRHS)
+ : fromBinOp(NewLHS, Op, NewRHS,
+ LTy->isSignedIntegerOrEnumerationType());
+ }
+
+ // Wrapper to generate SMTExprRef from a range. If From == To, an equality
+ // will be created instead.
+ SMTExprRef getRangeExpr(ASTContext &Ctx, SymbolRef Sym,
+ const llvm::APSInt &From, const llvm::APSInt &To,
+ bool InRange) {
+ // Convert lower bound
+ QualType FromTy;
+ llvm::APSInt NewFromInt;
+ std::tie(NewFromInt, FromTy) = fixAPSInt(Ctx, From);
+ SMTExprRef FromExp = fromAPSInt(NewFromInt);
+
+ // Convert symbol
+ QualType SymTy;
+ SMTExprRef Exp = getExpr(Ctx, Sym, &SymTy);
+
+ // Construct single (in)equality
+ if (From == To)
+ return getBinExpr(Ctx, Exp, SymTy, InRange ? BO_EQ : BO_NE, FromExp,
+ FromTy, /*RetTy=*/nullptr);
+
+ QualType ToTy;
+ llvm::APSInt NewToInt;
+ std::tie(NewToInt, ToTy) = fixAPSInt(Ctx, To);
+ SMTExprRef ToExp = fromAPSInt(NewToInt);
+ assert(FromTy == ToTy && "Range values have different types!");
+
+ // Construct two (in)equalities, and a logical and/or
+ SMTExprRef LHS = getBinExpr(Ctx, Exp, SymTy, InRange ? BO_GE : BO_LT,
+ FromExp, FromTy, /*RetTy=*/nullptr);
+ SMTExprRef RHS =
+ getBinExpr(Ctx, Exp, SymTy, InRange ? BO_LE : BO_GT, ToExp, ToTy,
+ /*RetTy=*/nullptr);
+
+ return fromBinOp(LHS, InRange ? BO_LAnd : BO_LOr, RHS,
+ SymTy->isSignedIntegerOrEnumerationType());
+ }
+
+ // Recover the QualType of an APSInt.
+ // TODO: Refactor to put elsewhere
+ QualType getAPSIntType(ASTContext &Ctx, const llvm::APSInt &Int) {
+ return Ctx.getIntTypeForBitwidth(Int.getBitWidth(), Int.isSigned());
+ }
+
+ // Get the QualTy for the input APSInt, and fix it if it has a bitwidth of 1.
+ std::pair<llvm::APSInt, QualType> fixAPSInt(ASTContext &Ctx,
+ const llvm::APSInt &Int) {
+ llvm::APSInt NewInt;
+
+ // FIXME: This should be a cast from a 1-bit integer type to a boolean type,
+ // but the former is not available in Clang. Instead, extend the APSInt
+ // directly.
+ if (Int.getBitWidth() == 1 && getAPSIntType(Ctx, Int).isNull()) {
+ NewInt = Int.extend(Ctx.getTypeSize(Ctx.BoolTy));
+ } else
+ NewInt = Int;
+
+ return std::make_pair(NewInt, getAPSIntType(Ctx, NewInt));
+ }
+
+ // Perform implicit type conversion on binary symbolic expressions.
+ // May modify all input parameters.
+ // TODO: Refactor to use built-in conversion functions
+ void doTypeConversion(ASTContext &Ctx, SMTExprRef &LHS, SMTExprRef &RHS,
+ QualType &LTy, QualType &RTy) {
+ assert(!LTy.isNull() && !RTy.isNull() && "Input type is null!");
+
+ // Perform type conversion
+ if ((LTy->isIntegralOrEnumerationType() &&
+ RTy->isIntegralOrEnumerationType()) &&
+ (LTy->isArithmeticType() && RTy->isArithmeticType())) {
+ doIntTypeConversion<SMTExprRef, &SMTSolver::fromCast>(Ctx, LHS, LTy, RHS,
+ RTy);
+ return;
+ }
+
+ if (LTy->isRealFloatingType() || RTy->isRealFloatingType()) {
+ doFloatTypeConversion<SMTExprRef, &SMTSolver::fromCast>(Ctx, LHS, LTy,
+ RHS, RTy);
+ return;
+ }
+
+ if ((LTy->isAnyPointerType() || RTy->isAnyPointerType()) ||
+ (LTy->isBlockPointerType() || RTy->isBlockPointerType()) ||
+ (LTy->isReferenceType() || RTy->isReferenceType())) {
+ // TODO: Refactor to Sema::FindCompositePointerType(), and
+ // Sema::CheckCompareOperands().
+
+ uint64_t LBitWidth = Ctx.getTypeSize(LTy);
+ uint64_t RBitWidth = Ctx.getTypeSize(RTy);
+
+ // Cast the non-pointer type to the pointer type.
+ // TODO: Be more strict about this.
+ if ((LTy->isAnyPointerType() ^ RTy->isAnyPointerType()) ||
+ (LTy->isBlockPointerType() ^ RTy->isBlockPointerType()) ||
+ (LTy->isReferenceType() ^ RTy->isReferenceType())) {
+ if (LTy->isNullPtrType() || LTy->isBlockPointerType() ||
+ LTy->isReferenceType()) {
+ LHS = fromCast(LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ } else {
+ RHS = fromCast(RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ }
+ }
+
+ // Cast the void pointer type to the non-void pointer type.
+ // For void types, this assumes that the casted value is equal to the
+ // value of the original pointer, and does not account for alignment
+ // requirements.
+ if (LTy->isVoidPointerType() ^ RTy->isVoidPointerType()) {
+ assert((Ctx.getTypeSize(LTy) == Ctx.getTypeSize(RTy)) &&
+ "Pointer types have different bitwidths!");
+ if (RTy->isVoidPointerType())
+ RTy = LTy;
+ else
+ LTy = RTy;
+ }
+
+ if (LTy == RTy)
+ return;
+ }
+
+ // Fallback: for the solver, assume that these types don't really matter
+ if ((LTy.getCanonicalType() == RTy.getCanonicalType()) ||
+ (LTy->isObjCObjectPointerType() && RTy->isObjCObjectPointerType())) {
+ LTy = RTy;
+ return;
+ }
+
+ // TODO: Refine behavior for invalid type casts
+ }
+
+ // Perform implicit integer type conversion.
+ // May modify all input parameters.
+ // TODO: Refactor to use Sema::handleIntegerConversion()
+ template <typename T, T (SMTSolver::*doCast)(const T &, QualType, uint64_t,
+ QualType, uint64_t)>
+ void doIntTypeConversion(ASTContext &Ctx, T &LHS, QualType &LTy, T &RHS,
+ QualType &RTy) {
+
+ uint64_t LBitWidth = Ctx.getTypeSize(LTy);
+ uint64_t RBitWidth = Ctx.getTypeSize(RTy);
+
+ assert(!LTy.isNull() && !RTy.isNull() && "Input type is null!");
+ // Always perform integer promotion before checking type equality.
+ // Otherwise, e.g. (bool) a + (bool) b could trigger a backend assertion
+ if (LTy->isPromotableIntegerType()) {
+ QualType NewTy = Ctx.getPromotedIntegerType(LTy);
+ uint64_t NewBitWidth = Ctx.getTypeSize(NewTy);
+ LHS = (this->*doCast)(LHS, NewTy, NewBitWidth, LTy, LBitWidth);
+ LTy = NewTy;
+ LBitWidth = NewBitWidth;
+ }
+ if (RTy->isPromotableIntegerType()) {
+ QualType NewTy = Ctx.getPromotedIntegerType(RTy);
+ uint64_t NewBitWidth = Ctx.getTypeSize(NewTy);
+ RHS = (this->*doCast)(RHS, NewTy, NewBitWidth, RTy, RBitWidth);
+ RTy = NewTy;
+ RBitWidth = NewBitWidth;
+ }
+
+ if (LTy == RTy)
+ return;
+
+ // Perform integer type conversion
+ // Note: Safe to skip updating bitwidth because this must terminate
+ bool isLSignedTy = LTy->isSignedIntegerOrEnumerationType();
+ bool isRSignedTy = RTy->isSignedIntegerOrEnumerationType();
+
+ int order = Ctx.getIntegerTypeOrder(LTy, RTy);
+ if (isLSignedTy == isRSignedTy) {
+ // Same signedness; use the higher-ranked type
+ if (order == 1) {
+ RHS = (this->*doCast)(RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ } else {
+ LHS = (this->*doCast)(LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ }
+ } else if (order != (isLSignedTy ? 1 : -1)) {
+ // The unsigned type has greater than or equal rank to the
+ // signed type, so use the unsigned type
+ if (isRSignedTy) {
+ RHS = (this->*doCast)(RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ } else {
+ LHS = (this->*doCast)(LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ }
+ } else if (LBitWidth != RBitWidth) {
+ // The two types are different widths; if we are here, that
+ // means the signed type is larger than the unsigned type, so
+ // use the signed type.
+ if (isLSignedTy) {
+ RHS = (this->*doCast)(RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ } else {
+ LHS = (this->*doCast)(LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ }
+ } else {
+ // The signed type is higher-ranked than the unsigned type,
+ // but isn't actually any bigger (like unsigned int and long
+ // on most 32-bit systems). Use the unsigned type corresponding
+ // to the signed type.
+ QualType NewTy =
+ Ctx.getCorrespondingUnsignedType(isLSignedTy ? LTy : RTy);
+ RHS = (this->*doCast)(RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = NewTy;
+ LHS = (this->*doCast)(LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = NewTy;
+ }
+ }
+
+ // Perform implicit floating-point type conversion.
+ // May modify all input parameters.
+ // TODO: Refactor to use Sema::handleFloatConversion()
+ template <typename T, T (SMTSolver::*doCast)(const T &, QualType, uint64_t,
+ QualType, uint64_t)>
+ void doFloatTypeConversion(ASTContext &Ctx, T &LHS, QualType &LTy, T &RHS,
+ QualType &RTy) {
+
+ uint64_t LBitWidth = Ctx.getTypeSize(LTy);
+ uint64_t RBitWidth = Ctx.getTypeSize(RTy);
+
+ // Perform float-point type promotion
+ if (!LTy->isRealFloatingType()) {
+ LHS = (this->*doCast)(LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ LBitWidth = RBitWidth;
+ }
+ if (!RTy->isRealFloatingType()) {
+ RHS = (this->*doCast)(RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ RBitWidth = LBitWidth;
+ }
+
+ if (LTy == RTy)
+ return;
+
+ // If we have two real floating types, convert the smaller operand to the
+ // bigger result
+ // Note: Safe to skip updating bitwidth because this must terminate
+ int order = Ctx.getFloatingTypeOrder(LTy, RTy);
+ if (order > 0) {
+ RHS = (this->*doCast)(RHS, LTy, LBitWidth, RTy, RBitWidth);
+ RTy = LTy;
+ } else if (order == 0) {
+ LHS = (this->*doCast)(LHS, RTy, RBitWidth, LTy, LBitWidth);
+ LTy = RTy;
+ } else {
+ llvm_unreachable("Unsupported floating-point type cast!");
+ }
+ }
+
+ // Returns a boolean sort.
+ virtual SMTSortRef getBoolSort() = 0;
+
+ // Returns an appropriate bitvector sort for the given bitwidth.
+ virtual SMTSortRef getBitvectorSort(const unsigned BitWidth) = 0;
+
+ // Returns a floating-point sort of width 16
+ virtual SMTSortRef getFloat16Sort() = 0;
+
+ // Returns a floating-point sort of width 32
+ virtual SMTSortRef getFloat32Sort() = 0;
+
+ // Returns a floating-point sort of width 64
+ virtual SMTSortRef getFloat64Sort() = 0;
+
+ // Returns a floating-point sort of width 128
+ virtual SMTSortRef getFloat128Sort() = 0;
+
+ // Returns an appropriate sort for the given AST.
+ virtual SMTSortRef getSort(const SMTExprRef &AST) = 0;
+
+ // Returns a new SMTExprRef from an SMTExpr
+ virtual SMTExprRef newExprRef(const SMTExpr &E) const = 0;
+
+ /// Given a constraint, adds it to the solver
+ virtual void addConstraint(const SMTExprRef &Exp) const = 0;
+
+ /// Creates a bitvector addition operation
+ virtual SMTExprRef mkBVAdd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector subtraction operation
+ virtual SMTExprRef mkBVSub(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector multiplication operation
+ virtual SMTExprRef mkBVMul(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed modulus operation
+ virtual SMTExprRef mkBVSRem(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned modulus operation
+ virtual SMTExprRef mkBVURem(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed division operation
+ virtual SMTExprRef mkBVSDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned division operation
+ virtual SMTExprRef mkBVUDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector logical shift left operation
+ virtual SMTExprRef mkBVShl(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector arithmetic shift right operation
+ virtual SMTExprRef mkBVAshr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector logical shift right operation
+ virtual SMTExprRef mkBVLshr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector negation operation
+ virtual SMTExprRef mkBVNeg(const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector not operation
+ virtual SMTExprRef mkBVNot(const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector xor operation
+ virtual SMTExprRef mkBVXor(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector or operation
+ virtual SMTExprRef mkBVOr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector and operation
+ virtual SMTExprRef mkBVAnd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned less-than operation
+ virtual SMTExprRef mkBVUlt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed less-than operation
+ virtual SMTExprRef mkBVSlt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned greater-than operation
+ virtual SMTExprRef mkBVUgt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed greater-than operation
+ virtual SMTExprRef mkBVSgt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned less-equal-than operation
+ virtual SMTExprRef mkBVUle(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed less-equal-than operation
+ virtual SMTExprRef mkBVSle(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned greater-equal-than operation
+ virtual SMTExprRef mkBVUge(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed greater-equal-than operation
+ virtual SMTExprRef mkBVSge(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a boolean not operation
+ virtual SMTExprRef mkNot(const SMTExprRef &Exp) = 0;
+
+ /// Creates a boolean equality operation
+ virtual SMTExprRef mkEqual(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a boolean and operation
+ virtual SMTExprRef mkAnd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a boolean or operation
+ virtual SMTExprRef mkOr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a boolean ite operation
+ virtual SMTExprRef mkIte(const SMTExprRef &Cond, const SMTExprRef &T,
+ const SMTExprRef &F) = 0;
+
+ /// Creates a bitvector sign extension operation
+ virtual SMTExprRef mkBVSignExt(unsigned i, const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector zero extension operation
+ virtual SMTExprRef mkBVZeroExt(unsigned i, const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector extract operation
+ virtual SMTExprRef mkBVExtract(unsigned High, unsigned Low,
+ const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector concat operation
+ virtual SMTExprRef mkBVConcat(const SMTExprRef &LHS,
+ const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point negation operation
+ virtual SMTExprRef mkFPNeg(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point isInfinite operation
+ virtual SMTExprRef mkFPIsInfinite(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point isNaN operation
+ virtual SMTExprRef mkFPIsNaN(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point isNormal operation
+ virtual SMTExprRef mkFPIsNormal(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point isZero operation
+ virtual SMTExprRef mkFPIsZero(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point multiplication operation
+ virtual SMTExprRef mkFPMul(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point division operation
+ virtual SMTExprRef mkFPDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point remainder operation
+ virtual SMTExprRef mkFPRem(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point addition operation
+ virtual SMTExprRef mkFPAdd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point subtraction operation
+ virtual SMTExprRef mkFPSub(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point less-than operation
+ virtual SMTExprRef mkFPLt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point greater-than operation
+ virtual SMTExprRef mkFPGt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point less-than-or-equal operation
+ virtual SMTExprRef mkFPLe(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point greater-than-or-equal operation
+ virtual SMTExprRef mkFPGe(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point equality operation
+ virtual SMTExprRef mkFPEqual(const SMTExprRef &LHS,
+ const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point conversion from floatint-point to floating-point
+ /// 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;
+
+ /// Creates a floating-point conversion from unsigned bitvector to
+ /// floatint-point operation
+ virtual SMTExprRef mkUBVtoFP(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;
+
+ // Returns an appropriate floating-point rounding mode.
+ virtual SMTExprRef getFloatRoundingMode() = 0;
+
+ // If the a model is available, returns the value of a given bitvector symbol
+ virtual llvm::APSInt getBitvector(const SMTExprRef &Exp, unsigned BitWidth,
+ bool isUnsigned) = 0;
+
+ // If the a model is available, returns the value of a given boolean symbol
+ virtual bool getBoolean(const SMTExprRef &Exp) = 0;
+
+ /// Constructs an SMTExprRef from a boolean.
+ virtual SMTExprRef mkBoolean(const bool b) = 0;
+
+ /// Constructs an SMTExprRef from a finite APFloat.
+ virtual SMTExprRef mkFloat(const llvm::APFloat Float) = 0;
+
+ /// Constructs an SMTExprRef from an APSInt and its bit width
+ virtual SMTExprRef mkBitvector(const llvm::APSInt Int, unsigned BitWidth) = 0;
+
+ /// Given an expression, extract the value of this operand in the model.
+ virtual bool getInterpretation(const SMTExprRef &Exp, llvm::APSInt &Int) = 0;
+
+ /// Given an expression extract the value of this operand in the model.
+ 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;
+
+ /// Construct an SMTExprRef from a SymbolData.
+ virtual SMTExprRef fromData(const SymbolID ID, const QualType &Ty,
+ uint64_t BitWidth) = 0;
+
+ /// Check if the constraints are satisfiable
+ virtual ConditionTruthVal check() const = 0;
+
+ /// Push the current solver state
+ virtual void push() = 0;
+
+ /// Pop the previous solver state
+ virtual void pop(unsigned NumStates = 1) = 0;
+
+ /// Reset the solver and remove all constraints.
+ virtual void reset() const = 0;
+
+ virtual void print(raw_ostream &OS) const = 0;
+};
+
+/// Shared pointer for SMTSolvers.
+using SMTSolverRef = std::shared_ptr<SMTSolver>;
+
+/// Convenience method to create and Z3Solver object
+std::unique_ptr<SMTSolver> CreateZ3Solver();
+
+} // namespace ento
+} // namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTSort.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTSort.h
new file mode 100644
index 0000000000000..41ef573f0c713
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTSort.h
@@ -0,0 +1,91 @@
+//== SMTSort.h --------------------------------------------------*- 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 a SMT generic Sort API, which will be the base class
+// for every SMT solver sort specific class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTSORT_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTSORT_H
+
+#include "clang/Basic/TargetInfo.h"
+
+namespace clang {
+namespace ento {
+
+/// Generic base class for SMT sorts
+class SMTSort {
+public:
+ SMTSort() = default;
+ virtual ~SMTSort() = default;
+
+ /// Returns true if the sort is a bitvector, calls isBitvectorSortImpl().
+ virtual bool isBitvectorSort() const { return isBitvectorSortImpl(); }
+
+ /// Returns true if the sort is a floating-point, calls isFloatSortImpl().
+ virtual bool isFloatSort() const { return isFloatSortImpl(); }
+
+ /// Returns true if the sort is a boolean, calls isBooleanSortImpl().
+ virtual bool isBooleanSort() const { return isBooleanSortImpl(); }
+
+ /// Returns the bitvector size, fails if the sort is not a bitvector
+ /// Calls getBitvectorSortSizeImpl().
+ virtual unsigned getBitvectorSortSize() const {
+ assert(isBitvectorSort() && "Not a bitvector sort!");
+ unsigned Size = getBitvectorSortSizeImpl();
+ assert(Size && "Size is zero!");
+ return Size;
+ };
+
+ /// Returns the floating-point size, fails if the sort is not a floating-point
+ /// Calls getFloatSortSizeImpl().
+ virtual unsigned getFloatSortSize() const {
+ assert(isFloatSort() && "Not a floating-point sort!");
+ unsigned Size = getFloatSortSizeImpl();
+ assert(Size && "Size is zero!");
+ return Size;
+ };
+
+ friend bool operator==(SMTSort const &LHS, SMTSort const &RHS) {
+ return LHS.equal_to(RHS);
+ }
+
+ virtual void print(raw_ostream &OS) const = 0;
+
+ LLVM_DUMP_METHOD void dump() const { print(llvm::errs()); }
+
+protected:
+ /// Query the SMT solver and returns true if two sorts are equal (same kind
+ /// and bit width). This does not check if the two sorts are the same objects.
+ virtual bool equal_to(SMTSort const &other) const = 0;
+
+ /// Query the SMT solver and checks if a sort is bitvector.
+ virtual bool isBitvectorSortImpl() const = 0;
+
+ /// Query the SMT solver and checks if a sort is floating-point.
+ virtual bool isFloatSortImpl() const = 0;
+
+ /// Query the SMT solver and checks if a sort is boolean.
+ virtual bool isBooleanSortImpl() const = 0;
+
+ /// Query the SMT solver and returns the sort bit width.
+ virtual unsigned getBitvectorSortSizeImpl() const = 0;
+
+ /// Query the SMT solver and returns the sort bit width.
+ virtual unsigned getFloatSortSizeImpl() const = 0;
+};
+
+/// Shared pointer for SMTSorts, used by SMTSolver API.
+using SMTSortRef = std::shared_ptr<SMTSort>;
+
+} // namespace ento
+} // namespace clang
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index d58d0a690c88e..31300d69f2ff7 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -16,21 +16,43 @@
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALBUILDER_H
#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/Optional.h"
+#include <cstdint>
namespace clang {
+class BlockDecl;
class CXXBoolLiteralExpr;
+class CXXMethodDecl;
+class CXXRecordDecl;
+class DeclaratorDecl;
+class FunctionDecl;
+class LocationContext;
+class StackFrameContext;
+class Stmt;
namespace ento {
+class ConditionTruthVal;
+class ProgramStateManager;
+class StoreRef;
+
class SValBuilder {
virtual void anchor();
+
protected:
ASTContext &Context;
@@ -62,14 +84,12 @@ public:
public:
SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
ProgramStateManager &stateMgr)
- : Context(context), BasicVals(context, alloc),
- SymMgr(context, BasicVals, alloc),
- MemMgr(context, alloc),
- StateMgr(stateMgr),
- ArrayIndexTy(context.LongLongTy),
- ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {}
+ : Context(context), BasicVals(context, alloc),
+ SymMgr(context, BasicVals, alloc), MemMgr(context, alloc),
+ StateMgr(stateMgr), ArrayIndexTy(context.LongLongTy),
+ ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {}
- virtual ~SValBuilder() {}
+ virtual ~SValBuilder() = default;
bool haveSameType(const SymExpr *Sym1, const SymExpr *Sym2) {
return haveSameType(Sym1->getType(), Sym2->getType());
@@ -124,7 +144,12 @@ public:
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
SVal lhs, SVal rhs, QualType type);
-
+
+ /// \return Whether values in \p lhs and \p rhs are equal at \p state.
+ ConditionTruthVal areEqual(ProgramStateRef state, SVal lhs, SVal rhs);
+
+ SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs);
+
DefinedOrUnknownSVal evalEQ(ProgramStateRef state, DefinedOrUnknownSVal lhs,
DefinedOrUnknownSVal rhs);
@@ -173,7 +198,7 @@ public:
/// Make a unique symbol for value of region.
DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedValueRegion *region);
- /// \brief Create a new symbol with a unique 'name'.
+ /// Create a new symbol with a unique 'name'.
///
/// We resort to conjured symbols when we cannot construct a derived symbol.
/// The advantage of symbols derived/built from other symbols is that we
@@ -188,12 +213,12 @@ public:
const LocationContext *LCtx,
QualType type,
unsigned count);
-
DefinedOrUnknownSVal conjureSymbolVal(const Stmt *stmt,
const LocationContext *LCtx,
QualType type,
unsigned visitCount);
- /// \brief Conjure a symbol representing heap allocated memory region.
+
+ /// Conjure a symbol representing heap allocated memory region.
///
/// Note, the expression should represent a location.
DefinedOrUnknownSVal getConjuredHeapSymbolVal(const Expr *E,
@@ -304,7 +329,7 @@ public:
NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
const SymExpr *rhs, QualType type);
- /// \brief Create a NonLoc value for cast.
+ /// Create a NonLoc value for cast.
NonLoc makeNonLoc(const SymExpr *operand, QualType fromTy, QualType toTy);
nonloc::ConcreteInt makeTruthVal(bool b, QualType type) {
@@ -342,6 +367,15 @@ public:
return loc::ConcreteInt(BasicVals.getValue(integer));
}
+ /// Make an SVal that represents the given symbol. This follows the convention
+ /// of representing Loc-type symbols (symbolic pointers and references)
+ /// as Loc values wrapping the symbol rather than as plain symbol values.
+ SVal makeSymbolVal(SymbolRef Sym) {
+ if (Loc::isLocType(Sym->getType()))
+ return makeLoc(Sym);
+ return nonloc::SymbolVal(Sym);
+ }
+
/// Return a memory region for the 'this' object reference.
loc::MemRegionVal getCXXThis(const CXXMethodDecl *D,
const StackFrameContext *SFC);
@@ -355,8 +389,8 @@ SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
ASTContext &context,
ProgramStateManager &stateMgr);
-} // end GR namespace
+} // namespace ento
-} // end clang namespace
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALBUILDER_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 06132587b4aaf..0fde63e9eb09b 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -1,4 +1,4 @@
-//== SVals.h - Abstract Values for Static Analysis ---------*- C++ -*--==//
+//===- SVals.h - Abstract Values for Static Analysis ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -16,11 +16,18 @@
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/LLVM.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/Support/Casting.h"
+#include <cassert>
+#include <cstdint>
+#include <utility>
//==------------------------------------------------------------------------==//
// Base SVal types.
@@ -28,34 +35,40 @@
namespace clang {
+class CXXBaseSpecifier;
+class DeclaratorDecl;
+class FunctionDecl;
+class LabelDecl;
+
namespace ento {
+class BasicValueFactory;
class CompoundValData;
class LazyCompoundValData;
-class PointerToMemberData;
-class ProgramState;
-class BasicValueFactory;
class MemRegion;
-class TypedValueRegion;
-class MemRegionManager;
-class ProgramStateManager;
+class PointerToMemberData;
class SValBuilder;
+class TypedValueRegion;
namespace nonloc {
+
/// Sub-kinds for NonLoc values.
enum Kind {
#define NONLOC_SVAL(Id, Parent) Id ## Kind,
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
};
-}
+
+} // namespace nonloc
namespace loc {
+
/// Sub-kinds for Loc values.
enum Kind {
#define LOC_SVAL(Id, Parent) Id ## Kind,
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def"
};
-}
+
+} // namespace loc
/// SVal - This represents a symbolic expression, which can be either
/// an L-value or an R-value.
@@ -71,22 +84,21 @@ public:
enum { BaseBits = 2, BaseMask = 0x3 };
protected:
- const void *Data;
+ const void *Data = nullptr;
/// The lowest 2 bits are a BaseKind (0 -- 3).
/// The higher bits are an unsigned "kind" value.
- unsigned Kind;
+ unsigned Kind = 0;
explicit SVal(const void *d, bool isLoc, unsigned ValKind)
- : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {}
+ : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {}
- explicit SVal(BaseKind k, const void *D = nullptr)
- : Data(D), Kind(k) {}
+ explicit SVal(BaseKind k, const void *D = nullptr) : Data(D), Kind(k) {}
public:
- explicit SVal() : Data(nullptr), Kind(0) {}
+ explicit SVal() = default;
- /// \brief Convert to the specified SVal type, asserting that this SVal is of
+ /// Convert to the specified SVal type, asserting that this SVal is of
/// the desired type.
template<typename T>
T castAs() const {
@@ -94,7 +106,7 @@ public:
return *static_cast<const T *>(this);
}
- /// \brief Convert to the specified SVal type, returning None if this SVal is
+ /// Convert to the specified SVal type, returning None if this SVal is
/// not of the desired type.
template<typename T>
Optional<T> getAs() const {
@@ -103,38 +115,38 @@ public:
return *static_cast<const T *>(this);
}
- inline unsigned getRawKind() const { return Kind; }
- inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
- inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
+ unsigned getRawKind() const { return Kind; }
+ BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
+ unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
// This method is required for using SVal in a FoldingSetNode. It
// extracts a unique signature for this SVal object.
- inline void Profile(llvm::FoldingSetNodeID& ID) const {
+ void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger((unsigned) getRawKind());
ID.AddPointer(Data);
}
- inline bool operator==(const SVal& R) const {
+ bool operator==(const SVal &R) const {
return getRawKind() == R.getRawKind() && Data == R.Data;
}
- inline bool operator!=(const SVal& R) const {
+ bool operator!=(const SVal &R) const {
return !(*this == R);
}
- inline bool isUnknown() const {
+ bool isUnknown() const {
return getRawKind() == UnknownValKind;
}
- inline bool isUndef() const {
+ bool isUndef() const {
return getRawKind() == UndefinedValKind;
}
- inline bool isUnknownOrUndef() const {
+ bool isUnknownOrUndef() const {
return getRawKind() <= UnknownValKind;
}
- inline bool isValid() const {
+ bool isValid() const {
return getRawKind() > UnknownValKind;
}
@@ -152,7 +164,7 @@ public:
/// Otherwise return 0.
const FunctionDecl *getAsFunctionDecl() const;
- /// \brief If this SVal is a location and wraps a symbol, return that
+ /// If this SVal is a location and wraps a symbol, return that
/// SymbolRef. Otherwise return 0.
///
/// Casts are ignored during lookup.
@@ -163,7 +175,7 @@ public:
/// Get the symbol in the SVal or its base region.
SymbolRef getLocSymbolInBase() const;
- /// \brief If this SVal wraps a symbol return that SymbolRef.
+ /// If this SVal wraps a symbol return that SymbolRef.
/// Otherwise, return 0.
///
/// Casts are ignored during lookup.
@@ -175,7 +187,7 @@ public:
/// return that expression. Otherwise return NULL.
const SymExpr *getAsSymbolicExpression() const;
- const SymExpr* getAsSymExpr() const;
+ const SymExpr *getAsSymExpr() const;
const MemRegion *getAsRegion() const;
@@ -183,7 +195,7 @@ public:
void dump() const;
SymExpr::symbol_iterator symbol_begin() const {
- const SymExpr *SE = getAsSymbolicExpression();
+ const SymExpr *SE = getAsSymbol(/*IncludeBaseRegions=*/true);
if (SE)
return SE->symbol_begin();
else
@@ -206,28 +218,28 @@ public:
private:
friend class SVal;
+
static bool isKind(const SVal& V) {
return V.getBaseKind() == UndefinedValKind;
}
};
class DefinedOrUnknownSVal : public SVal {
-private:
+public:
// We want calling these methods to be a compiler error since they are
// tautologically false.
bool isUndef() const = delete;
bool isValid() const = delete;
protected:
- DefinedOrUnknownSVal() {}
+ DefinedOrUnknownSVal() = default;
explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind)
- : SVal(d, isLoc, ValKind) {}
-
- explicit DefinedOrUnknownSVal(BaseKind k, void *D = nullptr)
- : SVal(k, D) {}
+ : SVal(d, isLoc, ValKind) {}
+ explicit DefinedOrUnknownSVal(BaseKind k, void *D = nullptr) : SVal(k, D) {}
private:
friend class SVal;
+
static bool isKind(const SVal& V) {
return !V.isUndef();
}
@@ -239,37 +251,43 @@ public:
private:
friend class SVal;
+
static bool isKind(const SVal &V) {
return V.getBaseKind() == UnknownValKind;
}
};
class DefinedSVal : public DefinedOrUnknownSVal {
-private:
+public:
// We want calling these methods to be a compiler error since they are
// tautologically true/false.
bool isUnknown() const = delete;
bool isUnknownOrUndef() const = delete;
bool isValid() const = delete;
+
protected:
- DefinedSVal() {}
+ DefinedSVal() = default;
explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind)
- : DefinedOrUnknownSVal(d, isLoc, ValKind) {}
+ : DefinedOrUnknownSVal(d, isLoc, ValKind) {}
+
private:
friend class SVal;
+
static bool isKind(const SVal& V) {
return !V.isUnknownOrUndef();
}
};
-
-/// \brief Represents an SVal that is guaranteed to not be UnknownVal.
+/// Represents an SVal that is guaranteed to not be UnknownVal.
class KnownSVal : public SVal {
- KnownSVal() {}
friend class SVal;
+
+ KnownSVal() = default;
+
static bool isKind(const SVal &V) {
return !V.isUnknown();
}
+
public:
KnownSVal(const DefinedSVal &V) : SVal(V) {}
KnownSVal(const UndefinedVal &V) : SVal(V) {}
@@ -277,20 +295,21 @@ public:
class NonLoc : public DefinedSVal {
protected:
- NonLoc() {}
+ NonLoc() = default;
explicit NonLoc(unsigned SubKind, const void *d)
- : DefinedSVal(d, false, SubKind) {}
+ : DefinedSVal(d, false, SubKind) {}
public:
void dumpToStream(raw_ostream &Out) const;
- static inline bool isCompoundType(QualType T) {
+ static bool isCompoundType(QualType T) {
return T->isArrayType() || T->isRecordType() ||
T->isComplexType() || T->isVectorType();
}
private:
friend class SVal;
+
static bool isKind(const SVal& V) {
return V.getBaseKind() == NonLocKind;
}
@@ -298,20 +317,21 @@ private:
class Loc : public DefinedSVal {
protected:
- Loc() {}
+ Loc() = default;
explicit Loc(unsigned SubKind, const void *D)
- : DefinedSVal(const_cast<void*>(D), true, SubKind) {}
+ : DefinedSVal(const_cast<void *>(D), true, SubKind) {}
public:
void dumpToStream(raw_ostream &Out) const;
- static inline bool isLocType(QualType T) {
+ static bool isLocType(QualType T) {
return T->isAnyPointerType() || T->isBlockPointerType() ||
T->isReferenceType() || T->isNullPtrType();
}
private:
friend class SVal;
+
static bool isKind(const SVal& V) {
return V.getBaseKind() == LocKind;
}
@@ -323,14 +343,17 @@ private:
namespace nonloc {
-/// \brief Represents symbolic expression.
+/// Represents symbolic expression that isn't a location.
class SymbolVal : public NonLoc {
public:
SymbolVal() = delete;
- SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) { assert(sym); }
+ SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {
+ assert(sym);
+ assert(!Loc::isLocType(sym->getType()));
+ }
SymbolRef getSymbol() const {
- return (const SymExpr*) Data;
+ return (const SymExpr *) Data;
}
bool isExpression() const {
@@ -339,6 +362,7 @@ public:
private:
friend class SVal;
+
static bool isKind(const SVal& V) {
return V.getBaseKind() == NonLocKind &&
V.getSubKind() == SymbolValKind;
@@ -349,13 +373,13 @@ private:
}
};
-/// \brief Value representing integer constant.
+/// Value representing integer constant.
class ConcreteInt : public NonLoc {
public:
explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
const llvm::APSInt& getValue() const {
- return *static_cast<const llvm::APSInt*>(Data);
+ return *static_cast<const llvm::APSInt *>(Data);
}
// Transfer functions for binary/unary operations on ConcreteInts.
@@ -368,7 +392,9 @@ public:
private:
friend class SVal;
- ConcreteInt() {}
+
+ ConcreteInt() = default;
+
static bool isKind(const SVal& V) {
return V.getBaseKind() == NonLocKind &&
V.getSubKind() == ConcreteIntKind;
@@ -392,7 +418,6 @@ class LocAsInteger : public NonLoc {
}
public:
-
Loc getLoc() const {
const std::pair<SVal, uintptr_t> *D =
static_cast<const std::pair<SVal, uintptr_t> *>(Data);
@@ -414,7 +439,9 @@ public:
private:
friend class SVal;
- LocAsInteger() {}
+
+ LocAsInteger() = default;
+
static bool isKind(const SVal& V) {
return V.getBaseKind() == NonLocKind &&
V.getSubKind() == LocAsIntegerKind;
@@ -432,16 +459,19 @@ class CompoundVal : public NonLoc {
public:
const CompoundValData* getValue() const {
- return static_cast<const CompoundValData*>(Data);
+ return static_cast<const CompoundValData *>(Data);
}
- typedef llvm::ImmutableList<SVal>::iterator iterator;
+ using iterator = llvm::ImmutableList<SVal>::iterator;
+
iterator begin() const;
iterator end() const;
private:
friend class SVal;
- CompoundVal() {}
+
+ CompoundVal() = default;
+
static bool isKind(const SVal& V) {
return V.getBaseKind() == NonLocKind && V.getSubKind() == CompoundValKind;
}
@@ -455,30 +485,35 @@ class LazyCompoundVal : public NonLoc {
friend class ento::SValBuilder;
explicit LazyCompoundVal(const LazyCompoundValData *D)
- : NonLoc(LazyCompoundValKind, D) {}
+ : NonLoc(LazyCompoundValKind, D) {}
+
public:
const LazyCompoundValData *getCVData() const {
- return static_cast<const LazyCompoundValData*>(Data);
+ return static_cast<const LazyCompoundValData *>(Data);
}
+
const void *getStore() const;
const TypedValueRegion *getRegion() const;
private:
friend class SVal;
- LazyCompoundVal() {}
+
+ LazyCompoundVal() = default;
+
static bool isKind(const SVal& V) {
return V.getBaseKind() == NonLocKind &&
V.getSubKind() == LazyCompoundValKind;
}
+
static bool isKind(const NonLoc& V) {
return V.getSubKind() == LazyCompoundValKind;
}
};
-/// \brief Value representing pointer-to-member.
+/// Value representing pointer-to-member.
///
/// This value is qualified as NonLoc because neither loading nor storing
-/// operations are aplied to it. Instead, the analyzer uses the L-value coming
+/// operations are applied to it. Instead, the analyzer uses the L-value coming
/// from pointer-to-member applied to an object.
/// This SVal is represented by a DeclaratorDecl which can be a member function
/// pointer or a member data pointer and a list of CXXBaseSpecifiers. This list
@@ -488,28 +523,36 @@ class PointerToMember : public NonLoc {
friend class ento::SValBuilder;
public:
- typedef llvm::PointerUnion<const DeclaratorDecl *,
- const PointerToMemberData *> PTMDataType;
+ using PTMDataType =
+ llvm::PointerUnion<const DeclaratorDecl *, const PointerToMemberData *>;
+
const PTMDataType getPTMData() const {
return PTMDataType::getFromOpaqueValue(const_cast<void *>(Data));
}
+
bool isNullMemberPointer() const {
return getPTMData().isNull();
}
+
const DeclaratorDecl *getDecl() const;
+
template<typename AdjustedDecl>
- const AdjustedDecl* getDeclAs() const {
+ const AdjustedDecl *getDeclAs() const {
return dyn_cast_or_null<AdjustedDecl>(getDecl());
}
- typedef llvm::ImmutableList<const CXXBaseSpecifier *>::iterator iterator;
+
+ using iterator = llvm::ImmutableList<const CXXBaseSpecifier *>::iterator;
+
iterator begin() const;
iterator end() const;
private:
- explicit PointerToMember(const PTMDataType D)
- : NonLoc(PointerToMemberKind, D.getOpaqueValue()) {}
friend class SVal;
- PointerToMember() {}
+
+ PointerToMember() = default;
+ explicit PointerToMember(const PTMDataType D)
+ : NonLoc(PointerToMemberKind, D.getOpaqueValue()) {}
+
static bool isKind(const SVal& V) {
return V.getBaseKind() == NonLocKind &&
V.getSubKind() == PointerToMemberKind;
@@ -520,7 +563,7 @@ private:
}
};
-} // end namespace ento::nonloc
+} // namespace nonloc
//==------------------------------------------------------------------------==//
// Subclasses of Loc.
@@ -535,12 +578,14 @@ public:
}
const LabelDecl *getLabel() const {
- return static_cast<const LabelDecl*>(Data);
+ return static_cast<const LabelDecl *>(Data);
}
private:
friend class SVal;
- GotoLabel() {}
+
+ GotoLabel() = default;
+
static bool isKind(const SVal& V) {
return V.getBaseKind() == LocKind && V.getSubKind() == GotoLabelKind;
}
@@ -550,19 +595,18 @@ private:
}
};
-
class MemRegionVal : public Loc {
public:
explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) {
assert(r);
}
- /// \brief Get the underlining region.
- const MemRegion* getRegion() const {
- return static_cast<const MemRegion*>(Data);
+ /// Get the underlining region.
+ const MemRegion *getRegion() const {
+ return static_cast<const MemRegion *>(Data);
}
- /// \brief Get the underlining region and strip casts.
+ /// Get the underlining region and strip casts.
const MemRegion* stripCasts(bool StripBaseCasts = true) const;
template <typename REGION>
@@ -570,17 +614,19 @@ public:
return dyn_cast<REGION>(getRegion());
}
- inline bool operator==(const MemRegionVal& R) const {
+ bool operator==(const MemRegionVal &R) const {
return getRegion() == R.getRegion();
}
- inline bool operator!=(const MemRegionVal& R) const {
+ bool operator!=(const MemRegionVal &R) const {
return getRegion() != R.getRegion();
}
private:
friend class SVal;
- MemRegionVal() {}
+
+ MemRegionVal() = default;
+
static bool isKind(const SVal& V) {
return V.getBaseKind() == LocKind &&
V.getSubKind() == MemRegionValKind;
@@ -595,8 +641,8 @@ class ConcreteInt : public Loc {
public:
explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {}
- const llvm::APSInt& getValue() const {
- return *static_cast<const llvm::APSInt*>(Data);
+ const llvm::APSInt &getValue() const {
+ return *static_cast<const llvm::APSInt *>(Data);
}
// Transfer functions for binary/unary operations on ConcreteInts.
@@ -605,7 +651,9 @@ public:
private:
friend class SVal;
- ConcreteInt() {}
+
+ ConcreteInt() = default;
+
static bool isKind(const SVal& V) {
return V.getBaseKind() == LocKind &&
V.getSubKind() == ConcreteIntKind;
@@ -616,11 +664,11 @@ private:
}
};
-} // end ento::loc namespace
+} // namespace loc
-} // end ento namespace
+} // namespace ento
-} // end clang namespace
+} // namespace clang
namespace llvm {
@@ -629,6 +677,6 @@ template <> struct isPodLike<clang::ento::SVal> {
static const bool value = true;
};
-} // end llvm namespace
+} // namespace llvm
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h
index 2c9802bbc5360..d64b90e2d380a 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h
@@ -75,6 +75,7 @@ protected:
// Internal implementation.
//===------------------------------------------------------------------===//
+ SValBuilder &getSValBuilder() const { return SVB; }
BasicValueFactory &getBasicVals() const { return SVB.getBasicValueFactory(); }
SymbolManager &getSymbolManager() const { return SVB.getSymbolManager(); }
@@ -85,8 +86,8 @@ private:
bool Assumption);
};
-} // end GR namespace
+} // end namespace ento
-} // end clang namespace
+} // end namespace clang
#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index 25d20a17afaa7..dc0644df8aabe 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -1,4 +1,4 @@
-//== Store.h - Interface for maps from Locations to Values ------*- C++ -*--==//
+//===- Store.h - Interface for maps from Locations to Values ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -14,27 +14,42 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H
+#include "clang/AST/Type.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include <cassert>
+#include <cstdint>
+#include <memory>
namespace clang {
-class Stmt;
+class ASTContext;
+class CastExpr;
+class CompoundLiteralExpr;
+class CXXBasePath;
+class Decl;
class Expr;
+class LocationContext;
class ObjCIvarDecl;
-class CXXBasePath;
class StackFrameContext;
namespace ento {
class CallEvent;
-class ProgramState;
class ProgramStateManager;
class ScanReachableSymbols;
+class SymbolReaper;
-typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
+using InvalidatedSymbols = llvm::DenseSet<SymbolRef>;
class StoreManager {
protected:
@@ -48,7 +63,7 @@ protected:
StoreManager(ProgramStateManager &stateMgr);
public:
- virtual ~StoreManager() {}
+ virtual ~StoreManager() = default;
/// Return the value bound to specified location in a given state.
/// \param[in] store The store in which to make the lookup.
@@ -92,9 +107,17 @@ public:
/// by \c val bound to the location given for \c loc.
virtual StoreRef Bind(Store store, Loc loc, SVal val) = 0;
- virtual StoreRef BindDefault(Store store, const MemRegion *R, SVal V);
+ /// Return a store with the specified value bound to all sub-regions of the
+ /// region. The region must not have previous bindings. If you need to
+ /// invalidate existing bindings, consider invalidateRegions().
+ virtual StoreRef BindDefaultInitial(Store store, const MemRegion *R,
+ SVal V) = 0;
- /// \brief Create a new store with the specified binding removed.
+ /// Return a store with in which all values within the given region are
+ /// reset to zero. This method is allowed to overwrite previous bindings.
+ virtual StoreRef BindDefaultZero(Store store, const MemRegion *R) = 0;
+
+ /// Create a new store with the specified binding removed.
/// \param ST the original store, that is the basis for the new store.
/// \param L the location whose binding should be removed.
virtual StoreRef killBinding(Store ST, Loc L) = 0;
@@ -147,7 +170,7 @@ public:
SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType,
bool IsVirtual);
- /// \brief Attempts to do a down cast. Used to model BaseToDerived and C++
+ /// Attempts to do a down cast. Used to model BaseToDerived and C++
/// dynamic_cast.
/// The callback may result in the following 3 scenarios:
/// - Successful cast (ex: derived is subclass of base).
@@ -168,7 +191,7 @@ public:
const MemRegion *castRegion(const MemRegion *region, QualType CastToTy);
virtual StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx,
- SymbolReaper& SymReaper) = 0;
+ SymbolReaper &SymReaper) = 0;
virtual bool includedInBindings(Store store,
const MemRegion *region) const = 0;
@@ -182,7 +205,7 @@ public:
/// associated with the object is recycled.
virtual void decrementReferenceCount(Store store) {}
- typedef SmallVector<const MemRegion *, 8> InvalidatedRegions;
+ using InvalidatedRegions = SmallVector<const MemRegion *, 8>;
/// invalidateRegions - Clears out the specified regions from the store,
/// marking their values as unknown. Depending on the store, this may also
@@ -235,6 +258,7 @@ public:
class BindingsHandler {
public:
virtual ~BindingsHandler();
+
virtual bool HandleBinding(StoreManager& SMgr, Store store,
const MemRegion *region, SVal val) = 0;
};
@@ -242,16 +266,16 @@ public:
class FindUniqueBinding :
public BindingsHandler {
SymbolRef Sym;
- const MemRegion* Binding;
- bool First;
+ const MemRegion* Binding = nullptr;
+ bool First = true;
public:
- FindUniqueBinding(SymbolRef sym)
- : Sym(sym), Binding(nullptr), First(true) {}
+ FindUniqueBinding(SymbolRef sym) : Sym(sym) {}
+
+ explicit operator bool() { return First && Binding; }
bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
SVal val) override;
- explicit operator bool() { return First && Binding; }
const MemRegion *getRegion() { return Binding; }
};
@@ -266,22 +290,21 @@ protected:
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
/// as another region.
- SVal CastRetrievedVal(SVal val, const TypedValueRegion *region,
- QualType castTy, bool performTestOnly = true);
+ SVal CastRetrievedVal(SVal val, const TypedValueRegion *region,
+ QualType castTy);
private:
SVal getLValueFieldOrIvar(const Decl *decl, SVal base);
};
-
inline StoreRef::StoreRef(Store store, StoreManager & smgr)
- : store(store), mgr(smgr) {
+ : store(store), mgr(smgr) {
if (store)
mgr.incrementReferenceCount(store);
}
-inline StoreRef::StoreRef(const StoreRef &sr)
- : store(sr.store), mgr(sr.mgr)
+inline StoreRef::StoreRef(const StoreRef &sr)
+ : store(sr.store), mgr(sr.mgr)
{
if (store)
mgr.incrementReferenceCount(store);
@@ -308,8 +331,8 @@ CreateRegionStoreManager(ProgramStateManager &StMgr);
std::unique_ptr<StoreManager>
CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr);
-} // end GR namespace
+} // namespace ento
-} // end clang namespace
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STORE_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h b/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
index 958c8c377ea2a..c5b4e5036bdf4 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h
@@ -1,4 +1,4 @@
-//== StoreRef.h - Smart pointer for store objects ---------------*- C++ -*--==//
+//===- StoreRef.h - Smart pointer for store objects -------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -19,33 +19,36 @@
namespace clang {
namespace ento {
+class StoreManager;
+
/// Store - This opaque type encapsulates an immutable mapping from
/// locations to values. At a high-level, it represents the symbolic
/// memory model. Different subclasses of StoreManager may choose
/// different types to represent the locations and values.
-typedef const void *Store;
-
-class StoreManager;
+using Store = const void *;
class StoreRef {
Store store;
StoreManager &mgr;
+
public:
- StoreRef(Store, StoreManager &);
- StoreRef(const StoreRef &);
- StoreRef &operator=(StoreRef const &);
+ StoreRef(Store store, StoreManager &smgr);
+ StoreRef(const StoreRef &sr);
+ StoreRef &operator=(StoreRef const &newStore);
+ ~StoreRef();
bool operator==(const StoreRef &x) const {
assert(&mgr == &x.mgr);
return x.store == store;
}
+
bool operator!=(const StoreRef &x) const { return !operator==(x); }
- ~StoreRef();
-
Store getStore() const { return store; }
const StoreManager &getStoreManager() const { return mgr; }
};
-}}
-#endif
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_STOREREF_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index 8ccd34751bbe1..e574ffdd6a159 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -24,6 +24,10 @@ class CFGElement;
class LocationContext;
class Stmt;
+namespace cross_tu {
+class CrossTranslationUnitContext;
+}
+
namespace ento {
struct NodeBuilderContext;
@@ -49,6 +53,9 @@ public:
virtual AnalysisManager &getAnalysisManager() = 0;
+ virtual cross_tu::CrossTranslationUnitContext *
+ getCrossTranslationUnitContext() = 0;
+
virtual ProgramStateManager &getStateManager() = 0;
/// Called by CoreEngine. Used to generate new successor
@@ -155,7 +162,8 @@ public:
/// printState - Called by ProgramStateManager to print checker-specific data.
virtual void printState(raw_ostream &Out, ProgramStateRef State,
- const char *NL, const char *Sep) = 0;
+ const char *NL, const char *Sep,
+ const LocationContext *LCtx = nullptr) = 0;
/// Called by CoreEngine when the analysis worklist is either empty or the
// maximum number of analysis steps have been reached.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
index 9780d0144746e..69b9858d3feb7 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
@@ -1,4 +1,4 @@
-//== SymExpr.h - Management of Symbolic Values ------------------*- C++ -*--==//
+//===- SymExpr.h - Management of Symbolic Values ----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,16 +15,17 @@
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMEXPR_H
#include "clang/AST/Type.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/raw_ostream.h"
+#include <cassert>
namespace clang {
namespace ento {
class MemRegion;
-/// \brief Symbolic value. These values used to capture symbolic execution of
+/// Symbolic value. These values used to capture symbolic execution of
/// the program.
class SymExpr : public llvm::FoldingSetNode {
virtual void anchor();
@@ -48,8 +49,10 @@ protected:
return !T.isNull() && !T->isVoidType();
}
+ mutable unsigned Complexity = 0;
+
public:
- virtual ~SymExpr() {}
+ virtual ~SymExpr() = default;
Kind getKind() const { return K; }
@@ -60,17 +63,18 @@ public:
virtual QualType getType() const = 0;
virtual void Profile(llvm::FoldingSetNodeID &profile) = 0;
- /// \brief Iterator over symbols that the current symbol depends on.
+ /// Iterator over symbols that the current symbol depends on.
///
/// For SymbolData, it's the symbol itself; for expressions, it's the
/// expression symbol and all the operands in it. Note, SymbolDerived is
/// treated as SymbolData - the iterator will NOT visit the parent region.
class symbol_iterator {
SmallVector<const SymExpr *, 5> itr;
+
void expand();
public:
- symbol_iterator() {}
+ symbol_iterator() = default;
symbol_iterator(const SymExpr *SE);
symbol_iterator &operator++();
@@ -83,9 +87,9 @@ public:
symbol_iterator symbol_begin() const { return symbol_iterator(this); }
static symbol_iterator symbol_end() { return symbol_iterator(); }
- unsigned computeComplexity() const;
+ virtual unsigned computeComplexity() const = 0;
- /// \brief Find the region from which this symbol originates.
+ /// Find the region from which this symbol originates.
///
/// Whenever the symbol was constructed to denote an unknown value of
/// a certain memory region, return this region. This method
@@ -104,26 +108,31 @@ inline raw_ostream &operator<<(raw_ostream &os,
return os;
}
-typedef const SymExpr *SymbolRef;
-typedef SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy;
+using SymbolRef = const SymExpr *;
+using SymbolRefSmallVectorTy = SmallVector<SymbolRef, 2>;
+using SymbolID = unsigned;
-typedef unsigned SymbolID;
-/// \brief A symbol representing data which can be stored in a memory location
+/// A symbol representing data which can be stored in a memory location
/// (region).
class SymbolData : public SymExpr {
- void anchor() override;
const SymbolID Sym;
+ void anchor() override;
+
protected:
SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {
assert(classof(this));
}
public:
- ~SymbolData() override {}
+ ~SymbolData() override = default;
SymbolID getSymbolID() const { return Sym; }
+ unsigned computeComplexity() const override {
+ return 1;
+ };
+
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
Kind k = SE->getKind();
@@ -134,4 +143,4 @@ public:
} // namespace ento
} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMEXPR_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 7d2e5ad8ba915..cc3ce72f9e569 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -1,4 +1,4 @@
-//== SymbolManager.h - Management of Symbolic Values ------------*- C++ -*--==//
+//===- SymbolManager.h - Management of Symbolic Values ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,8 +15,8 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H
-#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
@@ -26,19 +26,19 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/Allocator.h"
-#include "llvm/Support/DataTypes.h"
+#include <cassert>
namespace clang {
- class ASTContext;
- class StackFrameContext;
+
+class ASTContext;
+class Stmt;
namespace ento {
- class BasicValueFactory;
- class SubRegion;
- class TypedValueRegion;
- class VarRegion;
-///\brief A symbol representing the value stored at a MemRegion.
+class BasicValueFactory;
+class StoreManager;
+
+///A symbol representing the value stored at a MemRegion.
class SymbolRegionValue : public SymbolData {
const TypedValueRegion *R;
@@ -66,7 +66,7 @@ public:
QualType getType() const override;
// Implement isa<T> support.
- static inline bool classof(const SymExpr *SE) {
+ static bool classof(const SymExpr *SE) {
return SE->getKind() == SymbolRegionValueKind;
}
};
@@ -118,7 +118,7 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr *SE) {
+ static bool classof(const SymExpr *SE) {
return SE->getKind() == SymbolConjuredKind;
}
};
@@ -157,7 +157,7 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr *SE) {
+ static bool classof(const SymExpr *SE) {
return SE->getKind() == SymbolDerivedKind;
}
};
@@ -190,7 +190,7 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr *SE) {
+ static bool classof(const SymExpr *SE) {
return SE->getKind() == SymbolExtentKind;
}
};
@@ -206,11 +206,12 @@ class SymbolMetadata : public SymbolData {
const LocationContext *LCtx;
unsigned Count;
const void *Tag;
+
public:
SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt *s, QualType t,
const LocationContext *LCtx, unsigned count, const void *tag)
- : SymbolData(SymbolMetadataKind, sym), R(r), S(s), T(t), LCtx(LCtx),
- Count(count), Tag(tag) {
+ : SymbolData(SymbolMetadataKind, sym), R(r), S(s), T(t), LCtx(LCtx),
+ Count(count), Tag(tag) {
assert(r);
assert(s);
assert(isValidTypeForSymbol(t));
@@ -245,16 +246,18 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr *SE) {
+ static bool classof(const SymExpr *SE) {
return SE->getKind() == SymbolMetadataKind;
}
};
-/// \brief Represents a cast expression.
+/// Represents a cast expression.
class SymbolCast : public SymExpr {
const SymExpr *Operand;
+
/// Type of the operand.
QualType FromTy;
+
/// The type of the result.
QualType ToTy;
@@ -267,6 +270,12 @@ public:
// Otherwise, 'To' should also be a valid type.
}
+ unsigned computeComplexity() const override {
+ if (Complexity == 0)
+ Complexity = 1 + Operand->computeComplexity();
+ return Complexity;
+ }
+
QualType getType() const override { return ToTy; }
const SymExpr *getOperand() const { return Operand; }
@@ -286,12 +295,12 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr *SE) {
+ static bool classof(const SymExpr *SE) {
return SE->getKind() == SymbolCastKind;
}
};
-/// \brief Represents a symbolic expression involving a binary operator
+/// Represents a symbolic expression involving a binary operator
class BinarySymExpr : public SymExpr {
BinaryOperator::Opcode Op;
QualType T;
@@ -311,13 +320,13 @@ public:
BinaryOperator::Opcode getOpcode() const { return Op; }
// Implement isa<T> support.
- static inline bool classof(const SymExpr *SE) {
+ static bool classof(const SymExpr *SE) {
Kind k = SE->getKind();
return k >= BEGIN_BINARYSYMEXPRS && k <= END_BINARYSYMEXPRS;
}
};
-/// \brief Represents a symbolic expression like 'x' + 3.
+/// Represents a symbolic expression like 'x' + 3.
class SymIntExpr : public BinarySymExpr {
const SymExpr *LHS;
const llvm::APSInt& RHS;
@@ -334,6 +343,12 @@ public:
const SymExpr *getLHS() const { return LHS; }
const llvm::APSInt &getRHS() const { return RHS; }
+ unsigned computeComplexity() const override {
+ if (Complexity == 0)
+ Complexity = 1 + LHS->computeComplexity();
+ return Complexity;
+ }
+
static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
BinaryOperator::Opcode op, const llvm::APSInt& rhs,
QualType t) {
@@ -349,12 +364,12 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr *SE) {
+ static bool classof(const SymExpr *SE) {
return SE->getKind() == SymIntExprKind;
}
};
-/// \brief Represents a symbolic expression like 3 - 'x'.
+/// Represents a symbolic expression like 3 - 'x'.
class IntSymExpr : public BinarySymExpr {
const llvm::APSInt& LHS;
const SymExpr *RHS;
@@ -371,6 +386,12 @@ public:
const SymExpr *getRHS() const { return RHS; }
const llvm::APSInt &getLHS() const { return LHS; }
+ unsigned computeComplexity() const override {
+ if (Complexity == 0)
+ Complexity = 1 + RHS->computeComplexity();
+ return Complexity;
+ }
+
static void Profile(llvm::FoldingSetNodeID& ID, const llvm::APSInt& lhs,
BinaryOperator::Opcode op, const SymExpr *rhs,
QualType t) {
@@ -386,12 +407,12 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr *SE) {
+ static bool classof(const SymExpr *SE) {
return SE->getKind() == IntSymExprKind;
}
};
-/// \brief Represents a symbolic expression like 'x' + 'y'.
+/// Represents a symbolic expression like 'x' + 'y'.
class SymSymExpr : public BinarySymExpr {
const SymExpr *LHS;
const SymExpr *RHS;
@@ -409,6 +430,12 @@ public:
void dumpToStream(raw_ostream &os) const override;
+ unsigned computeComplexity() const override {
+ if (Complexity == 0)
+ Complexity = RHS->computeComplexity() + LHS->computeComplexity();
+ return Complexity;
+ }
+
static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) {
ID.AddInteger((unsigned) SymSymExprKind);
@@ -423,20 +450,22 @@ public:
}
// Implement isa<T> support.
- static inline bool classof(const SymExpr *SE) {
+ static bool classof(const SymExpr *SE) {
return SE->getKind() == SymSymExprKind;
}
};
class SymbolManager {
- typedef llvm::FoldingSet<SymExpr> DataSetTy;
- typedef llvm::DenseMap<SymbolRef, SymbolRefSmallVectorTy*> SymbolDependTy;
+ using DataSetTy = llvm::FoldingSet<SymExpr>;
+ using SymbolDependTy = llvm::DenseMap<SymbolRef, SymbolRefSmallVectorTy *>;
DataSetTy DataSet;
+
/// Stores the extra dependencies between symbols: the data should be kept
/// alive as long as the key is live.
SymbolDependTy SymbolDependencies;
- unsigned SymbolCounter;
+
+ unsigned SymbolCounter = 0;
llvm::BumpPtrAllocator& BPAlloc;
BasicValueFactory &BV;
ASTContext &Ctx;
@@ -444,14 +473,12 @@ class SymbolManager {
public:
SymbolManager(ASTContext &ctx, BasicValueFactory &bv,
llvm::BumpPtrAllocator& bpalloc)
- : SymbolDependencies(16), SymbolCounter(0),
- BPAlloc(bpalloc), BV(bv), Ctx(ctx) {}
-
+ : SymbolDependencies(16), BPAlloc(bpalloc), BV(bv), Ctx(ctx) {}
~SymbolManager();
static bool canSymbolicate(QualType T);
- /// \brief Make a unique symbol for MemRegion R according to its kind.
+ /// Make a unique symbol for MemRegion R according to its kind.
const SymbolRegionValue* getRegionValueSymbol(const TypedValueRegion* R);
const SymbolConjured* conjureSymbol(const Stmt *E,
@@ -472,7 +499,7 @@ public:
const SymbolExtent *getExtentSymbol(const SubRegion *R);
- /// \brief Creates a metadata symbol associated with a specific region.
+ /// Creates a metadata symbol associated with a specific region.
///
/// VisitCount can be used to differentiate regions corresponding to
/// different loop iterations, thus, making the symbol path-dependent.
@@ -504,7 +531,7 @@ public:
return SE->getType();
}
- /// \brief Add artificial symbol dependency.
+ /// Add artificial symbol dependency.
///
/// The dependent symbol should stay alive as long as the primary is alive.
void addSymbolDependency(const SymbolRef Primary, const SymbolRef Dependent);
@@ -515,16 +542,16 @@ public:
BasicValueFactory &getBasicVals() { return BV; }
};
-/// \brief A class responsible for cleaning up unused symbols.
+/// A class responsible for cleaning up unused symbols.
class SymbolReaper {
enum SymbolStatus {
NotProcessed,
HaveMarkedDependents
};
- typedef llvm::DenseSet<SymbolRef> SymbolSetTy;
- typedef llvm::DenseMap<SymbolRef, SymbolStatus> SymbolMapTy;
- typedef llvm::DenseSet<const MemRegion *> RegionSetTy;
+ using SymbolSetTy = llvm::DenseSet<SymbolRef>;
+ using SymbolMapTy = llvm::DenseMap<SymbolRef, SymbolStatus>;
+ using RegionSetTy = llvm::DenseSet<const MemRegion *>;
SymbolMapTy TheLiving;
SymbolSetTy MetadataInUse;
@@ -539,17 +566,16 @@ class SymbolReaper {
llvm::DenseMap<const MemRegion *, unsigned> includedRegionCache;
public:
- /// \brief Construct a reaper object, which removes everything which is not
+ /// Construct a reaper object, which removes everything which is not
/// live before we execute statement s in the given location context.
///
/// If the statement is NULL, everything is this and parent contexts is
/// considered live.
/// If the stack frame context is NULL, everything on stack is considered
/// dead.
- SymbolReaper(const StackFrameContext *Ctx, const Stmt *s, SymbolManager& symmgr,
- StoreManager &storeMgr)
- : LCtx(Ctx), Loc(s), SymMgr(symmgr),
- reapedStore(nullptr, storeMgr) {}
+ SymbolReaper(const StackFrameContext *Ctx, const Stmt *s,
+ SymbolManager &symmgr, StoreManager &storeMgr)
+ : LCtx(Ctx), Loc(s), SymMgr(symmgr), reapedStore(nullptr, storeMgr) {}
const LocationContext *getLocationContext() const { return LCtx; }
@@ -558,14 +584,14 @@ public:
bool isLive(const Stmt *ExprVal, const LocationContext *LCtx) const;
bool isLive(const VarRegion *VR, bool includeStoreBindings = false) const;
- /// \brief Unconditionally marks a symbol as live.
+ /// Unconditionally marks a symbol as live.
///
/// This should never be
/// used by checkers, only by the state infrastructure such as the store and
/// environment. Checkers should instead use metadata symbols and markInUse.
void markLive(SymbolRef sym);
- /// \brief Marks a symbol as important to a checker.
+ /// Marks a symbol as important to a checker.
///
/// For metadata symbols,
/// this will keep the symbol alive as long as its associated region is also
@@ -574,13 +600,14 @@ public:
/// symbol marking has occurred, i.e. in the MarkLiveSymbols callback.
void markInUse(SymbolRef sym);
- /// \brief If a symbol is known to be live, marks the symbol as live.
+ /// 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);
- typedef SymbolSetTy::const_iterator dead_iterator;
+ using dead_iterator = SymbolSetTy::const_iterator;
+
dead_iterator dead_begin() const { return TheDead.begin(); }
dead_iterator dead_end() const { return TheDead.end(); }
@@ -588,11 +615,12 @@ public:
return !TheDead.empty();
}
- typedef RegionSetTy::const_iterator region_iterator;
+ using region_iterator = RegionSetTy::const_iterator;
+
region_iterator region_begin() const { return RegionRoots.begin(); }
region_iterator region_end() const { return RegionRoots.end(); }
- /// \brief Returns whether or not a symbol has been confirmed dead.
+ /// 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.)
@@ -603,7 +631,7 @@ public:
void markLive(const MemRegion *region);
void markElementIndicesLive(const MemRegion *region);
- /// \brief Set to the value of the symbolic store after
+ /// Set to the value of the symbolic store after
/// StoreManager::removeDeadBindings has been called.
void setReapedStore(StoreRef st) { reapedStore = st; }
@@ -621,7 +649,7 @@ public:
SymbolVisitor(const SymbolVisitor &) = default;
SymbolVisitor(SymbolVisitor &&) {}
- /// \brief A visitor method invoked by ProgramStateManager::scanReachableSymbols.
+ /// A visitor method invoked by ProgramStateManager::scanReachableSymbols.
///
/// The method returns \c true if symbols should continue be scanned and \c
/// false otherwise.
@@ -629,8 +657,8 @@ public:
virtual bool VisitMemRegion(const MemRegion *region) { return true; }
};
-} // end GR namespace
+} // namespace ento
-} // end clang namespace
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SYMBOLMANAGER_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
index 7b76263f040c9..ce19b7131d42d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
@@ -1,4 +1,4 @@
-//== TaintManager.h - Managing taint --------------------------- -*- C++ -*--=//
+//===- TaintManager.h - Managing taint --------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -14,9 +14,9 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTMANAGER_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTMANAGER_H
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h"
#include "llvm/ADT/ImmutableMap.h"
@@ -29,28 +29,37 @@ namespace ento {
// FIXME: This does not use the nice trait macros because it must be accessible
// from multiple translation units.
struct TaintMap {};
-typedef llvm::ImmutableMap<SymbolRef, TaintTagType> TaintMapImpl;
+
+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() {
+ static int index = 0;
+ return &index;
+ }
};
/// The GDM component mapping derived symbols' parent symbols to their
/// underlying regions. This is used to efficiently check whether a symbol is
/// tainted when it represents a sub-region of a tainted symbol.
struct DerivedSymTaint {};
-typedef llvm::ImmutableMap<SymbolRef, TaintedSubRegions> DerivedSymTaintImpl;
+
+using DerivedSymTaintImpl = llvm::ImmutableMap<SymbolRef, TaintedSubRegions>;
+
template<> struct ProgramStateTrait<DerivedSymTaint>
: public ProgramStatePartialTrait<DerivedSymTaintImpl> {
- static void *GDMIndex() { static int index; return &index; }
+ static void *GDMIndex() {
+ static int index;
+ return &index;
+ }
};
class TaintManager {
-
- TaintManager() {}
+ TaintManager() = default;
};
-}
-}
+} // namespace ento
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTMANAGER_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
index 0c56e7d8ea698..50c4b8194cff8 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
@@ -1,4 +1,4 @@
-//== TaintTag.h - Path-sensitive "State" for tracking values -*- C++ -*--=//
+//===- TaintTag.h - Path-sensitive "State" for tracking values --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,6 +11,7 @@
// of taint.
//
//===----------------------------------------------------------------------===//
+
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTTAG_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTTAG_H
@@ -19,9 +20,11 @@ namespace ento {
/// The type of taint, which helps to differentiate between different types of
/// taint.
-typedef unsigned TaintTagType;
+using TaintTagType = unsigned;
+
static const TaintTagType TaintTagGeneric = 0;
-}}
+} // namespace ento
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_TAINTTAG_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
index 4f1a60e675569..7df8f373b3663 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
@@ -80,20 +80,14 @@ public:
void setBlockCounter(BlockCounter C) { CurrentCounter = C; }
BlockCounter getBlockCounter() const { return CurrentCounter; }
- class Visitor {
- public:
- Visitor() {}
- virtual ~Visitor();
- virtual bool visit(const WorkListUnit &U) = 0;
- };
- virtual bool visitItemsInWorkList(Visitor &V) = 0;
-
- static WorkList *makeDFS();
- static WorkList *makeBFS();
- static WorkList *makeBFSBlockDFSContents();
+ static std::unique_ptr<WorkList> makeDFS();
+ static std::unique_ptr<WorkList> makeBFS();
+ static std::unique_ptr<WorkList> makeBFSBlockDFSContents();
+ static std::unique_ptr<WorkList> makeUnexploredFirst();
+ static std::unique_ptr<WorkList> makeUnexploredFirstPriorityQueue();
};
-} // end GR namespace
+} // end ento namespace
} // end clang namespace