summaryrefslogtreecommitdiff
path: root/clang-r353983/include/clang/Analysis
diff options
context:
space:
mode:
authorRalf Luther <luther.ralf@gmail.com>2019-03-27 20:23:17 +0000
committerGerrit Code Review <gerrit2@aicp-server-3>2019-03-27 20:23:17 +0000
commit1ce3a9d272e564b22a1333a1e36a3d3ab7cfab01 (patch)
tree391382eadd4fec5bb480f2e8934fa352770221d1 /clang-r353983/include/clang/Analysis
parentd1d48b140bafaa8a50107292f5fce95562575765 (diff)
parent4f56932d3416ac03f646bc1a611b3135fec2fe08 (diff)
Merge "Update prebuilt Clang to r353983." into p9.0HEADp9.0-backupp9.0
Diffstat (limited to 'clang-r353983/include/clang/Analysis')
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h50
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/Consumed.h272
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/Dominators.h201
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h95
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/LiveVariables.h122
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/PostOrderCFGView.h116
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/ReachableCode.h68
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/ThreadSafety.h249
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyCommon.h520
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyLogical.h107
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyOps.def56
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyTIL.h1910
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h931
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyUtil.h357
-rw-r--r--clang-r353983/include/clang/Analysis/Analyses/UninitializedValues.h131
-rw-r--r--clang-r353983/include/clang/Analysis/AnalysisDeclContext.h517
-rw-r--r--clang-r353983/include/clang/Analysis/AnalysisDiagnostic.h14
-rw-r--r--clang-r353983/include/clang/Analysis/AnyCall.h208
-rw-r--r--clang-r353983/include/clang/Analysis/BodyFarm.h53
-rw-r--r--clang-r353983/include/clang/Analysis/CFG.h1338
-rw-r--r--clang-r353983/include/clang/Analysis/CFGStmtMap.h49
-rw-r--r--clang-r353983/include/clang/Analysis/CallGraph.h258
-rw-r--r--clang-r353983/include/clang/Analysis/CloneDetection.h446
-rw-r--r--clang-r353983/include/clang/Analysis/CodeInjector.h45
-rw-r--r--clang-r353983/include/clang/Analysis/ConstructionContext.h660
-rw-r--r--clang-r353983/include/clang/Analysis/DomainSpecific/CocoaConventions.h41
-rw-r--r--clang-r353983/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h45
-rw-r--r--clang-r353983/include/clang/Analysis/FlowSensitive/DataflowValues.h171
-rw-r--r--clang-r353983/include/clang/Analysis/ProgramPoint.h782
-rw-r--r--clang-r353983/include/clang/Analysis/RetainSummaryManager.h767
-rw-r--r--clang-r353983/include/clang/Analysis/SelectorExtras.h36
-rw-r--r--clang-r353983/include/clang/Analysis/Support/BumpVector.h256
32 files changed, 10871 insertions, 0 deletions
diff --git a/clang-r353983/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h b/clang-r353983/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h
new file mode 100644
index 00000000..16c0a7af
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h
@@ -0,0 +1,50 @@
+//===- CFGReachabilityAnalysis.h - Basic reachability analysis --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a flow-sensitive, (mostly) path-insensitive reachability
+// analysis based on Clang's CFGs. Clients can query if a given basic block
+// is reachable within the CFG.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_CFGREACHABILITYANALYSIS_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_CFGREACHABILITYANALYSIS_H
+
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+
+class CFG;
+class CFGBlock;
+
+// A class that performs reachability queries for CFGBlocks. Several internal
+// checks in this checker require reachability information. The requests all
+// tend to have a common destination, so we lazily do a predecessor search
+// from the destination node and cache the results to prevent work
+// duplication.
+class CFGReverseBlockReachabilityAnalysis {
+ using ReachableSet = llvm::BitVector;
+ using ReachableMap = llvm::DenseMap<unsigned, ReachableSet>;
+
+ ReachableSet analyzed;
+ ReachableMap reachable;
+
+public:
+ CFGReverseBlockReachabilityAnalysis(const CFG &cfg);
+
+ /// Returns true if the block 'Dst' can be reached from block 'Src'.
+ bool isReachable(const CFGBlock *Src, const CFGBlock *Dst);
+
+private:
+ void mapReachability(const CFGBlock *Dst);
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_ANALYSES_CFGREACHABILITYANALYSIS_H
diff --git a/clang-r353983/include/clang/Analysis/Analyses/Consumed.h b/clang-r353983/include/clang/Analysis/Analyses/Consumed.h
new file mode 100644
index 00000000..dec1ae3b
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/Consumed.h
@@ -0,0 +1,272 @@
+//===- Consumed.h -----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// A intra-procedural analysis for checking consumed properties. This is based,
+// in part, on research on linear types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H
+
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include <list>
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace clang {
+
+class AnalysisDeclContext;
+class CXXBindTemporaryExpr;
+class FunctionDecl;
+class PostOrderCFGView;
+class Stmt;
+class VarDecl;
+
+namespace consumed {
+
+ class ConsumedStmtVisitor;
+
+ enum ConsumedState {
+ // No state information for the given variable.
+ CS_None,
+
+ CS_Unknown,
+ CS_Unconsumed,
+ CS_Consumed
+ };
+
+ using OptionalNotes = SmallVector<PartialDiagnosticAt, 1>;
+ using DelayedDiag = std::pair<PartialDiagnosticAt, OptionalNotes>;
+ using DiagList = std::list<DelayedDiag>;
+
+ class ConsumedWarningsHandlerBase {
+ public:
+ virtual ~ConsumedWarningsHandlerBase();
+
+ /// Emit the warnings and notes left by the analysis.
+ virtual void emitDiagnostics() {}
+
+ /// Warn that a variable's state doesn't match at the entry and exit
+ /// of a loop.
+ ///
+ /// \param Loc -- The location of the end of the loop.
+ ///
+ /// \param VariableName -- The name of the variable that has a mismatched
+ /// state.
+ virtual void warnLoopStateMismatch(SourceLocation Loc,
+ StringRef VariableName) {}
+
+ /// Warn about parameter typestate mismatches upon return.
+ ///
+ /// \param Loc -- The SourceLocation of the return statement.
+ ///
+ /// \param ExpectedState -- The state the return value was expected to be
+ /// in.
+ ///
+ /// \param ObservedState -- The state the return value was observed to be
+ /// in.
+ virtual void warnParamReturnTypestateMismatch(SourceLocation Loc,
+ StringRef VariableName,
+ StringRef ExpectedState,
+ StringRef ObservedState) {}
+
+ // FIXME: Add documentation.
+ virtual void warnParamTypestateMismatch(SourceLocation LOC,
+ StringRef ExpectedState,
+ StringRef ObservedState) {}
+
+ // FIXME: This can be removed when the attr propagation fix for templated
+ // classes lands.
+ /// Warn about return typestates set for unconsumable types.
+ ///
+ /// \param Loc -- The location of the attributes.
+ ///
+ /// \param TypeName -- The name of the unconsumable type.
+ virtual void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
+ StringRef TypeName) {}
+
+ /// Warn about return typestate mismatches.
+ ///
+ /// \param Loc -- The SourceLocation of the return statement.
+ ///
+ /// \param ExpectedState -- The state the return value was expected to be
+ /// in.
+ ///
+ /// \param ObservedState -- The state the return value was observed to be
+ /// in.
+ virtual void warnReturnTypestateMismatch(SourceLocation Loc,
+ StringRef ExpectedState,
+ StringRef ObservedState) {}
+
+ /// Warn about use-while-consumed errors.
+ /// \param MethodName -- The name of the method that was incorrectly
+ /// invoked.
+ ///
+ /// \param State -- The state the object was used in.
+ ///
+ /// \param Loc -- The SourceLocation of the method invocation.
+ virtual void warnUseOfTempInInvalidState(StringRef MethodName,
+ StringRef State,
+ SourceLocation Loc) {}
+
+ /// Warn about use-while-consumed errors.
+ /// \param MethodName -- The name of the method that was incorrectly
+ /// invoked.
+ ///
+ /// \param State -- The state the object was used in.
+ ///
+ /// \param VariableName -- The name of the variable that holds the unique
+ /// value.
+ ///
+ /// \param Loc -- The SourceLocation of the method invocation.
+ virtual void warnUseInInvalidState(StringRef MethodName,
+ StringRef VariableName,
+ StringRef State,
+ SourceLocation Loc) {}
+ };
+
+ class ConsumedStateMap {
+ using VarMapType = llvm::DenseMap<const VarDecl *, ConsumedState>;
+ using TmpMapType =
+ llvm::DenseMap<const CXXBindTemporaryExpr *, ConsumedState>;
+
+ protected:
+ bool Reachable = true;
+ const Stmt *From = nullptr;
+ VarMapType VarMap;
+ TmpMapType TmpMap;
+
+ public:
+ ConsumedStateMap() = default;
+ ConsumedStateMap(const ConsumedStateMap &Other)
+ : Reachable(Other.Reachable), From(Other.From), VarMap(Other.VarMap),
+ TmpMap() {}
+
+ /// Warn if any of the parameters being tracked are not in the state
+ /// they were declared to be in upon return from a function.
+ void checkParamsForReturnTypestate(SourceLocation BlameLoc,
+ ConsumedWarningsHandlerBase &WarningsHandler) const;
+
+ /// Clear the TmpMap.
+ void clearTemporaries();
+
+ /// Get the consumed state of a given variable.
+ ConsumedState getState(const VarDecl *Var) const;
+
+ /// Get the consumed state of a given temporary value.
+ ConsumedState getState(const CXXBindTemporaryExpr *Tmp) const;
+
+ /// Merge this state map with another map.
+ void intersect(const ConsumedStateMap &Other);
+
+ void intersectAtLoopHead(const CFGBlock *LoopHead, const CFGBlock *LoopBack,
+ const ConsumedStateMap *LoopBackStates,
+ ConsumedWarningsHandlerBase &WarningsHandler);
+
+ /// Return true if this block is reachable.
+ bool isReachable() const { return Reachable; }
+
+ /// Mark the block as unreachable.
+ void markUnreachable();
+
+ /// Set the source for a decision about the branching of states.
+ /// \param Source -- The statement that was the origin of a branching
+ /// decision.
+ void setSource(const Stmt *Source) { this->From = Source; }
+
+ /// Set the consumed state of a given variable.
+ void setState(const VarDecl *Var, ConsumedState State);
+
+ /// Set the consumed state of a given temporary value.
+ void setState(const CXXBindTemporaryExpr *Tmp, ConsumedState State);
+
+ /// Remove the temporary value from our state map.
+ void remove(const CXXBindTemporaryExpr *Tmp);
+
+ /// Tests to see if there is a mismatch in the states stored in two
+ /// maps.
+ ///
+ /// \param Other -- The second map to compare against.
+ bool operator!=(const ConsumedStateMap *Other) const;
+ };
+
+ class ConsumedBlockInfo {
+ std::vector<std::unique_ptr<ConsumedStateMap>> StateMapsArray;
+ std::vector<unsigned int> VisitOrder;
+
+ public:
+ ConsumedBlockInfo() = default;
+
+ ConsumedBlockInfo(unsigned int NumBlocks, PostOrderCFGView *SortedGraph)
+ : StateMapsArray(NumBlocks), VisitOrder(NumBlocks, 0) {
+ unsigned int VisitOrderCounter = 0;
+ for (const auto BI : *SortedGraph)
+ VisitOrder[BI->getBlockID()] = VisitOrderCounter++;
+ }
+
+ bool allBackEdgesVisited(const CFGBlock *CurrBlock,
+ const CFGBlock *TargetBlock);
+
+ void addInfo(const CFGBlock *Block, ConsumedStateMap *StateMap,
+ std::unique_ptr<ConsumedStateMap> &OwnedStateMap);
+ void addInfo(const CFGBlock *Block,
+ std::unique_ptr<ConsumedStateMap> StateMap);
+
+ ConsumedStateMap* borrowInfo(const CFGBlock *Block);
+
+ void discardInfo(const CFGBlock *Block);
+
+ std::unique_ptr<ConsumedStateMap> getInfo(const CFGBlock *Block);
+
+ bool isBackEdge(const CFGBlock *From, const CFGBlock *To);
+ bool isBackEdgeTarget(const CFGBlock *Block);
+ };
+
+ /// A class that handles the analysis of uniqueness violations.
+ class ConsumedAnalyzer {
+ ConsumedBlockInfo BlockInfo;
+ std::unique_ptr<ConsumedStateMap> CurrStates;
+
+ ConsumedState ExpectedReturnState;
+
+ void determineExpectedReturnState(AnalysisDeclContext &AC,
+ const FunctionDecl *D);
+ bool splitState(const CFGBlock *CurrBlock,
+ const ConsumedStmtVisitor &Visitor);
+
+ public:
+ ConsumedWarningsHandlerBase &WarningsHandler;
+
+ ConsumedAnalyzer(ConsumedWarningsHandlerBase &WarningsHandler)
+ : WarningsHandler(WarningsHandler) {}
+
+ ConsumedState getExpectedReturnState() const { return ExpectedReturnState; }
+
+ /// Check a function's CFG for consumed violations.
+ ///
+ /// We traverse the blocks in the CFG, keeping track of the state of each
+ /// value who's type has uniquness annotations. If methods are invoked in
+ /// the wrong state a warning is issued. Each block in the CFG is traversed
+ /// exactly once.
+ void run(AnalysisDeclContext &AC);
+ };
+
+} // namespace consumed
+
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_ANALYSES_CONSUMED_H
diff --git a/clang-r353983/include/clang/Analysis/Analyses/Dominators.h b/clang-r353983/include/clang/Analysis/Analyses/Dominators.h
new file mode 100644
index 00000000..0015b0d7
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/Dominators.h
@@ -0,0 +1,201 @@
+//- Dominators.h - Implementation of dominators tree for Clang CFG -*- C++ -*-//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the dominators tree functionality for Clang CFGs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H
+
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Analysis/CFG.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/Support/GenericDomTree.h"
+#include "llvm/Support/GenericDomTreeConstruction.h"
+#include "llvm/Support/raw_ostream.h"
+
+// FIXME: There is no good reason for the domtree to require a print method
+// which accepts an LLVM Module, so remove this (and the method's argument that
+// needs it) when that is fixed.
+
+namespace llvm {
+
+class Module;
+
+} // namespace llvm
+
+namespace clang {
+
+using DomTreeNode = llvm::DomTreeNodeBase<CFGBlock>;
+
+/// Concrete subclass of DominatorTreeBase for Clang
+/// This class implements the dominators tree functionality given a Clang CFG.
+///
+class DominatorTree : public ManagedAnalysis {
+ virtual void anchor();
+
+public:
+ llvm::DomTreeBase<CFGBlock> *DT;
+
+ DominatorTree() {
+ DT = new llvm::DomTreeBase<CFGBlock>();
+ }
+
+ ~DominatorTree() override { delete DT; }
+
+ llvm::DomTreeBase<CFGBlock>& getBase() { return *DT; }
+
+ /// This method returns the root CFGBlock of the dominators tree.
+ CFGBlock *getRoot() const {
+ return DT->getRoot();
+ }
+
+ /// This method returns the root DomTreeNode, which is the wrapper
+ /// for CFGBlock.
+ DomTreeNode *getRootNode() const {
+ return DT->getRootNode();
+ }
+
+ /// This method compares two dominator trees.
+ /// The method returns false if the other dominator tree matches this
+ /// dominator tree, otherwise returns true.
+ bool compare(DominatorTree &Other) const {
+ DomTreeNode *R = getRootNode();
+ DomTreeNode *OtherR = Other.getRootNode();
+
+ if (!R || !OtherR || R->getBlock() != OtherR->getBlock())
+ return true;
+
+ if (DT->compare(Other.getBase()))
+ return true;
+
+ return false;
+ }
+
+ /// This method builds the dominator tree for a given CFG
+ /// The CFG information is passed via AnalysisDeclContext
+ void buildDominatorTree(AnalysisDeclContext &AC) {
+ cfg = AC.getCFG();
+ DT->recalculate(*cfg);
+ }
+
+ /// This method dumps immediate dominators for each block,
+ /// mainly used for debug purposes.
+ void dump() {
+ llvm::errs() << "Immediate dominance tree (Node#,IDom#):\n";
+ for (CFG::const_iterator I = cfg->begin(),
+ E = cfg->end(); I != E; ++I) {
+ if(DT->getNode(*I)->getIDom())
+ llvm::errs() << "(" << (*I)->getBlockID()
+ << ","
+ << DT->getNode(*I)->getIDom()->getBlock()->getBlockID()
+ << ")\n";
+ else llvm::errs() << "(" << (*I)->getBlockID()
+ << "," << (*I)->getBlockID() << ")\n";
+ }
+ }
+
+ /// This method tests if one CFGBlock dominates the other.
+ /// The method return true if A dominates B, false otherwise.
+ /// Note a block always dominates itself.
+ bool dominates(const CFGBlock *A, const CFGBlock *B) const {
+ return DT->dominates(A, B);
+ }
+
+ /// This method tests if one CFGBlock properly dominates the other.
+ /// The method return true if A properly dominates B, false otherwise.
+ bool properlyDominates(const CFGBlock *A, const CFGBlock *B) const {
+ return DT->properlyDominates(A, B);
+ }
+
+ /// This method finds the nearest common dominator CFG block
+ /// for CFG block A and B. If there is no such block then return NULL.
+ CFGBlock *findNearestCommonDominator(CFGBlock *A, CFGBlock *B) {
+ return DT->findNearestCommonDominator(A, B);
+ }
+
+ const CFGBlock *findNearestCommonDominator(const CFGBlock *A,
+ const CFGBlock *B) {
+ return DT->findNearestCommonDominator(A, B);
+ }
+
+ /// This method is used to update the dominator
+ /// tree information when a node's immediate dominator changes.
+ void changeImmediateDominator(CFGBlock *N, CFGBlock *NewIDom) {
+ DT->changeImmediateDominator(N, NewIDom);
+ }
+
+ /// This method tests if the given CFGBlock can be reachable from root.
+ /// Returns true if reachable, false otherwise.
+ bool isReachableFromEntry(const CFGBlock *A) {
+ return DT->isReachableFromEntry(A);
+ }
+
+ /// This method releases the memory held by the dominator tree.
+ virtual void releaseMemory() {
+ DT->releaseMemory();
+ }
+
+ /// This method converts the dominator tree to human readable form.
+ virtual void print(raw_ostream &OS, const llvm::Module* M= nullptr) const {
+ DT->print(OS);
+ }
+
+private:
+ CFG *cfg;
+};
+
+} // namespace clang
+
+//===-------------------------------------
+/// DominatorTree GraphTraits specialization so the DominatorTree can be
+/// iterable by generic graph iterators.
+///
+namespace llvm {
+
+template <> struct GraphTraits< ::clang::DomTreeNode* > {
+ using NodeRef = ::clang::DomTreeNode *;
+ using ChildIteratorType = ::clang::DomTreeNode::iterator;
+
+ static NodeRef getEntryNode(NodeRef N) { return N; }
+ static ChildIteratorType child_begin(NodeRef N) { return N->begin(); }
+ static ChildIteratorType child_end(NodeRef N) { return N->end(); }
+
+ using nodes_iterator =
+ llvm::pointer_iterator<df_iterator<::clang::DomTreeNode *>>;
+
+ static nodes_iterator nodes_begin(::clang::DomTreeNode *N) {
+ return nodes_iterator(df_begin(getEntryNode(N)));
+ }
+
+ static nodes_iterator nodes_end(::clang::DomTreeNode *N) {
+ return nodes_iterator(df_end(getEntryNode(N)));
+ }
+};
+
+template <> struct GraphTraits< ::clang::DominatorTree* >
+ : public GraphTraits< ::clang::DomTreeNode* > {
+ static NodeRef getEntryNode(::clang::DominatorTree *DT) {
+ return DT->getRootNode();
+ }
+
+ static nodes_iterator nodes_begin(::clang::DominatorTree *N) {
+ return nodes_iterator(df_begin(getEntryNode(N)));
+ }
+
+ static nodes_iterator nodes_end(::clang::DominatorTree *N) {
+ return nodes_iterator(df_end(getEntryNode(N)));
+ }
+};
+
+} // namespace llvm
+
+#endif // LLVM_CLANG_ANALYSIS_ANALYSES_DOMINATORS_H
diff --git a/clang-r353983/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h b/clang-r353983/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
new file mode 100644
index 00000000..9397c5df
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
@@ -0,0 +1,95 @@
+//===---------- ExprMutationAnalyzer.h ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
+
+#include <type_traits>
+
+#include "clang/AST/AST.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace clang {
+
+class FunctionParmMutationAnalyzer;
+
+/// Analyzes whether any mutative operations are applied to an expression within
+/// a given statement.
+class ExprMutationAnalyzer {
+public:
+ ExprMutationAnalyzer(const Stmt &Stm, ASTContext &Context)
+ : Stm(Stm), Context(Context) {}
+
+ bool isMutated(const Expr *Exp) { return findMutation(Exp) != nullptr; }
+ bool isMutated(const Decl *Dec) { return findMutation(Dec) != nullptr; }
+ const Stmt *findMutation(const Expr *Exp);
+ const Stmt *findMutation(const Decl *Dec);
+
+ bool isPointeeMutated(const Expr *Exp) {
+ return findPointeeMutation(Exp) != nullptr;
+ }
+ bool isPointeeMutated(const Decl *Dec) {
+ return findPointeeMutation(Dec) != nullptr;
+ }
+ const Stmt *findPointeeMutation(const Expr *Exp);
+ const Stmt *findPointeeMutation(const Decl *Dec);
+
+private:
+ using MutationFinder = const Stmt *(ExprMutationAnalyzer::*)(const Expr *);
+ using ResultMap = llvm::DenseMap<const Expr *, const Stmt *>;
+
+ const Stmt *findMutationMemoized(const Expr *Exp,
+ llvm::ArrayRef<MutationFinder> Finders,
+ ResultMap &MemoizedResults);
+ const Stmt *tryEachDeclRef(const Decl *Dec, MutationFinder Finder);
+
+ bool isUnevaluated(const Expr *Exp);
+
+ const Stmt *findExprMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
+ const Stmt *findDeclMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
+ const Stmt *
+ findExprPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
+ const Stmt *
+ findDeclPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
+
+ const Stmt *findDirectMutation(const Expr *Exp);
+ const Stmt *findMemberMutation(const Expr *Exp);
+ const Stmt *findArrayElementMutation(const Expr *Exp);
+ const Stmt *findCastMutation(const Expr *Exp);
+ const Stmt *findRangeLoopMutation(const Expr *Exp);
+ const Stmt *findReferenceMutation(const Expr *Exp);
+ const Stmt *findFunctionArgMutation(const Expr *Exp);
+
+ const Stmt &Stm;
+ ASTContext &Context;
+ llvm::DenseMap<const FunctionDecl *,
+ std::unique_ptr<FunctionParmMutationAnalyzer>>
+ FuncParmAnalyzer;
+ ResultMap Results;
+ ResultMap PointeeResults;
+};
+
+// A convenient wrapper around ExprMutationAnalyzer for analyzing function
+// params.
+class FunctionParmMutationAnalyzer {
+public:
+ FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context);
+
+ bool isMutated(const ParmVarDecl *Parm) {
+ return findMutation(Parm) != nullptr;
+ }
+ const Stmt *findMutation(const ParmVarDecl *Parm);
+
+private:
+ ExprMutationAnalyzer BodyAnalyzer;
+ llvm::DenseMap<const ParmVarDecl *, const Stmt *> Results;
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
diff --git a/clang-r353983/include/clang/Analysis/Analyses/LiveVariables.h b/clang-r353983/include/clang/Analysis/Analyses/LiveVariables.h
new file mode 100644
index 00000000..a46c35ee
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/LiveVariables.h
@@ -0,0 +1,122 @@
+//===- LiveVariables.h - Live Variable Analysis for Source CFGs -*- C++ --*-//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements Live Variables analysis for source-level CFGs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_LIVEVARIABLES_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_LIVEVARIABLES_H
+
+#include "clang/AST/Decl.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "llvm/ADT/ImmutableSet.h"
+
+namespace clang {
+
+class CFG;
+class CFGBlock;
+class Stmt;
+class DeclRefExpr;
+class SourceManager;
+
+class LiveVariables : public ManagedAnalysis {
+public:
+ class LivenessValues {
+ public:
+
+ llvm::ImmutableSet<const Stmt *> liveStmts;
+ llvm::ImmutableSet<const VarDecl *> liveDecls;
+ llvm::ImmutableSet<const BindingDecl *> liveBindings;
+
+ bool equals(const LivenessValues &V) const;
+
+ LivenessValues()
+ : liveStmts(nullptr), liveDecls(nullptr), liveBindings(nullptr) {}
+
+ LivenessValues(llvm::ImmutableSet<const Stmt *> LiveStmts,
+ llvm::ImmutableSet<const VarDecl *> LiveDecls,
+ llvm::ImmutableSet<const BindingDecl *> LiveBindings)
+ : liveStmts(LiveStmts), liveDecls(LiveDecls),
+ liveBindings(LiveBindings) {}
+
+ bool isLive(const Stmt *S) const;
+ bool isLive(const VarDecl *D) const;
+
+ friend class LiveVariables;
+ };
+
+ class Observer {
+ virtual void anchor();
+ public:
+ virtual ~Observer() {}
+
+ /// A callback invoked right before invoking the
+ /// liveness transfer function on the given statement.
+ virtual void observeStmt(const Stmt *S,
+ const CFGBlock *currentBlock,
+ const LivenessValues& V) {}
+
+ /// Called when the live variables analysis registers
+ /// that a variable is killed.
+ virtual void observerKill(const DeclRefExpr *DR) {}
+ };
+
+ ~LiveVariables() override;
+
+ /// Compute the liveness information for a given CFG.
+ static LiveVariables *computeLiveness(AnalysisDeclContext &analysisContext,
+ bool killAtAssign);
+
+ /// Return true if a variable is live at the end of a
+ /// specified block.
+ bool isLive(const CFGBlock *B, const VarDecl *D);
+
+ /// Returns true if a variable is live at the beginning of the
+ /// the statement. This query only works if liveness information
+ /// has been recorded at the statement level (see runOnAllBlocks), and
+ /// only returns liveness information for block-level expressions.
+ bool isLive(const Stmt *S, const VarDecl *D);
+
+ /// Returns true the block-level expression "value" is live
+ /// before the given block-level expression (see runOnAllBlocks).
+ bool isLive(const Stmt *Loc, const Stmt *StmtVal);
+
+ /// Print to stderr the variable liveness information associated with
+ /// each basic block.
+ void dumpBlockLiveness(const SourceManager &M);
+
+ /// Print to stderr the statement liveness information associated with
+ /// each basic block.
+ void dumpStmtLiveness(const SourceManager &M);
+
+ void runOnAllBlocks(Observer &obs);
+
+ static LiveVariables *create(AnalysisDeclContext &analysisContext) {
+ return computeLiveness(analysisContext, true);
+ }
+
+ static const void *getTag();
+
+private:
+ LiveVariables(void *impl);
+ void *impl;
+};
+
+class RelaxedLiveVariables : public LiveVariables {
+public:
+ static LiveVariables *create(AnalysisDeclContext &analysisContext) {
+ return computeLiveness(analysisContext, false);
+ }
+
+ static const void *getTag();
+};
+
+} // end namespace clang
+
+#endif
diff --git a/clang-r353983/include/clang/Analysis/Analyses/PostOrderCFGView.h b/clang-r353983/include/clang/Analysis/Analyses/PostOrderCFGView.h
new file mode 100644
index 00000000..08fda098
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/PostOrderCFGView.h
@@ -0,0 +1,116 @@
+//===- PostOrderCFGView.h - Post order view of CFG blocks -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements post order view of the blocks in a CFG.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_POSTORDERCFGVIEW_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_POSTORDERCFGVIEW_H
+
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include <utility>
+#include <vector>
+
+namespace clang {
+
+class PostOrderCFGView : public ManagedAnalysis {
+ virtual void anchor();
+
+public:
+ /// Implements a set of CFGBlocks using a BitVector.
+ ///
+ /// This class contains a minimal interface, primarily dictated by the SetType
+ /// template parameter of the llvm::po_iterator template, as used with
+ /// external storage. We also use this set to keep track of which CFGBlocks we
+ /// visit during the analysis.
+ class CFGBlockSet {
+ llvm::BitVector VisitedBlockIDs;
+
+ public:
+ // po_iterator requires this iterator, but the only interface needed is the
+ // value_type type.
+ struct iterator { using value_type = const CFGBlock *; };
+
+ CFGBlockSet() = default;
+ CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {}
+
+ /// Set the bit associated with a particular CFGBlock.
+ /// This is the important method for the SetType template parameter.
+ std::pair<llvm::NoneType, bool> insert(const CFGBlock *Block) {
+ // Note that insert() is called by po_iterator, which doesn't check to
+ // make sure that Block is non-null. Moreover, the CFGBlock iterator will
+ // occasionally hand out null pointers for pruned edges, so we catch those
+ // here.
+ if (!Block)
+ return std::make_pair(None, false); // if an edge is trivially false.
+ if (VisitedBlockIDs.test(Block->getBlockID()))
+ return std::make_pair(None, false);
+ VisitedBlockIDs.set(Block->getBlockID());
+ return std::make_pair(None, true);
+ }
+
+ /// Check if the bit for a CFGBlock has been already set.
+ /// This method is for tracking visited blocks in the main threadsafety
+ /// loop. Block must not be null.
+ bool alreadySet(const CFGBlock *Block) {
+ return VisitedBlockIDs.test(Block->getBlockID());
+ }
+ };
+
+private:
+ using po_iterator = llvm::po_iterator<const CFG *, CFGBlockSet, true>;
+ std::vector<const CFGBlock *> Blocks;
+
+ using BlockOrderTy = llvm::DenseMap<const CFGBlock *, unsigned>;
+ BlockOrderTy BlockOrder;
+
+public:
+ friend struct BlockOrderCompare;
+
+ using iterator = std::vector<const CFGBlock *>::reverse_iterator;
+ using const_iterator = std::vector<const CFGBlock *>::const_reverse_iterator;
+
+ PostOrderCFGView(const CFG *cfg);
+
+ iterator begin() { return Blocks.rbegin(); }
+ iterator end() { return Blocks.rend(); }
+
+ const_iterator begin() const { return Blocks.rbegin(); }
+ const_iterator end() const { return Blocks.rend(); }
+
+ bool empty() const { return begin() == end(); }
+
+ struct BlockOrderCompare {
+ const PostOrderCFGView &POV;
+
+ public:
+ BlockOrderCompare(const PostOrderCFGView &pov) : POV(pov) {}
+
+ bool operator()(const CFGBlock *b1, const CFGBlock *b2) const;
+ };
+
+ BlockOrderCompare getComparator() const {
+ return BlockOrderCompare(*this);
+ }
+
+ // Used by AnalyisContext to construct this object.
+ static const void *getTag();
+
+ static PostOrderCFGView *create(AnalysisDeclContext &analysisContext);
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_ANALYSES_POSTORDERCFGVIEW_H
diff --git a/clang-r353983/include/clang/Analysis/Analyses/ReachableCode.h b/clang-r353983/include/clang/Analysis/Analyses/ReachableCode.h
new file mode 100644
index 00000000..514b9458
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/ReachableCode.h
@@ -0,0 +1,68 @@
+//===- ReachableCode.h -----------------------------------------*- C++ --*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// A flow-sensitive, path-insensitive analysis of unreachable code.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_REACHABLECODE_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_REACHABLECODE_H
+
+#include "clang/Basic/SourceLocation.h"
+
+//===----------------------------------------------------------------------===//
+// Forward declarations.
+//===----------------------------------------------------------------------===//
+
+namespace llvm {
+ class BitVector;
+}
+
+namespace clang {
+ class AnalysisDeclContext;
+ class CFGBlock;
+ class Preprocessor;
+}
+
+//===----------------------------------------------------------------------===//
+// API.
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+namespace reachable_code {
+
+/// Classifications of unreachable code.
+enum UnreachableKind {
+ UK_Return,
+ UK_Break,
+ UK_Loop_Increment,
+ UK_Other
+};
+
+class Callback {
+ virtual void anchor();
+public:
+ virtual ~Callback() {}
+ virtual void HandleUnreachable(UnreachableKind UK,
+ SourceLocation L,
+ SourceRange ConditionVal,
+ SourceRange R1,
+ SourceRange R2) = 0;
+};
+
+/// ScanReachableFromBlock - Mark all blocks reachable from Start.
+/// Returns the total number of blocks that were marked reachable.
+unsigned ScanReachableFromBlock(const CFGBlock *Start,
+ llvm::BitVector &Reachable);
+
+void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP,
+ Callback &CB);
+
+}} // end namespace clang::reachable_code
+
+#endif
diff --git a/clang-r353983/include/clang/Analysis/Analyses/ThreadSafety.h b/clang-r353983/include/clang/Analysis/Analyses/ThreadSafety.h
new file mode 100644
index 00000000..2f0c68c8
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/ThreadSafety.h
@@ -0,0 +1,249 @@
+//===- ThreadSafety.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//
+// A intra-procedural analysis for thread safety (e.g. deadlocks and race
+// conditions), based off of an annotation system.
+//
+// See http://clang.llvm.org/docs/LanguageExtensions.html#thread-safety-annotation-checking
+// for more information.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+
+class AnalysisDeclContext;
+class FunctionDecl;
+class NamedDecl;
+
+namespace threadSafety {
+
+class BeforeSet;
+
+/// This enum distinguishes between different kinds of operations that may
+/// need to be protected by locks. We use this enum in error handling.
+enum ProtectedOperationKind {
+ /// Dereferencing a variable (e.g. p in *p = 5;)
+ POK_VarDereference,
+
+ /// Reading or writing a variable (e.g. x in x = 5;)
+ POK_VarAccess,
+
+ /// Making a function call (e.g. fool())
+ POK_FunctionCall,
+
+ /// Passing a guarded variable by reference.
+ POK_PassByRef,
+
+ /// Passing a pt-guarded variable by reference.
+ POK_PtPassByRef
+};
+
+/// This enum distinguishes between different kinds of lock actions. For
+/// example, it is an error to write a variable protected by shared version of a
+/// mutex.
+enum LockKind {
+ /// Shared/reader lock of a mutex.
+ LK_Shared,
+
+ /// Exclusive/writer lock of a mutex.
+ LK_Exclusive,
+
+ /// Can be either Shared or Exclusive.
+ LK_Generic
+};
+
+/// This enum distinguishes between different ways to access (read or write) a
+/// variable.
+enum AccessKind {
+ /// Reading a variable.
+ AK_Read,
+
+ /// Writing a variable.
+ AK_Written
+};
+
+/// This enum distinguishes between different situations where we warn due to
+/// inconsistent locking.
+/// \enum SK_LockedSomeLoopIterations -- a mutex is locked for some but not all
+/// loop iterations.
+/// \enum SK_LockedSomePredecessors -- a mutex is locked in some but not all
+/// predecessors of a CFGBlock.
+/// \enum SK_LockedAtEndOfFunction -- a mutex is still locked at the end of a
+/// function.
+enum LockErrorKind {
+ LEK_LockedSomeLoopIterations,
+ LEK_LockedSomePredecessors,
+ LEK_LockedAtEndOfFunction,
+ LEK_NotLockedAtEndOfFunction
+};
+
+/// Handler class for thread safety warnings.
+class ThreadSafetyHandler {
+public:
+ using Name = StringRef;
+
+ ThreadSafetyHandler() = default;
+ virtual ~ThreadSafetyHandler();
+
+ /// Warn about lock expressions which fail to resolve to lockable objects.
+ /// \param Kind -- the capability's name parameter (role, mutex, etc).
+ /// \param Loc -- the SourceLocation of the unresolved expression.
+ virtual void handleInvalidLockExp(StringRef Kind, SourceLocation Loc) {}
+
+ /// Warn about unlock function calls that do not have a prior matching lock
+ /// expression.
+ /// \param Kind -- the capability's name parameter (role, mutex, etc).
+ /// \param LockName -- A StringRef name for the lock expression, to be printed
+ /// in the error message.
+ /// \param Loc -- The SourceLocation of the Unlock
+ virtual void handleUnmatchedUnlock(StringRef Kind, Name LockName,
+ SourceLocation Loc) {}
+
+ /// Warn about an unlock function call that attempts to unlock a lock with
+ /// the incorrect lock kind. For instance, a shared lock being unlocked
+ /// exclusively, or vice versa.
+ /// \param LockName -- A StringRef name for the lock expression, to be printed
+ /// in the error message.
+ /// \param Kind -- the capability's name parameter (role, mutex, etc).
+ /// \param Expected -- the kind of lock expected.
+ /// \param Received -- the kind of lock received.
+ /// \param Loc -- The SourceLocation of the Unlock.
+ virtual void handleIncorrectUnlockKind(StringRef Kind, Name LockName,
+ LockKind Expected, LockKind Received,
+ SourceLocation Loc) {}
+
+ /// Warn about lock function calls for locks which are already held.
+ /// \param Kind -- the capability's name parameter (role, mutex, etc).
+ /// \param LockName -- A StringRef name for the lock expression, to be printed
+ /// in the error message.
+ /// \param LocLocked -- The location of the first lock expression.
+ /// \param Loc -- The location of the second lock expression.
+ virtual void handleDoubleLock(StringRef Kind, Name LockName,
+ SourceLocation LocLocked, SourceLocation Loc) {}
+
+ /// Warn about situations where a mutex is sometimes held and sometimes not.
+ /// The three situations are:
+ /// 1. a mutex is locked on an "if" branch but not the "else" branch,
+ /// 2, or a mutex is only held at the start of some loop iterations,
+ /// 3. or when a mutex is locked but not unlocked inside a function.
+ /// \param Kind -- the capability's name parameter (role, mutex, etc).
+ /// \param LockName -- A StringRef name for the lock expression, to be printed
+ /// in the error message.
+ /// \param LocLocked -- The location of the lock expression where the mutex is
+ /// locked
+ /// \param LocEndOfScope -- The location of the end of the scope where the
+ /// mutex is no longer held
+ /// \param LEK -- which of the three above cases we should warn for
+ virtual void handleMutexHeldEndOfScope(StringRef Kind, Name LockName,
+ SourceLocation LocLocked,
+ SourceLocation LocEndOfScope,
+ LockErrorKind LEK) {}
+
+ /// Warn when a mutex is held exclusively and shared at the same point. For
+ /// example, if a mutex is locked exclusively during an if branch and shared
+ /// during the else branch.
+ /// \param Kind -- the capability's name parameter (role, mutex, etc).
+ /// \param LockName -- A StringRef name for the lock expression, to be printed
+ /// in the error message.
+ /// \param Loc1 -- The location of the first lock expression.
+ /// \param Loc2 -- The location of the second lock expression.
+ virtual void handleExclusiveAndShared(StringRef Kind, Name LockName,
+ SourceLocation Loc1,
+ SourceLocation Loc2) {}
+
+ /// Warn when a protected operation occurs while no locks are held.
+ /// \param Kind -- the capability's name parameter (role, mutex, etc).
+ /// \param D -- The decl for the protected variable or function
+ /// \param POK -- The kind of protected operation (e.g. variable access)
+ /// \param AK -- The kind of access (i.e. read or write) that occurred
+ /// \param Loc -- The location of the protected operation.
+ virtual void handleNoMutexHeld(StringRef Kind, const NamedDecl *D,
+ ProtectedOperationKind POK, AccessKind AK,
+ SourceLocation Loc) {}
+
+ /// Warn when a protected operation occurs while the specific mutex protecting
+ /// the operation is not locked.
+ /// \param Kind -- the capability's name parameter (role, mutex, etc).
+ /// \param D -- The decl for the protected variable or function
+ /// \param POK -- The kind of protected operation (e.g. variable access)
+ /// \param LockName -- A StringRef name for the lock expression, to be printed
+ /// in the error message.
+ /// \param LK -- The kind of access (i.e. read or write) that occurred
+ /// \param Loc -- The location of the protected operation.
+ virtual void handleMutexNotHeld(StringRef Kind, const NamedDecl *D,
+ ProtectedOperationKind POK, Name LockName,
+ LockKind LK, SourceLocation Loc,
+ Name *PossibleMatch = nullptr) {}
+
+ /// Warn when acquiring a lock that the negative capability is not held.
+ /// \param Kind -- the capability's name parameter (role, mutex, etc).
+ /// \param LockName -- The name for the lock expression, to be printed in the
+ /// diagnostic.
+ /// \param Neg -- The name of the negative capability to be printed in the
+ /// diagnostic.
+ /// \param Loc -- The location of the protected operation.
+ virtual void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg,
+ SourceLocation Loc) {}
+
+ /// Warn when a function is called while an excluded mutex is locked. For
+ /// example, the mutex may be locked inside the function.
+ /// \param Kind -- the capability's name parameter (role, mutex, etc).
+ /// \param FunName -- The name of the function
+ /// \param LockName -- A StringRef name for the lock expression, to be printed
+ /// in the error message.
+ /// \param Loc -- The location of the function call.
+ virtual void handleFunExcludesLock(StringRef Kind, Name FunName,
+ Name LockName, SourceLocation Loc) {}
+
+ /// Warn that L1 cannot be acquired before L2.
+ virtual void handleLockAcquiredBefore(StringRef Kind, Name L1Name,
+ Name L2Name, SourceLocation Loc) {}
+
+ /// Warn that there is a cycle in acquired_before/after dependencies.
+ virtual void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) {}
+
+ /// Called by the analysis when starting analysis of a function.
+ /// Used to issue suggestions for changes to annotations.
+ virtual void enterFunction(const FunctionDecl *FD) {}
+
+ /// Called by the analysis when finishing analysis of a function.
+ virtual void leaveFunction(const FunctionDecl *FD) {}
+
+ bool issueBetaWarnings() { return IssueBetaWarnings; }
+ void setIssueBetaWarnings(bool b) { IssueBetaWarnings = b; }
+
+private:
+ bool IssueBetaWarnings = false;
+};
+
+/// Check a function's CFG for thread-safety violations.
+///
+/// We traverse the blocks in the CFG, compute the set of mutexes that are held
+/// at the end of each block, and issue warnings for thread safety violations.
+/// Each block in the CFG is traversed exactly once.
+void runThreadSafetyAnalysis(AnalysisDeclContext &AC,
+ ThreadSafetyHandler &Handler,
+ BeforeSet **Bset);
+
+void threadSafetyCleanup(BeforeSet *Cache);
+
+/// Helper function that returns a LockKind required for the given level
+/// of access.
+LockKind getLockKindFromAccessKind(AccessKind AK);
+
+} // namespace threadSafety
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETY_H
diff --git a/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyCommon.h b/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
new file mode 100644
index 00000000..4a58fe87
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
@@ -0,0 +1,520 @@
+//===- ThreadSafetyCommon.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Parts of thread safety analysis that are not specific to thread safety
+// itself have been factored into classes here, where they can be potentially
+// used by other analyses. Currently these include:
+//
+// * Generalize clang CFG visitors.
+// * Conversion of the clang CFG to SSA form.
+// * Translation of clang Exprs to TIL SExprs
+//
+// UNDER CONSTRUCTION. USE AT YOUR OWN RISK.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYCOMMON_H
+
+#include "clang/AST/Decl.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
+#include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Casting.h"
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace clang {
+
+class AbstractConditionalOperator;
+class ArraySubscriptExpr;
+class BinaryOperator;
+class CallExpr;
+class CastExpr;
+class CXXDestructorDecl;
+class CXXMemberCallExpr;
+class CXXOperatorCallExpr;
+class CXXThisExpr;
+class DeclRefExpr;
+class DeclStmt;
+class Expr;
+class MemberExpr;
+class Stmt;
+class UnaryOperator;
+
+namespace threadSafety {
+
+// Various helper functions on til::SExpr
+namespace sx {
+
+inline bool equals(const til::SExpr *E1, const til::SExpr *E2) {
+ return til::EqualsComparator::compareExprs(E1, E2);
+}
+
+inline bool matches(const til::SExpr *E1, const til::SExpr *E2) {
+ // We treat a top-level wildcard as the "univsersal" lock.
+ // It matches everything for the purpose of checking locks, but not
+ // for unlocking them.
+ if (isa<til::Wildcard>(E1))
+ return isa<til::Wildcard>(E2);
+ if (isa<til::Wildcard>(E2))
+ return isa<til::Wildcard>(E1);
+
+ return til::MatchComparator::compareExprs(E1, E2);
+}
+
+inline bool partiallyMatches(const til::SExpr *E1, const til::SExpr *E2) {
+ const auto *PE1 = dyn_cast_or_null<til::Project>(E1);
+ if (!PE1)
+ return false;
+ const auto *PE2 = dyn_cast_or_null<til::Project>(E2);
+ if (!PE2)
+ return false;
+ return PE1->clangDecl() == PE2->clangDecl();
+}
+
+inline std::string toString(const til::SExpr *E) {
+ std::stringstream ss;
+ til::StdPrinter::print(E, ss);
+ return ss.str();
+}
+
+} // namespace sx
+
+// This class defines the interface of a clang CFG Visitor.
+// CFGWalker will invoke the following methods.
+// Note that methods are not virtual; the visitor is templatized.
+class CFGVisitor {
+ // Enter the CFG for Decl D, and perform any initial setup operations.
+ void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {}
+
+ // Enter a CFGBlock.
+ void enterCFGBlock(const CFGBlock *B) {}
+
+ // Returns true if this visitor implements handlePredecessor
+ bool visitPredecessors() { return true; }
+
+ // Process a predecessor edge.
+ void handlePredecessor(const CFGBlock *Pred) {}
+
+ // Process a successor back edge to a previously visited block.
+ void handlePredecessorBackEdge(const CFGBlock *Pred) {}
+
+ // Called just before processing statements.
+ void enterCFGBlockBody(const CFGBlock *B) {}
+
+ // Process an ordinary statement.
+ void handleStatement(const Stmt *S) {}
+
+ // Process a destructor call
+ void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {}
+
+ // Called after all statements have been handled.
+ void exitCFGBlockBody(const CFGBlock *B) {}
+
+ // Return true
+ bool visitSuccessors() { return true; }
+
+ // Process a successor edge.
+ void handleSuccessor(const CFGBlock *Succ) {}
+
+ // Process a successor back edge to a previously visited block.
+ void handleSuccessorBackEdge(const CFGBlock *Succ) {}
+
+ // Leave a CFGBlock.
+ void exitCFGBlock(const CFGBlock *B) {}
+
+ // Leave the CFG, and perform any final cleanup operations.
+ void exitCFG(const CFGBlock *Last) {}
+};
+
+// Walks the clang CFG, and invokes methods on a given CFGVisitor.
+class CFGWalker {
+public:
+ CFGWalker() = default;
+
+ // Initialize the CFGWalker. This setup only needs to be done once, even
+ // if there are multiple passes over the CFG.
+ bool init(AnalysisDeclContext &AC) {
+ ACtx = &AC;
+ CFGraph = AC.getCFG();
+ if (!CFGraph)
+ return false;
+
+ // Ignore anonymous functions.
+ if (!dyn_cast_or_null<NamedDecl>(AC.getDecl()))
+ return false;
+
+ SortedGraph = AC.getAnalysis<PostOrderCFGView>();
+ if (!SortedGraph)
+ return false;
+
+ return true;
+ }
+
+ // Traverse the CFG, calling methods on V as appropriate.
+ template <class Visitor>
+ void walk(Visitor &V) {
+ PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
+
+ V.enterCFG(CFGraph, getDecl(), &CFGraph->getEntry());
+
+ for (const auto *CurrBlock : *SortedGraph) {
+ VisitedBlocks.insert(CurrBlock);
+
+ V.enterCFGBlock(CurrBlock);
+
+ // Process predecessors, handling back edges last
+ if (V.visitPredecessors()) {
+ SmallVector<CFGBlock*, 4> BackEdges;
+ // Process successors
+ for (CFGBlock::const_pred_iterator SI = CurrBlock->pred_begin(),
+ SE = CurrBlock->pred_end();
+ SI != SE; ++SI) {
+ if (*SI == nullptr)
+ continue;
+
+ if (!VisitedBlocks.alreadySet(*SI)) {
+ BackEdges.push_back(*SI);
+ continue;
+ }
+ V.handlePredecessor(*SI);
+ }
+
+ for (auto *Blk : BackEdges)
+ V.handlePredecessorBackEdge(Blk);
+ }
+
+ V.enterCFGBlockBody(CurrBlock);
+
+ // Process statements
+ for (const auto &BI : *CurrBlock) {
+ switch (BI.getKind()) {
+ case CFGElement::Statement:
+ V.handleStatement(BI.castAs<CFGStmt>().getStmt());
+ break;
+
+ case CFGElement::AutomaticObjectDtor: {
+ CFGAutomaticObjDtor AD = BI.castAs<CFGAutomaticObjDtor>();
+ auto *DD = const_cast<CXXDestructorDecl *>(
+ AD.getDestructorDecl(ACtx->getASTContext()));
+ auto *VD = const_cast<VarDecl *>(AD.getVarDecl());
+ V.handleDestructorCall(VD, DD);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ V.exitCFGBlockBody(CurrBlock);
+
+ // Process successors, handling back edges first.
+ if (V.visitSuccessors()) {
+ SmallVector<CFGBlock*, 8> ForwardEdges;
+
+ // Process successors
+ for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
+ SE = CurrBlock->succ_end();
+ SI != SE; ++SI) {
+ if (*SI == nullptr)
+ continue;
+
+ if (!VisitedBlocks.alreadySet(*SI)) {
+ ForwardEdges.push_back(*SI);
+ continue;
+ }
+ V.handleSuccessorBackEdge(*SI);
+ }
+
+ for (auto *Blk : ForwardEdges)
+ V.handleSuccessor(Blk);
+ }
+
+ V.exitCFGBlock(CurrBlock);
+ }
+ V.exitCFG(&CFGraph->getExit());
+ }
+
+ const CFG *getGraph() const { return CFGraph; }
+ CFG *getGraph() { return CFGraph; }
+
+ const NamedDecl *getDecl() const {
+ return dyn_cast<NamedDecl>(ACtx->getDecl());
+ }
+
+ const PostOrderCFGView *getSortedGraph() const { return SortedGraph; }
+
+private:
+ CFG *CFGraph = nullptr;
+ AnalysisDeclContext *ACtx = nullptr;
+ PostOrderCFGView *SortedGraph = nullptr;
+};
+
+// TODO: move this back into ThreadSafety.cpp
+// This is specific to thread safety. It is here because
+// translateAttrExpr needs it, but that should be moved too.
+class CapabilityExpr {
+private:
+ /// The capability expression.
+ const til::SExpr* CapExpr;
+
+ /// True if this is a negative capability.
+ bool Negated;
+
+public:
+ CapabilityExpr(const til::SExpr *E, bool Neg) : CapExpr(E), Negated(Neg) {}
+
+ const til::SExpr* sexpr() const { return CapExpr; }
+ bool negative() const { return Negated; }
+
+ CapabilityExpr operator!() const {
+ return CapabilityExpr(CapExpr, !Negated);
+ }
+
+ bool equals(const CapabilityExpr &other) const {
+ return (Negated == other.Negated) && sx::equals(CapExpr, other.CapExpr);
+ }
+
+ bool matches(const CapabilityExpr &other) const {
+ return (Negated == other.Negated) && sx::matches(CapExpr, other.CapExpr);
+ }
+
+ bool matchesUniv(const CapabilityExpr &CapE) const {
+ return isUniversal() || matches(CapE);
+ }
+
+ bool partiallyMatches(const CapabilityExpr &other) const {
+ return (Negated == other.Negated) &&
+ sx::partiallyMatches(CapExpr, other.CapExpr);
+ }
+
+ const ValueDecl* valueDecl() const {
+ if (Negated || CapExpr == nullptr)
+ return nullptr;
+ if (const auto *P = dyn_cast<til::Project>(CapExpr))
+ return P->clangDecl();
+ if (const auto *P = dyn_cast<til::LiteralPtr>(CapExpr))
+ return P->clangDecl();
+ return nullptr;
+ }
+
+ std::string toString() const {
+ if (Negated)
+ return "!" + sx::toString(CapExpr);
+ return sx::toString(CapExpr);
+ }
+
+ bool shouldIgnore() const { return CapExpr == nullptr; }
+
+ bool isInvalid() const { return sexpr() && isa<til::Undefined>(sexpr()); }
+
+ bool isUniversal() const { return sexpr() && isa<til::Wildcard>(sexpr()); }
+};
+
+// Translate clang::Expr to til::SExpr.
+class SExprBuilder {
+public:
+ /// Encapsulates the lexical context of a function call. The lexical
+ /// context includes the arguments to the call, including the implicit object
+ /// argument. When an attribute containing a mutex expression is attached to
+ /// a method, the expression may refer to formal parameters of the method.
+ /// Actual arguments must be substituted for formal parameters to derive
+ /// the appropriate mutex expression in the lexical context where the function
+ /// is called. PrevCtx holds the context in which the arguments themselves
+ /// should be evaluated; multiple calling contexts can be chained together
+ /// by the lock_returned attribute.
+ struct CallingContext {
+ // The previous context; or 0 if none.
+ CallingContext *Prev;
+
+ // The decl to which the attr is attached.
+ const NamedDecl *AttrDecl;
+
+ // Implicit object argument -- e.g. 'this'
+ const Expr *SelfArg = nullptr;
+
+ // Number of funArgs
+ unsigned NumArgs = 0;
+
+ // Function arguments
+ const Expr *const *FunArgs = nullptr;
+
+ // is Self referred to with -> or .?
+ bool SelfArrow = false;
+
+ CallingContext(CallingContext *P, const NamedDecl *D = nullptr)
+ : Prev(P), AttrDecl(D) {}
+ };
+
+ SExprBuilder(til::MemRegionRef A) : Arena(A) {
+ // FIXME: we don't always have a self-variable.
+ SelfVar = new (Arena) til::Variable(nullptr);
+ SelfVar->setKind(til::Variable::VK_SFun);
+ }
+
+ // Translate a clang expression in an attribute to a til::SExpr.
+ // Constructs the context from D, DeclExp, and SelfDecl.
+ CapabilityExpr translateAttrExpr(const Expr *AttrExp, const NamedDecl *D,
+ const Expr *DeclExp, VarDecl *SelfD=nullptr);
+
+ CapabilityExpr translateAttrExpr(const Expr *AttrExp, CallingContext *Ctx);
+
+ // Translate a clang statement or expression to a TIL expression.
+ // Also performs substitution of variables; Ctx provides the context.
+ // Dispatches on the type of S.
+ til::SExpr *translate(const Stmt *S, CallingContext *Ctx);
+ til::SCFG *buildCFG(CFGWalker &Walker);
+
+ til::SExpr *lookupStmt(const Stmt *S);
+
+ til::BasicBlock *lookupBlock(const CFGBlock *B) {
+ return BlockMap[B->getBlockID()];
+ }
+
+ const til::SCFG *getCFG() const { return Scfg; }
+ til::SCFG *getCFG() { return Scfg; }
+
+private:
+ // We implement the CFGVisitor API
+ friend class CFGWalker;
+
+ til::SExpr *translateDeclRefExpr(const DeclRefExpr *DRE,
+ CallingContext *Ctx) ;
+ til::SExpr *translateCXXThisExpr(const CXXThisExpr *TE, CallingContext *Ctx);
+ til::SExpr *translateMemberExpr(const MemberExpr *ME, CallingContext *Ctx);
+ til::SExpr *translateObjCIVarRefExpr(const ObjCIvarRefExpr *IVRE,
+ CallingContext *Ctx);
+ til::SExpr *translateCallExpr(const CallExpr *CE, CallingContext *Ctx,
+ const Expr *SelfE = nullptr);
+ til::SExpr *translateCXXMemberCallExpr(const CXXMemberCallExpr *ME,
+ CallingContext *Ctx);
+ til::SExpr *translateCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE,
+ CallingContext *Ctx);
+ til::SExpr *translateUnaryOperator(const UnaryOperator *UO,
+ CallingContext *Ctx);
+ til::SExpr *translateBinOp(til::TIL_BinaryOpcode Op,
+ const BinaryOperator *BO,
+ CallingContext *Ctx, bool Reverse = false);
+ til::SExpr *translateBinAssign(til::TIL_BinaryOpcode Op,
+ const BinaryOperator *BO,
+ CallingContext *Ctx, bool Assign = false);
+ til::SExpr *translateBinaryOperator(const BinaryOperator *BO,
+ CallingContext *Ctx);
+ til::SExpr *translateCastExpr(const CastExpr *CE, CallingContext *Ctx);
+ til::SExpr *translateArraySubscriptExpr(const ArraySubscriptExpr *E,
+ CallingContext *Ctx);
+ til::SExpr *translateAbstractConditionalOperator(
+ const AbstractConditionalOperator *C, CallingContext *Ctx);
+
+ til::SExpr *translateDeclStmt(const DeclStmt *S, CallingContext *Ctx);
+
+ // Map from statements in the clang CFG to SExprs in the til::SCFG.
+ using StatementMap = llvm::DenseMap<const Stmt *, til::SExpr *>;
+
+ // Map from clang local variables to indices in a LVarDefinitionMap.
+ using LVarIndexMap = llvm::DenseMap<const ValueDecl *, unsigned>;
+
+ // Map from local variable indices to SSA variables (or constants).
+ using NameVarPair = std::pair<const ValueDecl *, til::SExpr *>;
+ using LVarDefinitionMap = CopyOnWriteVector<NameVarPair>;
+
+ struct BlockInfo {
+ LVarDefinitionMap ExitMap;
+ bool HasBackEdges = false;
+
+ // Successors yet to be processed
+ unsigned UnprocessedSuccessors = 0;
+
+ // Predecessors already processed
+ unsigned ProcessedPredecessors = 0;
+
+ BlockInfo() = default;
+ BlockInfo(BlockInfo &&) = default;
+ BlockInfo &operator=(BlockInfo &&) = default;
+ };
+
+ void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First);
+ void enterCFGBlock(const CFGBlock *B);
+ bool visitPredecessors() { return true; }
+ void handlePredecessor(const CFGBlock *Pred);
+ void handlePredecessorBackEdge(const CFGBlock *Pred);
+ void enterCFGBlockBody(const CFGBlock *B);
+ void handleStatement(const Stmt *S);
+ void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD);
+ void exitCFGBlockBody(const CFGBlock *B);
+ bool visitSuccessors() { return true; }
+ void handleSuccessor(const CFGBlock *Succ);
+ void handleSuccessorBackEdge(const CFGBlock *Succ);
+ void exitCFGBlock(const CFGBlock *B);
+ void exitCFG(const CFGBlock *Last);
+
+ void insertStmt(const Stmt *S, til::SExpr *E) {
+ SMap.insert(std::make_pair(S, E));
+ }
+
+ til::SExpr *getCurrentLVarDefinition(const ValueDecl *VD);
+
+ til::SExpr *addStatement(til::SExpr *E, const Stmt *S,
+ const ValueDecl *VD = nullptr);
+ til::SExpr *lookupVarDecl(const ValueDecl *VD);
+ til::SExpr *addVarDecl(const ValueDecl *VD, til::SExpr *E);
+ til::SExpr *updateVarDecl(const ValueDecl *VD, til::SExpr *E);
+
+ void makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E);
+ void mergeEntryMap(LVarDefinitionMap Map);
+ void mergeEntryMapBackEdge();
+ void mergePhiNodesBackEdge(const CFGBlock *Blk);
+
+private:
+ // Set to true when parsing capability expressions, which get translated
+ // inaccurately in order to hack around smart pointers etc.
+ static const bool CapabilityExprMode = true;
+
+ til::MemRegionRef Arena;
+
+ // Variable to use for 'this'. May be null.
+ til::Variable *SelfVar = nullptr;
+
+ til::SCFG *Scfg = nullptr;
+
+ // Map from Stmt to TIL Variables
+ StatementMap SMap;
+
+ // Indices of clang local vars.
+ LVarIndexMap LVarIdxMap;
+
+ // Map from clang to til BBs.
+ std::vector<til::BasicBlock *> BlockMap;
+
+ // Extra information per BB. Indexed by clang BlockID.
+ std::vector<BlockInfo> BBInfo;
+
+ LVarDefinitionMap CurrentLVarMap;
+ std::vector<til::Phi *> CurrentArguments;
+ std::vector<til::SExpr *> CurrentInstructions;
+ std::vector<til::Phi *> IncompleteArgs;
+ til::BasicBlock *CurrentBB = nullptr;
+ BlockInfo *CurrentBlockInfo = nullptr;
+};
+
+// Dump an SCFG to llvm::errs().
+void printSCFG(CFGWalker &Walker);
+
+} // namespace threadSafety
+} // namespace clang
+
+#endif // LLVM_CLANG_THREAD_SAFETY_COMMON_H
diff --git a/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyLogical.h b/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyLogical.h
new file mode 100644
index 00000000..8d938c1b
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyLogical.h
@@ -0,0 +1,107 @@
+//===- ThreadSafetyLogical.h -----------------------------------*- C++ --*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// This file defines a representation for logical expressions with SExpr leaves
+// that are used as part of fact-checking capability expressions.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYLOGICAL_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYLOGICAL_H
+
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+
+namespace clang {
+namespace threadSafety {
+namespace lexpr {
+
+class LExpr {
+public:
+ enum Opcode {
+ Terminal,
+ And,
+ Or,
+ Not
+ };
+ Opcode kind() const { return Kind; }
+
+ /// Logical implication. Returns true if the LExpr implies RHS, i.e. if
+ /// the LExpr holds, then RHS must hold. For example, (A & B) implies A.
+ inline bool implies(const LExpr *RHS) const;
+
+protected:
+ LExpr(Opcode Kind) : Kind(Kind) {}
+
+private:
+ Opcode Kind;
+};
+
+class Terminal : public LExpr {
+ til::SExpr *Expr;
+
+public:
+ Terminal(til::SExpr *Expr) : LExpr(LExpr::Terminal), Expr(Expr) {}
+
+ const til::SExpr *expr() const { return Expr; }
+ til::SExpr *expr() { return Expr; }
+
+ static bool classof(const LExpr *E) { return E->kind() == LExpr::Terminal; }
+};
+
+class BinOp : public LExpr {
+ LExpr *LHS, *RHS;
+
+protected:
+ BinOp(LExpr *LHS, LExpr *RHS, Opcode Code) : LExpr(Code), LHS(LHS), RHS(RHS) {}
+
+public:
+ const LExpr *left() const { return LHS; }
+ LExpr *left() { return LHS; }
+
+ const LExpr *right() const { return RHS; }
+ LExpr *right() { return RHS; }
+};
+
+class And : public BinOp {
+public:
+ And(LExpr *LHS, LExpr *RHS) : BinOp(LHS, RHS, LExpr::And) {}
+
+ static bool classof(const LExpr *E) { return E->kind() == LExpr::And; }
+};
+
+class Or : public BinOp {
+public:
+ Or(LExpr *LHS, LExpr *RHS) : BinOp(LHS, RHS, LExpr::Or) {}
+
+ static bool classof(const LExpr *E) { return E->kind() == LExpr::Or; }
+};
+
+class Not : public LExpr {
+ LExpr *Exp;
+
+public:
+ Not(LExpr *Exp) : LExpr(LExpr::Not), Exp(Exp) {}
+
+ const LExpr *exp() const { return Exp; }
+ LExpr *exp() { return Exp; }
+
+ static bool classof(const LExpr *E) { return E->kind() == LExpr::Not; }
+};
+
+/// Logical implication. Returns true if LHS implies RHS, i.e. if LHS
+/// holds, then RHS must hold. For example, (A & B) implies A.
+bool implies(const LExpr *LHS, const LExpr *RHS);
+
+bool LExpr::implies(const LExpr *RHS) const {
+ return lexpr::implies(this, RHS);
+}
+
+}
+}
+}
+
+#endif
+
diff --git a/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyOps.def b/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyOps.def
new file mode 100644
index 00000000..fc4881a7
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyOps.def
@@ -0,0 +1,56 @@
+//===- ThreadSafetyTIL.h ---------------------------------------*- C++ --*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the list of core opcodes for the Thread Safety
+// Typed Intermediate language. Please see ThreadSafetyTIL.h for more
+// information.
+//
+//===----------------------------------------------------------------------===//
+
+
+TIL_OPCODE_DEF(Future)
+TIL_OPCODE_DEF(Undefined)
+TIL_OPCODE_DEF(Wildcard)
+
+TIL_OPCODE_DEF(Literal)
+TIL_OPCODE_DEF(LiteralPtr)
+TIL_OPCODE_DEF(Variable)
+TIL_OPCODE_DEF(Function)
+TIL_OPCODE_DEF(SFunction)
+TIL_OPCODE_DEF(Code)
+TIL_OPCODE_DEF(Field)
+
+TIL_OPCODE_DEF(Apply)
+TIL_OPCODE_DEF(SApply)
+TIL_OPCODE_DEF(Project)
+
+TIL_OPCODE_DEF(Call)
+TIL_OPCODE_DEF(Alloc)
+TIL_OPCODE_DEF(Load)
+TIL_OPCODE_DEF(Store)
+TIL_OPCODE_DEF(ArrayIndex)
+TIL_OPCODE_DEF(ArrayAdd)
+
+TIL_OPCODE_DEF(UnaryOp)
+TIL_OPCODE_DEF(BinaryOp)
+TIL_OPCODE_DEF(Cast)
+
+TIL_OPCODE_DEF(SCFG)
+TIL_OPCODE_DEF(BasicBlock)
+TIL_OPCODE_DEF(Phi)
+
+// Terminator instructions
+TIL_OPCODE_DEF(Goto)
+TIL_OPCODE_DEF(Branch)
+TIL_OPCODE_DEF(Return)
+
+// pseudo-terms
+TIL_OPCODE_DEF(Identifier)
+TIL_OPCODE_DEF(IfThenElse)
+TIL_OPCODE_DEF(Let)
+
diff --git a/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyTIL.h b/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
new file mode 100644
index 00000000..ca2193d2
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
@@ -0,0 +1,1910 @@
+//===- ThreadSafetyTIL.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a simple Typed Intermediate Language, or TIL, that is used
+// by the thread safety analysis (See ThreadSafety.cpp). The TIL is intended
+// to be largely independent of clang, in the hope that the analysis can be
+// reused for other non-C++ languages. All dependencies on clang/llvm should
+// go in ThreadSafetyUtil.h.
+//
+// Thread safety analysis works by comparing mutex expressions, e.g.
+//
+// class A { Mutex mu; int dat GUARDED_BY(this->mu); }
+// class B { A a; }
+//
+// void foo(B* b) {
+// (*b).a.mu.lock(); // locks (*b).a.mu
+// b->a.dat = 0; // substitute &b->a for 'this';
+// // requires lock on (&b->a)->mu
+// (b->a.mu).unlock(); // unlocks (b->a.mu)
+// }
+//
+// As illustrated by the above example, clang Exprs are not well-suited to
+// represent mutex expressions directly, since there is no easy way to compare
+// Exprs for equivalence. The thread safety analysis thus lowers clang Exprs
+// into a simple intermediate language (IL). The IL supports:
+//
+// (1) comparisons for semantic equality of expressions
+// (2) SSA renaming of variables
+// (3) wildcards and pattern matching over expressions
+// (4) hash-based expression lookup
+//
+// The TIL is currently very experimental, is intended only for use within
+// the thread safety analysis, and is subject to change without notice.
+// After the API stabilizes and matures, it may be appropriate to make this
+// more generally available to other analyses.
+//
+// UNDER CONSTRUCTION. USE AT YOUR OWN RISK.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H
+
+#include "clang/AST/Decl.h"
+#include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <string>
+#include <utility>
+
+namespace clang {
+
+class CallExpr;
+class Expr;
+class Stmt;
+
+namespace threadSafety {
+namespace til {
+
+class BasicBlock;
+
+/// Enum for the different distinct classes of SExpr
+enum TIL_Opcode {
+#define TIL_OPCODE_DEF(X) COP_##X,
+#include "ThreadSafetyOps.def"
+#undef TIL_OPCODE_DEF
+};
+
+/// Opcode for unary arithmetic operations.
+enum TIL_UnaryOpcode : unsigned char {
+ UOP_Minus, // -
+ UOP_BitNot, // ~
+ UOP_LogicNot // !
+};
+
+/// Opcode for binary arithmetic operations.
+enum TIL_BinaryOpcode : unsigned char {
+ BOP_Add, // +
+ BOP_Sub, // -
+ BOP_Mul, // *
+ BOP_Div, // /
+ BOP_Rem, // %
+ BOP_Shl, // <<
+ BOP_Shr, // >>
+ BOP_BitAnd, // &
+ BOP_BitXor, // ^
+ BOP_BitOr, // |
+ BOP_Eq, // ==
+ BOP_Neq, // !=
+ BOP_Lt, // <
+ BOP_Leq, // <=
+ BOP_Cmp, // <=>
+ BOP_LogicAnd, // && (no short-circuit)
+ BOP_LogicOr // || (no short-circuit)
+};
+
+/// Opcode for cast operations.
+enum TIL_CastOpcode : unsigned char {
+ CAST_none = 0,
+
+ // Extend precision of numeric type
+ CAST_extendNum,
+
+ // Truncate precision of numeric type
+ CAST_truncNum,
+
+ // Convert to floating point type
+ CAST_toFloat,
+
+ // Convert to integer type
+ CAST_toInt,
+
+ // Convert smart pointer to pointer (C++ only)
+ CAST_objToPtr
+};
+
+const TIL_Opcode COP_Min = COP_Future;
+const TIL_Opcode COP_Max = COP_Branch;
+const TIL_UnaryOpcode UOP_Min = UOP_Minus;
+const TIL_UnaryOpcode UOP_Max = UOP_LogicNot;
+const TIL_BinaryOpcode BOP_Min = BOP_Add;
+const TIL_BinaryOpcode BOP_Max = BOP_LogicOr;
+const TIL_CastOpcode CAST_Min = CAST_none;
+const TIL_CastOpcode CAST_Max = CAST_toInt;
+
+/// Return the name of a unary opcode.
+StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op);
+
+/// Return the name of a binary opcode.
+StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op);
+
+/// ValueTypes are data types that can actually be held in registers.
+/// All variables and expressions must have a value type.
+/// Pointer types are further subdivided into the various heap-allocated
+/// types, such as functions, records, etc.
+/// Structured types that are passed by value (e.g. complex numbers)
+/// require special handling; they use BT_ValueRef, and size ST_0.
+struct ValueType {
+ enum BaseType : unsigned char {
+ BT_Void = 0,
+ BT_Bool,
+ BT_Int,
+ BT_Float,
+ BT_String, // String literals
+ BT_Pointer,
+ BT_ValueRef
+ };
+
+ enum SizeType : unsigned char {
+ ST_0 = 0,
+ ST_1,
+ ST_8,
+ ST_16,
+ ST_32,
+ ST_64,
+ ST_128
+ };
+
+ ValueType(BaseType B, SizeType Sz, bool S, unsigned char VS)
+ : Base(B), Size(Sz), Signed(S), VectSize(VS) {}
+
+ inline static SizeType getSizeType(unsigned nbytes);
+
+ template <class T>
+ inline static ValueType getValueType();
+
+ BaseType Base;
+ SizeType Size;
+ bool Signed;
+
+ // 0 for scalar, otherwise num elements in vector
+ unsigned char VectSize;
+};
+
+inline ValueType::SizeType ValueType::getSizeType(unsigned nbytes) {
+ switch (nbytes) {
+ case 1: return ST_8;
+ case 2: return ST_16;
+ case 4: return ST_32;
+ case 8: return ST_64;
+ case 16: return ST_128;
+ default: return ST_0;
+ }
+}
+
+template<>
+inline ValueType ValueType::getValueType<void>() {
+ return ValueType(BT_Void, ST_0, false, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<bool>() {
+ return ValueType(BT_Bool, ST_1, false, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<int8_t>() {
+ return ValueType(BT_Int, ST_8, true, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<uint8_t>() {
+ return ValueType(BT_Int, ST_8, false, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<int16_t>() {
+ return ValueType(BT_Int, ST_16, true, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<uint16_t>() {
+ return ValueType(BT_Int, ST_16, false, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<int32_t>() {
+ return ValueType(BT_Int, ST_32, true, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<uint32_t>() {
+ return ValueType(BT_Int, ST_32, false, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<int64_t>() {
+ return ValueType(BT_Int, ST_64, true, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<uint64_t>() {
+ return ValueType(BT_Int, ST_64, false, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<float>() {
+ return ValueType(BT_Float, ST_32, true, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<double>() {
+ return ValueType(BT_Float, ST_64, true, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<long double>() {
+ return ValueType(BT_Float, ST_128, true, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<StringRef>() {
+ return ValueType(BT_String, getSizeType(sizeof(StringRef)), false, 0);
+}
+
+template<>
+inline ValueType ValueType::getValueType<void*>() {
+ return ValueType(BT_Pointer, getSizeType(sizeof(void*)), false, 0);
+}
+
+/// Base class for AST nodes in the typed intermediate language.
+class SExpr {
+public:
+ SExpr() = delete;
+
+ TIL_Opcode opcode() const { return static_cast<TIL_Opcode>(Opcode); }
+
+ // Subclasses of SExpr must define the following:
+ //
+ // This(const This& E, ...) {
+ // copy constructor: construct copy of E, with some additional arguments.
+ // }
+ //
+ // template <class V>
+ // typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ // traverse all subexpressions, following the traversal/rewriter interface.
+ // }
+ //
+ // template <class C> typename C::CType compare(CType* E, C& Cmp) {
+ // compare all subexpressions, following the comparator interface
+ // }
+ void *operator new(size_t S, MemRegionRef &R) {
+ return ::operator new(S, R);
+ }
+
+ /// SExpr objects must be created in an arena.
+ void *operator new(size_t) = delete;
+
+ /// SExpr objects cannot be deleted.
+ // This declaration is public to workaround a gcc bug that breaks building
+ // with REQUIRES_EH=1.
+ void operator delete(void *) = delete;
+
+ /// Returns the instruction ID for this expression.
+ /// All basic block instructions have a unique ID (i.e. virtual register).
+ unsigned id() const { return SExprID; }
+
+ /// Returns the block, if this is an instruction in a basic block,
+ /// otherwise returns null.
+ BasicBlock *block() const { return Block; }
+
+ /// Set the basic block and instruction ID for this expression.
+ void setID(BasicBlock *B, unsigned id) { Block = B; SExprID = id; }
+
+protected:
+ SExpr(TIL_Opcode Op) : Opcode(Op) {}
+ SExpr(const SExpr &E) : Opcode(E.Opcode), Flags(E.Flags) {}
+
+ const unsigned char Opcode;
+ unsigned char Reserved = 0;
+ unsigned short Flags = 0;
+ unsigned SExprID = 0;
+ BasicBlock *Block = nullptr;
+};
+
+// Contains various helper functions for SExprs.
+namespace ThreadSafetyTIL {
+
+inline bool isTrivial(const SExpr *E) {
+ unsigned Op = E->opcode();
+ return Op == COP_Variable || Op == COP_Literal || Op == COP_LiteralPtr;
+}
+
+} // namespace ThreadSafetyTIL
+
+// Nodes which declare variables
+
+/// A named variable, e.g. "x".
+///
+/// There are two distinct places in which a Variable can appear in the AST.
+/// A variable declaration introduces a new variable, and can occur in 3 places:
+/// Let-expressions: (Let (x = t) u)
+/// Functions: (Function (x : t) u)
+/// Self-applicable functions (SFunction (x) t)
+///
+/// If a variable occurs in any other location, it is a reference to an existing
+/// variable declaration -- e.g. 'x' in (x * y + z). To save space, we don't
+/// allocate a separate AST node for variable references; a reference is just a
+/// pointer to the original declaration.
+class Variable : public SExpr {
+public:
+ enum VariableKind {
+ /// Let-variable
+ VK_Let,
+
+ /// Function parameter
+ VK_Fun,
+
+ /// SFunction (self) parameter
+ VK_SFun
+ };
+
+ Variable(StringRef s, SExpr *D = nullptr)
+ : SExpr(COP_Variable), Name(s), Definition(D) {
+ Flags = VK_Let;
+ }
+
+ Variable(SExpr *D, const ValueDecl *Cvd = nullptr)
+ : SExpr(COP_Variable), Name(Cvd ? Cvd->getName() : "_x"),
+ Definition(D), Cvdecl(Cvd) {
+ Flags = VK_Let;
+ }
+
+ Variable(const Variable &Vd, SExpr *D) // rewrite constructor
+ : SExpr(Vd), Name(Vd.Name), Definition(D), Cvdecl(Vd.Cvdecl) {
+ Flags = Vd.kind();
+ }
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Variable; }
+
+ /// Return the kind of variable (let, function param, or self)
+ VariableKind kind() const { return static_cast<VariableKind>(Flags); }
+
+ /// Return the name of the variable, if any.
+ StringRef name() const { return Name; }
+
+ /// Return the clang declaration for this variable, if any.
+ const ValueDecl *clangDecl() const { return Cvdecl; }
+
+ /// Return the definition of the variable.
+ /// For let-vars, this is the setting expression.
+ /// For function and self parameters, it is the type of the variable.
+ SExpr *definition() { return Definition; }
+ const SExpr *definition() const { return Definition; }
+
+ void setName(StringRef S) { Name = S; }
+ void setKind(VariableKind K) { Flags = K; }
+ void setDefinition(SExpr *E) { Definition = E; }
+ void setClangDecl(const ValueDecl *VD) { Cvdecl = VD; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ // This routine is only called for variable references.
+ return Vs.reduceVariableRef(this);
+ }
+
+ template <class C>
+ typename C::CType compare(const Variable* E, C& Cmp) const {
+ return Cmp.compareVariableRefs(this, E);
+ }
+
+private:
+ friend class BasicBlock;
+ friend class Function;
+ friend class Let;
+ friend class SFunction;
+
+ // The name of the variable.
+ StringRef Name;
+
+ // The TIL type or definition.
+ SExpr *Definition;
+
+ // The clang declaration for this variable.
+ const ValueDecl *Cvdecl = nullptr;
+};
+
+/// Placeholder for an expression that has not yet been created.
+/// Used to implement lazy copy and rewriting strategies.
+class Future : public SExpr {
+public:
+ enum FutureStatus {
+ FS_pending,
+ FS_evaluating,
+ FS_done
+ };
+
+ Future() : SExpr(COP_Future) {}
+ virtual ~Future() = delete;
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Future; }
+
+ // A lazy rewriting strategy should subclass Future and override this method.
+ virtual SExpr *compute() { return nullptr; }
+
+ // Return the result of this future if it exists, otherwise return null.
+ SExpr *maybeGetResult() const { return Result; }
+
+ // Return the result of this future; forcing it if necessary.
+ SExpr *result() {
+ switch (Status) {
+ case FS_pending:
+ return force();
+ case FS_evaluating:
+ return nullptr; // infinite loop; illegal recursion.
+ case FS_done:
+ return Result;
+ }
+ }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ assert(Result && "Cannot traverse Future that has not been forced.");
+ return Vs.traverse(Result, Ctx);
+ }
+
+ template <class C>
+ typename C::CType compare(const Future* E, C& Cmp) const {
+ if (!Result || !E->Result)
+ return Cmp.comparePointers(this, E);
+ return Cmp.compare(Result, E->Result);
+ }
+
+private:
+ SExpr* force();
+
+ FutureStatus Status = FS_pending;
+ SExpr *Result = nullptr;
+};
+
+/// Placeholder for expressions that cannot be represented in the TIL.
+class Undefined : public SExpr {
+public:
+ Undefined(const Stmt *S = nullptr) : SExpr(COP_Undefined), Cstmt(S) {}
+ Undefined(const Undefined &U) : SExpr(U), Cstmt(U.Cstmt) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Undefined; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ return Vs.reduceUndefined(*this);
+ }
+
+ template <class C>
+ typename C::CType compare(const Undefined* E, C& Cmp) const {
+ return Cmp.trueResult();
+ }
+
+private:
+ const Stmt *Cstmt;
+};
+
+/// Placeholder for a wildcard that matches any other expression.
+class Wildcard : public SExpr {
+public:
+ Wildcard() : SExpr(COP_Wildcard) {}
+ Wildcard(const Wildcard &) = default;
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Wildcard; }
+
+ template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ return Vs.reduceWildcard(*this);
+ }
+
+ template <class C>
+ typename C::CType compare(const Wildcard* E, C& Cmp) const {
+ return Cmp.trueResult();
+ }
+};
+
+template <class T> class LiteralT;
+
+// Base class for literal values.
+class Literal : public SExpr {
+public:
+ Literal(const Expr *C)
+ : SExpr(COP_Literal), ValType(ValueType::getValueType<void>()), Cexpr(C) {}
+ Literal(ValueType VT) : SExpr(COP_Literal), ValType(VT) {}
+ Literal(const Literal &) = default;
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Literal; }
+
+ // The clang expression for this literal.
+ const Expr *clangExpr() const { return Cexpr; }
+
+ ValueType valueType() const { return ValType; }
+
+ template<class T> const LiteralT<T>& as() const {
+ return *static_cast<const LiteralT<T>*>(this);
+ }
+ template<class T> LiteralT<T>& as() {
+ return *static_cast<LiteralT<T>*>(this);
+ }
+
+ template <class V> typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx);
+
+ template <class C>
+ typename C::CType compare(const Literal* E, C& Cmp) const {
+ // TODO: defer actual comparison to LiteralT
+ return Cmp.trueResult();
+ }
+
+private:
+ const ValueType ValType;
+ const Expr *Cexpr = nullptr;
+};
+
+// Derived class for literal values, which stores the actual value.
+template<class T>
+class LiteralT : public Literal {
+public:
+ LiteralT(T Dat) : Literal(ValueType::getValueType<T>()), Val(Dat) {}
+ LiteralT(const LiteralT<T> &L) : Literal(L), Val(L.Val) {}
+
+ T value() const { return Val;}
+ T& value() { return Val; }
+
+private:
+ T Val;
+};
+
+template <class V>
+typename V::R_SExpr Literal::traverse(V &Vs, typename V::R_Ctx Ctx) {
+ if (Cexpr)
+ return Vs.reduceLiteral(*this);
+
+ switch (ValType.Base) {
+ case ValueType::BT_Void:
+ break;
+ case ValueType::BT_Bool:
+ return Vs.reduceLiteralT(as<bool>());
+ case ValueType::BT_Int: {
+ switch (ValType.Size) {
+ case ValueType::ST_8:
+ if (ValType.Signed)
+ return Vs.reduceLiteralT(as<int8_t>());
+ else
+ return Vs.reduceLiteralT(as<uint8_t>());
+ case ValueType::ST_16:
+ if (ValType.Signed)
+ return Vs.reduceLiteralT(as<int16_t>());
+ else
+ return Vs.reduceLiteralT(as<uint16_t>());
+ case ValueType::ST_32:
+ if (ValType.Signed)
+ return Vs.reduceLiteralT(as<int32_t>());
+ else
+ return Vs.reduceLiteralT(as<uint32_t>());
+ case ValueType::ST_64:
+ if (ValType.Signed)
+ return Vs.reduceLiteralT(as<int64_t>());
+ else
+ return Vs.reduceLiteralT(as<uint64_t>());
+ default:
+ break;
+ }
+ }
+ case ValueType::BT_Float: {
+ switch (ValType.Size) {
+ case ValueType::ST_32:
+ return Vs.reduceLiteralT(as<float>());
+ case ValueType::ST_64:
+ return Vs.reduceLiteralT(as<double>());
+ default:
+ break;
+ }
+ }
+ case ValueType::BT_String:
+ return Vs.reduceLiteralT(as<StringRef>());
+ case ValueType::BT_Pointer:
+ return Vs.reduceLiteralT(as<void*>());
+ case ValueType::BT_ValueRef:
+ break;
+ }
+ return Vs.reduceLiteral(*this);
+}
+
+/// A Literal pointer to an object allocated in memory.
+/// At compile time, pointer literals are represented by symbolic names.
+class LiteralPtr : public SExpr {
+public:
+ LiteralPtr(const ValueDecl *D) : SExpr(COP_LiteralPtr), Cvdecl(D) {}
+ LiteralPtr(const LiteralPtr &) = default;
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_LiteralPtr; }
+
+ // The clang declaration for the value that this pointer points to.
+ const ValueDecl *clangDecl() const { return Cvdecl; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ return Vs.reduceLiteralPtr(*this);
+ }
+
+ template <class C>
+ typename C::CType compare(const LiteralPtr* E, C& Cmp) const {
+ return Cmp.comparePointers(Cvdecl, E->Cvdecl);
+ }
+
+private:
+ const ValueDecl *Cvdecl;
+};
+
+/// A function -- a.k.a. lambda abstraction.
+/// Functions with multiple arguments are created by currying,
+/// e.g. (Function (x: Int) (Function (y: Int) (Code { return x + y })))
+class Function : public SExpr {
+public:
+ Function(Variable *Vd, SExpr *Bd)
+ : SExpr(COP_Function), VarDecl(Vd), Body(Bd) {
+ Vd->setKind(Variable::VK_Fun);
+ }
+
+ Function(const Function &F, Variable *Vd, SExpr *Bd) // rewrite constructor
+ : SExpr(F), VarDecl(Vd), Body(Bd) {
+ Vd->setKind(Variable::VK_Fun);
+ }
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Function; }
+
+ Variable *variableDecl() { return VarDecl; }
+ const Variable *variableDecl() const { return VarDecl; }
+
+ SExpr *body() { return Body; }
+ const SExpr *body() const { return Body; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ // This is a variable declaration, so traverse the definition.
+ auto E0 = Vs.traverse(VarDecl->Definition, Vs.typeCtx(Ctx));
+ // Tell the rewriter to enter the scope of the function.
+ Variable *Nvd = Vs.enterScope(*VarDecl, E0);
+ auto E1 = Vs.traverse(Body, Vs.declCtx(Ctx));
+ Vs.exitScope(*VarDecl);
+ return Vs.reduceFunction(*this, Nvd, E1);
+ }
+
+ template <class C>
+ typename C::CType compare(const Function* E, C& Cmp) const {
+ typename C::CType Ct =
+ Cmp.compare(VarDecl->definition(), E->VarDecl->definition());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ Cmp.enterScope(variableDecl(), E->variableDecl());
+ Ct = Cmp.compare(body(), E->body());
+ Cmp.leaveScope();
+ return Ct;
+ }
+
+private:
+ Variable *VarDecl;
+ SExpr* Body;
+};
+
+/// A self-applicable function.
+/// A self-applicable function can be applied to itself. It's useful for
+/// implementing objects and late binding.
+class SFunction : public SExpr {
+public:
+ SFunction(Variable *Vd, SExpr *B)
+ : SExpr(COP_SFunction), VarDecl(Vd), Body(B) {
+ assert(Vd->Definition == nullptr);
+ Vd->setKind(Variable::VK_SFun);
+ Vd->Definition = this;
+ }
+
+ SFunction(const SFunction &F, Variable *Vd, SExpr *B) // rewrite constructor
+ : SExpr(F), VarDecl(Vd), Body(B) {
+ assert(Vd->Definition == nullptr);
+ Vd->setKind(Variable::VK_SFun);
+ Vd->Definition = this;
+ }
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_SFunction; }
+
+ Variable *variableDecl() { return VarDecl; }
+ const Variable *variableDecl() const { return VarDecl; }
+
+ SExpr *body() { return Body; }
+ const SExpr *body() const { return Body; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ // A self-variable points to the SFunction itself.
+ // A rewrite must introduce the variable with a null definition, and update
+ // it after 'this' has been rewritten.
+ Variable *Nvd = Vs.enterScope(*VarDecl, nullptr);
+ auto E1 = Vs.traverse(Body, Vs.declCtx(Ctx));
+ Vs.exitScope(*VarDecl);
+ // A rewrite operation will call SFun constructor to set Vvd->Definition.
+ return Vs.reduceSFunction(*this, Nvd, E1);
+ }
+
+ template <class C>
+ typename C::CType compare(const SFunction* E, C& Cmp) const {
+ Cmp.enterScope(variableDecl(), E->variableDecl());
+ typename C::CType Ct = Cmp.compare(body(), E->body());
+ Cmp.leaveScope();
+ return Ct;
+ }
+
+private:
+ Variable *VarDecl;
+ SExpr* Body;
+};
+
+/// A block of code -- e.g. the body of a function.
+class Code : public SExpr {
+public:
+ Code(SExpr *T, SExpr *B) : SExpr(COP_Code), ReturnType(T), Body(B) {}
+ Code(const Code &C, SExpr *T, SExpr *B) // rewrite constructor
+ : SExpr(C), ReturnType(T), Body(B) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Code; }
+
+ SExpr *returnType() { return ReturnType; }
+ const SExpr *returnType() const { return ReturnType; }
+
+ SExpr *body() { return Body; }
+ const SExpr *body() const { return Body; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Nt = Vs.traverse(ReturnType, Vs.typeCtx(Ctx));
+ auto Nb = Vs.traverse(Body, Vs.lazyCtx(Ctx));
+ return Vs.reduceCode(*this, Nt, Nb);
+ }
+
+ template <class C>
+ typename C::CType compare(const Code* E, C& Cmp) const {
+ typename C::CType Ct = Cmp.compare(returnType(), E->returnType());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(body(), E->body());
+ }
+
+private:
+ SExpr* ReturnType;
+ SExpr* Body;
+};
+
+/// A typed, writable location in memory
+class Field : public SExpr {
+public:
+ Field(SExpr *R, SExpr *B) : SExpr(COP_Field), Range(R), Body(B) {}
+ Field(const Field &C, SExpr *R, SExpr *B) // rewrite constructor
+ : SExpr(C), Range(R), Body(B) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Field; }
+
+ SExpr *range() { return Range; }
+ const SExpr *range() const { return Range; }
+
+ SExpr *body() { return Body; }
+ const SExpr *body() const { return Body; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Nr = Vs.traverse(Range, Vs.typeCtx(Ctx));
+ auto Nb = Vs.traverse(Body, Vs.lazyCtx(Ctx));
+ return Vs.reduceField(*this, Nr, Nb);
+ }
+
+ template <class C>
+ typename C::CType compare(const Field* E, C& Cmp) const {
+ typename C::CType Ct = Cmp.compare(range(), E->range());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(body(), E->body());
+ }
+
+private:
+ SExpr* Range;
+ SExpr* Body;
+};
+
+/// Apply an argument to a function.
+/// Note that this does not actually call the function. Functions are curried,
+/// so this returns a closure in which the first parameter has been applied.
+/// Once all parameters have been applied, Call can be used to invoke the
+/// function.
+class Apply : public SExpr {
+public:
+ Apply(SExpr *F, SExpr *A) : SExpr(COP_Apply), Fun(F), Arg(A) {}
+ Apply(const Apply &A, SExpr *F, SExpr *Ar) // rewrite constructor
+ : SExpr(A), Fun(F), Arg(Ar) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Apply; }
+
+ SExpr *fun() { return Fun; }
+ const SExpr *fun() const { return Fun; }
+
+ SExpr *arg() { return Arg; }
+ const SExpr *arg() const { return Arg; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Nf = Vs.traverse(Fun, Vs.subExprCtx(Ctx));
+ auto Na = Vs.traverse(Arg, Vs.subExprCtx(Ctx));
+ return Vs.reduceApply(*this, Nf, Na);
+ }
+
+ template <class C>
+ typename C::CType compare(const Apply* E, C& Cmp) const {
+ typename C::CType Ct = Cmp.compare(fun(), E->fun());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(arg(), E->arg());
+ }
+
+private:
+ SExpr* Fun;
+ SExpr* Arg;
+};
+
+/// Apply a self-argument to a self-applicable function.
+class SApply : public SExpr {
+public:
+ SApply(SExpr *Sf, SExpr *A = nullptr) : SExpr(COP_SApply), Sfun(Sf), Arg(A) {}
+ SApply(SApply &A, SExpr *Sf, SExpr *Ar = nullptr) // rewrite constructor
+ : SExpr(A), Sfun(Sf), Arg(Ar) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_SApply; }
+
+ SExpr *sfun() { return Sfun; }
+ const SExpr *sfun() const { return Sfun; }
+
+ SExpr *arg() { return Arg ? Arg : Sfun; }
+ const SExpr *arg() const { return Arg ? Arg : Sfun; }
+
+ bool isDelegation() const { return Arg != nullptr; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Nf = Vs.traverse(Sfun, Vs.subExprCtx(Ctx));
+ typename V::R_SExpr Na = Arg ? Vs.traverse(Arg, Vs.subExprCtx(Ctx))
+ : nullptr;
+ return Vs.reduceSApply(*this, Nf, Na);
+ }
+
+ template <class C>
+ typename C::CType compare(const SApply* E, C& Cmp) const {
+ typename C::CType Ct = Cmp.compare(sfun(), E->sfun());
+ if (Cmp.notTrue(Ct) || (!arg() && !E->arg()))
+ return Ct;
+ return Cmp.compare(arg(), E->arg());
+ }
+
+private:
+ SExpr* Sfun;
+ SExpr* Arg;
+};
+
+/// Project a named slot from a C++ struct or class.
+class Project : public SExpr {
+public:
+ Project(SExpr *R, const ValueDecl *Cvd)
+ : SExpr(COP_Project), Rec(R), Cvdecl(Cvd) {
+ assert(Cvd && "ValueDecl must not be null");
+ }
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Project; }
+
+ SExpr *record() { return Rec; }
+ const SExpr *record() const { return Rec; }
+
+ const ValueDecl *clangDecl() const { return Cvdecl; }
+
+ bool isArrow() const { return (Flags & 0x01) != 0; }
+
+ void setArrow(bool b) {
+ if (b) Flags |= 0x01;
+ else Flags &= 0xFFFE;
+ }
+
+ StringRef slotName() const {
+ if (Cvdecl->getDeclName().isIdentifier())
+ return Cvdecl->getName();
+ if (!SlotName) {
+ SlotName = "";
+ llvm::raw_string_ostream OS(*SlotName);
+ Cvdecl->printName(OS);
+ }
+ return *SlotName;
+ }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Nr = Vs.traverse(Rec, Vs.subExprCtx(Ctx));
+ return Vs.reduceProject(*this, Nr);
+ }
+
+ template <class C>
+ typename C::CType compare(const Project* E, C& Cmp) const {
+ typename C::CType Ct = Cmp.compare(record(), E->record());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.comparePointers(Cvdecl, E->Cvdecl);
+ }
+
+private:
+ SExpr* Rec;
+ mutable llvm::Optional<std::string> SlotName;
+ const ValueDecl *Cvdecl;
+};
+
+/// Call a function (after all arguments have been applied).
+class Call : public SExpr {
+public:
+ Call(SExpr *T, const CallExpr *Ce = nullptr)
+ : SExpr(COP_Call), Target(T), Cexpr(Ce) {}
+ Call(const Call &C, SExpr *T) : SExpr(C), Target(T), Cexpr(C.Cexpr) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Call; }
+
+ SExpr *target() { return Target; }
+ const SExpr *target() const { return Target; }
+
+ const CallExpr *clangCallExpr() const { return Cexpr; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Nt = Vs.traverse(Target, Vs.subExprCtx(Ctx));
+ return Vs.reduceCall(*this, Nt);
+ }
+
+ template <class C>
+ typename C::CType compare(const Call* E, C& Cmp) const {
+ return Cmp.compare(target(), E->target());
+ }
+
+private:
+ SExpr* Target;
+ const CallExpr *Cexpr;
+};
+
+/// Allocate memory for a new value on the heap or stack.
+class Alloc : public SExpr {
+public:
+ enum AllocKind {
+ AK_Stack,
+ AK_Heap
+ };
+
+ Alloc(SExpr *D, AllocKind K) : SExpr(COP_Alloc), Dtype(D) { Flags = K; }
+ Alloc(const Alloc &A, SExpr *Dt) : SExpr(A), Dtype(Dt) { Flags = A.kind(); }
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Call; }
+
+ AllocKind kind() const { return static_cast<AllocKind>(Flags); }
+
+ SExpr *dataType() { return Dtype; }
+ const SExpr *dataType() const { return Dtype; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Nd = Vs.traverse(Dtype, Vs.declCtx(Ctx));
+ return Vs.reduceAlloc(*this, Nd);
+ }
+
+ template <class C>
+ typename C::CType compare(const Alloc* E, C& Cmp) const {
+ typename C::CType Ct = Cmp.compareIntegers(kind(), E->kind());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(dataType(), E->dataType());
+ }
+
+private:
+ SExpr* Dtype;
+};
+
+/// Load a value from memory.
+class Load : public SExpr {
+public:
+ Load(SExpr *P) : SExpr(COP_Load), Ptr(P) {}
+ Load(const Load &L, SExpr *P) : SExpr(L), Ptr(P) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Load; }
+
+ SExpr *pointer() { return Ptr; }
+ const SExpr *pointer() const { return Ptr; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Np = Vs.traverse(Ptr, Vs.subExprCtx(Ctx));
+ return Vs.reduceLoad(*this, Np);
+ }
+
+ template <class C>
+ typename C::CType compare(const Load* E, C& Cmp) const {
+ return Cmp.compare(pointer(), E->pointer());
+ }
+
+private:
+ SExpr* Ptr;
+};
+
+/// Store a value to memory.
+/// The destination is a pointer to a field, the source is the value to store.
+class Store : public SExpr {
+public:
+ Store(SExpr *P, SExpr *V) : SExpr(COP_Store), Dest(P), Source(V) {}
+ Store(const Store &S, SExpr *P, SExpr *V) : SExpr(S), Dest(P), Source(V) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Store; }
+
+ SExpr *destination() { return Dest; } // Address to store to
+ const SExpr *destination() const { return Dest; }
+
+ SExpr *source() { return Source; } // Value to store
+ const SExpr *source() const { return Source; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Np = Vs.traverse(Dest, Vs.subExprCtx(Ctx));
+ auto Nv = Vs.traverse(Source, Vs.subExprCtx(Ctx));
+ return Vs.reduceStore(*this, Np, Nv);
+ }
+
+ template <class C>
+ typename C::CType compare(const Store* E, C& Cmp) const {
+ typename C::CType Ct = Cmp.compare(destination(), E->destination());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(source(), E->source());
+ }
+
+private:
+ SExpr* Dest;
+ SExpr* Source;
+};
+
+/// If p is a reference to an array, then p[i] is a reference to the i'th
+/// element of the array.
+class ArrayIndex : public SExpr {
+public:
+ ArrayIndex(SExpr *A, SExpr *N) : SExpr(COP_ArrayIndex), Array(A), Index(N) {}
+ ArrayIndex(const ArrayIndex &E, SExpr *A, SExpr *N)
+ : SExpr(E), Array(A), Index(N) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayIndex; }
+
+ SExpr *array() { return Array; }
+ const SExpr *array() const { return Array; }
+
+ SExpr *index() { return Index; }
+ const SExpr *index() const { return Index; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Na = Vs.traverse(Array, Vs.subExprCtx(Ctx));
+ auto Ni = Vs.traverse(Index, Vs.subExprCtx(Ctx));
+ return Vs.reduceArrayIndex(*this, Na, Ni);
+ }
+
+ template <class C>
+ typename C::CType compare(const ArrayIndex* E, C& Cmp) const {
+ typename C::CType Ct = Cmp.compare(array(), E->array());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(index(), E->index());
+ }
+
+private:
+ SExpr* Array;
+ SExpr* Index;
+};
+
+/// Pointer arithmetic, restricted to arrays only.
+/// If p is a reference to an array, then p + n, where n is an integer, is
+/// a reference to a subarray.
+class ArrayAdd : public SExpr {
+public:
+ ArrayAdd(SExpr *A, SExpr *N) : SExpr(COP_ArrayAdd), Array(A), Index(N) {}
+ ArrayAdd(const ArrayAdd &E, SExpr *A, SExpr *N)
+ : SExpr(E), Array(A), Index(N) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayAdd; }
+
+ SExpr *array() { return Array; }
+ const SExpr *array() const { return Array; }
+
+ SExpr *index() { return Index; }
+ const SExpr *index() const { return Index; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Na = Vs.traverse(Array, Vs.subExprCtx(Ctx));
+ auto Ni = Vs.traverse(Index, Vs.subExprCtx(Ctx));
+ return Vs.reduceArrayAdd(*this, Na, Ni);
+ }
+
+ template <class C>
+ typename C::CType compare(const ArrayAdd* E, C& Cmp) const {
+ typename C::CType Ct = Cmp.compare(array(), E->array());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(index(), E->index());
+ }
+
+private:
+ SExpr* Array;
+ SExpr* Index;
+};
+
+/// Simple arithmetic unary operations, e.g. negate and not.
+/// These operations have no side-effects.
+class UnaryOp : public SExpr {
+public:
+ UnaryOp(TIL_UnaryOpcode Op, SExpr *E) : SExpr(COP_UnaryOp), Expr0(E) {
+ Flags = Op;
+ }
+
+ UnaryOp(const UnaryOp &U, SExpr *E) : SExpr(U), Expr0(E) { Flags = U.Flags; }
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_UnaryOp; }
+
+ TIL_UnaryOpcode unaryOpcode() const {
+ return static_cast<TIL_UnaryOpcode>(Flags);
+ }
+
+ SExpr *expr() { return Expr0; }
+ const SExpr *expr() const { return Expr0; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Ne = Vs.traverse(Expr0, Vs.subExprCtx(Ctx));
+ return Vs.reduceUnaryOp(*this, Ne);
+ }
+
+ template <class C>
+ typename C::CType compare(const UnaryOp* E, C& Cmp) const {
+ typename C::CType Ct =
+ Cmp.compareIntegers(unaryOpcode(), E->unaryOpcode());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(expr(), E->expr());
+ }
+
+private:
+ SExpr* Expr0;
+};
+
+/// Simple arithmetic binary operations, e.g. +, -, etc.
+/// These operations have no side effects.
+class BinaryOp : public SExpr {
+public:
+ BinaryOp(TIL_BinaryOpcode Op, SExpr *E0, SExpr *E1)
+ : SExpr(COP_BinaryOp), Expr0(E0), Expr1(E1) {
+ Flags = Op;
+ }
+
+ BinaryOp(const BinaryOp &B, SExpr *E0, SExpr *E1)
+ : SExpr(B), Expr0(E0), Expr1(E1) {
+ Flags = B.Flags;
+ }
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_BinaryOp; }
+
+ TIL_BinaryOpcode binaryOpcode() const {
+ return static_cast<TIL_BinaryOpcode>(Flags);
+ }
+
+ SExpr *expr0() { return Expr0; }
+ const SExpr *expr0() const { return Expr0; }
+
+ SExpr *expr1() { return Expr1; }
+ const SExpr *expr1() const { return Expr1; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Ne0 = Vs.traverse(Expr0, Vs.subExprCtx(Ctx));
+ auto Ne1 = Vs.traverse(Expr1, Vs.subExprCtx(Ctx));
+ return Vs.reduceBinaryOp(*this, Ne0, Ne1);
+ }
+
+ template <class C>
+ typename C::CType compare(const BinaryOp* E, C& Cmp) const {
+ typename C::CType Ct =
+ Cmp.compareIntegers(binaryOpcode(), E->binaryOpcode());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ Ct = Cmp.compare(expr0(), E->expr0());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(expr1(), E->expr1());
+ }
+
+private:
+ SExpr* Expr0;
+ SExpr* Expr1;
+};
+
+/// Cast expressions.
+/// Cast expressions are essentially unary operations, but we treat them
+/// as a distinct AST node because they only change the type of the result.
+class Cast : public SExpr {
+public:
+ Cast(TIL_CastOpcode Op, SExpr *E) : SExpr(COP_Cast), Expr0(E) { Flags = Op; }
+ Cast(const Cast &C, SExpr *E) : SExpr(C), Expr0(E) { Flags = C.Flags; }
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Cast; }
+
+ TIL_CastOpcode castOpcode() const {
+ return static_cast<TIL_CastOpcode>(Flags);
+ }
+
+ SExpr *expr() { return Expr0; }
+ const SExpr *expr() const { return Expr0; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Ne = Vs.traverse(Expr0, Vs.subExprCtx(Ctx));
+ return Vs.reduceCast(*this, Ne);
+ }
+
+ template <class C>
+ typename C::CType compare(const Cast* E, C& Cmp) const {
+ typename C::CType Ct =
+ Cmp.compareIntegers(castOpcode(), E->castOpcode());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(expr(), E->expr());
+ }
+
+private:
+ SExpr* Expr0;
+};
+
+class SCFG;
+
+/// Phi Node, for code in SSA form.
+/// Each Phi node has an array of possible values that it can take,
+/// depending on where control flow comes from.
+class Phi : public SExpr {
+public:
+ using ValArray = SimpleArray<SExpr *>;
+
+ // In minimal SSA form, all Phi nodes are MultiVal.
+ // During conversion to SSA, incomplete Phi nodes may be introduced, which
+ // are later determined to be SingleVal, and are thus redundant.
+ enum Status {
+ PH_MultiVal = 0, // Phi node has multiple distinct values. (Normal)
+ PH_SingleVal, // Phi node has one distinct value, and can be eliminated
+ PH_Incomplete // Phi node is incomplete
+ };
+
+ Phi() : SExpr(COP_Phi) {}
+ Phi(MemRegionRef A, unsigned Nvals) : SExpr(COP_Phi), Values(A, Nvals) {}
+ Phi(const Phi &P, ValArray &&Vs) : SExpr(P), Values(std::move(Vs)) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Phi; }
+
+ const ValArray &values() const { return Values; }
+ ValArray &values() { return Values; }
+
+ Status status() const { return static_cast<Status>(Flags); }
+ void setStatus(Status s) { Flags = s; }
+
+ /// Return the clang declaration of the variable for this Phi node, if any.
+ const ValueDecl *clangDecl() const { return Cvdecl; }
+
+ /// Set the clang variable associated with this Phi node.
+ void setClangDecl(const ValueDecl *Cvd) { Cvdecl = Cvd; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ typename V::template Container<typename V::R_SExpr>
+ Nvs(Vs, Values.size());
+
+ for (const auto *Val : Values)
+ Nvs.push_back( Vs.traverse(Val, Vs.subExprCtx(Ctx)) );
+ return Vs.reducePhi(*this, Nvs);
+ }
+
+ template <class C>
+ typename C::CType compare(const Phi *E, C &Cmp) const {
+ // TODO: implement CFG comparisons
+ return Cmp.comparePointers(this, E);
+ }
+
+private:
+ ValArray Values;
+ const ValueDecl* Cvdecl = nullptr;
+};
+
+/// Base class for basic block terminators: Branch, Goto, and Return.
+class Terminator : public SExpr {
+protected:
+ Terminator(TIL_Opcode Op) : SExpr(Op) {}
+ Terminator(const SExpr &E) : SExpr(E) {}
+
+public:
+ static bool classof(const SExpr *E) {
+ return E->opcode() >= COP_Goto && E->opcode() <= COP_Return;
+ }
+
+ /// Return the list of basic blocks that this terminator can branch to.
+ ArrayRef<BasicBlock *> successors();
+
+ ArrayRef<BasicBlock *> successors() const {
+ return const_cast<Terminator*>(this)->successors();
+ }
+};
+
+/// Jump to another basic block.
+/// A goto instruction is essentially a tail-recursive call into another
+/// block. In addition to the block pointer, it specifies an index into the
+/// phi nodes of that block. The index can be used to retrieve the "arguments"
+/// of the call.
+class Goto : public Terminator {
+public:
+ Goto(BasicBlock *B, unsigned I)
+ : Terminator(COP_Goto), TargetBlock(B), Index(I) {}
+ Goto(const Goto &G, BasicBlock *B, unsigned I)
+ : Terminator(COP_Goto), TargetBlock(B), Index(I) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Goto; }
+
+ const BasicBlock *targetBlock() const { return TargetBlock; }
+ BasicBlock *targetBlock() { return TargetBlock; }
+
+ /// Returns the index into the
+ unsigned index() const { return Index; }
+
+ /// Return the list of basic blocks that this terminator can branch to.
+ ArrayRef<BasicBlock *> successors() { return TargetBlock; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ BasicBlock *Ntb = Vs.reduceBasicBlockRef(TargetBlock);
+ return Vs.reduceGoto(*this, Ntb);
+ }
+
+ template <class C>
+ typename C::CType compare(const Goto *E, C &Cmp) const {
+ // TODO: implement CFG comparisons
+ return Cmp.comparePointers(this, E);
+ }
+
+private:
+ BasicBlock *TargetBlock;
+ unsigned Index;
+};
+
+/// A conditional branch to two other blocks.
+/// Note that unlike Goto, Branch does not have an index. The target blocks
+/// must be child-blocks, and cannot have Phi nodes.
+class Branch : public Terminator {
+public:
+ Branch(SExpr *C, BasicBlock *T, BasicBlock *E)
+ : Terminator(COP_Branch), Condition(C) {
+ Branches[0] = T;
+ Branches[1] = E;
+ }
+
+ Branch(const Branch &Br, SExpr *C, BasicBlock *T, BasicBlock *E)
+ : Terminator(Br), Condition(C) {
+ Branches[0] = T;
+ Branches[1] = E;
+ }
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Branch; }
+
+ const SExpr *condition() const { return Condition; }
+ SExpr *condition() { return Condition; }
+
+ const BasicBlock *thenBlock() const { return Branches[0]; }
+ BasicBlock *thenBlock() { return Branches[0]; }
+
+ const BasicBlock *elseBlock() const { return Branches[1]; }
+ BasicBlock *elseBlock() { return Branches[1]; }
+
+ /// Return the list of basic blocks that this terminator can branch to.
+ ArrayRef<BasicBlock*> successors() {
+ return llvm::makeArrayRef(Branches);
+ }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Nc = Vs.traverse(Condition, Vs.subExprCtx(Ctx));
+ BasicBlock *Ntb = Vs.reduceBasicBlockRef(Branches[0]);
+ BasicBlock *Nte = Vs.reduceBasicBlockRef(Branches[1]);
+ return Vs.reduceBranch(*this, Nc, Ntb, Nte);
+ }
+
+ template <class C>
+ typename C::CType compare(const Branch *E, C &Cmp) const {
+ // TODO: implement CFG comparisons
+ return Cmp.comparePointers(this, E);
+ }
+
+private:
+ SExpr *Condition;
+ BasicBlock *Branches[2];
+};
+
+/// Return from the enclosing function, passing the return value to the caller.
+/// Only the exit block should end with a return statement.
+class Return : public Terminator {
+public:
+ Return(SExpr* Rval) : Terminator(COP_Return), Retval(Rval) {}
+ Return(const Return &R, SExpr* Rval) : Terminator(R), Retval(Rval) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Return; }
+
+ /// Return an empty list.
+ ArrayRef<BasicBlock *> successors() { return None; }
+
+ SExpr *returnValue() { return Retval; }
+ const SExpr *returnValue() const { return Retval; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Ne = Vs.traverse(Retval, Vs.subExprCtx(Ctx));
+ return Vs.reduceReturn(*this, Ne);
+ }
+
+ template <class C>
+ typename C::CType compare(const Return *E, C &Cmp) const {
+ return Cmp.compare(Retval, E->Retval);
+ }
+
+private:
+ SExpr* Retval;
+};
+
+inline ArrayRef<BasicBlock*> Terminator::successors() {
+ switch (opcode()) {
+ case COP_Goto: return cast<Goto>(this)->successors();
+ case COP_Branch: return cast<Branch>(this)->successors();
+ case COP_Return: return cast<Return>(this)->successors();
+ default:
+ return None;
+ }
+}
+
+/// A basic block is part of an SCFG. It can be treated as a function in
+/// continuation passing style. A block consists of a sequence of phi nodes,
+/// which are "arguments" to the function, followed by a sequence of
+/// instructions. It ends with a Terminator, which is a Branch or Goto to
+/// another basic block in the same SCFG.
+class BasicBlock : public SExpr {
+public:
+ using InstrArray = SimpleArray<SExpr *>;
+ using BlockArray = SimpleArray<BasicBlock *>;
+
+ // TopologyNodes are used to overlay tree structures on top of the CFG,
+ // such as dominator and postdominator trees. Each block is assigned an
+ // ID in the tree according to a depth-first search. Tree traversals are
+ // always up, towards the parents.
+ struct TopologyNode {
+ int NodeID = 0;
+
+ // Includes this node, so must be > 1.
+ int SizeOfSubTree = 0;
+
+ // Pointer to parent.
+ BasicBlock *Parent = nullptr;
+
+ TopologyNode() = default;
+
+ bool isParentOf(const TopologyNode& OtherNode) {
+ return OtherNode.NodeID > NodeID &&
+ OtherNode.NodeID < NodeID + SizeOfSubTree;
+ }
+
+ bool isParentOfOrEqual(const TopologyNode& OtherNode) {
+ return OtherNode.NodeID >= NodeID &&
+ OtherNode.NodeID < NodeID + SizeOfSubTree;
+ }
+ };
+
+ explicit BasicBlock(MemRegionRef A)
+ : SExpr(COP_BasicBlock), Arena(A), BlockID(0), Visited(false) {}
+ BasicBlock(BasicBlock &B, MemRegionRef A, InstrArray &&As, InstrArray &&Is,
+ Terminator *T)
+ : SExpr(COP_BasicBlock), Arena(A), BlockID(0), Visited(false),
+ Args(std::move(As)), Instrs(std::move(Is)), TermInstr(T) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_BasicBlock; }
+
+ /// Returns the block ID. Every block has a unique ID in the CFG.
+ int blockID() const { return BlockID; }
+
+ /// Returns the number of predecessors.
+ size_t numPredecessors() const { return Predecessors.size(); }
+ size_t numSuccessors() const { return successors().size(); }
+
+ const SCFG* cfg() const { return CFGPtr; }
+ SCFG* cfg() { return CFGPtr; }
+
+ const BasicBlock *parent() const { return DominatorNode.Parent; }
+ BasicBlock *parent() { return DominatorNode.Parent; }
+
+ const InstrArray &arguments() const { return Args; }
+ InstrArray &arguments() { return Args; }
+
+ InstrArray &instructions() { return Instrs; }
+ const InstrArray &instructions() const { return Instrs; }
+
+ /// Returns a list of predecessors.
+ /// The order of predecessors in the list is important; each phi node has
+ /// exactly one argument for each precessor, in the same order.
+ BlockArray &predecessors() { return Predecessors; }
+ const BlockArray &predecessors() const { return Predecessors; }
+
+ ArrayRef<BasicBlock*> successors() { return TermInstr->successors(); }
+ ArrayRef<BasicBlock*> successors() const { return TermInstr->successors(); }
+
+ const Terminator *terminator() const { return TermInstr; }
+ Terminator *terminator() { return TermInstr; }
+
+ void setTerminator(Terminator *E) { TermInstr = E; }
+
+ bool Dominates(const BasicBlock &Other) {
+ return DominatorNode.isParentOfOrEqual(Other.DominatorNode);
+ }
+
+ bool PostDominates(const BasicBlock &Other) {
+ return PostDominatorNode.isParentOfOrEqual(Other.PostDominatorNode);
+ }
+
+ /// Add a new argument.
+ void addArgument(Phi *V) {
+ Args.reserveCheck(1, Arena);
+ Args.push_back(V);
+ }
+
+ /// Add a new instruction.
+ void addInstruction(SExpr *V) {
+ Instrs.reserveCheck(1, Arena);
+ Instrs.push_back(V);
+ }
+
+ // Add a new predecessor, and return the phi-node index for it.
+ // Will add an argument to all phi-nodes, initialized to nullptr.
+ unsigned addPredecessor(BasicBlock *Pred);
+
+ // Reserve space for Nargs arguments.
+ void reserveArguments(unsigned Nargs) { Args.reserve(Nargs, Arena); }
+
+ // Reserve space for Nins instructions.
+ void reserveInstructions(unsigned Nins) { Instrs.reserve(Nins, Arena); }
+
+ // Reserve space for NumPreds predecessors, including space in phi nodes.
+ void reservePredecessors(unsigned NumPreds);
+
+ /// Return the index of BB, or Predecessors.size if BB is not a predecessor.
+ unsigned findPredecessorIndex(const BasicBlock *BB) const {
+ auto I = std::find(Predecessors.cbegin(), Predecessors.cend(), BB);
+ return std::distance(Predecessors.cbegin(), I);
+ }
+
+ template <class V>
+ typename V::R_BasicBlock traverse(V &Vs, typename V::R_Ctx Ctx) {
+ typename V::template Container<SExpr*> Nas(Vs, Args.size());
+ typename V::template Container<SExpr*> Nis(Vs, Instrs.size());
+
+ // Entering the basic block should do any scope initialization.
+ Vs.enterBasicBlock(*this);
+
+ for (const auto *E : Args) {
+ auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx));
+ Nas.push_back(Ne);
+ }
+ for (const auto *E : Instrs) {
+ auto Ne = Vs.traverse(E, Vs.subExprCtx(Ctx));
+ Nis.push_back(Ne);
+ }
+ auto Nt = Vs.traverse(TermInstr, Ctx);
+
+ // Exiting the basic block should handle any scope cleanup.
+ Vs.exitBasicBlock(*this);
+
+ return Vs.reduceBasicBlock(*this, Nas, Nis, Nt);
+ }
+
+ template <class C>
+ typename C::CType compare(const BasicBlock *E, C &Cmp) const {
+ // TODO: implement CFG comparisons
+ return Cmp.comparePointers(this, E);
+ }
+
+private:
+ friend class SCFG;
+
+ // assign unique ids to all instructions
+ unsigned renumberInstrs(unsigned id);
+
+ unsigned topologicalSort(SimpleArray<BasicBlock *> &Blocks, unsigned ID);
+ unsigned topologicalFinalSort(SimpleArray<BasicBlock *> &Blocks, unsigned ID);
+ void computeDominator();
+ void computePostDominator();
+
+ // The arena used to allocate this block.
+ MemRegionRef Arena;
+
+ // The CFG that contains this block.
+ SCFG *CFGPtr = nullptr;
+
+ // Unique ID for this BB in the containing CFG. IDs are in topological order.
+ unsigned BlockID : 31;
+
+ // Bit to determine if a block has been visited during a traversal.
+ bool Visited : 1;
+
+ // Predecessor blocks in the CFG.
+ BlockArray Predecessors;
+
+ // Phi nodes. One argument per predecessor.
+ InstrArray Args;
+
+ // Instructions.
+ InstrArray Instrs;
+
+ // Terminating instruction.
+ Terminator *TermInstr = nullptr;
+
+ // The dominator tree.
+ TopologyNode DominatorNode;
+
+ // The post-dominator tree.
+ TopologyNode PostDominatorNode;
+};
+
+/// An SCFG is a control-flow graph. It consists of a set of basic blocks,
+/// each of which terminates in a branch to another basic block. There is one
+/// entry point, and one exit point.
+class SCFG : public SExpr {
+public:
+ using BlockArray = SimpleArray<BasicBlock *>;
+ using iterator = BlockArray::iterator;
+ using const_iterator = BlockArray::const_iterator;
+
+ SCFG(MemRegionRef A, unsigned Nblocks)
+ : SExpr(COP_SCFG), Arena(A), Blocks(A, Nblocks) {
+ Entry = new (A) BasicBlock(A);
+ Exit = new (A) BasicBlock(A);
+ auto *V = new (A) Phi();
+ Exit->addArgument(V);
+ Exit->setTerminator(new (A) Return(V));
+ add(Entry);
+ add(Exit);
+ }
+
+ SCFG(const SCFG &Cfg, BlockArray &&Ba) // steals memory from Ba
+ : SExpr(COP_SCFG), Arena(Cfg.Arena), Blocks(std::move(Ba)) {
+ // TODO: set entry and exit!
+ }
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_SCFG; }
+
+ /// Return true if this CFG is valid.
+ bool valid() const { return Entry && Exit && Blocks.size() > 0; }
+
+ /// Return true if this CFG has been normalized.
+ /// After normalization, blocks are in topological order, and block and
+ /// instruction IDs have been assigned.
+ bool normal() const { return Normal; }
+
+ iterator begin() { return Blocks.begin(); }
+ iterator end() { return Blocks.end(); }
+
+ const_iterator begin() const { return cbegin(); }
+ const_iterator end() const { return cend(); }
+
+ const_iterator cbegin() const { return Blocks.cbegin(); }
+ const_iterator cend() const { return Blocks.cend(); }
+
+ const BasicBlock *entry() const { return Entry; }
+ BasicBlock *entry() { return Entry; }
+ const BasicBlock *exit() const { return Exit; }
+ BasicBlock *exit() { return Exit; }
+
+ /// Return the number of blocks in the CFG.
+ /// Block::blockID() will return a number less than numBlocks();
+ size_t numBlocks() const { return Blocks.size(); }
+
+ /// Return the total number of instructions in the CFG.
+ /// This is useful for building instruction side-tables;
+ /// A call to SExpr::id() will return a number less than numInstructions().
+ unsigned numInstructions() { return NumInstructions; }
+
+ inline void add(BasicBlock *BB) {
+ assert(BB->CFGPtr == nullptr);
+ BB->CFGPtr = this;
+ Blocks.reserveCheck(1, Arena);
+ Blocks.push_back(BB);
+ }
+
+ void setEntry(BasicBlock *BB) { Entry = BB; }
+ void setExit(BasicBlock *BB) { Exit = BB; }
+
+ void computeNormalForm();
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ Vs.enterCFG(*this);
+ typename V::template Container<BasicBlock *> Bbs(Vs, Blocks.size());
+
+ for (const auto *B : Blocks) {
+ Bbs.push_back( B->traverse(Vs, Vs.subExprCtx(Ctx)) );
+ }
+ Vs.exitCFG(*this);
+ return Vs.reduceSCFG(*this, Bbs);
+ }
+
+ template <class C>
+ typename C::CType compare(const SCFG *E, C &Cmp) const {
+ // TODO: implement CFG comparisons
+ return Cmp.comparePointers(this, E);
+ }
+
+private:
+ // assign unique ids to all instructions
+ void renumberInstrs();
+
+ MemRegionRef Arena;
+ BlockArray Blocks;
+ BasicBlock *Entry = nullptr;
+ BasicBlock *Exit = nullptr;
+ unsigned NumInstructions = 0;
+ bool Normal = false;
+};
+
+/// An identifier, e.g. 'foo' or 'x'.
+/// This is a pseduo-term; it will be lowered to a variable or projection.
+class Identifier : public SExpr {
+public:
+ Identifier(StringRef Id): SExpr(COP_Identifier), Name(Id) {}
+ Identifier(const Identifier &) = default;
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Identifier; }
+
+ StringRef name() const { return Name; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ return Vs.reduceIdentifier(*this);
+ }
+
+ template <class C>
+ typename C::CType compare(const Identifier* E, C& Cmp) const {
+ return Cmp.compareStrings(name(), E->name());
+ }
+
+private:
+ StringRef Name;
+};
+
+/// An if-then-else expression.
+/// This is a pseduo-term; it will be lowered to a branch in a CFG.
+class IfThenElse : public SExpr {
+public:
+ IfThenElse(SExpr *C, SExpr *T, SExpr *E)
+ : SExpr(COP_IfThenElse), Condition(C), ThenExpr(T), ElseExpr(E) {}
+ IfThenElse(const IfThenElse &I, SExpr *C, SExpr *T, SExpr *E)
+ : SExpr(I), Condition(C), ThenExpr(T), ElseExpr(E) {}
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_IfThenElse; }
+
+ SExpr *condition() { return Condition; } // Address to store to
+ const SExpr *condition() const { return Condition; }
+
+ SExpr *thenExpr() { return ThenExpr; } // Value to store
+ const SExpr *thenExpr() const { return ThenExpr; }
+
+ SExpr *elseExpr() { return ElseExpr; } // Value to store
+ const SExpr *elseExpr() const { return ElseExpr; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ auto Nc = Vs.traverse(Condition, Vs.subExprCtx(Ctx));
+ auto Nt = Vs.traverse(ThenExpr, Vs.subExprCtx(Ctx));
+ auto Ne = Vs.traverse(ElseExpr, Vs.subExprCtx(Ctx));
+ return Vs.reduceIfThenElse(*this, Nc, Nt, Ne);
+ }
+
+ template <class C>
+ typename C::CType compare(const IfThenElse* E, C& Cmp) const {
+ typename C::CType Ct = Cmp.compare(condition(), E->condition());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ Ct = Cmp.compare(thenExpr(), E->thenExpr());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(elseExpr(), E->elseExpr());
+ }
+
+private:
+ SExpr* Condition;
+ SExpr* ThenExpr;
+ SExpr* ElseExpr;
+};
+
+/// A let-expression, e.g. let x=t; u.
+/// This is a pseduo-term; it will be lowered to instructions in a CFG.
+class Let : public SExpr {
+public:
+ Let(Variable *Vd, SExpr *Bd) : SExpr(COP_Let), VarDecl(Vd), Body(Bd) {
+ Vd->setKind(Variable::VK_Let);
+ }
+
+ Let(const Let &L, Variable *Vd, SExpr *Bd) : SExpr(L), VarDecl(Vd), Body(Bd) {
+ Vd->setKind(Variable::VK_Let);
+ }
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Let; }
+
+ Variable *variableDecl() { return VarDecl; }
+ const Variable *variableDecl() const { return VarDecl; }
+
+ SExpr *body() { return Body; }
+ const SExpr *body() const { return Body; }
+
+ template <class V>
+ typename V::R_SExpr traverse(V &Vs, typename V::R_Ctx Ctx) {
+ // This is a variable declaration, so traverse the definition.
+ auto E0 = Vs.traverse(VarDecl->Definition, Vs.subExprCtx(Ctx));
+ // Tell the rewriter to enter the scope of the let variable.
+ Variable *Nvd = Vs.enterScope(*VarDecl, E0);
+ auto E1 = Vs.traverse(Body, Ctx);
+ Vs.exitScope(*VarDecl);
+ return Vs.reduceLet(*this, Nvd, E1);
+ }
+
+ template <class C>
+ typename C::CType compare(const Let* E, C& Cmp) const {
+ typename C::CType Ct =
+ Cmp.compare(VarDecl->definition(), E->VarDecl->definition());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ Cmp.enterScope(variableDecl(), E->variableDecl());
+ Ct = Cmp.compare(body(), E->body());
+ Cmp.leaveScope();
+ return Ct;
+ }
+
+private:
+ Variable *VarDecl;
+ SExpr* Body;
+};
+
+const SExpr *getCanonicalVal(const SExpr *E);
+SExpr* simplifyToCanonicalVal(SExpr *E);
+void simplifyIncompleteArg(til::Phi *Ph);
+
+} // namespace til
+} // namespace threadSafety
+
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTIL_H
diff --git a/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h b/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
new file mode 100644
index 00000000..e81c00d3
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
@@ -0,0 +1,931 @@
+//===- ThreadSafetyTraverse.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a framework for doing generic traversals and rewriting
+// operations over the Thread Safety TIL.
+//
+// UNDER CONSTRUCTION. USE AT YOUR OWN RISK.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H
+
+#include "clang/AST/Decl.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include <cstdint>
+#include <ostream>
+
+namespace clang {
+namespace threadSafety {
+namespace til {
+
+// Defines an interface used to traverse SExprs. Traversals have been made as
+// generic as possible, and are intended to handle any kind of pass over the
+// AST, e.g. visitors, copying, non-destructive rewriting, destructive
+// (in-place) rewriting, hashing, typing, etc.
+//
+// Traversals implement the functional notion of a "fold" operation on SExprs.
+// Each SExpr class provides a traverse method, which does the following:
+// * e->traverse(v):
+// // compute a result r_i for each subexpression e_i
+// for (i = 1..n) r_i = v.traverse(e_i);
+// // combine results into a result for e, where X is the class of e
+// return v.reduceX(*e, r_1, .. r_n).
+//
+// A visitor can control the traversal by overriding the following methods:
+// * v.traverse(e):
+// return v.traverseByCase(e), which returns v.traverseX(e)
+// * v.traverseX(e): (X is the class of e)
+// return e->traverse(v).
+// * v.reduceX(*e, r_1, .. r_n):
+// compute a result for a node of type X
+//
+// The reduceX methods control the kind of traversal (visitor, copy, etc.).
+// They are defined in derived classes.
+//
+// Class R defines the basic interface types (R_SExpr).
+template <class Self, class R>
+class Traversal {
+public:
+ Self *self() { return static_cast<Self *>(this); }
+
+ // Traverse an expression -- returning a result of type R_SExpr.
+ // Override this method to do something for every expression, regardless
+ // of which kind it is.
+ // E is a reference, so this can be use for in-place updates.
+ // The type T must be a subclass of SExpr.
+ template <class T>
+ typename R::R_SExpr traverse(T* &E, typename R::R_Ctx Ctx) {
+ return traverseSExpr(E, Ctx);
+ }
+
+ // Override this method to do something for every expression.
+ // Does not allow in-place updates.
+ typename R::R_SExpr traverseSExpr(SExpr *E, typename R::R_Ctx Ctx) {
+ return traverseByCase(E, Ctx);
+ }
+
+ // Helper method to call traverseX(e) on the appropriate type.
+ typename R::R_SExpr traverseByCase(SExpr *E, typename R::R_Ctx Ctx) {
+ switch (E->opcode()) {
+#define TIL_OPCODE_DEF(X) \
+ case COP_##X: \
+ return self()->traverse##X(cast<X>(E), Ctx);
+#include "ThreadSafetyOps.def"
+#undef TIL_OPCODE_DEF
+ }
+ return self()->reduceNull();
+ }
+
+// Traverse e, by static dispatch on the type "X" of e.
+// Override these methods to do something for a particular kind of term.
+#define TIL_OPCODE_DEF(X) \
+ typename R::R_SExpr traverse##X(X *e, typename R::R_Ctx Ctx) { \
+ return e->traverse(*self(), Ctx); \
+ }
+#include "ThreadSafetyOps.def"
+#undef TIL_OPCODE_DEF
+};
+
+// Base class for simple reducers that don't much care about the context.
+class SimpleReducerBase {
+public:
+ enum TraversalKind {
+ // Ordinary subexpressions.
+ TRV_Normal,
+
+ // Declarations (e.g. function bodies).
+ TRV_Decl,
+
+ // Expressions that require lazy evaluation.
+ TRV_Lazy,
+
+ // Type expressions.
+ TRV_Type
+ };
+
+ // R_Ctx defines a "context" for the traversal, which encodes information
+ // about where a term appears. This can be used to encoding the
+ // "current continuation" for CPS transforms, or other information.
+ using R_Ctx = TraversalKind;
+
+ // Create context for an ordinary subexpression.
+ R_Ctx subExprCtx(R_Ctx Ctx) { return TRV_Normal; }
+
+ // Create context for a subexpression that occurs in a declaration position
+ // (e.g. function body).
+ R_Ctx declCtx(R_Ctx Ctx) { return TRV_Decl; }
+
+ // Create context for a subexpression that occurs in a position that
+ // should be reduced lazily. (e.g. code body).
+ R_Ctx lazyCtx(R_Ctx Ctx) { return TRV_Lazy; }
+
+ // Create context for a subexpression that occurs in a type position.
+ R_Ctx typeCtx(R_Ctx Ctx) { return TRV_Type; }
+};
+
+// Base class for traversals that rewrite an SExpr to another SExpr.
+class CopyReducerBase : public SimpleReducerBase {
+public:
+ // R_SExpr is the result type for a traversal.
+ // A copy or non-destructive rewrite returns a newly allocated term.
+ using R_SExpr = SExpr *;
+ using R_BasicBlock = BasicBlock *;
+
+ // Container is a minimal interface used to store results when traversing
+ // SExprs of variable arity, such as Phi, Goto, and SCFG.
+ template <class T> class Container {
+ public:
+ // Allocate a new container with a capacity for n elements.
+ Container(CopyReducerBase &S, unsigned N) : Elems(S.Arena, N) {}
+
+ // Push a new element onto the container.
+ void push_back(T E) { Elems.push_back(E); }
+
+ SimpleArray<T> Elems;
+ };
+
+ CopyReducerBase(MemRegionRef A) : Arena(A) {}
+
+protected:
+ MemRegionRef Arena;
+};
+
+// Base class for visit traversals.
+class VisitReducerBase : public SimpleReducerBase {
+public:
+ // A visitor returns a bool, representing success or failure.
+ using R_SExpr = bool;
+ using R_BasicBlock = bool;
+
+ // A visitor "container" is a single bool, which accumulates success.
+ template <class T> class Container {
+ public:
+ bool Success = true;
+
+ Container(VisitReducerBase &S, unsigned N) {}
+
+ void push_back(bool E) { Success = Success && E; }
+ };
+};
+
+// Implements a traversal that visits each subexpression, and returns either
+// true or false.
+template <class Self>
+class VisitReducer : public Traversal<Self, VisitReducerBase>,
+ public VisitReducerBase {
+public:
+ VisitReducer() = default;
+
+public:
+ R_SExpr reduceNull() { return true; }
+ R_SExpr reduceUndefined(Undefined &Orig) { return true; }
+ R_SExpr reduceWildcard(Wildcard &Orig) { return true; }
+
+ R_SExpr reduceLiteral(Literal &Orig) { return true; }
+ template<class T>
+ R_SExpr reduceLiteralT(LiteralT<T> &Orig) { return true; }
+ R_SExpr reduceLiteralPtr(Literal &Orig) { return true; }
+
+ R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0) {
+ return Nvd && E0;
+ }
+
+ R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0) {
+ return Nvd && E0;
+ }
+
+ R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) {
+ return E0 && E1;
+ }
+
+ R_SExpr reduceField(Field &Orig, R_SExpr E0, R_SExpr E1) {
+ return E0 && E1;
+ }
+
+ R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) {
+ return E0 && E1;
+ }
+
+ R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1) {
+ return E0 && E1;
+ }
+
+ R_SExpr reduceProject(Project &Orig, R_SExpr E0) { return E0; }
+ R_SExpr reduceCall(Call &Orig, R_SExpr E0) { return E0; }
+ R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) { return E0; }
+ R_SExpr reduceLoad(Load &Orig, R_SExpr E0) { return E0; }
+ R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) { return E0 && E1; }
+
+ R_SExpr reduceArrayIndex(Store &Orig, R_SExpr E0, R_SExpr E1) {
+ return E0 && E1;
+ }
+
+ R_SExpr reduceArrayAdd(Store &Orig, R_SExpr E0, R_SExpr E1) {
+ return E0 && E1;
+ }
+
+ R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) { return E0; }
+
+ R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) {
+ return E0 && E1;
+ }
+
+ R_SExpr reduceCast(Cast &Orig, R_SExpr E0) { return E0; }
+
+ R_SExpr reduceSCFG(SCFG &Orig, Container<BasicBlock *> Bbs) {
+ return Bbs.Success;
+ }
+
+ R_BasicBlock reduceBasicBlock(BasicBlock &Orig, Container<R_SExpr> &As,
+ Container<R_SExpr> &Is, R_SExpr T) {
+ return (As.Success && Is.Success && T);
+ }
+
+ R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &As) {
+ return As.Success;
+ }
+
+ R_SExpr reduceGoto(Goto &Orig, BasicBlock *B) {
+ return true;
+ }
+
+ R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) {
+ return C;
+ }
+
+ R_SExpr reduceReturn(Return &O, R_SExpr E) {
+ return E;
+ }
+
+ R_SExpr reduceIdentifier(Identifier &Orig) {
+ return true;
+ }
+
+ R_SExpr reduceIfThenElse(IfThenElse &Orig, R_SExpr C, R_SExpr T, R_SExpr E) {
+ return C && T && E;
+ }
+
+ R_SExpr reduceLet(Let &Orig, Variable *Nvd, R_SExpr B) {
+ return Nvd && B;
+ }
+
+ Variable *enterScope(Variable &Orig, R_SExpr E0) { return &Orig; }
+ void exitScope(const Variable &Orig) {}
+ void enterCFG(SCFG &Cfg) {}
+ void exitCFG(SCFG &Cfg) {}
+ void enterBasicBlock(BasicBlock &BB) {}
+ void exitBasicBlock(BasicBlock &BB) {}
+
+ Variable *reduceVariableRef(Variable *Ovd) { return Ovd; }
+ BasicBlock *reduceBasicBlockRef(BasicBlock *Obb) { return Obb; }
+
+public:
+ bool traverse(SExpr *E, TraversalKind K = TRV_Normal) {
+ Success = Success && this->traverseByCase(E);
+ return Success;
+ }
+
+ static bool visit(SExpr *E) {
+ Self Visitor;
+ return Visitor.traverse(E, TRV_Normal);
+ }
+
+private:
+ bool Success;
+};
+
+// Basic class for comparison operations over expressions.
+template <typename Self>
+class Comparator {
+protected:
+ Self *self() { return reinterpret_cast<Self *>(this); }
+
+public:
+ bool compareByCase(const SExpr *E1, const SExpr* E2) {
+ switch (E1->opcode()) {
+#define TIL_OPCODE_DEF(X) \
+ case COP_##X: \
+ return cast<X>(E1)->compare(cast<X>(E2), *self());
+#include "ThreadSafetyOps.def"
+#undef TIL_OPCODE_DEF
+ }
+ return false;
+ }
+};
+
+class EqualsComparator : public Comparator<EqualsComparator> {
+public:
+ // Result type for the comparison, e.g. bool for simple equality,
+ // or int for lexigraphic comparison (-1, 0, 1). Must have one value which
+ // denotes "true".
+ using CType = bool;
+
+ CType trueResult() { return true; }
+ bool notTrue(CType ct) { return !ct; }
+
+ bool compareIntegers(unsigned i, unsigned j) { return i == j; }
+ bool compareStrings (StringRef s, StringRef r) { return s == r; }
+ bool comparePointers(const void* P, const void* Q) { return P == Q; }
+
+ bool compare(const SExpr *E1, const SExpr* E2) {
+ if (E1->opcode() != E2->opcode())
+ return false;
+ return compareByCase(E1, E2);
+ }
+
+ // TODO -- handle alpha-renaming of variables
+ void enterScope(const Variable *V1, const Variable *V2) {}
+ void leaveScope() {}
+
+ bool compareVariableRefs(const Variable *V1, const Variable *V2) {
+ return V1 == V2;
+ }
+
+ static bool compareExprs(const SExpr *E1, const SExpr* E2) {
+ EqualsComparator Eq;
+ return Eq.compare(E1, E2);
+ }
+};
+
+class MatchComparator : public Comparator<MatchComparator> {
+public:
+ // Result type for the comparison, e.g. bool for simple equality,
+ // or int for lexigraphic comparison (-1, 0, 1). Must have one value which
+ // denotes "true".
+ using CType = bool;
+
+ CType trueResult() { return true; }
+ bool notTrue(CType ct) { return !ct; }
+
+ bool compareIntegers(unsigned i, unsigned j) { return i == j; }
+ bool compareStrings (StringRef s, StringRef r) { return s == r; }
+ bool comparePointers(const void *P, const void *Q) { return P == Q; }
+
+ bool compare(const SExpr *E1, const SExpr *E2) {
+ // Wildcards match anything.
+ if (E1->opcode() == COP_Wildcard || E2->opcode() == COP_Wildcard)
+ return true;
+ // otherwise normal equality.
+ if (E1->opcode() != E2->opcode())
+ return false;
+ return compareByCase(E1, E2);
+ }
+
+ // TODO -- handle alpha-renaming of variables
+ void enterScope(const Variable* V1, const Variable* V2) {}
+ void leaveScope() {}
+
+ bool compareVariableRefs(const Variable* V1, const Variable* V2) {
+ return V1 == V2;
+ }
+
+ static bool compareExprs(const SExpr *E1, const SExpr* E2) {
+ MatchComparator Matcher;
+ return Matcher.compare(E1, E2);
+ }
+};
+
+// inline std::ostream& operator<<(std::ostream& SS, StringRef R) {
+// return SS.write(R.data(), R.size());
+// }
+
+// Pretty printer for TIL expressions
+template <typename Self, typename StreamType>
+class PrettyPrinter {
+private:
+ // Print out additional information.
+ bool Verbose;
+
+ // Omit redundant decls.
+ bool Cleanup;
+
+ // Print exprs in C-like syntax.
+ bool CStyle;
+
+public:
+ PrettyPrinter(bool V = false, bool C = true, bool CS = true)
+ : Verbose(V), Cleanup(C), CStyle(CS) {}
+
+ static void print(const SExpr *E, StreamType &SS) {
+ Self printer;
+ printer.printSExpr(E, SS, Prec_MAX);
+ }
+
+protected:
+ Self *self() { return reinterpret_cast<Self *>(this); }
+
+ void newline(StreamType &SS) {
+ SS << "\n";
+ }
+
+ // TODO: further distinguish between binary operations.
+ static const unsigned Prec_Atom = 0;
+ static const unsigned Prec_Postfix = 1;
+ static const unsigned Prec_Unary = 2;
+ static const unsigned Prec_Binary = 3;
+ static const unsigned Prec_Other = 4;
+ static const unsigned Prec_Decl = 5;
+ static const unsigned Prec_MAX = 6;
+
+ // Return the precedence of a given node, for use in pretty printing.
+ unsigned precedence(const SExpr *E) {
+ switch (E->opcode()) {
+ case COP_Future: return Prec_Atom;
+ case COP_Undefined: return Prec_Atom;
+ case COP_Wildcard: return Prec_Atom;
+
+ case COP_Literal: return Prec_Atom;
+ case COP_LiteralPtr: return Prec_Atom;
+ case COP_Variable: return Prec_Atom;
+ case COP_Function: return Prec_Decl;
+ case COP_SFunction: return Prec_Decl;
+ case COP_Code: return Prec_Decl;
+ case COP_Field: return Prec_Decl;
+
+ case COP_Apply: return Prec_Postfix;
+ case COP_SApply: return Prec_Postfix;
+ case COP_Project: return Prec_Postfix;
+
+ case COP_Call: return Prec_Postfix;
+ case COP_Alloc: return Prec_Other;
+ case COP_Load: return Prec_Postfix;
+ case COP_Store: return Prec_Other;
+ case COP_ArrayIndex: return Prec_Postfix;
+ case COP_ArrayAdd: return Prec_Postfix;
+
+ case COP_UnaryOp: return Prec_Unary;
+ case COP_BinaryOp: return Prec_Binary;
+ case COP_Cast: return Prec_Atom;
+
+ case COP_SCFG: return Prec_Decl;
+ case COP_BasicBlock: return Prec_MAX;
+ case COP_Phi: return Prec_Atom;
+ case COP_Goto: return Prec_Atom;
+ case COP_Branch: return Prec_Atom;
+ case COP_Return: return Prec_Other;
+
+ case COP_Identifier: return Prec_Atom;
+ case COP_IfThenElse: return Prec_Other;
+ case COP_Let: return Prec_Decl;
+ }
+ return Prec_MAX;
+ }
+
+ void printBlockLabel(StreamType & SS, const BasicBlock *BB, int index) {
+ if (!BB) {
+ SS << "BB_null";
+ return;
+ }
+ SS << "BB_";
+ SS << BB->blockID();
+ if (index >= 0) {
+ SS << ":";
+ SS << index;
+ }
+ }
+
+ void printSExpr(const SExpr *E, StreamType &SS, unsigned P, bool Sub=true) {
+ if (!E) {
+ self()->printNull(SS);
+ return;
+ }
+ if (Sub && E->block() && E->opcode() != COP_Variable) {
+ SS << "_x" << E->id();
+ return;
+ }
+ if (self()->precedence(E) > P) {
+ // Wrap expr in () if necessary.
+ SS << "(";
+ self()->printSExpr(E, SS, Prec_MAX);
+ SS << ")";
+ return;
+ }
+
+ switch (E->opcode()) {
+#define TIL_OPCODE_DEF(X) \
+ case COP_##X: \
+ self()->print##X(cast<X>(E), SS); \
+ return;
+#include "ThreadSafetyOps.def"
+#undef TIL_OPCODE_DEF
+ }
+ }
+
+ void printNull(StreamType &SS) {
+ SS << "#null";
+ }
+
+ void printFuture(const Future *E, StreamType &SS) {
+ self()->printSExpr(E->maybeGetResult(), SS, Prec_Atom);
+ }
+
+ void printUndefined(const Undefined *E, StreamType &SS) {
+ SS << "#undefined";
+ }
+
+ void printWildcard(const Wildcard *E, StreamType &SS) {
+ SS << "*";
+ }
+
+ template<class T>
+ void printLiteralT(const LiteralT<T> *E, StreamType &SS) {
+ SS << E->value();
+ }
+
+ void printLiteralT(const LiteralT<uint8_t> *E, StreamType &SS) {
+ SS << "'" << E->value() << "'";
+ }
+
+ void printLiteral(const Literal *E, StreamType &SS) {
+ if (E->clangExpr()) {
+ SS << getSourceLiteralString(E->clangExpr());
+ return;
+ }
+ else {
+ ValueType VT = E->valueType();
+ switch (VT.Base) {
+ case ValueType::BT_Void:
+ SS << "void";
+ return;
+ case ValueType::BT_Bool:
+ if (E->as<bool>().value())
+ SS << "true";
+ else
+ SS << "false";
+ return;
+ case ValueType::BT_Int:
+ switch (VT.Size) {
+ case ValueType::ST_8:
+ if (VT.Signed)
+ printLiteralT(&E->as<int8_t>(), SS);
+ else
+ printLiteralT(&E->as<uint8_t>(), SS);
+ return;
+ case ValueType::ST_16:
+ if (VT.Signed)
+ printLiteralT(&E->as<int16_t>(), SS);
+ else
+ printLiteralT(&E->as<uint16_t>(), SS);
+ return;
+ case ValueType::ST_32:
+ if (VT.Signed)
+ printLiteralT(&E->as<int32_t>(), SS);
+ else
+ printLiteralT(&E->as<uint32_t>(), SS);
+ return;
+ case ValueType::ST_64:
+ if (VT.Signed)
+ printLiteralT(&E->as<int64_t>(), SS);
+ else
+ printLiteralT(&E->as<uint64_t>(), SS);
+ return;
+ default:
+ break;
+ }
+ break;
+ case ValueType::BT_Float:
+ switch (VT.Size) {
+ case ValueType::ST_32:
+ printLiteralT(&E->as<float>(), SS);
+ return;
+ case ValueType::ST_64:
+ printLiteralT(&E->as<double>(), SS);
+ return;
+ default:
+ break;
+ }
+ break;
+ case ValueType::BT_String:
+ SS << "\"";
+ printLiteralT(&E->as<StringRef>(), SS);
+ SS << "\"";
+ return;
+ case ValueType::BT_Pointer:
+ SS << "#ptr";
+ return;
+ case ValueType::BT_ValueRef:
+ SS << "#vref";
+ return;
+ }
+ }
+ SS << "#lit";
+ }
+
+ void printLiteralPtr(const LiteralPtr *E, StreamType &SS) {
+ SS << E->clangDecl()->getNameAsString();
+ }
+
+ void printVariable(const Variable *V, StreamType &SS, bool IsVarDecl=false) {
+ if (CStyle && V->kind() == Variable::VK_SFun)
+ SS << "this";
+ else
+ SS << V->name() << V->id();
+ }
+
+ void printFunction(const Function *E, StreamType &SS, unsigned sugared = 0) {
+ switch (sugared) {
+ default:
+ SS << "\\("; // Lambda
+ break;
+ case 1:
+ SS << "("; // Slot declarations
+ break;
+ case 2:
+ SS << ", "; // Curried functions
+ break;
+ }
+ self()->printVariable(E->variableDecl(), SS, true);
+ SS << ": ";
+ self()->printSExpr(E->variableDecl()->definition(), SS, Prec_MAX);
+
+ const SExpr *B = E->body();
+ if (B && B->opcode() == COP_Function)
+ self()->printFunction(cast<Function>(B), SS, 2);
+ else {
+ SS << ")";
+ self()->printSExpr(B, SS, Prec_Decl);
+ }
+ }
+
+ void printSFunction(const SFunction *E, StreamType &SS) {
+ SS << "@";
+ self()->printVariable(E->variableDecl(), SS, true);
+ SS << " ";
+ self()->printSExpr(E->body(), SS, Prec_Decl);
+ }
+
+ void printCode(const Code *E, StreamType &SS) {
+ SS << ": ";
+ self()->printSExpr(E->returnType(), SS, Prec_Decl-1);
+ SS << " -> ";
+ self()->printSExpr(E->body(), SS, Prec_Decl);
+ }
+
+ void printField(const Field *E, StreamType &SS) {
+ SS << ": ";
+ self()->printSExpr(E->range(), SS, Prec_Decl-1);
+ SS << " = ";
+ self()->printSExpr(E->body(), SS, Prec_Decl);
+ }
+
+ void printApply(const Apply *E, StreamType &SS, bool sugared = false) {
+ const SExpr *F = E->fun();
+ if (F->opcode() == COP_Apply) {
+ printApply(cast<Apply>(F), SS, true);
+ SS << ", ";
+ } else {
+ self()->printSExpr(F, SS, Prec_Postfix);
+ SS << "(";
+ }
+ self()->printSExpr(E->arg(), SS, Prec_MAX);
+ if (!sugared)
+ SS << ")$";
+ }
+
+ void printSApply(const SApply *E, StreamType &SS) {
+ self()->printSExpr(E->sfun(), SS, Prec_Postfix);
+ if (E->isDelegation()) {
+ SS << "@(";
+ self()->printSExpr(E->arg(), SS, Prec_MAX);
+ SS << ")";
+ }
+ }
+
+ void printProject(const Project *E, StreamType &SS) {
+ if (CStyle) {
+ // Omit the this->
+ if (const auto *SAP = dyn_cast<SApply>(E->record())) {
+ if (const auto *V = dyn_cast<Variable>(SAP->sfun())) {
+ if (!SAP->isDelegation() && V->kind() == Variable::VK_SFun) {
+ SS << E->slotName();
+ return;
+ }
+ }
+ }
+ if (isa<Wildcard>(E->record())) {
+ // handle existentials
+ SS << "&";
+ SS << E->clangDecl()->getQualifiedNameAsString();
+ return;
+ }
+ }
+ self()->printSExpr(E->record(), SS, Prec_Postfix);
+ if (CStyle && E->isArrow())
+ SS << "->";
+ else
+ SS << ".";
+ SS << E->slotName();
+ }
+
+ void printCall(const Call *E, StreamType &SS) {
+ const SExpr *T = E->target();
+ if (T->opcode() == COP_Apply) {
+ self()->printApply(cast<Apply>(T), SS, true);
+ SS << ")";
+ }
+ else {
+ self()->printSExpr(T, SS, Prec_Postfix);
+ SS << "()";
+ }
+ }
+
+ void printAlloc(const Alloc *E, StreamType &SS) {
+ SS << "new ";
+ self()->printSExpr(E->dataType(), SS, Prec_Other-1);
+ }
+
+ void printLoad(const Load *E, StreamType &SS) {
+ self()->printSExpr(E->pointer(), SS, Prec_Postfix);
+ if (!CStyle)
+ SS << "^";
+ }
+
+ void printStore(const Store *E, StreamType &SS) {
+ self()->printSExpr(E->destination(), SS, Prec_Other-1);
+ SS << " := ";
+ self()->printSExpr(E->source(), SS, Prec_Other-1);
+ }
+
+ void printArrayIndex(const ArrayIndex *E, StreamType &SS) {
+ self()->printSExpr(E->array(), SS, Prec_Postfix);
+ SS << "[";
+ self()->printSExpr(E->index(), SS, Prec_MAX);
+ SS << "]";
+ }
+
+ void printArrayAdd(const ArrayAdd *E, StreamType &SS) {
+ self()->printSExpr(E->array(), SS, Prec_Postfix);
+ SS << " + ";
+ self()->printSExpr(E->index(), SS, Prec_Atom);
+ }
+
+ void printUnaryOp(const UnaryOp *E, StreamType &SS) {
+ SS << getUnaryOpcodeString(E->unaryOpcode());
+ self()->printSExpr(E->expr(), SS, Prec_Unary);
+ }
+
+ void printBinaryOp(const BinaryOp *E, StreamType &SS) {
+ self()->printSExpr(E->expr0(), SS, Prec_Binary-1);
+ SS << " " << getBinaryOpcodeString(E->binaryOpcode()) << " ";
+ self()->printSExpr(E->expr1(), SS, Prec_Binary-1);
+ }
+
+ void printCast(const Cast *E, StreamType &SS) {
+ if (!CStyle) {
+ SS << "cast[";
+ switch (E->castOpcode()) {
+ case CAST_none:
+ SS << "none";
+ break;
+ case CAST_extendNum:
+ SS << "extendNum";
+ break;
+ case CAST_truncNum:
+ SS << "truncNum";
+ break;
+ case CAST_toFloat:
+ SS << "toFloat";
+ break;
+ case CAST_toInt:
+ SS << "toInt";
+ break;
+ case CAST_objToPtr:
+ SS << "objToPtr";
+ break;
+ }
+ SS << "](";
+ self()->printSExpr(E->expr(), SS, Prec_Unary);
+ SS << ")";
+ return;
+ }
+ self()->printSExpr(E->expr(), SS, Prec_Unary);
+ }
+
+ void printSCFG(const SCFG *E, StreamType &SS) {
+ SS << "CFG {\n";
+ for (const auto *BBI : *E)
+ printBasicBlock(BBI, SS);
+ SS << "}";
+ newline(SS);
+ }
+
+ void printBBInstr(const SExpr *E, StreamType &SS) {
+ bool Sub = false;
+ if (E->opcode() == COP_Variable) {
+ const auto *V = cast<Variable>(E);
+ SS << "let " << V->name() << V->id() << " = ";
+ E = V->definition();
+ Sub = true;
+ }
+ else if (E->opcode() != COP_Store) {
+ SS << "let _x" << E->id() << " = ";
+ }
+ self()->printSExpr(E, SS, Prec_MAX, Sub);
+ SS << ";";
+ newline(SS);
+ }
+
+ void printBasicBlock(const BasicBlock *E, StreamType &SS) {
+ SS << "BB_" << E->blockID() << ":";
+ if (E->parent())
+ SS << " BB_" << E->parent()->blockID();
+ newline(SS);
+
+ for (const auto *A : E->arguments())
+ printBBInstr(A, SS);
+
+ for (const auto *I : E->instructions())
+ printBBInstr(I, SS);
+
+ const SExpr *T = E->terminator();
+ if (T) {
+ self()->printSExpr(T, SS, Prec_MAX, false);
+ SS << ";";
+ newline(SS);
+ }
+ newline(SS);
+ }
+
+ void printPhi(const Phi *E, StreamType &SS) {
+ SS << "phi(";
+ if (E->status() == Phi::PH_SingleVal)
+ self()->printSExpr(E->values()[0], SS, Prec_MAX);
+ else {
+ unsigned i = 0;
+ for (const auto *V : E->values()) {
+ if (i++ > 0)
+ SS << ", ";
+ self()->printSExpr(V, SS, Prec_MAX);
+ }
+ }
+ SS << ")";
+ }
+
+ void printGoto(const Goto *E, StreamType &SS) {
+ SS << "goto ";
+ printBlockLabel(SS, E->targetBlock(), E->index());
+ }
+
+ void printBranch(const Branch *E, StreamType &SS) {
+ SS << "branch (";
+ self()->printSExpr(E->condition(), SS, Prec_MAX);
+ SS << ") ";
+ printBlockLabel(SS, E->thenBlock(), -1);
+ SS << " ";
+ printBlockLabel(SS, E->elseBlock(), -1);
+ }
+
+ void printReturn(const Return *E, StreamType &SS) {
+ SS << "return ";
+ self()->printSExpr(E->returnValue(), SS, Prec_Other);
+ }
+
+ void printIdentifier(const Identifier *E, StreamType &SS) {
+ SS << E->name();
+ }
+
+ void printIfThenElse(const IfThenElse *E, StreamType &SS) {
+ if (CStyle) {
+ printSExpr(E->condition(), SS, Prec_Unary);
+ SS << " ? ";
+ printSExpr(E->thenExpr(), SS, Prec_Unary);
+ SS << " : ";
+ printSExpr(E->elseExpr(), SS, Prec_Unary);
+ return;
+ }
+ SS << "if (";
+ printSExpr(E->condition(), SS, Prec_MAX);
+ SS << ") then ";
+ printSExpr(E->thenExpr(), SS, Prec_Other);
+ SS << " else ";
+ printSExpr(E->elseExpr(), SS, Prec_Other);
+ }
+
+ void printLet(const Let *E, StreamType &SS) {
+ SS << "let ";
+ printVariable(E->variableDecl(), SS, true);
+ SS << " = ";
+ printSExpr(E->variableDecl()->definition(), SS, Prec_Decl-1);
+ SS << "; ";
+ printSExpr(E->body(), SS, Prec_Decl-1);
+ }
+};
+
+class StdPrinter : public PrettyPrinter<StdPrinter, std::ostream> {};
+
+} // namespace til
+} // namespace threadSafety
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYTRAVERSE_H
diff --git a/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyUtil.h b/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyUtil.h
new file mode 100644
index 00000000..e3b6e61d
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/ThreadSafetyUtil.h
@@ -0,0 +1,357 @@
+//===- ThreadSafetyUtil.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines some basic utility classes for use by ThreadSafetyTIL.h
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYUTIL_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_THREADSAFETYUTIL_H
+
+#include "clang/AST/Decl.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Allocator.h"
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <iterator>
+#include <ostream>
+#include <string>
+#include <vector>
+
+namespace clang {
+
+class Expr;
+
+namespace threadSafety {
+namespace til {
+
+// Simple wrapper class to abstract away from the details of memory management.
+// SExprs are allocated in pools, and deallocated all at once.
+class MemRegionRef {
+private:
+ union AlignmentType {
+ double d;
+ void *p;
+ long double dd;
+ long long ii;
+ };
+
+public:
+ MemRegionRef() = default;
+ MemRegionRef(llvm::BumpPtrAllocator *A) : Allocator(A) {}
+
+ void *allocate(size_t Sz) {
+ return Allocator->Allocate(Sz, alignof(AlignmentType));
+ }
+
+ template <typename T> T *allocateT() { return Allocator->Allocate<T>(); }
+
+ template <typename T> T *allocateT(size_t NumElems) {
+ return Allocator->Allocate<T>(NumElems);
+ }
+
+private:
+ llvm::BumpPtrAllocator *Allocator = nullptr;
+};
+
+} // namespace til
+} // namespace threadSafety
+
+} // namespace clang
+
+inline void *operator new(size_t Sz,
+ clang::threadSafety::til::MemRegionRef &R) {
+ return R.allocate(Sz);
+}
+
+namespace clang {
+namespace threadSafety {
+
+std::string getSourceLiteralString(const Expr *CE);
+
+namespace til {
+
+// A simple fixed size array class that does not manage its own memory,
+// suitable for use with bump pointer allocation.
+template <class T> class SimpleArray {
+public:
+ SimpleArray() = default;
+ SimpleArray(T *Dat, size_t Cp, size_t Sz = 0)
+ : Data(Dat), Size(Sz), Capacity(Cp) {}
+ SimpleArray(MemRegionRef A, size_t Cp)
+ : Data(Cp == 0 ? nullptr : A.allocateT<T>(Cp)), Capacity(Cp) {}
+ SimpleArray(const SimpleArray<T> &A) = delete;
+
+ SimpleArray(SimpleArray<T> &&A)
+ : Data(A.Data), Size(A.Size), Capacity(A.Capacity) {
+ A.Data = nullptr;
+ A.Size = 0;
+ A.Capacity = 0;
+ }
+
+ SimpleArray &operator=(SimpleArray &&RHS) {
+ if (this != &RHS) {
+ Data = RHS.Data;
+ Size = RHS.Size;
+ Capacity = RHS.Capacity;
+
+ RHS.Data = nullptr;
+ RHS.Size = RHS.Capacity = 0;
+ }
+ return *this;
+ }
+
+ // Reserve space for at least Ncp items, reallocating if necessary.
+ void reserve(size_t Ncp, MemRegionRef A) {
+ if (Ncp <= Capacity)
+ return;
+ T *Odata = Data;
+ Data = A.allocateT<T>(Ncp);
+ Capacity = Ncp;
+ memcpy(Data, Odata, sizeof(T) * Size);
+ }
+
+ // Reserve space for at least N more items.
+ void reserveCheck(size_t N, MemRegionRef A) {
+ if (Capacity == 0)
+ reserve(u_max(InitialCapacity, N), A);
+ else if (Size + N < Capacity)
+ reserve(u_max(Size + N, Capacity * 2), A);
+ }
+
+ using iterator = T *;
+ using const_iterator = const T *;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ size_t size() const { return Size; }
+ size_t capacity() const { return Capacity; }
+
+ T &operator[](unsigned i) {
+ assert(i < Size && "Array index out of bounds.");
+ return Data[i];
+ }
+
+ const T &operator[](unsigned i) const {
+ assert(i < Size && "Array index out of bounds.");
+ return Data[i];
+ }
+
+ T &back() {
+ assert(Size && "No elements in the array.");
+ return Data[Size - 1];
+ }
+
+ const T &back() const {
+ assert(Size && "No elements in the array.");
+ return Data[Size - 1];
+ }
+
+ iterator begin() { return Data; }
+ iterator end() { return Data + Size; }
+
+ const_iterator begin() const { return Data; }
+ const_iterator end() const { return Data + Size; }
+
+ const_iterator cbegin() const { return Data; }
+ const_iterator cend() const { return Data + Size; }
+
+ reverse_iterator rbegin() { return reverse_iterator(end()); }
+ reverse_iterator rend() { return reverse_iterator(begin()); }
+
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(end());
+ }
+
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(begin());
+ }
+
+ void push_back(const T &Elem) {
+ assert(Size < Capacity);
+ Data[Size++] = Elem;
+ }
+
+ // drop last n elements from array
+ void drop(unsigned n = 0) {
+ assert(Size > n);
+ Size -= n;
+ }
+
+ void setValues(unsigned Sz, const T& C) {
+ assert(Sz <= Capacity);
+ Size = Sz;
+ for (unsigned i = 0; i < Sz; ++i) {
+ Data[i] = C;
+ }
+ }
+
+ template <class Iter> unsigned append(Iter I, Iter E) {
+ size_t Osz = Size;
+ size_t J = Osz;
+ for (; J < Capacity && I != E; ++J, ++I)
+ Data[J] = *I;
+ Size = J;
+ return J - Osz;
+ }
+
+ llvm::iterator_range<reverse_iterator> reverse() {
+ return llvm::make_range(rbegin(), rend());
+ }
+
+ llvm::iterator_range<const_reverse_iterator> reverse() const {
+ return llvm::make_range(rbegin(), rend());
+ }
+
+private:
+ // std::max is annoying here, because it requires a reference,
+ // thus forcing InitialCapacity to be initialized outside the .h file.
+ size_t u_max(size_t i, size_t j) { return (i < j) ? j : i; }
+
+ static const size_t InitialCapacity = 4;
+
+ T *Data = nullptr;
+ size_t Size = 0;
+ size_t Capacity = 0;
+};
+
+} // namespace til
+
+// A copy on write vector.
+// The vector can be in one of three states:
+// * invalid -- no operations are permitted.
+// * read-only -- read operations are permitted.
+// * writable -- read and write operations are permitted.
+// The init(), destroy(), and makeWritable() methods will change state.
+template<typename T>
+class CopyOnWriteVector {
+ class VectorData {
+ public:
+ unsigned NumRefs = 1;
+ std::vector<T> Vect;
+
+ VectorData() = default;
+ VectorData(const VectorData &VD) : Vect(VD.Vect) {}
+ };
+
+public:
+ CopyOnWriteVector() = default;
+ CopyOnWriteVector(CopyOnWriteVector &&V) : Data(V.Data) { V.Data = nullptr; }
+
+ CopyOnWriteVector &operator=(CopyOnWriteVector &&V) {
+ destroy();
+ Data = V.Data;
+ V.Data = nullptr;
+ return *this;
+ }
+
+ // No copy constructor or copy assignment. Use clone() with move assignment.
+ CopyOnWriteVector(const CopyOnWriteVector &) = delete;
+ CopyOnWriteVector &operator=(const CopyOnWriteVector &) = delete;
+
+ ~CopyOnWriteVector() { destroy(); }
+
+ // Returns true if this holds a valid vector.
+ bool valid() const { return Data; }
+
+ // Returns true if this vector is writable.
+ bool writable() const { return Data && Data->NumRefs == 1; }
+
+ // If this vector is not valid, initialize it to a valid vector.
+ void init() {
+ if (!Data) {
+ Data = new VectorData();
+ }
+ }
+
+ // Destroy this vector; thus making it invalid.
+ void destroy() {
+ if (!Data)
+ return;
+ if (Data->NumRefs <= 1)
+ delete Data;
+ else
+ --Data->NumRefs;
+ Data = nullptr;
+ }
+
+ // Make this vector writable, creating a copy if needed.
+ void makeWritable() {
+ if (!Data) {
+ Data = new VectorData();
+ return;
+ }
+ if (Data->NumRefs == 1)
+ return; // already writeable.
+ --Data->NumRefs;
+ Data = new VectorData(*Data);
+ }
+
+ // Create a lazy copy of this vector.
+ CopyOnWriteVector clone() { return CopyOnWriteVector(Data); }
+
+ using const_iterator = typename std::vector<T>::const_iterator;
+
+ const std::vector<T> &elements() const { return Data->Vect; }
+
+ const_iterator begin() const { return elements().cbegin(); }
+ const_iterator end() const { return elements().cend(); }
+
+ const T& operator[](unsigned i) const { return elements()[i]; }
+
+ unsigned size() const { return Data ? elements().size() : 0; }
+
+ // Return true if V and this vector refer to the same data.
+ bool sameAs(const CopyOnWriteVector &V) const { return Data == V.Data; }
+
+ // Clear vector. The vector must be writable.
+ void clear() {
+ assert(writable() && "Vector is not writable!");
+ Data->Vect.clear();
+ }
+
+ // Push a new element onto the end. The vector must be writable.
+ void push_back(const T &Elem) {
+ assert(writable() && "Vector is not writable!");
+ Data->Vect.push_back(Elem);
+ }
+
+ // Gets a mutable reference to the element at index(i).
+ // The vector must be writable.
+ T& elem(unsigned i) {
+ assert(writable() && "Vector is not writable!");
+ return Data->Vect[i];
+ }
+
+ // Drops elements from the back until the vector has size i.
+ void downsize(unsigned i) {
+ assert(writable() && "Vector is not writable!");
+ Data->Vect.erase(Data->Vect.begin() + i, Data->Vect.end());
+ }
+
+private:
+ CopyOnWriteVector(VectorData *D) : Data(D) {
+ if (!Data)
+ return;
+ ++Data->NumRefs;
+ }
+
+ VectorData *Data = nullptr;
+};
+
+inline std::ostream& operator<<(std::ostream& ss, const StringRef str) {
+ return ss.write(str.data(), str.size());
+}
+
+} // namespace threadSafety
+} // namespace clang
+
+#endif // LLVM_CLANG_THREAD_SAFETY_UTIL_H
diff --git a/clang-r353983/include/clang/Analysis/Analyses/UninitializedValues.h b/clang-r353983/include/clang/Analysis/Analyses/UninitializedValues.h
new file mode 100644
index 00000000..479be1fe
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Analyses/UninitializedValues.h
@@ -0,0 +1,131 @@
+//=- UninitializedValues.h - Finding uses of uninitialized values -*- C++ -*-=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines APIs for invoking and reported uninitialized values
+// warnings.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+
+class AnalysisDeclContext;
+class CFG;
+class DeclContext;
+class Expr;
+class Stmt;
+class VarDecl;
+
+/// A use of a variable, which might be uninitialized.
+class UninitUse {
+public:
+ struct Branch {
+ const Stmt *Terminator;
+ unsigned Output;
+ };
+
+private:
+ /// The expression which uses this variable.
+ const Expr *User;
+
+ /// Is this use uninitialized whenever the function is called?
+ bool UninitAfterCall = false;
+
+ /// Is this use uninitialized whenever the variable declaration is reached?
+ bool UninitAfterDecl = false;
+
+ /// Does this use always see an uninitialized value?
+ bool AlwaysUninit;
+
+ /// This use is always uninitialized if it occurs after any of these branches
+ /// is taken.
+ SmallVector<Branch, 2> UninitBranches;
+
+public:
+ UninitUse(const Expr *User, bool AlwaysUninit)
+ : User(User), AlwaysUninit(AlwaysUninit) {}
+
+ void addUninitBranch(Branch B) {
+ UninitBranches.push_back(B);
+ }
+
+ void setUninitAfterCall() { UninitAfterCall = true; }
+ void setUninitAfterDecl() { UninitAfterDecl = true; }
+
+ /// Get the expression containing the uninitialized use.
+ const Expr *getUser() const { return User; }
+
+ /// The kind of uninitialized use.
+ enum Kind {
+ /// The use might be uninitialized.
+ Maybe,
+
+ /// The use is uninitialized whenever a certain branch is taken.
+ Sometimes,
+
+ /// The use is uninitialized the first time it is reached after we reach
+ /// the variable's declaration.
+ AfterDecl,
+
+ /// The use is uninitialized the first time it is reached after the function
+ /// is called.
+ AfterCall,
+
+ /// The use is always uninitialized.
+ Always
+ };
+
+ /// Get the kind of uninitialized use.
+ Kind getKind() const {
+ return AlwaysUninit ? Always :
+ UninitAfterCall ? AfterCall :
+ UninitAfterDecl ? AfterDecl :
+ !branch_empty() ? Sometimes : Maybe;
+ }
+
+ using branch_iterator = SmallVectorImpl<Branch>::const_iterator;
+
+ /// Branches which inevitably result in the variable being used uninitialized.
+ branch_iterator branch_begin() const { return UninitBranches.begin(); }
+ branch_iterator branch_end() const { return UninitBranches.end(); }
+ bool branch_empty() const { return UninitBranches.empty(); }
+};
+
+class UninitVariablesHandler {
+public:
+ UninitVariablesHandler() = default;
+ virtual ~UninitVariablesHandler();
+
+ /// Called when the uninitialized variable is used at the given expression.
+ virtual void handleUseOfUninitVariable(const VarDecl *vd,
+ const UninitUse &use) {}
+
+ /// Called when the uninitialized variable analysis detects the
+ /// idiom 'int x = x'. All other uses of 'x' within the initializer
+ /// are handled by handleUseOfUninitVariable.
+ virtual void handleSelfInit(const VarDecl *vd) {}
+};
+
+struct UninitVariablesAnalysisStats {
+ unsigned NumVariablesAnalyzed;
+ unsigned NumBlockVisits;
+};
+
+void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg,
+ AnalysisDeclContext &ac,
+ UninitVariablesHandler &handler,
+ UninitVariablesAnalysisStats &stats);
+
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_ANALYSES_UNINITIALIZEDVALUES_H
diff --git a/clang-r353983/include/clang/Analysis/AnalysisDeclContext.h b/clang-r353983/include/clang/Analysis/AnalysisDeclContext.h
new file mode 100644
index 00000000..d42432a2
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/AnalysisDeclContext.h
@@ -0,0 +1,517 @@
+// AnalysisDeclContext.h - Analysis context for Path Sens analysis -*- C++ -*-//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines AnalysisDeclContext, a class that manages the analysis
+// context data for path sensitive analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H
+#define LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H
+
+#include "clang/AST/DeclBase.h"
+#include "clang/Analysis/BodyFarm.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CodeInjector.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Allocator.h"
+#include <functional>
+#include <memory>
+
+namespace clang {
+
+class AnalysisDeclContextManager;
+class ASTContext;
+class BlockDecl;
+class BlockInvocationContext;
+class CFGReverseBlockReachabilityAnalysis;
+class CFGStmtMap;
+class ImplicitParamDecl;
+class LocationContext;
+class LocationContextManager;
+class ParentMap;
+class StackFrameContext;
+class Stmt;
+class VarDecl;
+
+/// The base class of a hierarchy of objects representing analyses tied
+/// to AnalysisDeclContext.
+class ManagedAnalysis {
+protected:
+ ManagedAnalysis() = default;
+
+public:
+ virtual ~ManagedAnalysis();
+
+ // Subclasses need to implement:
+ //
+ // static const void *getTag();
+ //
+ // Which returns a fixed pointer address to distinguish classes of
+ // analysis objects. They also need to implement:
+ //
+ // static [Derived*] create(AnalysisDeclContext &Ctx);
+ //
+ // which creates the analysis object given an AnalysisDeclContext.
+};
+
+/// AnalysisDeclContext contains the context data for the function or method
+/// under analysis.
+class AnalysisDeclContext {
+ /// Backpoint to the AnalysisManager object that created this
+ /// AnalysisDeclContext. This may be null.
+ AnalysisDeclContextManager *Manager;
+
+ const Decl * const D;
+
+ std::unique_ptr<CFG> cfg, completeCFG;
+ std::unique_ptr<CFGStmtMap> cfgStmtMap;
+
+ CFG::BuildOptions cfgBuildOptions;
+ CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs = nullptr;
+
+ bool builtCFG = false;
+ bool builtCompleteCFG = false;
+ std::unique_ptr<ParentMap> PM;
+ std::unique_ptr<CFGReverseBlockReachabilityAnalysis> CFA;
+
+ llvm::BumpPtrAllocator A;
+
+ llvm::DenseMap<const BlockDecl *,void *> *ReferencedBlockVars = nullptr;
+
+ void *ManagedAnalyses = nullptr;
+
+public:
+ AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
+ const Decl *D);
+
+ AnalysisDeclContext(AnalysisDeclContextManager *Mgr,
+ const Decl *D,
+ const CFG::BuildOptions &BuildOptions);
+
+ ~AnalysisDeclContext();
+
+ ASTContext &getASTContext() const { return D->getASTContext(); }
+ const Decl *getDecl() const { return D; }
+
+ /// Return the AnalysisDeclContextManager (if any) that created
+ /// this AnalysisDeclContext.
+ AnalysisDeclContextManager *getManager() const {
+ return Manager;
+ }
+
+ /// Return the build options used to construct the CFG.
+ CFG::BuildOptions &getCFGBuildOptions() {
+ return cfgBuildOptions;
+ }
+
+ const CFG::BuildOptions &getCFGBuildOptions() const {
+ return cfgBuildOptions;
+ }
+
+ /// getAddEHEdges - Return true iff we are adding exceptional edges from
+ /// callExprs. If this is false, then try/catch statements and blocks
+ /// reachable from them can appear to be dead in the CFG, analysis passes must
+ /// cope with that.
+ bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; }
+ bool getUseUnoptimizedCFG() const {
+ return !cfgBuildOptions.PruneTriviallyFalseEdges;
+ }
+ bool getAddImplicitDtors() const { return cfgBuildOptions.AddImplicitDtors; }
+ bool getAddInitializers() const { return cfgBuildOptions.AddInitializers; }
+
+ void registerForcedBlockExpression(const Stmt *stmt);
+ const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt);
+
+ /// Get the body of the Declaration.
+ Stmt *getBody() const;
+
+ /// Get the body of the Declaration.
+ /// \param[out] IsAutosynthesized Specifies if the body is auto-generated
+ /// by the BodyFarm.
+ Stmt *getBody(bool &IsAutosynthesized) const;
+
+ /// Checks if the body of the Decl is generated by the BodyFarm.
+ ///
+ /// Note, the lookup is not free. We are going to call getBody behind
+ /// the scenes.
+ /// \sa getBody
+ bool isBodyAutosynthesized() const;
+
+ /// Checks if the body of the Decl is generated by the BodyFarm from a
+ /// model file.
+ ///
+ /// Note, the lookup is not free. We are going to call getBody behind
+ /// the scenes.
+ /// \sa getBody
+ bool isBodyAutosynthesizedFromModelFile() const;
+
+ CFG *getCFG();
+
+ CFGStmtMap *getCFGStmtMap();
+
+ CFGReverseBlockReachabilityAnalysis *getCFGReachablityAnalysis();
+
+ /// Return a version of the CFG without any edges pruned.
+ CFG *getUnoptimizedCFG();
+
+ void dumpCFG(bool ShowColors);
+
+ /// Returns true if we have built a CFG for this analysis context.
+ /// Note that this doesn't correspond to whether or not a valid CFG exists, it
+ /// corresponds to whether we *attempted* to build one.
+ bool isCFGBuilt() const { return builtCFG; }
+
+ ParentMap &getParentMap();
+
+ using referenced_decls_iterator = const VarDecl * const *;
+
+ llvm::iterator_range<referenced_decls_iterator>
+ getReferencedBlockVars(const BlockDecl *BD);
+
+ /// Return the ImplicitParamDecl* associated with 'self' if this
+ /// AnalysisDeclContext wraps an ObjCMethodDecl. Returns NULL otherwise.
+ const ImplicitParamDecl *getSelfDecl() const;
+
+ const StackFrameContext *getStackFrame(LocationContext const *Parent,
+ const Stmt *S,
+ const CFGBlock *Blk,
+ unsigned Idx);
+
+ const BlockInvocationContext *
+ getBlockInvocationContext(const LocationContext *parent,
+ const BlockDecl *BD,
+ const void *ContextData);
+
+ /// Return the specified analysis object, lazily running the analysis if
+ /// necessary. Return NULL if the analysis could not run.
+ template <typename T>
+ T *getAnalysis() {
+ const void *tag = T::getTag();
+ ManagedAnalysis *&data = getAnalysisImpl(tag);
+ if (!data) {
+ data = T::create(*this);
+ }
+ return static_cast<T *>(data);
+ }
+
+ /// Returns true if the root namespace of the given declaration is the 'std'
+ /// C++ namespace.
+ static bool isInStdNamespace(const Decl *D);
+
+private:
+ ManagedAnalysis *&getAnalysisImpl(const void* tag);
+
+ LocationContextManager &getLocationContextManager();
+};
+
+class LocationContext : public llvm::FoldingSetNode {
+public:
+ enum ContextKind { StackFrame, Scope, Block };
+
+private:
+ ContextKind Kind;
+
+ // AnalysisDeclContext can't be const since some methods may modify its
+ // member.
+ AnalysisDeclContext *Ctx;
+
+ const LocationContext *Parent;
+ int64_t ID;
+
+protected:
+ LocationContext(ContextKind k, AnalysisDeclContext *ctx,
+ const LocationContext *parent,
+ int64_t ID)
+ : Kind(k), Ctx(ctx), Parent(parent), ID(ID) {}
+
+public:
+ virtual ~LocationContext();
+
+ ContextKind getKind() const { return Kind; }
+
+ int64_t getID() const {
+ return ID;
+ }
+
+ AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; }
+
+ const LocationContext *getParent() const { return Parent; }
+
+ bool isParentOf(const LocationContext *LC) const;
+
+ const Decl *getDecl() const { return getAnalysisDeclContext()->getDecl(); }
+
+ CFG *getCFG() const { return getAnalysisDeclContext()->getCFG(); }
+
+ template <typename T>
+ T *getAnalysis() const {
+ return getAnalysisDeclContext()->getAnalysis<T>();
+ }
+
+ ParentMap &getParentMap() const {
+ return getAnalysisDeclContext()->getParentMap();
+ }
+
+ const ImplicitParamDecl *getSelfDecl() const {
+ return Ctx->getSelfDecl();
+ }
+
+ const StackFrameContext *getStackFrame() const;
+
+ /// Return true if the current LocationContext has no caller context.
+ virtual bool inTopFrame() const;
+
+ virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
+
+ void dumpStack(
+ raw_ostream &OS, StringRef Indent = {}, const char *NL = "\n",
+ const char *Sep = "",
+ std::function<void(const LocationContext *)> printMoreInfoPerContext =
+ [](const LocationContext *) {}) const;
+ void dumpStack() const;
+
+public:
+ static void ProfileCommon(llvm::FoldingSetNodeID &ID,
+ ContextKind ck,
+ AnalysisDeclContext *ctx,
+ const LocationContext *parent,
+ const void *data);
+};
+
+class StackFrameContext : public LocationContext {
+ friend class LocationContextManager;
+
+ // The callsite where this stack frame is established.
+ const Stmt *CallSite;
+
+ // The parent block of the callsite.
+ const CFGBlock *Block;
+
+ // The index of the callsite in the CFGBlock.
+ unsigned Index;
+
+ StackFrameContext(AnalysisDeclContext *ctx, const LocationContext *parent,
+ const Stmt *s, const CFGBlock *blk,
+ unsigned idx,
+ int64_t ID)
+ : LocationContext(StackFrame, ctx, parent, ID), CallSite(s),
+ Block(blk), Index(idx) {}
+
+public:
+ ~StackFrameContext() override = default;
+
+ const Stmt *getCallSite() const { return CallSite; }
+
+ const CFGBlock *getCallSiteBlock() const { return Block; }
+
+ /// Return true if the current LocationContext has no caller context.
+ bool inTopFrame() const override { return getParent() == nullptr; }
+
+ unsigned getIndex() const { return Index; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) override;
+
+ static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
+ const LocationContext *parent, const Stmt *s,
+ const CFGBlock *blk, unsigned idx) {
+ ProfileCommon(ID, StackFrame, ctx, parent, s);
+ ID.AddPointer(blk);
+ ID.AddInteger(idx);
+ }
+
+ static bool classof(const LocationContext *Ctx) {
+ return Ctx->getKind() == StackFrame;
+ }
+};
+
+class ScopeContext : public LocationContext {
+ friend class LocationContextManager;
+
+ const Stmt *Enter;
+
+ ScopeContext(AnalysisDeclContext *ctx, const LocationContext *parent,
+ const Stmt *s, int64_t ID)
+ : LocationContext(Scope, ctx, parent, ID), Enter(s) {}
+
+public:
+ ~ScopeContext() override = default;
+
+ void Profile(llvm::FoldingSetNodeID &ID) override;
+
+ static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
+ const LocationContext *parent, const Stmt *s) {
+ ProfileCommon(ID, Scope, ctx, parent, s);
+ }
+
+ static bool classof(const LocationContext *Ctx) {
+ return Ctx->getKind() == Scope;
+ }
+};
+
+class BlockInvocationContext : public LocationContext {
+ friend class LocationContextManager;
+
+ const BlockDecl *BD;
+
+ // FIXME: Come up with a more type-safe way to model context-sensitivity.
+ const void *ContextData;
+
+ BlockInvocationContext(AnalysisDeclContext *ctx,
+ const LocationContext *parent, const BlockDecl *bd,
+ const void *contextData, int64_t ID)
+ : LocationContext(Block, ctx, parent, ID), BD(bd),
+ ContextData(contextData) {}
+
+public:
+ ~BlockInvocationContext() override = default;
+
+ const BlockDecl *getBlockDecl() const { return BD; }
+
+ const void *getContextData() const { return ContextData; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) override;
+
+ static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
+ const LocationContext *parent, const BlockDecl *bd,
+ const void *contextData) {
+ ProfileCommon(ID, Block, ctx, parent, bd);
+ ID.AddPointer(contextData);
+ }
+
+ static bool classof(const LocationContext *Ctx) {
+ return Ctx->getKind() == Block;
+ }
+};
+
+class LocationContextManager {
+ llvm::FoldingSet<LocationContext> Contexts;
+
+ /// ID used for generating a new location context.
+ int64_t NewID = 0;
+
+public:
+ ~LocationContextManager();
+
+ const StackFrameContext *getStackFrame(AnalysisDeclContext *ctx,
+ const LocationContext *parent,
+ const Stmt *s,
+ const CFGBlock *blk, unsigned idx);
+
+ const ScopeContext *getScope(AnalysisDeclContext *ctx,
+ const LocationContext *parent,
+ const Stmt *s);
+
+ const BlockInvocationContext *
+ getBlockInvocationContext(AnalysisDeclContext *ctx,
+ const LocationContext *parent,
+ const BlockDecl *BD,
+ const void *ContextData);
+
+ /// Discard all previously created LocationContext objects.
+ void clear();
+private:
+ template <typename LOC, typename DATA>
+ const LOC *getLocationContext(AnalysisDeclContext *ctx,
+ const LocationContext *parent,
+ const DATA *d);
+};
+
+class AnalysisDeclContextManager {
+ using ContextMap =
+ llvm::DenseMap<const Decl *, std::unique_ptr<AnalysisDeclContext>>;
+
+ ContextMap Contexts;
+ LocationContextManager LocContexts;
+ CFG::BuildOptions cfgBuildOptions;
+
+ /// Pointer to an interface that can provide function bodies for
+ /// declarations from external source.
+ std::unique_ptr<CodeInjector> Injector;
+
+ /// A factory for creating and caching implementations for common
+ /// methods during the analysis.
+ BodyFarm FunctionBodyFarm;
+
+ /// Flag to indicate whether or not bodies should be synthesized
+ /// for well-known functions.
+ bool SynthesizeBodies;
+
+public:
+ AnalysisDeclContextManager(ASTContext &ASTCtx, bool useUnoptimizedCFG = false,
+ bool addImplicitDtors = false,
+ bool addInitializers = false,
+ bool addTemporaryDtors = false,
+ bool addLifetime = false,
+ bool addLoopExit = false,
+ bool addScopes = false,
+ bool synthesizeBodies = false,
+ bool addStaticInitBranches = false,
+ bool addCXXNewAllocator = true,
+ bool addRichCXXConstructors = true,
+ bool markElidedCXXConstructors = true,
+ CodeInjector *injector = nullptr);
+
+ AnalysisDeclContext *getContext(const Decl *D);
+
+ bool getUseUnoptimizedCFG() const {
+ return !cfgBuildOptions.PruneTriviallyFalseEdges;
+ }
+
+ CFG::BuildOptions &getCFGBuildOptions() {
+ return cfgBuildOptions;
+ }
+
+ /// Return true if faux bodies should be synthesized for well-known
+ /// functions.
+ bool synthesizeBodies() const { return SynthesizeBodies; }
+
+ const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx,
+ LocationContext const *Parent,
+ const Stmt *S,
+ const CFGBlock *Blk,
+ unsigned Idx) {
+ return LocContexts.getStackFrame(Ctx, Parent, S, Blk, Idx);
+ }
+
+ // Get the top level stack frame.
+ const StackFrameContext *getStackFrame(const Decl *D) {
+ return LocContexts.getStackFrame(getContext(D), nullptr, nullptr, nullptr,
+ 0);
+ }
+
+ // Get a stack frame with parent.
+ StackFrameContext const *getStackFrame(const Decl *D,
+ LocationContext const *Parent,
+ const Stmt *S,
+ const CFGBlock *Blk,
+ unsigned Idx) {
+ return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx);
+ }
+
+ /// Get a reference to {@code BodyFarm} instance.
+ BodyFarm &getBodyFarm();
+
+ /// Discard all previously created AnalysisDeclContexts.
+ void clear();
+
+private:
+ friend class AnalysisDeclContext;
+
+ LocationContextManager &getLocationContextManager() {
+ return LocContexts;
+ }
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H
diff --git a/clang-r353983/include/clang/Analysis/AnalysisDiagnostic.h b/clang-r353983/include/clang/Analysis/AnalysisDiagnostic.h
new file mode 100644
index 00000000..fd5f2ffe
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/AnalysisDiagnostic.h
@@ -0,0 +1,14 @@
+//===--- DiagnosticAnalysis.h - Diagnostics for libanalysis -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSISDIAGNOSTIC_H
+#define LLVM_CLANG_ANALYSIS_ANALYSISDIAGNOSTIC_H
+
+#include "clang/Basic/DiagnosticAnalysis.h"
+
+#endif
diff --git a/clang-r353983/include/clang/Analysis/AnyCall.h b/clang-r353983/include/clang/Analysis/AnyCall.h
new file mode 100644
index 00000000..a9098adc
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/AnyCall.h
@@ -0,0 +1,208 @@
+//=== AnyCall.h - Abstraction over different callables --------*- C++ -*--//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// A utility class for performing generic operations over different callables.
+//
+//===----------------------------------------------------------------------===//
+//
+#ifndef LLVM_CLANG_ANALYSIS_ANY_CALL_H
+#define LLVM_CLANG_ANALYSIS_ANY_CALL_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+
+namespace clang {
+
+/// An instance of this class corresponds to a call.
+/// It might be a syntactically-concrete call, done as a part of evaluating an
+/// expression, or it may be an abstract callee with no associated expression.
+class AnyCall {
+public:
+ enum Kind {
+ /// A function, function pointer, or a C++ method call
+ Function,
+
+ /// A call to an Objective-C method
+ ObjCMethod,
+
+ /// A call to an Objective-C block
+ Block,
+
+ /// An implicit C++ destructor call (called implicitly
+ /// or by operator 'delete')
+ Destructor,
+
+ /// An implicit or explicit C++ constructor call
+ Constructor,
+
+ /// A C++ allocation function call (operator `new`), via C++ new-expression
+ Allocator,
+
+ /// A C++ deallocation function call (operator `delete`), via C++
+ /// delete-expression
+ Deallocator
+ };
+
+private:
+ /// Either expression or declaration (but not both at the same time)
+ /// can be null.
+
+ /// Call expression, is null when is not known (then declaration is non-null),
+ /// or for implicit destructor calls (when no expression exists.)
+ const Expr *E = nullptr;
+
+ /// Corresponds to a statically known declaration of the called function,
+ /// or null if it is not known (e.g. for a function pointer).
+ const Decl *D = nullptr;
+ Kind K;
+
+public:
+ AnyCall(const CallExpr *CE) : E(CE) {
+ D = CE->getCalleeDecl();
+ K = (CE->getCallee()->getType()->getAs<BlockPointerType>()) ? Block
+ : Function;
+ if (D && ((K == Function && !isa<FunctionDecl>(D)) ||
+ (K == Block && !isa<BlockDecl>(D))))
+ D = nullptr;
+ }
+
+ AnyCall(const ObjCMessageExpr *ME)
+ : E(ME), D(ME->getMethodDecl()), K(ObjCMethod) {}
+
+ AnyCall(const CXXNewExpr *NE)
+ : E(NE), D(NE->getOperatorNew()), K(Allocator) {}
+
+ AnyCall(const CXXDeleteExpr *NE)
+ : E(NE), D(NE->getOperatorDelete()), K(Deallocator) {}
+
+ AnyCall(const CXXConstructExpr *NE)
+ : E(NE), D(NE->getConstructor()), K(Constructor) {}
+
+ AnyCall(const CXXDestructorDecl *D) : E(nullptr), D(D), K(Destructor) {}
+
+ AnyCall(const CXXConstructorDecl *D) : E(nullptr), D(D), K(Constructor) {}
+
+ AnyCall(const ObjCMethodDecl *D) : E(nullptr), D(D), K(ObjCMethod) {}
+
+ AnyCall(const FunctionDecl *D) : E(nullptr), D(D) {
+ if (isa<CXXConstructorDecl>(D)) {
+ K = Constructor;
+ } else if (isa <CXXDestructorDecl>(D)) {
+ K = Destructor;
+ } else {
+ K = Function;
+ }
+
+ }
+
+ /// If {@code E} is a generic call (to ObjC method /function/block/etc),
+ /// return a constructed {@code AnyCall} object. Return None otherwise.
+ static Optional<AnyCall> forExpr(const Expr *E) {
+ if (const auto *ME = dyn_cast<ObjCMessageExpr>(E)) {
+ return AnyCall(ME);
+ } else if (const auto *CE = dyn_cast<CallExpr>(E)) {
+ return AnyCall(CE);
+ } else if (const auto *CXNE = dyn_cast<CXXNewExpr>(E)) {
+ return AnyCall(CXNE);
+ } else if (const auto *CXDE = dyn_cast<CXXDeleteExpr>(E)) {
+ return AnyCall(CXDE);
+ } else if (const auto *CXCE = dyn_cast<CXXConstructExpr>(E)) {
+ return AnyCall(CXCE);
+ } else {
+ return None;
+ }
+ }
+
+ /// If {@code D} is a callable (Objective-C method or a function), return
+ /// a constructed {@code AnyCall} object. Return None otherwise.
+ // FIXME: block support.
+ static Optional<AnyCall> forDecl(const Decl *D) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ return AnyCall(FD);
+ } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ return AnyCall(MD);
+ }
+ return None;
+ }
+
+ /// \returns formal parameters for direct calls (including virtual calls)
+ ArrayRef<ParmVarDecl *> parameters() const {
+ if (!D)
+ return None;
+
+ if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ return FD->parameters();
+ } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ return MD->parameters();
+ } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
+ return BD->parameters();
+ } else {
+ return None;
+ }
+ }
+
+ using param_const_iterator = ArrayRef<ParmVarDecl *>::const_iterator;
+ param_const_iterator param_begin() const { return parameters().begin(); }
+ param_const_iterator param_end() const { return parameters().end(); }
+ size_t param_size() const { return parameters().size(); }
+ bool param_empty() const { return parameters().empty(); }
+
+ QualType getReturnType(ASTContext &Ctx) const {
+ switch (K) {
+ case Function:
+ if (E)
+ return cast<CallExpr>(E)->getCallReturnType(Ctx);
+ return cast<FunctionDecl>(D)->getReturnType();
+ case ObjCMethod:
+ if (E)
+ return cast<ObjCMessageExpr>(E)->getCallReturnType(Ctx);
+ return cast<ObjCMethodDecl>(D)->getReturnType();
+ case Block:
+ // FIXME: BlockDecl does not know its return type,
+ // hence the asymmetry with the function and method cases above.
+ return cast<CallExpr>(E)->getCallReturnType(Ctx);
+ case Destructor:
+ case Constructor:
+ case Allocator:
+ case Deallocator:
+ return cast<FunctionDecl>(D)->getReturnType();
+ }
+ }
+
+ /// \returns Function identifier if it is a named declaration,
+ /// {@code nullptr} otherwise.
+ const IdentifierInfo *getIdentifier() const {
+ if (const auto *ND = dyn_cast_or_null<NamedDecl>(D))
+ return ND->getIdentifier();
+ return nullptr;
+ }
+
+ const Decl *getDecl() const {
+ return D;
+ }
+
+ const Expr *getExpr() const {
+ return E;
+ }
+
+ Kind getKind() const {
+ return K;
+ }
+
+ void dump() const {
+ if (E)
+ E->dump();
+ if (D)
+ D->dump();
+ }
+};
+
+}
+
+#endif // LLVM_CLANG_ANALYSIS_ANY_CALL_H
diff --git a/clang-r353983/include/clang/Analysis/BodyFarm.h b/clang-r353983/include/clang/Analysis/BodyFarm.h
new file mode 100644
index 00000000..72607f88
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/BodyFarm.h
@@ -0,0 +1,53 @@
+//== BodyFarm.h - Factory for conjuring up fake bodies -------------*- C++ -*-//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// BodyFarm is a factory for creating faux implementations for functions/methods
+// for analysis purposes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_ANALYSIS_BODYFARM_H
+#define LLVM_CLANG_LIB_ANALYSIS_BODYFARM_H
+
+#include "clang/AST/DeclBase.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+
+namespace clang {
+
+class ASTContext;
+class FunctionDecl;
+class ObjCMethodDecl;
+class ObjCPropertyDecl;
+class Stmt;
+class CodeInjector;
+
+class BodyFarm {
+public:
+ BodyFarm(ASTContext &C, CodeInjector *injector) : C(C), Injector(injector) {}
+
+ /// Factory method for creating bodies for ordinary functions.
+ Stmt *getBody(const FunctionDecl *D);
+
+ /// Factory method for creating bodies for Objective-C properties.
+ Stmt *getBody(const ObjCMethodDecl *D);
+
+ /// Remove copy constructor to avoid accidental copying.
+ BodyFarm(const BodyFarm &other) = delete;
+
+private:
+ typedef llvm::DenseMap<const Decl *, Optional<Stmt *>> BodyMap;
+
+ ASTContext &C;
+ BodyMap Bodies;
+ CodeInjector *Injector;
+};
+} // namespace clang
+
+#endif
diff --git a/clang-r353983/include/clang/Analysis/CFG.h b/clang-r353983/include/clang/Analysis/CFG.h
new file mode 100644
index 00000000..dc83a99e
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/CFG.h
@@ -0,0 +1,1338 @@
+//===- CFG.h - Classes for representing and building CFGs -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the CFG and CFGBuilder classes for representing and
+// building Control-Flow Graphs (CFGs) from ASTs.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CFG_H
+#define LLVM_CLANG_ANALYSIS_CFG_H
+
+#include "clang/Analysis/Support/BumpVector.h"
+#include "clang/Analysis/ConstructionContext.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/raw_ostream.h"
+#include <bitset>
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+namespace clang {
+
+class ASTContext;
+class BinaryOperator;
+class CFG;
+class CXXBaseSpecifier;
+class CXXBindTemporaryExpr;
+class CXXCtorInitializer;
+class CXXDeleteExpr;
+class CXXDestructorDecl;
+class CXXNewExpr;
+class CXXRecordDecl;
+class Decl;
+class FieldDecl;
+class LangOptions;
+class VarDecl;
+
+/// Represents a top-level expression in a basic block.
+class CFGElement {
+public:
+ enum Kind {
+ // main kind
+ Initializer,
+ ScopeBegin,
+ ScopeEnd,
+ NewAllocator,
+ LifetimeEnds,
+ LoopExit,
+ // stmt kind
+ Statement,
+ Constructor,
+ CXXRecordTypedCall,
+ STMT_BEGIN = Statement,
+ STMT_END = CXXRecordTypedCall,
+ // dtor kind
+ AutomaticObjectDtor,
+ DeleteDtor,
+ BaseDtor,
+ MemberDtor,
+ TemporaryDtor,
+ DTOR_BEGIN = AutomaticObjectDtor,
+ DTOR_END = TemporaryDtor
+ };
+
+protected:
+ // The int bits are used to mark the kind.
+ llvm::PointerIntPair<void *, 2> Data1;
+ llvm::PointerIntPair<void *, 2> Data2;
+
+ CFGElement(Kind kind, const void *Ptr1, const void *Ptr2 = nullptr)
+ : Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3),
+ Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {
+ assert(getKind() == kind);
+ }
+
+ CFGElement() = default;
+
+public:
+ /// Convert to the specified CFGElement type, asserting that this
+ /// CFGElement is of the desired type.
+ template<typename T>
+ T castAs() const {
+ assert(T::isKind(*this));
+ T t;
+ CFGElement& e = t;
+ e = *this;
+ return t;
+ }
+
+ /// Convert to the specified CFGElement type, returning None if this
+ /// CFGElement is not of the desired type.
+ template<typename T>
+ Optional<T> getAs() const {
+ if (!T::isKind(*this))
+ return None;
+ T t;
+ CFGElement& e = t;
+ e = *this;
+ return t;
+ }
+
+ Kind getKind() const {
+ unsigned x = Data2.getInt();
+ x <<= 2;
+ x |= Data1.getInt();
+ return (Kind) x;
+ }
+};
+
+class CFGStmt : public CFGElement {
+public:
+ explicit CFGStmt(Stmt *S, Kind K = Statement) : CFGElement(K, S) {
+ assert(isKind(*this));
+ }
+
+ const Stmt *getStmt() const {
+ return static_cast<const Stmt *>(Data1.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+
+ static bool isKind(const CFGElement &E) {
+ return E.getKind() >= STMT_BEGIN && E.getKind() <= STMT_END;
+ }
+
+protected:
+ CFGStmt() = default;
+};
+
+/// Represents C++ constructor call. Maintains information necessary to figure
+/// out what memory is being initialized by the constructor expression. For now
+/// this is only used by the analyzer's CFG.
+class CFGConstructor : public CFGStmt {
+public:
+ explicit CFGConstructor(CXXConstructExpr *CE, const ConstructionContext *C)
+ : CFGStmt(CE, Constructor) {
+ assert(C);
+ Data2.setPointer(const_cast<ConstructionContext *>(C));
+ }
+
+ const ConstructionContext *getConstructionContext() const {
+ return static_cast<ConstructionContext *>(Data2.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+
+ CFGConstructor() = default;
+
+ static bool isKind(const CFGElement &E) {
+ return E.getKind() == Constructor;
+ }
+};
+
+/// Represents a function call that returns a C++ object by value. This, like
+/// constructor, requires a construction context in order to understand the
+/// storage of the returned object . In C such tracking is not necessary because
+/// no additional effort is required for destroying the object or modeling copy
+/// elision. Like CFGConstructor, this element is for now only used by the
+/// analyzer's CFG.
+class CFGCXXRecordTypedCall : public CFGStmt {
+public:
+ /// Returns true when call expression \p CE needs to be represented
+ /// by CFGCXXRecordTypedCall, as opposed to a regular CFGStmt.
+ static bool isCXXRecordTypedCall(Expr *E) {
+ assert(isa<CallExpr>(E) || isa<ObjCMessageExpr>(E));
+ // There is no such thing as reference-type expression. If the function
+ // returns a reference, it'll return the respective lvalue or xvalue
+ // instead, and we're only interested in objects.
+ return !E->isGLValue() &&
+ E->getType().getCanonicalType()->getAsCXXRecordDecl();
+ }
+
+ explicit CFGCXXRecordTypedCall(Expr *E, const ConstructionContext *C)
+ : CFGStmt(E, CXXRecordTypedCall) {
+ assert(isCXXRecordTypedCall(E));
+ assert(C && (isa<TemporaryObjectConstructionContext>(C) ||
+ // These are possible in C++17 due to mandatory copy elision.
+ isa<ReturnedValueConstructionContext>(C) ||
+ isa<VariableConstructionContext>(C) ||
+ isa<ConstructorInitializerConstructionContext>(C) ||
+ isa<ArgumentConstructionContext>(C)));
+ Data2.setPointer(const_cast<ConstructionContext *>(C));
+ }
+
+ const ConstructionContext *getConstructionContext() const {
+ return static_cast<ConstructionContext *>(Data2.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+
+ CFGCXXRecordTypedCall() = default;
+
+ static bool isKind(const CFGElement &E) {
+ return E.getKind() == CXXRecordTypedCall;
+ }
+};
+
+/// Represents C++ base or member initializer from constructor's initialization
+/// list.
+class CFGInitializer : public CFGElement {
+public:
+ explicit CFGInitializer(CXXCtorInitializer *initializer)
+ : CFGElement(Initializer, initializer) {}
+
+ CXXCtorInitializer* getInitializer() const {
+ return static_cast<CXXCtorInitializer*>(Data1.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+
+ CFGInitializer() = default;
+
+ static bool isKind(const CFGElement &E) {
+ return E.getKind() == Initializer;
+ }
+};
+
+/// Represents C++ allocator call.
+class CFGNewAllocator : public CFGElement {
+public:
+ explicit CFGNewAllocator(const CXXNewExpr *S)
+ : CFGElement(NewAllocator, S) {}
+
+ // Get the new expression.
+ const CXXNewExpr *getAllocatorExpr() const {
+ return static_cast<CXXNewExpr *>(Data1.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+
+ CFGNewAllocator() = default;
+
+ static bool isKind(const CFGElement &elem) {
+ return elem.getKind() == NewAllocator;
+ }
+};
+
+/// Represents the point where a loop ends.
+/// This element is is only produced when building the CFG for the static
+/// analyzer and hidden behind the 'cfg-loopexit' analyzer config flag.
+///
+/// Note: a loop exit element can be reached even when the loop body was never
+/// entered.
+class CFGLoopExit : public CFGElement {
+public:
+ explicit CFGLoopExit(const Stmt *stmt) : CFGElement(LoopExit, stmt) {}
+
+ const Stmt *getLoopStmt() const {
+ return static_cast<Stmt *>(Data1.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+
+ CFGLoopExit() = default;
+
+ static bool isKind(const CFGElement &elem) {
+ return elem.getKind() == LoopExit;
+ }
+};
+
+/// Represents the point where the lifetime of an automatic object ends
+class CFGLifetimeEnds : public CFGElement {
+public:
+ explicit CFGLifetimeEnds(const VarDecl *var, const Stmt *stmt)
+ : CFGElement(LifetimeEnds, var, stmt) {}
+
+ const VarDecl *getVarDecl() const {
+ return static_cast<VarDecl *>(Data1.getPointer());
+ }
+
+ const Stmt *getTriggerStmt() const {
+ return static_cast<Stmt *>(Data2.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+
+ CFGLifetimeEnds() = default;
+
+ static bool isKind(const CFGElement &elem) {
+ return elem.getKind() == LifetimeEnds;
+ }
+};
+
+/// Represents beginning of a scope implicitly generated
+/// by the compiler on encountering a CompoundStmt
+class CFGScopeBegin : public CFGElement {
+public:
+ CFGScopeBegin() {}
+ CFGScopeBegin(const VarDecl *VD, const Stmt *S)
+ : CFGElement(ScopeBegin, VD, S) {}
+
+ // Get statement that triggered a new scope.
+ const Stmt *getTriggerStmt() const {
+ return static_cast<Stmt*>(Data2.getPointer());
+ }
+
+ // Get VD that triggered a new scope.
+ const VarDecl *getVarDecl() const {
+ return static_cast<VarDecl *>(Data1.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+ static bool isKind(const CFGElement &E) {
+ Kind kind = E.getKind();
+ return kind == ScopeBegin;
+ }
+};
+
+/// Represents end of a scope implicitly generated by
+/// the compiler after the last Stmt in a CompoundStmt's body
+class CFGScopeEnd : public CFGElement {
+public:
+ CFGScopeEnd() {}
+ CFGScopeEnd(const VarDecl *VD, const Stmt *S) : CFGElement(ScopeEnd, VD, S) {}
+
+ const VarDecl *getVarDecl() const {
+ return static_cast<VarDecl *>(Data1.getPointer());
+ }
+
+ const Stmt *getTriggerStmt() const {
+ return static_cast<Stmt *>(Data2.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+ static bool isKind(const CFGElement &E) {
+ Kind kind = E.getKind();
+ return kind == ScopeEnd;
+ }
+};
+
+/// Represents C++ object destructor implicitly generated by compiler on various
+/// occasions.
+class CFGImplicitDtor : public CFGElement {
+protected:
+ CFGImplicitDtor() = default;
+
+ CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = nullptr)
+ : CFGElement(kind, data1, data2) {
+ assert(kind >= DTOR_BEGIN && kind <= DTOR_END);
+ }
+
+public:
+ const CXXDestructorDecl *getDestructorDecl(ASTContext &astContext) const;
+ bool isNoReturn(ASTContext &astContext) const;
+
+private:
+ friend class CFGElement;
+
+ static bool isKind(const CFGElement &E) {
+ Kind kind = E.getKind();
+ return kind >= DTOR_BEGIN && kind <= DTOR_END;
+ }
+};
+
+/// Represents C++ object destructor implicitly generated for automatic object
+/// or temporary bound to const reference at the point of leaving its local
+/// scope.
+class CFGAutomaticObjDtor: public CFGImplicitDtor {
+public:
+ CFGAutomaticObjDtor(const VarDecl *var, const Stmt *stmt)
+ : CFGImplicitDtor(AutomaticObjectDtor, var, stmt) {}
+
+ const VarDecl *getVarDecl() const {
+ return static_cast<VarDecl*>(Data1.getPointer());
+ }
+
+ // Get statement end of which triggered the destructor call.
+ const Stmt *getTriggerStmt() const {
+ return static_cast<Stmt*>(Data2.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+
+ CFGAutomaticObjDtor() = default;
+
+ static bool isKind(const CFGElement &elem) {
+ return elem.getKind() == AutomaticObjectDtor;
+ }
+};
+
+/// Represents C++ object destructor generated from a call to delete.
+class CFGDeleteDtor : public CFGImplicitDtor {
+public:
+ CFGDeleteDtor(const CXXRecordDecl *RD, const CXXDeleteExpr *DE)
+ : CFGImplicitDtor(DeleteDtor, RD, DE) {}
+
+ const CXXRecordDecl *getCXXRecordDecl() const {
+ return static_cast<CXXRecordDecl*>(Data1.getPointer());
+ }
+
+ // Get Delete expression which triggered the destructor call.
+ const CXXDeleteExpr *getDeleteExpr() const {
+ return static_cast<CXXDeleteExpr *>(Data2.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+
+ CFGDeleteDtor() = default;
+
+ static bool isKind(const CFGElement &elem) {
+ return elem.getKind() == DeleteDtor;
+ }
+};
+
+/// Represents C++ object destructor implicitly generated for base object in
+/// destructor.
+class CFGBaseDtor : public CFGImplicitDtor {
+public:
+ CFGBaseDtor(const CXXBaseSpecifier *base)
+ : CFGImplicitDtor(BaseDtor, base) {}
+
+ const CXXBaseSpecifier *getBaseSpecifier() const {
+ return static_cast<const CXXBaseSpecifier*>(Data1.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+
+ CFGBaseDtor() = default;
+
+ static bool isKind(const CFGElement &E) {
+ return E.getKind() == BaseDtor;
+ }
+};
+
+/// Represents C++ object destructor implicitly generated for member object in
+/// destructor.
+class CFGMemberDtor : public CFGImplicitDtor {
+public:
+ CFGMemberDtor(const FieldDecl *field)
+ : CFGImplicitDtor(MemberDtor, field, nullptr) {}
+
+ const FieldDecl *getFieldDecl() const {
+ return static_cast<const FieldDecl*>(Data1.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+
+ CFGMemberDtor() = default;
+
+ static bool isKind(const CFGElement &E) {
+ return E.getKind() == MemberDtor;
+ }
+};
+
+/// Represents C++ object destructor implicitly generated at the end of full
+/// expression for temporary object.
+class CFGTemporaryDtor : public CFGImplicitDtor {
+public:
+ CFGTemporaryDtor(CXXBindTemporaryExpr *expr)
+ : CFGImplicitDtor(TemporaryDtor, expr, nullptr) {}
+
+ const CXXBindTemporaryExpr *getBindTemporaryExpr() const {
+ return static_cast<const CXXBindTemporaryExpr *>(Data1.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+
+ CFGTemporaryDtor() = default;
+
+ static bool isKind(const CFGElement &E) {
+ return E.getKind() == TemporaryDtor;
+ }
+};
+
+/// Represents CFGBlock terminator statement.
+///
+/// TemporaryDtorsBranch bit is set to true if the terminator marks a branch
+/// in control flow of destructors of temporaries. In this case terminator
+/// statement is the same statement that branches control flow in evaluation
+/// of matching full expression.
+class CFGTerminator {
+ llvm::PointerIntPair<Stmt *, 1> Data;
+
+public:
+ CFGTerminator() = default;
+ CFGTerminator(Stmt *S, bool TemporaryDtorsBranch = false)
+ : Data(S, TemporaryDtorsBranch) {}
+
+ Stmt *getStmt() { return Data.getPointer(); }
+ const Stmt *getStmt() const { return Data.getPointer(); }
+
+ bool isTemporaryDtorsBranch() const { return Data.getInt(); }
+
+ operator Stmt *() { return getStmt(); }
+ operator const Stmt *() const { return getStmt(); }
+
+ Stmt *operator->() { return getStmt(); }
+ const Stmt *operator->() const { return getStmt(); }
+
+ Stmt &operator*() { return *getStmt(); }
+ const Stmt &operator*() const { return *getStmt(); }
+
+ explicit operator bool() const { return getStmt(); }
+};
+
+/// Represents a single basic block in a source-level CFG.
+/// It consists of:
+///
+/// (1) A set of statements/expressions (which may contain subexpressions).
+/// (2) A "terminator" statement (not in the set of statements).
+/// (3) A list of successors and predecessors.
+///
+/// Terminator: The terminator represents the type of control-flow that occurs
+/// at the end of the basic block. The terminator is a Stmt* referring to an
+/// AST node that has control-flow: if-statements, breaks, loops, etc.
+/// If the control-flow is conditional, the condition expression will appear
+/// within the set of statements in the block (usually the last statement).
+///
+/// Predecessors: the order in the set of predecessors is arbitrary.
+///
+/// Successors: the order in the set of successors is NOT arbitrary. We
+/// currently have the following orderings based on the terminator:
+///
+/// Terminator Successor Ordering
+/// -----------------------------------------------------
+/// if Then Block; Else Block
+/// ? operator LHS expression; RHS expression
+/// &&, || expression that uses result of && or ||, RHS
+///
+/// But note that any of that may be NULL in case of optimized-out edges.
+class CFGBlock {
+ class ElementList {
+ using ImplTy = BumpVector<CFGElement>;
+
+ ImplTy Impl;
+
+ public:
+ ElementList(BumpVectorContext &C) : Impl(C, 4) {}
+
+ using iterator = std::reverse_iterator<ImplTy::iterator>;
+ using const_iterator = std::reverse_iterator<ImplTy::const_iterator>;
+ using reverse_iterator = ImplTy::iterator;
+ using const_reverse_iterator = ImplTy::const_iterator;
+ using const_reference = ImplTy::const_reference;
+
+ void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); }
+
+ reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E,
+ BumpVectorContext &C) {
+ return Impl.insert(I, Cnt, E, C);
+ }
+
+ const_reference front() const { return Impl.back(); }
+ const_reference back() const { return Impl.front(); }
+
+ iterator begin() { return Impl.rbegin(); }
+ iterator end() { return Impl.rend(); }
+ const_iterator begin() const { return Impl.rbegin(); }
+ const_iterator end() const { return Impl.rend(); }
+ reverse_iterator rbegin() { return Impl.begin(); }
+ reverse_iterator rend() { return Impl.end(); }
+ const_reverse_iterator rbegin() const { return Impl.begin(); }
+ const_reverse_iterator rend() const { return Impl.end(); }
+
+ CFGElement operator[](size_t i) const {
+ assert(i < Impl.size());
+ return Impl[Impl.size() - 1 - i];
+ }
+
+ size_t size() const { return Impl.size(); }
+ bool empty() const { return Impl.empty(); }
+ };
+
+ /// The set of statements in the basic block.
+ ElementList Elements;
+
+ /// An (optional) label that prefixes the executable statements in the block.
+ /// When this variable is non-NULL, it is either an instance of LabelStmt,
+ /// SwitchCase or CXXCatchStmt.
+ Stmt *Label = nullptr;
+
+ /// The terminator for a basic block that indicates the type of control-flow
+ /// that occurs between a block and its successors.
+ CFGTerminator Terminator;
+
+ /// Some blocks are used to represent the "loop edge" to the start of a loop
+ /// from within the loop body. This Stmt* will be refer to the loop statement
+ /// for such blocks (and be null otherwise).
+ const Stmt *LoopTarget = nullptr;
+
+ /// A numerical ID assigned to a CFGBlock during construction of the CFG.
+ unsigned BlockID;
+
+public:
+ /// This class represents a potential adjacent block in the CFG. It encodes
+ /// whether or not the block is actually reachable, or can be proved to be
+ /// trivially unreachable. For some cases it allows one to encode scenarios
+ /// where a block was substituted because the original (now alternate) block
+ /// is unreachable.
+ class AdjacentBlock {
+ enum Kind {
+ AB_Normal,
+ AB_Unreachable,
+ AB_Alternate
+ };
+
+ CFGBlock *ReachableBlock;
+ llvm::PointerIntPair<CFGBlock *, 2> UnreachableBlock;
+
+ public:
+ /// Construct an AdjacentBlock with a possibly unreachable block.
+ AdjacentBlock(CFGBlock *B, bool IsReachable);
+
+ /// Construct an AdjacentBlock with a reachable block and an alternate
+ /// unreachable block.
+ AdjacentBlock(CFGBlock *B, CFGBlock *AlternateBlock);
+
+ /// Get the reachable block, if one exists.
+ CFGBlock *getReachableBlock() const {
+ return ReachableBlock;
+ }
+
+ /// Get the potentially unreachable block.
+ CFGBlock *getPossiblyUnreachableBlock() const {
+ return UnreachableBlock.getPointer();
+ }
+
+ /// Provide an implicit conversion to CFGBlock* so that
+ /// AdjacentBlock can be substituted for CFGBlock*.
+ operator CFGBlock*() const {
+ return getReachableBlock();
+ }
+
+ CFGBlock& operator *() const {
+ return *getReachableBlock();
+ }
+
+ CFGBlock* operator ->() const {
+ return getReachableBlock();
+ }
+
+ bool isReachable() const {
+ Kind K = (Kind) UnreachableBlock.getInt();
+ return K == AB_Normal || K == AB_Alternate;
+ }
+ };
+
+private:
+ /// Keep track of the predecessor / successor CFG blocks.
+ using AdjacentBlocks = BumpVector<AdjacentBlock>;
+ AdjacentBlocks Preds;
+ AdjacentBlocks Succs;
+
+ /// This bit is set when the basic block contains a function call
+ /// or implicit destructor that is attributed as 'noreturn'. In that case,
+ /// control cannot technically ever proceed past this block. All such blocks
+ /// will have a single immediate successor: the exit block. This allows them
+ /// to be easily reached from the exit block and using this bit quickly
+ /// recognized without scanning the contents of the block.
+ ///
+ /// Optimization Note: This bit could be profitably folded with Terminator's
+ /// storage if the memory usage of CFGBlock becomes an issue.
+ unsigned HasNoReturnElement : 1;
+
+ /// The parent CFG that owns this CFGBlock.
+ CFG *Parent;
+
+public:
+ explicit CFGBlock(unsigned blockid, BumpVectorContext &C, CFG *parent)
+ : Elements(C), Terminator(nullptr), BlockID(blockid), Preds(C, 1),
+ Succs(C, 1), HasNoReturnElement(false), Parent(parent) {}
+
+ // Statement iterators
+ using iterator = ElementList::iterator;
+ using const_iterator = ElementList::const_iterator;
+ using reverse_iterator = ElementList::reverse_iterator;
+ using const_reverse_iterator = ElementList::const_reverse_iterator;
+
+ CFGElement front() const { return Elements.front(); }
+ CFGElement back() const { return Elements.back(); }
+
+ iterator begin() { return Elements.begin(); }
+ iterator end() { return Elements.end(); }
+ const_iterator begin() const { return Elements.begin(); }
+ const_iterator end() const { return Elements.end(); }
+
+ reverse_iterator rbegin() { return Elements.rbegin(); }
+ reverse_iterator rend() { return Elements.rend(); }
+ const_reverse_iterator rbegin() const { return Elements.rbegin(); }
+ const_reverse_iterator rend() const { return Elements.rend(); }
+
+ unsigned size() const { return Elements.size(); }
+ bool empty() const { return Elements.empty(); }
+
+ CFGElement operator[](size_t i) const { return Elements[i]; }
+
+ // CFG iterators
+ using pred_iterator = AdjacentBlocks::iterator;
+ using const_pred_iterator = AdjacentBlocks::const_iterator;
+ using pred_reverse_iterator = AdjacentBlocks::reverse_iterator;
+ using const_pred_reverse_iterator = AdjacentBlocks::const_reverse_iterator;
+ using pred_range = llvm::iterator_range<pred_iterator>;
+ using pred_const_range = llvm::iterator_range<const_pred_iterator>;
+
+ using succ_iterator = AdjacentBlocks::iterator;
+ using const_succ_iterator = AdjacentBlocks::const_iterator;
+ using succ_reverse_iterator = AdjacentBlocks::reverse_iterator;
+ using const_succ_reverse_iterator = AdjacentBlocks::const_reverse_iterator;
+ using succ_range = llvm::iterator_range<succ_iterator>;
+ using succ_const_range = llvm::iterator_range<const_succ_iterator>;
+
+ pred_iterator pred_begin() { return Preds.begin(); }
+ pred_iterator pred_end() { return Preds.end(); }
+ const_pred_iterator pred_begin() const { return Preds.begin(); }
+ const_pred_iterator pred_end() const { return Preds.end(); }
+
+ pred_reverse_iterator pred_rbegin() { return Preds.rbegin(); }
+ pred_reverse_iterator pred_rend() { return Preds.rend(); }
+ const_pred_reverse_iterator pred_rbegin() const { return Preds.rbegin(); }
+ const_pred_reverse_iterator pred_rend() const { return Preds.rend(); }
+
+ pred_range preds() {
+ return pred_range(pred_begin(), pred_end());
+ }
+
+ pred_const_range preds() const {
+ return pred_const_range(pred_begin(), pred_end());
+ }
+
+ succ_iterator succ_begin() { return Succs.begin(); }
+ succ_iterator succ_end() { return Succs.end(); }
+ const_succ_iterator succ_begin() const { return Succs.begin(); }
+ const_succ_iterator succ_end() const { return Succs.end(); }
+
+ succ_reverse_iterator succ_rbegin() { return Succs.rbegin(); }
+ succ_reverse_iterator succ_rend() { return Succs.rend(); }
+ const_succ_reverse_iterator succ_rbegin() const { return Succs.rbegin(); }
+ const_succ_reverse_iterator succ_rend() const { return Succs.rend(); }
+
+ succ_range succs() {
+ return succ_range(succ_begin(), succ_end());
+ }
+
+ succ_const_range succs() const {
+ return succ_const_range(succ_begin(), succ_end());
+ }
+
+ unsigned succ_size() const { return Succs.size(); }
+ bool succ_empty() const { return Succs.empty(); }
+
+ unsigned pred_size() const { return Preds.size(); }
+ bool pred_empty() const { return Preds.empty(); }
+
+
+ class FilterOptions {
+ public:
+ unsigned IgnoreNullPredecessors : 1;
+ unsigned IgnoreDefaultsWithCoveredEnums : 1;
+
+ FilterOptions()
+ : IgnoreNullPredecessors(1), IgnoreDefaultsWithCoveredEnums(0) {}
+ };
+
+ static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src,
+ const CFGBlock *Dst);
+
+ template <typename IMPL, bool IsPred>
+ class FilteredCFGBlockIterator {
+ private:
+ IMPL I, E;
+ const FilterOptions F;
+ const CFGBlock *From;
+
+ public:
+ explicit FilteredCFGBlockIterator(const IMPL &i, const IMPL &e,
+ const CFGBlock *from,
+ const FilterOptions &f)
+ : I(i), E(e), F(f), From(from) {
+ while (hasMore() && Filter(*I))
+ ++I;
+ }
+
+ bool hasMore() const { return I != E; }
+
+ FilteredCFGBlockIterator &operator++() {
+ do { ++I; } while (hasMore() && Filter(*I));
+ return *this;
+ }
+
+ const CFGBlock *operator*() const { return *I; }
+
+ private:
+ bool Filter(const CFGBlock *To) {
+ return IsPred ? FilterEdge(F, To, From) : FilterEdge(F, From, To);
+ }
+ };
+
+ using filtered_pred_iterator =
+ FilteredCFGBlockIterator<const_pred_iterator, true>;
+
+ using filtered_succ_iterator =
+ FilteredCFGBlockIterator<const_succ_iterator, false>;
+
+ filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const {
+ return filtered_pred_iterator(pred_begin(), pred_end(), this, f);
+ }
+
+ filtered_succ_iterator filtered_succ_start_end(const FilterOptions &f) const {
+ return filtered_succ_iterator(succ_begin(), succ_end(), this, f);
+ }
+
+ // Manipulation of block contents
+
+ void setTerminator(CFGTerminator Term) { Terminator = Term; }
+ void setLabel(Stmt *Statement) { Label = Statement; }
+ void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; }
+ void setHasNoReturnElement() { HasNoReturnElement = true; }
+
+ CFGTerminator getTerminator() { return Terminator; }
+ const CFGTerminator getTerminator() const { return Terminator; }
+
+ Stmt *getTerminatorCondition(bool StripParens = true);
+
+ const Stmt *getTerminatorCondition(bool StripParens = true) const {
+ return const_cast<CFGBlock*>(this)->getTerminatorCondition(StripParens);
+ }
+
+ const Stmt *getLoopTarget() const { return LoopTarget; }
+
+ Stmt *getLabel() { return Label; }
+ const Stmt *getLabel() const { return Label; }
+
+ bool hasNoReturnElement() const { return HasNoReturnElement; }
+
+ unsigned getBlockID() const { return BlockID; }
+
+ CFG *getParent() const { return Parent; }
+
+ void dump() const;
+
+ void dump(const CFG *cfg, const LangOptions &LO, bool ShowColors = false) const;
+ void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO,
+ bool ShowColors) const;
+ void printTerminator(raw_ostream &OS, const LangOptions &LO) const;
+ void printAsOperand(raw_ostream &OS, bool /*PrintType*/) {
+ OS << "BB#" << getBlockID();
+ }
+
+ /// Adds a (potentially unreachable) successor block to the current block.
+ void addSuccessor(AdjacentBlock Succ, BumpVectorContext &C);
+
+ void appendStmt(Stmt *statement, BumpVectorContext &C) {
+ Elements.push_back(CFGStmt(statement), C);
+ }
+
+ void appendConstructor(CXXConstructExpr *CE, const ConstructionContext *CC,
+ BumpVectorContext &C) {
+ Elements.push_back(CFGConstructor(CE, CC), C);
+ }
+
+ void appendCXXRecordTypedCall(Expr *E,
+ const ConstructionContext *CC,
+ BumpVectorContext &C) {
+ Elements.push_back(CFGCXXRecordTypedCall(E, CC), C);
+ }
+
+ void appendInitializer(CXXCtorInitializer *initializer,
+ BumpVectorContext &C) {
+ Elements.push_back(CFGInitializer(initializer), C);
+ }
+
+ void appendNewAllocator(CXXNewExpr *NE,
+ BumpVectorContext &C) {
+ Elements.push_back(CFGNewAllocator(NE), C);
+ }
+
+ void appendScopeBegin(const VarDecl *VD, const Stmt *S,
+ BumpVectorContext &C) {
+ Elements.push_back(CFGScopeBegin(VD, S), C);
+ }
+
+ void prependScopeBegin(const VarDecl *VD, const Stmt *S,
+ BumpVectorContext &C) {
+ Elements.insert(Elements.rbegin(), 1, CFGScopeBegin(VD, S), C);
+ }
+
+ void appendScopeEnd(const VarDecl *VD, const Stmt *S, BumpVectorContext &C) {
+ Elements.push_back(CFGScopeEnd(VD, S), C);
+ }
+
+ void prependScopeEnd(const VarDecl *VD, const Stmt *S, BumpVectorContext &C) {
+ Elements.insert(Elements.rbegin(), 1, CFGScopeEnd(VD, S), C);
+ }
+
+ void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) {
+ Elements.push_back(CFGBaseDtor(BS), C);
+ }
+
+ void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C) {
+ Elements.push_back(CFGMemberDtor(FD), C);
+ }
+
+ void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C) {
+ Elements.push_back(CFGTemporaryDtor(E), C);
+ }
+
+ void appendAutomaticObjDtor(VarDecl *VD, Stmt *S, BumpVectorContext &C) {
+ Elements.push_back(CFGAutomaticObjDtor(VD, S), C);
+ }
+
+ void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C) {
+ Elements.push_back(CFGLifetimeEnds(VD, S), C);
+ }
+
+ void appendLoopExit(const Stmt *LoopStmt, BumpVectorContext &C) {
+ Elements.push_back(CFGLoopExit(LoopStmt), C);
+ }
+
+ void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) {
+ Elements.push_back(CFGDeleteDtor(RD, DE), C);
+ }
+
+ // Destructors must be inserted in reversed order. So insertion is in two
+ // steps. First we prepare space for some number of elements, then we insert
+ // the elements beginning at the last position in prepared space.
+ iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt,
+ BumpVectorContext &C) {
+ return iterator(Elements.insert(I.base(), Cnt,
+ CFGAutomaticObjDtor(nullptr, nullptr), C));
+ }
+ iterator insertAutomaticObjDtor(iterator I, VarDecl *VD, Stmt *S) {
+ *I = CFGAutomaticObjDtor(VD, S);
+ return ++I;
+ }
+
+ // Scope leaving must be performed in reversed order. So insertion is in two
+ // steps. First we prepare space for some number of elements, then we insert
+ // the elements beginning at the last position in prepared space.
+ iterator beginLifetimeEndsInsert(iterator I, size_t Cnt,
+ BumpVectorContext &C) {
+ return iterator(
+ Elements.insert(I.base(), Cnt, CFGLifetimeEnds(nullptr, nullptr), C));
+ }
+ iterator insertLifetimeEnds(iterator I, VarDecl *VD, Stmt *S) {
+ *I = CFGLifetimeEnds(VD, S);
+ return ++I;
+ }
+
+ // Scope leaving must be performed in reversed order. So insertion is in two
+ // steps. First we prepare space for some number of elements, then we insert
+ // the elements beginning at the last position in prepared space.
+ iterator beginScopeEndInsert(iterator I, size_t Cnt, BumpVectorContext &C) {
+ return iterator(
+ Elements.insert(I.base(), Cnt, CFGScopeEnd(nullptr, nullptr), C));
+ }
+ iterator insertScopeEnd(iterator I, VarDecl *VD, Stmt *S) {
+ *I = CFGScopeEnd(VD, S);
+ return ++I;
+ }
+
+};
+
+/// CFGCallback defines methods that should be called when a logical
+/// operator error is found when building the CFG.
+class CFGCallback {
+public:
+ CFGCallback() = default;
+ virtual ~CFGCallback() = default;
+
+ virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {}
+ virtual void compareBitwiseEquality(const BinaryOperator *B,
+ bool isAlwaysTrue) {}
+};
+
+/// Represents a source-level, intra-procedural CFG that represents the
+/// control-flow of a Stmt. The Stmt can represent an entire function body,
+/// or a single expression. A CFG will always contain one empty block that
+/// represents the Exit point of the CFG. A CFG will also contain a designated
+/// Entry block. The CFG solely represents control-flow; it consists of
+/// CFGBlocks which are simply containers of Stmt*'s in the AST the CFG
+/// was constructed from.
+class CFG {
+public:
+ //===--------------------------------------------------------------------===//
+ // CFG Construction & Manipulation.
+ //===--------------------------------------------------------------------===//
+
+ class BuildOptions {
+ std::bitset<Stmt::lastStmtConstant> alwaysAddMask;
+
+ public:
+ using ForcedBlkExprs = llvm::DenseMap<const Stmt *, const CFGBlock *>;
+
+ ForcedBlkExprs **forcedBlkExprs = nullptr;
+ CFGCallback *Observer = nullptr;
+ bool PruneTriviallyFalseEdges = true;
+ bool AddEHEdges = false;
+ bool AddInitializers = false;
+ bool AddImplicitDtors = false;
+ bool AddLifetime = false;
+ bool AddLoopExit = false;
+ bool AddTemporaryDtors = false;
+ bool AddScopes = false;
+ bool AddStaticInitBranches = false;
+ bool AddCXXNewAllocator = false;
+ bool AddCXXDefaultInitExprInCtors = false;
+ bool AddRichCXXConstructors = false;
+ bool MarkElidedCXXConstructors = false;
+
+ BuildOptions() = default;
+
+ bool alwaysAdd(const Stmt *stmt) const {
+ return alwaysAddMask[stmt->getStmtClass()];
+ }
+
+ BuildOptions &setAlwaysAdd(Stmt::StmtClass stmtClass, bool val = true) {
+ alwaysAddMask[stmtClass] = val;
+ return *this;
+ }
+
+ BuildOptions &setAllAlwaysAdd() {
+ alwaysAddMask.set();
+ return *this;
+ }
+ };
+
+ /// Builds a CFG from an AST.
+ static std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *AST, ASTContext *C,
+ const BuildOptions &BO);
+
+ /// Create a new block in the CFG. The CFG owns the block; the caller should
+ /// not directly free it.
+ CFGBlock *createBlock();
+
+ /// Set the entry block of the CFG. This is typically used only during CFG
+ /// construction. Most CFG clients expect that the entry block has no
+ /// predecessors and contains no statements.
+ void setEntry(CFGBlock *B) { Entry = B; }
+
+ /// Set the block used for indirect goto jumps. This is typically used only
+ /// during CFG construction.
+ void setIndirectGotoBlock(CFGBlock *B) { IndirectGotoBlock = B; }
+
+ //===--------------------------------------------------------------------===//
+ // Block Iterators
+ //===--------------------------------------------------------------------===//
+
+ using CFGBlockListTy = BumpVector<CFGBlock *>;
+ using iterator = CFGBlockListTy::iterator;
+ using const_iterator = CFGBlockListTy::const_iterator;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ CFGBlock & front() { return *Blocks.front(); }
+ CFGBlock & back() { return *Blocks.back(); }
+
+ iterator begin() { return Blocks.begin(); }
+ iterator end() { return Blocks.end(); }
+ const_iterator begin() const { return Blocks.begin(); }
+ const_iterator end() const { return Blocks.end(); }
+
+ iterator nodes_begin() { return iterator(Blocks.begin()); }
+ iterator nodes_end() { return iterator(Blocks.end()); }
+ const_iterator nodes_begin() const { return const_iterator(Blocks.begin()); }
+ const_iterator nodes_end() const { return const_iterator(Blocks.end()); }
+
+ reverse_iterator rbegin() { return Blocks.rbegin(); }
+ reverse_iterator rend() { return Blocks.rend(); }
+ const_reverse_iterator rbegin() const { return Blocks.rbegin(); }
+ const_reverse_iterator rend() const { return Blocks.rend(); }
+
+ CFGBlock & getEntry() { return *Entry; }
+ const CFGBlock & getEntry() const { return *Entry; }
+ CFGBlock & getExit() { return *Exit; }
+ const CFGBlock & getExit() const { return *Exit; }
+
+ CFGBlock * getIndirectGotoBlock() { return IndirectGotoBlock; }
+ const CFGBlock * getIndirectGotoBlock() const { return IndirectGotoBlock; }
+
+ using try_block_iterator = std::vector<const CFGBlock *>::const_iterator;
+
+ try_block_iterator try_blocks_begin() const {
+ return TryDispatchBlocks.begin();
+ }
+
+ try_block_iterator try_blocks_end() const {
+ return TryDispatchBlocks.end();
+ }
+
+ void addTryDispatchBlock(const CFGBlock *block) {
+ TryDispatchBlocks.push_back(block);
+ }
+
+ /// Records a synthetic DeclStmt and the DeclStmt it was constructed from.
+ ///
+ /// The CFG uses synthetic DeclStmts when a single AST DeclStmt contains
+ /// multiple decls.
+ void addSyntheticDeclStmt(const DeclStmt *Synthetic,
+ const DeclStmt *Source) {
+ assert(Synthetic->isSingleDecl() && "Can handle single declarations only");
+ assert(Synthetic != Source && "Don't include original DeclStmts in map");
+ assert(!SyntheticDeclStmts.count(Synthetic) && "Already in map");
+ SyntheticDeclStmts[Synthetic] = Source;
+ }
+
+ using synthetic_stmt_iterator =
+ llvm::DenseMap<const DeclStmt *, const DeclStmt *>::const_iterator;
+ using synthetic_stmt_range = llvm::iterator_range<synthetic_stmt_iterator>;
+
+ /// Iterates over synthetic DeclStmts in the CFG.
+ ///
+ /// Each element is a (synthetic statement, source statement) pair.
+ ///
+ /// \sa addSyntheticDeclStmt
+ synthetic_stmt_iterator synthetic_stmt_begin() const {
+ return SyntheticDeclStmts.begin();
+ }
+
+ /// \sa synthetic_stmt_begin
+ synthetic_stmt_iterator synthetic_stmt_end() const {
+ return SyntheticDeclStmts.end();
+ }
+
+ /// \sa synthetic_stmt_begin
+ synthetic_stmt_range synthetic_stmts() const {
+ return synthetic_stmt_range(synthetic_stmt_begin(), synthetic_stmt_end());
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Member templates useful for various batch operations over CFGs.
+ //===--------------------------------------------------------------------===//
+
+ template <typename CALLBACK>
+ void VisitBlockStmts(CALLBACK& O) const {
+ for (const_iterator I = begin(), E = end(); I != E; ++I)
+ for (CFGBlock::const_iterator BI = (*I)->begin(), BE = (*I)->end();
+ BI != BE; ++BI) {
+ if (Optional<CFGStmt> stmt = BI->getAs<CFGStmt>())
+ O(const_cast<Stmt*>(stmt->getStmt()));
+ }
+ }
+
+ //===--------------------------------------------------------------------===//
+ // CFG Introspection.
+ //===--------------------------------------------------------------------===//
+
+ /// Returns the total number of BlockIDs allocated (which start at 0).
+ unsigned getNumBlockIDs() const { return NumBlockIDs; }
+
+ /// Return the total number of CFGBlocks within the CFG This is simply a
+ /// renaming of the getNumBlockIDs(). This is necessary because the dominator
+ /// implementation needs such an interface.
+ unsigned size() const { return NumBlockIDs; }
+
+ //===--------------------------------------------------------------------===//
+ // CFG Debugging: Pretty-Printing and Visualization.
+ //===--------------------------------------------------------------------===//
+
+ void viewCFG(const LangOptions &LO) const;
+ void print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const;
+ void dump(const LangOptions &LO, bool ShowColors) const;
+
+ //===--------------------------------------------------------------------===//
+ // Internal: constructors and data.
+ //===--------------------------------------------------------------------===//
+
+ CFG() : Blocks(BlkBVC, 10) {}
+
+ llvm::BumpPtrAllocator& getAllocator() {
+ return BlkBVC.getAllocator();
+ }
+
+ BumpVectorContext &getBumpVectorContext() {
+ return BlkBVC;
+ }
+
+private:
+ CFGBlock *Entry = nullptr;
+ CFGBlock *Exit = nullptr;
+
+ // Special block to contain collective dispatch for indirect gotos
+ CFGBlock* IndirectGotoBlock = nullptr;
+
+ unsigned NumBlockIDs = 0;
+
+ BumpVectorContext BlkBVC;
+
+ CFGBlockListTy Blocks;
+
+ /// C++ 'try' statements are modeled with an indirect dispatch block.
+ /// This is the collection of such blocks present in the CFG.
+ std::vector<const CFGBlock *> TryDispatchBlocks;
+
+ /// Collects DeclStmts synthesized for this CFG and maps each one back to its
+ /// source DeclStmt.
+ llvm::DenseMap<const DeclStmt *, const DeclStmt *> SyntheticDeclStmts;
+};
+
+} // namespace clang
+
+//===----------------------------------------------------------------------===//
+// GraphTraits specializations for CFG basic block graphs (source-level CFGs)
+//===----------------------------------------------------------------------===//
+
+namespace llvm {
+
+/// Implement simplify_type for CFGTerminator, so that we can dyn_cast from
+/// CFGTerminator to a specific Stmt class.
+template <> struct simplify_type< ::clang::CFGTerminator> {
+ using SimpleType = ::clang::Stmt *;
+
+ static SimpleType getSimplifiedValue(::clang::CFGTerminator Val) {
+ return Val.getStmt();
+ }
+};
+
+// Traits for: CFGBlock
+
+template <> struct GraphTraits< ::clang::CFGBlock *> {
+ using NodeRef = ::clang::CFGBlock *;
+ using ChildIteratorType = ::clang::CFGBlock::succ_iterator;
+
+ static NodeRef getEntryNode(::clang::CFGBlock *BB) { return BB; }
+ static ChildIteratorType child_begin(NodeRef N) { return N->succ_begin(); }
+ static ChildIteratorType child_end(NodeRef N) { return N->succ_end(); }
+};
+
+template <> struct GraphTraits< const ::clang::CFGBlock *> {
+ using NodeRef = const ::clang::CFGBlock *;
+ using ChildIteratorType = ::clang::CFGBlock::const_succ_iterator;
+
+ static NodeRef getEntryNode(const clang::CFGBlock *BB) { return BB; }
+ static ChildIteratorType child_begin(NodeRef N) { return N->succ_begin(); }
+ static ChildIteratorType child_end(NodeRef N) { return N->succ_end(); }
+};
+
+template <> struct GraphTraits<Inverse< ::clang::CFGBlock *>> {
+ using NodeRef = ::clang::CFGBlock *;
+ using ChildIteratorType = ::clang::CFGBlock::const_pred_iterator;
+
+ static NodeRef getEntryNode(Inverse<::clang::CFGBlock *> G) {
+ return G.Graph;
+ }
+
+ static ChildIteratorType child_begin(NodeRef N) { return N->pred_begin(); }
+ static ChildIteratorType child_end(NodeRef N) { return N->pred_end(); }
+};
+
+template <> struct GraphTraits<Inverse<const ::clang::CFGBlock *>> {
+ using NodeRef = const ::clang::CFGBlock *;
+ using ChildIteratorType = ::clang::CFGBlock::const_pred_iterator;
+
+ static NodeRef getEntryNode(Inverse<const ::clang::CFGBlock *> G) {
+ return G.Graph;
+ }
+
+ static ChildIteratorType child_begin(NodeRef N) { return N->pred_begin(); }
+ static ChildIteratorType child_end(NodeRef N) { return N->pred_end(); }
+};
+
+// Traits for: CFG
+
+template <> struct GraphTraits< ::clang::CFG* >
+ : public GraphTraits< ::clang::CFGBlock *> {
+ using nodes_iterator = ::clang::CFG::iterator;
+
+ static NodeRef getEntryNode(::clang::CFG *F) { return &F->getEntry(); }
+ static nodes_iterator nodes_begin(::clang::CFG* F) { return F->nodes_begin();}
+ static nodes_iterator nodes_end(::clang::CFG* F) { return F->nodes_end(); }
+ static unsigned size(::clang::CFG* F) { return F->size(); }
+};
+
+template <> struct GraphTraits<const ::clang::CFG* >
+ : public GraphTraits<const ::clang::CFGBlock *> {
+ using nodes_iterator = ::clang::CFG::const_iterator;
+
+ static NodeRef getEntryNode(const ::clang::CFG *F) { return &F->getEntry(); }
+
+ static nodes_iterator nodes_begin( const ::clang::CFG* F) {
+ return F->nodes_begin();
+ }
+
+ static nodes_iterator nodes_end( const ::clang::CFG* F) {
+ return F->nodes_end();
+ }
+
+ static unsigned size(const ::clang::CFG* F) {
+ return F->size();
+ }
+};
+
+template <> struct GraphTraits<Inverse< ::clang::CFG *>>
+ : public GraphTraits<Inverse< ::clang::CFGBlock *>> {
+ using nodes_iterator = ::clang::CFG::iterator;
+
+ static NodeRef getEntryNode(::clang::CFG *F) { return &F->getExit(); }
+ static nodes_iterator nodes_begin( ::clang::CFG* F) {return F->nodes_begin();}
+ static nodes_iterator nodes_end( ::clang::CFG* F) { return F->nodes_end(); }
+};
+
+template <> struct GraphTraits<Inverse<const ::clang::CFG *>>
+ : public GraphTraits<Inverse<const ::clang::CFGBlock *>> {
+ using nodes_iterator = ::clang::CFG::const_iterator;
+
+ static NodeRef getEntryNode(const ::clang::CFG *F) { return &F->getExit(); }
+
+ static nodes_iterator nodes_begin(const ::clang::CFG* F) {
+ return F->nodes_begin();
+ }
+
+ static nodes_iterator nodes_end(const ::clang::CFG* F) {
+ return F->nodes_end();
+ }
+};
+
+} // namespace llvm
+
+#endif // LLVM_CLANG_ANALYSIS_CFG_H
diff --git a/clang-r353983/include/clang/Analysis/CFGStmtMap.h b/clang-r353983/include/clang/Analysis/CFGStmtMap.h
new file mode 100644
index 00000000..8cf02372
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/CFGStmtMap.h
@@ -0,0 +1,49 @@
+//===--- CFGStmtMap.h - Map from Stmt* to CFGBlock* -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the CFGStmtMap class, which defines a mapping from
+// Stmt* to CFGBlock*
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CFGSTMTMAP_H
+#define LLVM_CLANG_ANALYSIS_CFGSTMTMAP_H
+
+#include "clang/Analysis/CFG.h"
+
+namespace clang {
+
+class ParentMap;
+class Stmt;
+
+class CFGStmtMap {
+ ParentMap *PM;
+ void *M;
+
+ CFGStmtMap(ParentMap *pm, void *m) : PM(pm), M(m) {}
+
+public:
+ ~CFGStmtMap();
+
+ /// Returns a new CFGMap for the given CFG. It is the caller's
+ /// responsibility to 'delete' this object when done using it.
+ static CFGStmtMap *Build(CFG* C, ParentMap *PM);
+
+ /// Returns the CFGBlock the specified Stmt* appears in. For Stmt* that
+ /// are terminators, the CFGBlock is the block they appear as a terminator,
+ /// and not the block they appear as a block-level expression (e.g, '&&').
+ /// CaseStmts and LabelStmts map to the CFGBlock they label.
+ CFGBlock *getBlock(Stmt * S);
+
+ const CFGBlock *getBlock(const Stmt * S) const {
+ return const_cast<CFGStmtMap*>(this)->getBlock(const_cast<Stmt*>(S));
+ }
+};
+
+} // end clang namespace
+#endif
diff --git a/clang-r353983/include/clang/Analysis/CallGraph.h b/clang-r353983/include/clang/Analysis/CallGraph.h
new file mode 100644
index 00000000..49c04490
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/CallGraph.h
@@ -0,0 +1,258 @@
+//===- CallGraph.h - AST-based Call graph -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the AST-based CallGraph.
+//
+// A call graph for functions whose definitions/bodies are available in the
+// current translation unit. The graph has a "virtual" root node that contains
+// edges to all externally available functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH_H
+#define LLVM_CLANG_ANALYSIS_CALLGRAPH_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include <memory>
+
+namespace clang {
+
+class CallGraphNode;
+class Decl;
+class DeclContext;
+class Stmt;
+
+/// The AST-based call graph.
+///
+/// The call graph extends itself with the given declarations by implementing
+/// the recursive AST visitor, which constructs the graph by visiting the given
+/// declarations.
+class CallGraph : public RecursiveASTVisitor<CallGraph> {
+ friend class CallGraphNode;
+
+ using FunctionMapTy =
+ llvm::DenseMap<const Decl *, std::unique_ptr<CallGraphNode>>;
+
+ /// FunctionMap owns all CallGraphNodes.
+ FunctionMapTy FunctionMap;
+
+ /// This is a virtual root node that has edges to all the functions.
+ CallGraphNode *Root;
+
+public:
+ CallGraph();
+ ~CallGraph();
+
+ /// Populate the call graph with the functions in the given
+ /// declaration.
+ ///
+ /// Recursively walks the declaration to find all the dependent Decls as well.
+ void addToCallGraph(Decl *D) {
+ TraverseDecl(D);
+ }
+
+ /// Determine if a declaration should be included in the graph.
+ static bool includeInGraph(const Decl *D);
+
+ /// Lookup the node for the given declaration.
+ CallGraphNode *getNode(const Decl *) const;
+
+ /// Lookup the node for the given declaration. If none found, insert
+ /// one into the graph.
+ CallGraphNode *getOrInsertNode(Decl *);
+
+ using iterator = FunctionMapTy::iterator;
+ using const_iterator = FunctionMapTy::const_iterator;
+
+ /// Iterators through all the elements in the graph. Note, this gives
+ /// non-deterministic order.
+ iterator begin() { return FunctionMap.begin(); }
+ iterator end() { return FunctionMap.end(); }
+ const_iterator begin() const { return FunctionMap.begin(); }
+ const_iterator end() const { return FunctionMap.end(); }
+
+ /// Get the number of nodes in the graph.
+ unsigned size() const { return FunctionMap.size(); }
+
+ /// \ brief Get the virtual root of the graph, all the functions available
+ /// externally are represented as callees of the node.
+ CallGraphNode *getRoot() const { return Root; }
+
+ /// Iterators through all the nodes of the graph that have no parent. These
+ /// are the unreachable nodes, which are either unused or are due to us
+ /// failing to add a call edge due to the analysis imprecision.
+ using nodes_iterator = llvm::SetVector<CallGraphNode *>::iterator;
+ using const_nodes_iterator = llvm::SetVector<CallGraphNode *>::const_iterator;
+
+ void print(raw_ostream &os) const;
+ void dump() const;
+ void viewGraph() const;
+
+ void addNodesForBlocks(DeclContext *D);
+
+ /// Part of recursive declaration visitation. We recursively visit all the
+ /// declarations to collect the root functions.
+ bool VisitFunctionDecl(FunctionDecl *FD) {
+ // We skip function template definitions, as their semantics is
+ // only determined when they are instantiated.
+ if (includeInGraph(FD) && FD->isThisDeclarationADefinition()) {
+ // Add all blocks declared inside this function to the graph.
+ addNodesForBlocks(FD);
+ // If this function has external linkage, anything could call it.
+ // Note, we are not precise here. For example, the function could have
+ // its address taken.
+ addNodeForDecl(FD, FD->isGlobal());
+ }
+ return true;
+ }
+
+ /// Part of recursive declaration visitation.
+ bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
+ if (includeInGraph(MD)) {
+ addNodesForBlocks(MD);
+ addNodeForDecl(MD, true);
+ }
+ return true;
+ }
+
+ // We are only collecting the declarations, so do not step into the bodies.
+ bool TraverseStmt(Stmt *S) { return true; }
+
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+ bool shouldVisitTemplateInstantiations() const { return true; }
+
+private:
+ /// Add the given declaration to the call graph.
+ void addNodeForDecl(Decl *D, bool IsGlobal);
+
+ /// Allocate a new node in the graph.
+ CallGraphNode *allocateNewNode(Decl *);
+};
+
+class CallGraphNode {
+public:
+ using CallRecord = CallGraphNode *;
+
+private:
+ /// The function/method declaration.
+ Decl *FD;
+
+ /// The list of functions called from this node.
+ SmallVector<CallRecord, 5> CalledFunctions;
+
+public:
+ CallGraphNode(Decl *D) : FD(D) {}
+
+ using iterator = SmallVectorImpl<CallRecord>::iterator;
+ using const_iterator = SmallVectorImpl<CallRecord>::const_iterator;
+
+ /// Iterators through all the callees/children of the node.
+ iterator begin() { return CalledFunctions.begin(); }
+ iterator end() { return CalledFunctions.end(); }
+ const_iterator begin() const { return CalledFunctions.begin(); }
+ const_iterator end() const { return CalledFunctions.end(); }
+
+ bool empty() const { return CalledFunctions.empty(); }
+ unsigned size() const { return CalledFunctions.size(); }
+
+ void addCallee(CallGraphNode *N) {
+ CalledFunctions.push_back(N);
+ }
+
+ Decl *getDecl() const { return FD; }
+
+ void print(raw_ostream &os) const;
+ void dump() const;
+};
+
+} // namespace clang
+
+// Graph traits for iteration, viewing.
+namespace llvm {
+
+template <> struct GraphTraits<clang::CallGraphNode*> {
+ using NodeType = clang::CallGraphNode;
+ using NodeRef = clang::CallGraphNode *;
+ using ChildIteratorType = NodeType::iterator;
+
+ static NodeType *getEntryNode(clang::CallGraphNode *CGN) { return CGN; }
+ static ChildIteratorType child_begin(NodeType *N) { return N->begin(); }
+ static ChildIteratorType child_end(NodeType *N) { return N->end(); }
+};
+
+template <> struct GraphTraits<const clang::CallGraphNode*> {
+ using NodeType = const clang::CallGraphNode;
+ using NodeRef = const clang::CallGraphNode *;
+ using ChildIteratorType = NodeType::const_iterator;
+
+ static NodeType *getEntryNode(const clang::CallGraphNode *CGN) { return CGN; }
+ static ChildIteratorType child_begin(NodeType *N) { return N->begin();}
+ static ChildIteratorType child_end(NodeType *N) { return N->end(); }
+};
+
+template <> struct GraphTraits<clang::CallGraph*>
+ : public GraphTraits<clang::CallGraphNode*> {
+ static NodeType *getEntryNode(clang::CallGraph *CGN) {
+ return CGN->getRoot(); // Start at the external node!
+ }
+
+ static clang::CallGraphNode *
+ CGGetValue(clang::CallGraph::const_iterator::value_type &P) {
+ return P.second.get();
+ }
+
+ // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
+ using nodes_iterator =
+ mapped_iterator<clang::CallGraph::iterator, decltype(&CGGetValue)>;
+
+ static nodes_iterator nodes_begin(clang::CallGraph *CG) {
+ return nodes_iterator(CG->begin(), &CGGetValue);
+ }
+
+ static nodes_iterator nodes_end (clang::CallGraph *CG) {
+ return nodes_iterator(CG->end(), &CGGetValue);
+ }
+
+ static unsigned size(clang::CallGraph *CG) { return CG->size(); }
+};
+
+template <> struct GraphTraits<const clang::CallGraph*> :
+ public GraphTraits<const clang::CallGraphNode*> {
+ static NodeType *getEntryNode(const clang::CallGraph *CGN) {
+ return CGN->getRoot();
+ }
+
+ static clang::CallGraphNode *
+ CGGetValue(clang::CallGraph::const_iterator::value_type &P) {
+ return P.second.get();
+ }
+
+ // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
+ using nodes_iterator =
+ mapped_iterator<clang::CallGraph::const_iterator, decltype(&CGGetValue)>;
+
+ static nodes_iterator nodes_begin(const clang::CallGraph *CG) {
+ return nodes_iterator(CG->begin(), &CGGetValue);
+ }
+
+ static nodes_iterator nodes_end(const clang::CallGraph *CG) {
+ return nodes_iterator(CG->end(), &CGGetValue);
+ }
+
+ static unsigned size(const clang::CallGraph *CG) { return CG->size(); }
+};
+
+} // namespace llvm
+
+#endif // LLVM_CLANG_ANALYSIS_CALLGRAPH_H
diff --git a/clang-r353983/include/clang/Analysis/CloneDetection.h b/clang-r353983/include/clang/Analysis/CloneDetection.h
new file mode 100644
index 00000000..db827c3a
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/CloneDetection.h
@@ -0,0 +1,446 @@
+//===--- CloneDetection.h - Finds code clones in an AST ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines classes for searching and analyzing source code clones.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_CLONEDETECTION_H
+#define LLVM_CLANG_AST_CLONEDETECTION_H
+
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/Support/Regex.h"
+#include <vector>
+
+namespace clang {
+
+class Stmt;
+class Decl;
+class VarDecl;
+class ASTContext;
+class CompoundStmt;
+
+/// Identifies a list of statements.
+///
+/// Can either identify a single arbitrary Stmt object, a continuous sequence of
+/// child statements inside a CompoundStmt or no statements at all.
+class StmtSequence {
+ /// If this object identifies a sequence of statements inside a CompoundStmt,
+ /// S points to this CompoundStmt. If this object only identifies a single
+ /// Stmt, then S is a pointer to this Stmt.
+ const Stmt *S;
+
+ /// The declaration that contains the statements.
+ const Decl *D;
+
+ /// If EndIndex is non-zero, then S is a CompoundStmt and this StmtSequence
+ /// instance is representing the CompoundStmt children inside the array
+ /// [StartIndex, EndIndex).
+ unsigned StartIndex;
+ unsigned EndIndex;
+
+public:
+ /// Constructs a StmtSequence holding multiple statements.
+ ///
+ /// The resulting StmtSequence identifies a continuous sequence of statements
+ /// in the body of the given CompoundStmt. Which statements of the body should
+ /// be identified needs to be specified by providing a start and end index
+ /// that describe a non-empty sub-array in the body of the given CompoundStmt.
+ ///
+ /// \param Stmt A CompoundStmt that contains all statements in its body.
+ /// \param D The Decl containing this Stmt.
+ /// \param StartIndex The inclusive start index in the children array of
+ /// \p Stmt
+ /// \param EndIndex The exclusive end index in the children array of \p Stmt.
+ StmtSequence(const CompoundStmt *Stmt, const Decl *D, unsigned StartIndex,
+ unsigned EndIndex);
+
+ /// Constructs a StmtSequence holding a single statement.
+ ///
+ /// \param Stmt An arbitrary Stmt.
+ /// \param D The Decl containing this Stmt.
+ StmtSequence(const Stmt *Stmt, const Decl *D);
+
+ /// Constructs an empty StmtSequence.
+ StmtSequence();
+
+ typedef const Stmt *const *iterator;
+
+ /// Returns an iterator pointing to the first statement in this sequence.
+ iterator begin() const;
+
+ /// Returns an iterator pointing behind the last statement in this sequence.
+ iterator end() const;
+
+ /// Returns the first statement in this sequence.
+ ///
+ /// This method should only be called on a non-empty StmtSequence object.
+ const Stmt *front() const {
+ assert(!empty());
+ return begin()[0];
+ }
+
+ /// Returns the last statement in this sequence.
+ ///
+ /// This method should only be called on a non-empty StmtSequence object.
+ const Stmt *back() const {
+ assert(!empty());
+ return begin()[size() - 1];
+ }
+
+ /// Returns the number of statements this object holds.
+ unsigned size() const {
+ if (holdsSequence())
+ return EndIndex - StartIndex;
+ if (S == nullptr)
+ return 0;
+ return 1;
+ }
+
+ /// Returns true if and only if this StmtSequence contains no statements.
+ bool empty() const { return size() == 0; }
+
+ /// Returns the related ASTContext for the stored Stmts.
+ ASTContext &getASTContext() const;
+
+ /// Returns the declaration that contains the stored Stmts.
+ const Decl *getContainingDecl() const {
+ assert(D);
+ return D;
+ }
+
+ /// Returns true if this objects holds a list of statements.
+ bool holdsSequence() const { return EndIndex != 0; }
+
+ /// Returns the start sourcelocation of the first statement in this sequence.
+ ///
+ /// This method should only be called on a non-empty StmtSequence object.
+ SourceLocation getBeginLoc() const;
+
+ /// Returns the end sourcelocation of the last statement in this sequence.
+ ///
+ /// This method should only be called on a non-empty StmtSequence object.
+ SourceLocation getEndLoc() const;
+
+ /// Returns the source range of the whole sequence - from the beginning
+ /// of the first statement to the end of the last statement.
+ SourceRange getSourceRange() const;
+
+ bool operator==(const StmtSequence &Other) const {
+ return std::tie(S, StartIndex, EndIndex) ==
+ std::tie(Other.S, Other.StartIndex, Other.EndIndex);
+ }
+
+ bool operator!=(const StmtSequence &Other) const {
+ return std::tie(S, StartIndex, EndIndex) !=
+ std::tie(Other.S, Other.StartIndex, Other.EndIndex);
+ }
+
+ /// Returns true if and only if this sequence covers a source range that
+ /// contains the source range of the given sequence \p Other.
+ ///
+ /// This method should only be called on a non-empty StmtSequence object
+ /// and passed a non-empty StmtSequence object.
+ bool contains(const StmtSequence &Other) const;
+};
+
+/// Searches for similar subtrees in the AST.
+///
+/// First, this class needs several declarations with statement bodies which
+/// can be passed via analyzeCodeBody. Afterwards all statements can be
+/// searched for clones by calling findClones with a given list of constraints
+/// that should specify the wanted properties of the clones.
+///
+/// The result of findClones can be further constrained with the constrainClones
+/// method.
+///
+/// This class only searches for clones in executable source code
+/// (e.g. function bodies). Other clones (e.g. cloned comments or declarations)
+/// are not supported.
+class CloneDetector {
+
+public:
+ /// A collection of StmtSequences that share an arbitrary property.
+ typedef llvm::SmallVector<StmtSequence, 8> CloneGroup;
+
+ /// Generates and stores search data for all statements in the body of
+ /// the given Decl.
+ void analyzeCodeBody(const Decl *D);
+
+ /// Constrains the given list of clone groups with the given constraint.
+ ///
+ /// The constraint is expected to have a method with the signature
+ /// `void constrain(std::vector<CloneDetector::CloneGroup> &Sequences)`
+ /// as this is the interface that the CloneDetector uses for applying the
+ /// constraint. The constraint is supposed to directly modify the passed list
+ /// so that all clones in the list fulfill the specific property this
+ /// constraint ensures.
+ template <typename T>
+ static void constrainClones(std::vector<CloneGroup> &CloneGroups, T C) {
+ C.constrain(CloneGroups);
+ }
+
+ /// Constrains the given list of clone groups with the given list of
+ /// constraints.
+ ///
+ /// The constraints are applied in sequence in the order in which they are
+ /// passed to this function.
+ template <typename T1, typename... Ts>
+ static void constrainClones(std::vector<CloneGroup> &CloneGroups, T1 C,
+ Ts... ConstraintList) {
+ constrainClones(CloneGroups, C);
+ constrainClones(CloneGroups, ConstraintList...);
+ }
+
+ /// Searches for clones in all previously passed statements.
+ /// \param Result Output parameter to which all created clone groups are
+ /// added.
+ /// \param ConstraintList The constraints that should be applied to the
+ // result.
+ template <typename... Ts>
+ void findClones(std::vector<CloneGroup> &Result, Ts... ConstraintList) {
+ // The initial assumption is that there is only one clone group and every
+ // statement is a clone of the others. This clone group will then be
+ // split up with the help of the constraints.
+ CloneGroup AllClones;
+ AllClones.reserve(Sequences.size());
+ for (const auto &C : Sequences) {
+ AllClones.push_back(C);
+ }
+
+ Result.push_back(AllClones);
+
+ constrainClones(Result, ConstraintList...);
+ }
+
+private:
+ CloneGroup Sequences;
+};
+
+/// This class is a utility class that contains utility functions for building
+/// custom constraints.
+class CloneConstraint {
+public:
+ /// Removes all groups by using a filter function.
+ /// \param CloneGroups The list of CloneGroups that is supposed to be
+ /// filtered.
+ /// \param Filter The filter function that should return true for all groups
+ /// that should be removed from the list.
+ static void filterGroups(
+ std::vector<CloneDetector::CloneGroup> &CloneGroups,
+ llvm::function_ref<bool(const CloneDetector::CloneGroup &)> Filter) {
+ CloneGroups.erase(
+ std::remove_if(CloneGroups.begin(), CloneGroups.end(), Filter),
+ CloneGroups.end());
+ }
+
+ /// Splits the given CloneGroups until the given Compare function returns true
+ /// for all clones in a single group.
+ /// \param CloneGroups A list of CloneGroups that should be modified.
+ /// \param Compare The comparison function that all clones are supposed to
+ /// pass. Should return true if and only if two clones belong
+ /// to the same CloneGroup.
+ static void splitCloneGroups(
+ std::vector<CloneDetector::CloneGroup> &CloneGroups,
+ llvm::function_ref<bool(const StmtSequence &, const StmtSequence &)>
+ Compare);
+};
+
+/// This constraint moves clones into clone groups of type II via hashing.
+///
+/// Clones with different hash values are moved into separate clone groups.
+/// Collisions are possible, and this constraint does nothing to address this
+/// them. Add the slower RecursiveCloneTypeIIVerifyConstraint later in the
+/// constraint chain, not necessarily immediately, to eliminate hash collisions
+/// through a more detailed analysis.
+class RecursiveCloneTypeIIHashConstraint {
+public:
+ void constrain(std::vector<CloneDetector::CloneGroup> &Sequences);
+};
+
+/// This constraint moves clones into clone groups of type II by comparing them.
+///
+/// Clones that aren't type II clones are moved into separate clone groups.
+/// In contrast to the RecursiveCloneTypeIIHashConstraint, all clones in a clone
+/// group are guaranteed to be be type II clones of each other, but it is too
+/// slow to efficiently handle large amounts of clones.
+class RecursiveCloneTypeIIVerifyConstraint {
+public:
+ void constrain(std::vector<CloneDetector::CloneGroup> &Sequences);
+};
+
+/// Ensures that every clone has at least the given complexity.
+///
+/// Complexity is here defined as the total amount of children of a statement.
+/// This constraint assumes the first statement in the group is representative
+/// for all other statements in the group in terms of complexity.
+class MinComplexityConstraint {
+ unsigned MinComplexity;
+
+public:
+ MinComplexityConstraint(unsigned MinComplexity)
+ : MinComplexity(MinComplexity) {}
+
+ /// Calculates the complexity of the given StmtSequence.
+ /// \param Limit The limit of complexity we probe for. After reaching
+ /// this limit during calculation, this method is exiting
+ /// early to improve performance and returns this limit.
+ size_t calculateStmtComplexity(const StmtSequence &Seq, std::size_t Limit,
+ const std::string &ParentMacroStack = "");
+
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
+ CloneConstraint::filterGroups(
+ CloneGroups, [this](const CloneDetector::CloneGroup &A) {
+ if (!A.empty())
+ return calculateStmtComplexity(A.front(), MinComplexity) <
+ MinComplexity;
+ else
+ return false;
+ });
+ }
+};
+
+/// Ensures that all clone groups contain at least the given amount of clones.
+class MinGroupSizeConstraint {
+ unsigned MinGroupSize;
+
+public:
+ MinGroupSizeConstraint(unsigned MinGroupSize = 2)
+ : MinGroupSize(MinGroupSize) {}
+
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
+ CloneConstraint::filterGroups(CloneGroups,
+ [this](const CloneDetector::CloneGroup &A) {
+ return A.size() < MinGroupSize;
+ });
+ }
+};
+
+/// Ensures that no clone group fully contains another clone group.
+struct OnlyLargestCloneConstraint {
+ void constrain(std::vector<CloneDetector::CloneGroup> &Result);
+};
+
+struct FilenamePatternConstraint {
+ StringRef IgnoredFilesPattern;
+ std::shared_ptr<llvm::Regex> IgnoredFilesRegex;
+
+ FilenamePatternConstraint(StringRef IgnoredFilesPattern)
+ : IgnoredFilesPattern(IgnoredFilesPattern) {
+ IgnoredFilesRegex = std::make_shared<llvm::Regex>("^(" +
+ IgnoredFilesPattern.str() + "$)");
+ }
+
+ bool isAutoGenerated(const CloneDetector::CloneGroup &Group);
+
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups) {
+ CloneConstraint::filterGroups(
+ CloneGroups, [this](const CloneDetector::CloneGroup &Group) {
+ return isAutoGenerated(Group);
+ });
+ }
+};
+
+/// Analyzes the pattern of the referenced variables in a statement.
+class VariablePattern {
+
+ /// Describes an occurrence of a variable reference in a statement.
+ struct VariableOccurence {
+ /// The index of the associated VarDecl in the Variables vector.
+ size_t KindID;
+ /// The statement in the code where the variable was referenced.
+ const Stmt *Mention;
+
+ VariableOccurence(size_t KindID, const Stmt *Mention)
+ : KindID(KindID), Mention(Mention) {}
+ };
+
+ /// All occurrences of referenced variables in the order of appearance.
+ std::vector<VariableOccurence> Occurences;
+ /// List of referenced variables in the order of appearance.
+ /// Every item in this list is unique.
+ std::vector<const VarDecl *> Variables;
+
+ /// Adds a new variable referenced to this pattern.
+ /// \param VarDecl The declaration of the variable that is referenced.
+ /// \param Mention The SourceRange where this variable is referenced.
+ void addVariableOccurence(const VarDecl *VarDecl, const Stmt *Mention);
+
+ /// Adds each referenced variable from the given statement.
+ void addVariables(const Stmt *S);
+
+public:
+ /// Creates an VariablePattern object with information about the given
+ /// StmtSequence.
+ VariablePattern(const StmtSequence &Sequence) {
+ for (const Stmt *S : Sequence)
+ addVariables(S);
+ }
+
+ /// Describes two clones that reference their variables in a different pattern
+ /// which could indicate a programming error.
+ struct SuspiciousClonePair {
+ /// Utility class holding the relevant information about a single
+ /// clone in this pair.
+ struct SuspiciousCloneInfo {
+ /// The variable which referencing in this clone was against the pattern.
+ const VarDecl *Variable;
+ /// Where the variable was referenced.
+ const Stmt *Mention;
+ /// The variable that should have been referenced to follow the pattern.
+ /// If Suggestion is a nullptr then it's not possible to fix the pattern
+ /// by referencing a different variable in this clone.
+ const VarDecl *Suggestion;
+ SuspiciousCloneInfo(const VarDecl *Variable, const Stmt *Mention,
+ const VarDecl *Suggestion)
+ : Variable(Variable), Mention(Mention), Suggestion(Suggestion) {}
+ SuspiciousCloneInfo() {}
+ };
+ /// The first clone in the pair which always has a suggested variable.
+ SuspiciousCloneInfo FirstCloneInfo;
+ /// This other clone in the pair which can have a suggested variable.
+ SuspiciousCloneInfo SecondCloneInfo;
+ };
+
+ /// Counts the differences between this pattern and the given one.
+ /// \param Other The given VariablePattern to compare with.
+ /// \param FirstMismatch Output parameter that will be filled with information
+ /// about the first difference between the two patterns. This parameter
+ /// can be a nullptr, in which case it will be ignored.
+ /// \return Returns the number of differences between the pattern this object
+ /// is following and the given VariablePattern.
+ ///
+ /// For example, the following statements all have the same pattern and this
+ /// function would return zero:
+ ///
+ /// if (a < b) return a; return b;
+ /// if (x < y) return x; return y;
+ /// if (u2 < u1) return u2; return u1;
+ ///
+ /// But the following statement has a different pattern (note the changed
+ /// variables in the return statements) and would have two differences when
+ /// compared with one of the statements above.
+ ///
+ /// if (a < b) return b; return a;
+ ///
+ /// This function should only be called if the related statements of the given
+ /// pattern and the statements of this objects are clones of each other.
+ unsigned countPatternDifferences(
+ const VariablePattern &Other,
+ VariablePattern::SuspiciousClonePair *FirstMismatch = nullptr);
+};
+
+/// Ensures that all clones reference variables in the same pattern.
+struct MatchingVariablePatternConstraint {
+ void constrain(std::vector<CloneDetector::CloneGroup> &CloneGroups);
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_CLONEDETECTION_H
diff --git a/clang-r353983/include/clang/Analysis/CodeInjector.h b/clang-r353983/include/clang/Analysis/CodeInjector.h
new file mode 100644
index 00000000..a59dc0a9
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/CodeInjector.h
@@ -0,0 +1,45 @@
+//===-- CodeInjector.h ------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines the clang::CodeInjector interface which is responsible for
+/// injecting AST of function definitions that may not be available in the
+/// original source.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CODEINJECTOR_H
+#define LLVM_CLANG_ANALYSIS_CODEINJECTOR_H
+
+namespace clang {
+
+class Stmt;
+class FunctionDecl;
+class ObjCMethodDecl;
+
+/// CodeInjector is an interface which is responsible for injecting AST
+/// of function definitions that may not be available in the original source.
+///
+/// The getBody function will be called each time the static analyzer examines a
+/// function call that has no definition available in the current translation
+/// unit. If the returned statement is not a null pointer, it is assumed to be
+/// the body of a function which will be used for the analysis. The source of
+/// the body can be arbitrary, but it is advised to use memoization to avoid
+/// unnecessary reparsing of the external source that provides the body of the
+/// functions.
+class CodeInjector {
+public:
+ CodeInjector();
+ virtual ~CodeInjector();
+
+ virtual Stmt *getBody(const FunctionDecl *D) = 0;
+ virtual Stmt *getBody(const ObjCMethodDecl *D) = 0;
+};
+}
+
+#endif
diff --git a/clang-r353983/include/clang/Analysis/ConstructionContext.h b/clang-r353983/include/clang/Analysis/ConstructionContext.h
new file mode 100644
index 00000000..f1564f9f
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/ConstructionContext.h
@@ -0,0 +1,660 @@
+//===- ConstructionContext.h - CFG constructor information ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ConstructionContext class and its sub-classes,
+// which represent various different ways of constructing C++ objects
+// with the additional information the users may want to know about
+// the constructor.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H
+#define LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H
+
+#include "clang/Analysis/Support/BumpVector.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+
+namespace clang {
+
+/// Represents a single point (AST node) in the program that requires attention
+/// during construction of an object. ConstructionContext would be represented
+/// as a list of such items.
+class ConstructionContextItem {
+public:
+ enum ItemKind {
+ VariableKind,
+ NewAllocatorKind,
+ ReturnKind,
+ MaterializationKind,
+ TemporaryDestructorKind,
+ ElidedDestructorKind,
+ ElidableConstructorKind,
+ ArgumentKind,
+ STATEMENT_WITH_INDEX_KIND_BEGIN=ArgumentKind,
+ STATEMENT_WITH_INDEX_KIND_END=ArgumentKind,
+ STATEMENT_KIND_BEGIN = VariableKind,
+ STATEMENT_KIND_END = ArgumentKind,
+ InitializerKind,
+ INITIALIZER_KIND_BEGIN=InitializerKind,
+ INITIALIZER_KIND_END=InitializerKind
+ };
+
+ LLVM_DUMP_METHOD static StringRef getKindAsString(ItemKind K) {
+ switch (K) {
+ case VariableKind: return "construct into local variable";
+ case NewAllocatorKind: return "construct into new-allocator";
+ case ReturnKind: return "construct into return address";
+ case MaterializationKind: return "materialize temporary";
+ case TemporaryDestructorKind: return "destroy temporary";
+ case ElidedDestructorKind: return "elide destructor";
+ case ElidableConstructorKind: return "elide constructor";
+ case ArgumentKind: return "construct into argument";
+ case InitializerKind: return "construct into member variable";
+ };
+ llvm_unreachable("Unknown ItemKind");
+ }
+
+private:
+ const void *const Data;
+ const ItemKind Kind;
+ const unsigned Index = 0;
+
+ bool hasStatement() const {
+ return Kind >= STATEMENT_KIND_BEGIN &&
+ Kind <= STATEMENT_KIND_END;
+ }
+
+ bool hasIndex() const {
+ return Kind >= STATEMENT_WITH_INDEX_KIND_BEGIN &&
+ Kind >= STATEMENT_WITH_INDEX_KIND_END;
+ }
+
+ bool hasInitializer() const {
+ return Kind >= INITIALIZER_KIND_BEGIN &&
+ Kind <= INITIALIZER_KIND_END;
+ }
+
+public:
+ // ConstructionContextItem should be simple enough so that it was easy to
+ // re-construct it from the AST node it captures. For that reason we provide
+ // simple implicit conversions from all sorts of supported AST nodes.
+ ConstructionContextItem(const DeclStmt *DS)
+ : Data(DS), Kind(VariableKind) {}
+
+ ConstructionContextItem(const CXXNewExpr *NE)
+ : Data(NE), Kind(NewAllocatorKind) {}
+
+ ConstructionContextItem(const ReturnStmt *RS)
+ : Data(RS), Kind(ReturnKind) {}
+
+ ConstructionContextItem(const MaterializeTemporaryExpr *MTE)
+ : Data(MTE), Kind(MaterializationKind) {}
+
+ ConstructionContextItem(const CXXBindTemporaryExpr *BTE,
+ bool IsElided = false)
+ : Data(BTE),
+ Kind(IsElided ? ElidedDestructorKind : TemporaryDestructorKind) {}
+
+ ConstructionContextItem(const CXXConstructExpr *CE)
+ : Data(CE), Kind(ElidableConstructorKind) {}
+
+ ConstructionContextItem(const CallExpr *CE, unsigned Index)
+ : Data(CE), Kind(ArgumentKind), Index(Index) {}
+
+ ConstructionContextItem(const CXXConstructExpr *CE, unsigned Index)
+ : Data(CE), Kind(ArgumentKind), Index(Index) {}
+
+ ConstructionContextItem(const ObjCMessageExpr *ME, unsigned Index)
+ : Data(ME), Kind(ArgumentKind), Index(Index) {}
+
+ // A polymorphic version of the previous calls with dynamic type check.
+ ConstructionContextItem(const Expr *E, unsigned Index)
+ : Data(E), Kind(ArgumentKind), Index(Index) {
+ assert(isa<CallExpr>(E) || isa<CXXConstructExpr>(E) ||
+ isa<ObjCMessageExpr>(E));
+ }
+
+ ConstructionContextItem(const CXXCtorInitializer *Init)
+ : Data(Init), Kind(InitializerKind), Index(0) {}
+
+ ItemKind getKind() const { return Kind; }
+
+ LLVM_DUMP_METHOD StringRef getKindAsString() const {
+ return getKindAsString(getKind());
+ }
+
+ /// The construction site - the statement that triggered the construction
+ /// for one of its parts. For instance, stack variable declaration statement
+ /// triggers construction of itself or its elements if it's an array,
+ /// new-expression triggers construction of the newly allocated object(s).
+ const Stmt *getStmt() const {
+ assert(hasStatement());
+ return static_cast<const Stmt *>(Data);
+ }
+
+ const Stmt *getStmtOrNull() const {
+ return hasStatement() ? getStmt() : nullptr;
+ }
+
+ /// The construction site is not necessarily a statement. It may also be a
+ /// CXXCtorInitializer, which means that a member variable is being
+ /// constructed during initialization of the object that contains it.
+ const CXXCtorInitializer *getCXXCtorInitializer() const {
+ assert(hasInitializer());
+ return static_cast<const CXXCtorInitializer *>(Data);
+ }
+
+ /// If a single trigger statement triggers multiple constructors, they are
+ /// usually being enumerated. This covers function argument constructors
+ /// triggered by a call-expression and items in an initializer list triggered
+ /// by an init-list-expression.
+ unsigned getIndex() const {
+ // This is a fairly specific request. Let's make sure the user knows
+ // what he's doing.
+ assert(hasIndex());
+ return Index;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(Data);
+ ID.AddInteger(Kind);
+ ID.AddInteger(Index);
+ }
+
+ bool operator==(const ConstructionContextItem &Other) const {
+ // For most kinds the Index comparison is trivially true, but
+ // checking kind separately doesn't seem to be less expensive
+ // than checking Index. Same in operator<().
+ return std::make_tuple(Data, Kind, Index) ==
+ std::make_tuple(Other.Data, Other.Kind, Other.Index);
+ }
+
+ bool operator<(const ConstructionContextItem &Other) const {
+ return std::make_tuple(Data, Kind, Index) <
+ std::make_tuple(Other.Data, Other.Kind, Other.Index);
+ }
+};
+
+/// Construction context can be seen as a linked list of multiple layers.
+/// Sometimes a single trigger is not enough to describe the construction
+/// site. That's what causing us to have a chain of "partial" construction
+/// context layers. Some examples:
+/// - A constructor within in an aggregate initializer list within a variable
+/// would have a construction context of the initializer list with
+/// the parent construction context of a variable.
+/// - A constructor for a temporary that needs to be both destroyed
+/// and materialized into an elidable copy constructor would have a
+/// construction context of a CXXBindTemporaryExpr with the parent
+/// construction context of a MaterializeTemproraryExpr.
+/// Not all of these are currently supported.
+/// Layers are created gradually while traversing the AST, and layers that
+/// represent the outmost AST nodes are built first, while the node that
+/// immediately contains the constructor would be built last and capture the
+/// previous layers as its parents. Construction context captures the last layer
+/// (which has links to the previous layers) and classifies the seemingly
+/// arbitrary chain of layers into one of the possible ways of constructing
+/// an object in C++ for user-friendly experience.
+class ConstructionContextLayer {
+ const ConstructionContextLayer *Parent = nullptr;
+ ConstructionContextItem Item;
+
+ ConstructionContextLayer(ConstructionContextItem Item,
+ const ConstructionContextLayer *Parent)
+ : Parent(Parent), Item(Item) {}
+
+public:
+ static const ConstructionContextLayer *
+ create(BumpVectorContext &C, const ConstructionContextItem &Item,
+ const ConstructionContextLayer *Parent = nullptr);
+
+ const ConstructionContextItem &getItem() const { return Item; }
+ const ConstructionContextLayer *getParent() const { return Parent; }
+ bool isLast() const { return !Parent; }
+
+ /// See if Other is a proper initial segment of this construction context
+ /// in terms of the parent chain - i.e. a few first parents coincide and
+ /// then the other context terminates but our context goes further - i.e.,
+ /// we are providing the same context that the other context provides,
+ /// and a bit more above that.
+ bool isStrictlyMoreSpecificThan(const ConstructionContextLayer *Other) const;
+};
+
+
+/// ConstructionContext's subclasses describe different ways of constructing
+/// an object in C++. The context re-captures the essential parent AST nodes
+/// of the CXXConstructExpr it is assigned to and presents these nodes
+/// through easy-to-understand accessor methods.
+class ConstructionContext {
+public:
+ enum Kind {
+ SimpleVariableKind,
+ CXX17ElidedCopyVariableKind,
+ VARIABLE_BEGIN = SimpleVariableKind,
+ VARIABLE_END = CXX17ElidedCopyVariableKind,
+ SimpleConstructorInitializerKind,
+ CXX17ElidedCopyConstructorInitializerKind,
+ INITIALIZER_BEGIN = SimpleConstructorInitializerKind,
+ INITIALIZER_END = CXX17ElidedCopyConstructorInitializerKind,
+ NewAllocatedObjectKind,
+ SimpleTemporaryObjectKind,
+ ElidedTemporaryObjectKind,
+ TEMPORARY_BEGIN = SimpleTemporaryObjectKind,
+ TEMPORARY_END = ElidedTemporaryObjectKind,
+ SimpleReturnedValueKind,
+ CXX17ElidedCopyReturnedValueKind,
+ RETURNED_VALUE_BEGIN = SimpleReturnedValueKind,
+ RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind,
+ ArgumentKind
+ };
+
+protected:
+ Kind K;
+
+ // Do not make public! These need to only be constructed
+ // via createFromLayers().
+ explicit ConstructionContext(Kind K) : K(K) {}
+
+private:
+ // A helper function for constructing an instance into a bump vector context.
+ template <typename T, typename... ArgTypes>
+ static T *create(BumpVectorContext &C, ArgTypes... Args) {
+ auto *CC = C.getAllocator().Allocate<T>();
+ return new (CC) T(Args...);
+ }
+
+ // A sub-routine of createFromLayers() that deals with temporary objects
+ // that need to be materialized. The BTE argument is for the situation when
+ // the object also needs to be bound for destruction.
+ static const ConstructionContext *createMaterializedTemporaryFromLayers(
+ BumpVectorContext &C, const MaterializeTemporaryExpr *MTE,
+ const CXXBindTemporaryExpr *BTE,
+ const ConstructionContextLayer *ParentLayer);
+
+ // A sub-routine of createFromLayers() that deals with temporary objects
+ // that need to be bound for destruction. Automatically finds out if the
+ // object also needs to be materialized and delegates to
+ // createMaterializedTemporaryFromLayers() if necessary.
+ static const ConstructionContext *
+ createBoundTemporaryFromLayers(
+ BumpVectorContext &C, const CXXBindTemporaryExpr *BTE,
+ const ConstructionContextLayer *ParentLayer);
+
+public:
+ /// Consume the construction context layer, together with its parent layers,
+ /// and wrap it up into a complete construction context. May return null
+ /// if layers do not form any supported construction context.
+ static const ConstructionContext *
+ createFromLayers(BumpVectorContext &C,
+ const ConstructionContextLayer *TopLayer);
+
+ Kind getKind() const { return K; }
+};
+
+/// An abstract base class for local variable constructors.
+class VariableConstructionContext : public ConstructionContext {
+ const DeclStmt *DS;
+
+protected:
+ VariableConstructionContext(ConstructionContext::Kind K, const DeclStmt *DS)
+ : ConstructionContext(K), DS(DS) {
+ assert(classof(this));
+ assert(DS);
+ }
+
+public:
+ const DeclStmt *getDeclStmt() const { return DS; }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() >= VARIABLE_BEGIN &&
+ CC->getKind() <= VARIABLE_END;
+ }
+};
+
+/// Represents construction into a simple local variable, eg. T var(123);.
+/// If a variable has an initializer, eg. T var = makeT();, then the final
+/// elidable copy-constructor from makeT() into var would also be a simple
+/// variable constructor handled by this class.
+class SimpleVariableConstructionContext : public VariableConstructionContext {
+ friend class ConstructionContext; // Allows to create<>() itself.
+
+ explicit SimpleVariableConstructionContext(const DeclStmt *DS)
+ : VariableConstructionContext(ConstructionContext::SimpleVariableKind,
+ DS) {}
+
+public:
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == SimpleVariableKind;
+ }
+};
+
+/// Represents construction into a simple variable with an initializer syntax,
+/// with a single constructor, eg. T var = makeT();. Such construction context
+/// may only appear in C++17 because previously it was split into a temporary
+/// object constructor and an elidable simple variable copy-constructor and
+/// we were producing separate construction contexts for these constructors.
+/// In C++17 we have a single construction context that combines both.
+/// Note that if the object has trivial destructor, then this code is
+/// indistinguishable from a simple variable constructor on the AST level;
+/// in this case we provide a simple variable construction context.
+class CXX17ElidedCopyVariableConstructionContext
+ : public VariableConstructionContext {
+ const CXXBindTemporaryExpr *BTE;
+
+ friend class ConstructionContext; // Allows to create<>() itself.
+
+ explicit CXX17ElidedCopyVariableConstructionContext(
+ const DeclStmt *DS, const CXXBindTemporaryExpr *BTE)
+ : VariableConstructionContext(CXX17ElidedCopyVariableKind, DS), BTE(BTE) {
+ assert(BTE);
+ }
+
+public:
+ const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == CXX17ElidedCopyVariableKind;
+ }
+};
+
+// An abstract base class for constructor-initializer-based constructors.
+class ConstructorInitializerConstructionContext : public ConstructionContext {
+ const CXXCtorInitializer *I;
+
+protected:
+ explicit ConstructorInitializerConstructionContext(
+ ConstructionContext::Kind K, const CXXCtorInitializer *I)
+ : ConstructionContext(K), I(I) {
+ assert(classof(this));
+ assert(I);
+ }
+
+public:
+ const CXXCtorInitializer *getCXXCtorInitializer() const { return I; }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() >= INITIALIZER_BEGIN &&
+ CC->getKind() <= INITIALIZER_END;
+ }
+};
+
+/// Represents construction into a field or a base class within a bigger object
+/// via a constructor initializer, eg. T(): field(123) { ... }.
+class SimpleConstructorInitializerConstructionContext
+ : public ConstructorInitializerConstructionContext {
+ friend class ConstructionContext; // Allows to create<>() itself.
+
+ explicit SimpleConstructorInitializerConstructionContext(
+ const CXXCtorInitializer *I)
+ : ConstructorInitializerConstructionContext(
+ ConstructionContext::SimpleConstructorInitializerKind, I) {}
+
+public:
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == SimpleConstructorInitializerKind;
+ }
+};
+
+/// Represents construction into a field or a base class within a bigger object
+/// via a constructor initializer, with a single constructor, eg.
+/// T(): field(Field(123)) { ... }. Such construction context may only appear
+/// in C++17 because previously it was split into a temporary object constructor
+/// and an elidable simple constructor-initializer copy-constructor and we were
+/// producing separate construction contexts for these constructors. In C++17
+/// we have a single construction context that combines both. Note that if the
+/// object has trivial destructor, then this code is indistinguishable from
+/// a simple constructor-initializer constructor on the AST level; in this case
+/// we provide a simple constructor-initializer construction context.
+class CXX17ElidedCopyConstructorInitializerConstructionContext
+ : public ConstructorInitializerConstructionContext {
+ const CXXBindTemporaryExpr *BTE;
+
+ friend class ConstructionContext; // Allows to create<>() itself.
+
+ explicit CXX17ElidedCopyConstructorInitializerConstructionContext(
+ const CXXCtorInitializer *I, const CXXBindTemporaryExpr *BTE)
+ : ConstructorInitializerConstructionContext(
+ CXX17ElidedCopyConstructorInitializerKind, I),
+ BTE(BTE) {
+ assert(BTE);
+ }
+
+public:
+ const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == CXX17ElidedCopyConstructorInitializerKind;
+ }
+};
+
+/// Represents immediate initialization of memory allocated by operator new,
+/// eg. new T(123);.
+class NewAllocatedObjectConstructionContext : public ConstructionContext {
+ const CXXNewExpr *NE;
+
+ friend class ConstructionContext; // Allows to create<>() itself.
+
+ explicit NewAllocatedObjectConstructionContext(const CXXNewExpr *NE)
+ : ConstructionContext(ConstructionContext::NewAllocatedObjectKind),
+ NE(NE) {
+ assert(NE);
+ }
+
+public:
+ const CXXNewExpr *getCXXNewExpr() const { return NE; }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == NewAllocatedObjectKind;
+ }
+};
+
+/// Represents a temporary object, eg. T(123), that does not immediately cross
+/// function boundaries "by value"; constructors that construct function
+/// value-type arguments or values that are immediately returned from the
+/// function that returns a value receive separate construction context kinds.
+class TemporaryObjectConstructionContext : public ConstructionContext {
+ const CXXBindTemporaryExpr *BTE;
+ const MaterializeTemporaryExpr *MTE;
+
+protected:
+ explicit TemporaryObjectConstructionContext(
+ ConstructionContext::Kind K, const CXXBindTemporaryExpr *BTE,
+ const MaterializeTemporaryExpr *MTE)
+ : ConstructionContext(K), BTE(BTE), MTE(MTE) {
+ // Both BTE and MTE can be null here, all combinations possible.
+ // Even though for now at least one should be non-null, we simply haven't
+ // implemented the other case yet (this would be a temporary in the middle
+ // of nowhere that doesn't have a non-trivial destructor).
+ }
+
+public:
+ /// CXXBindTemporaryExpr here is non-null as long as the temporary has
+ /// a non-trivial destructor.
+ const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const {
+ return BTE;
+ }
+
+ /// MaterializeTemporaryExpr is non-null as long as the temporary is actually
+ /// used after construction, eg. by binding to a reference (lifetime
+ /// extension), accessing a field, calling a method, or passing it into
+ /// a function (an elidable copy or move constructor would be a common
+ /// example) by reference.
+ const MaterializeTemporaryExpr *getMaterializedTemporaryExpr() const {
+ return MTE;
+ }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() >= TEMPORARY_BEGIN && CC->getKind() <= TEMPORARY_END;
+ }
+};
+
+/// Represents a temporary object that is not constructed for the purpose of
+/// being immediately copied/moved by an elidable copy/move-constructor.
+/// This includes temporary objects "in the middle of nowhere" like T(123) and
+/// lifetime-extended temporaries.
+class SimpleTemporaryObjectConstructionContext
+ : public TemporaryObjectConstructionContext {
+ friend class ConstructionContext; // Allows to create<>() itself.
+
+ explicit SimpleTemporaryObjectConstructionContext(
+ const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr *MTE)
+ : TemporaryObjectConstructionContext(
+ ConstructionContext::SimpleTemporaryObjectKind, BTE, MTE) {}
+
+public:
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == SimpleTemporaryObjectKind;
+ }
+};
+
+/// Represents a temporary object that is constructed for the sole purpose
+/// of being immediately copied by an elidable copy/move constructor.
+/// For example, T t = T(123); includes a temporary T(123) that is immediately
+/// copied to variable t. In such cases the elidable copy can (but not
+/// necessarily should) be omitted ("elided") accodring to the rules of the
+/// language; the constructor would then construct variable t directly.
+/// This construction context contains information of the elidable constructor
+/// and its respective construction context.
+class ElidedTemporaryObjectConstructionContext
+ : public TemporaryObjectConstructionContext {
+ const CXXConstructExpr *ElidedCE;
+ const ConstructionContext *ElidedCC;
+
+ friend class ConstructionContext; // Allows to create<>() itself.
+
+ explicit ElidedTemporaryObjectConstructionContext(
+ const CXXBindTemporaryExpr *BTE, const MaterializeTemporaryExpr *MTE,
+ const CXXConstructExpr *ElidedCE, const ConstructionContext *ElidedCC)
+ : TemporaryObjectConstructionContext(
+ ConstructionContext::ElidedTemporaryObjectKind, BTE, MTE),
+ ElidedCE(ElidedCE), ElidedCC(ElidedCC) {
+ // Elided constructor and its context should be either both specified
+ // or both unspecified. In the former case, the constructor must be
+ // elidable.
+ assert(ElidedCE && ElidedCE->isElidable() && ElidedCC);
+ }
+
+public:
+ const CXXConstructExpr *getConstructorAfterElision() const {
+ return ElidedCE;
+ }
+
+ const ConstructionContext *getConstructionContextAfterElision() const {
+ return ElidedCC;
+ }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == ElidedTemporaryObjectKind;
+ }
+};
+
+class ReturnedValueConstructionContext : public ConstructionContext {
+ const ReturnStmt *RS;
+
+protected:
+ explicit ReturnedValueConstructionContext(ConstructionContext::Kind K,
+ const ReturnStmt *RS)
+ : ConstructionContext(K), RS(RS) {
+ assert(classof(this));
+ assert(RS);
+ }
+
+public:
+ const ReturnStmt *getReturnStmt() const { return RS; }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() >= RETURNED_VALUE_BEGIN &&
+ CC->getKind() <= RETURNED_VALUE_END;
+ }
+};
+
+/// Represents a temporary object that is being immediately returned from a
+/// function by value, eg. return t; or return T(123);. In this case there is
+/// always going to be a constructor at the return site. However, the usual
+/// temporary-related bureaucracy (CXXBindTemporaryExpr,
+/// MaterializeTemporaryExpr) is normally located in the caller function's AST.
+class SimpleReturnedValueConstructionContext
+ : public ReturnedValueConstructionContext {
+ friend class ConstructionContext; // Allows to create<>() itself.
+
+ explicit SimpleReturnedValueConstructionContext(const ReturnStmt *RS)
+ : ReturnedValueConstructionContext(
+ ConstructionContext::SimpleReturnedValueKind, RS) {}
+
+public:
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == SimpleReturnedValueKind;
+ }
+};
+
+/// Represents a temporary object that is being immediately returned from a
+/// function by value, eg. return t; or return T(123); in C++17.
+/// In C++17 there is not going to be an elidable copy constructor at the
+/// return site. However, the usual temporary-related bureaucracy (CXXBindTemporaryExpr,
+/// MaterializeTemporaryExpr) is normally located in the caller function's AST.
+/// Note that if the object has trivial destructor, then this code is
+/// indistinguishable from a simple returned value constructor on the AST level;
+/// in this case we provide a simple returned value construction context.
+class CXX17ElidedCopyReturnedValueConstructionContext
+ : public ReturnedValueConstructionContext {
+ const CXXBindTemporaryExpr *BTE;
+
+ friend class ConstructionContext; // Allows to create<>() itself.
+
+ explicit CXX17ElidedCopyReturnedValueConstructionContext(
+ const ReturnStmt *RS, const CXXBindTemporaryExpr *BTE)
+ : ReturnedValueConstructionContext(
+ ConstructionContext::CXX17ElidedCopyReturnedValueKind, RS),
+ BTE(BTE) {
+ assert(BTE);
+ }
+
+public:
+ const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == CXX17ElidedCopyReturnedValueKind;
+ }
+};
+
+class ArgumentConstructionContext : public ConstructionContext {
+ // The call of which the context is an argument.
+ const Expr *CE;
+
+ // Which argument we're constructing. Note that when numbering between
+ // arguments and parameters is inconsistent (eg., operator calls),
+ // this is the index of the argument, not of the parameter.
+ unsigned Index;
+
+ // Whether the object needs to be destroyed.
+ const CXXBindTemporaryExpr *BTE;
+
+ friend class ConstructionContext; // Allows to create<>() itself.
+
+ explicit ArgumentConstructionContext(const Expr *CE, unsigned Index,
+ const CXXBindTemporaryExpr *BTE)
+ : ConstructionContext(ArgumentKind), CE(CE),
+ Index(Index), BTE(BTE) {
+ assert(isa<CallExpr>(CE) || isa<CXXConstructExpr>(CE) ||
+ isa<ObjCMessageExpr>(CE));
+ // BTE is optional.
+ }
+
+public:
+ const Expr *getCallLikeExpr() const { return CE; }
+ unsigned getIndex() const { return Index; }
+ const CXXBindTemporaryExpr *getCXXBindTemporaryExpr() const { return BTE; }
+
+ static bool classof(const ConstructionContext *CC) {
+ return CC->getKind() == ArgumentKind;
+ }
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H
diff --git a/clang-r353983/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/clang-r353983/include/clang/Analysis/DomainSpecific/CocoaConventions.h
new file mode 100644
index 00000000..8531d177
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/DomainSpecific/CocoaConventions.h
@@ -0,0 +1,41 @@
+//===- CocoaConventions.h - Special handling of Cocoa conventions -*- C++ -*--//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements cocoa naming convention analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_COCOACONVENTIONS_H
+#define LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_COCOACONVENTIONS_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+class FunctionDecl;
+class QualType;
+
+namespace ento {
+namespace cocoa {
+
+ bool isRefType(QualType RetTy, StringRef Prefix,
+ StringRef Name = StringRef());
+
+ bool isCocoaObjectRef(QualType T);
+
+}
+
+namespace coreFoundation {
+ bool isCFObjectRef(QualType T);
+
+ bool followsCreateRule(const FunctionDecl *FD);
+}
+
+}} // end: "clang:ento"
+
+#endif
diff --git a/clang-r353983/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h b/clang-r353983/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h
new file mode 100644
index 00000000..80d7cb8e
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/DomainSpecific/ObjCNoReturn.h
@@ -0,0 +1,45 @@
+//= ObjCNoReturn.h - Handling of Cocoa APIs known not to return --*- C++ -*---//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements special handling of recognizing ObjC API hooks that
+// do not return but aren't marked as such in API headers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_OBJCNORETURN_H
+#define LLVM_CLANG_ANALYSIS_DOMAINSPECIFIC_OBJCNORETURN_H
+
+#include "clang/Basic/IdentifierTable.h"
+
+namespace clang {
+
+class ASTContext;
+class ObjCMessageExpr;
+
+class ObjCNoReturn {
+ /// Cached "raise" selector.
+ Selector RaiseSel;
+
+ /// Cached identifier for "NSException".
+ IdentifierInfo *NSExceptionII;
+
+ enum { NUM_RAISE_SELECTORS = 2 };
+
+ /// Cached set of selectors in NSException that are 'noreturn'.
+ Selector NSExceptionInstanceRaiseSelectors[NUM_RAISE_SELECTORS];
+
+public:
+ ObjCNoReturn(ASTContext &C);
+
+ /// Return true if the given message expression is known to never
+ /// return.
+ bool isImplicitNoReturn(const ObjCMessageExpr *ME);
+};
+}
+
+#endif
diff --git a/clang-r353983/include/clang/Analysis/FlowSensitive/DataflowValues.h b/clang-r353983/include/clang/Analysis/FlowSensitive/DataflowValues.h
new file mode 100644
index 00000000..70975333
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/FlowSensitive/DataflowValues.h
@@ -0,0 +1,171 @@
+//===--- DataflowValues.h - Data structure for dataflow values --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a skeleton data structure for encapsulating the dataflow
+// values for a CFG. Typically this is subclassed to provide methods for
+// computing these values from a CFG.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
+#define LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
+
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "llvm/ADT/DenseMap.h"
+
+//===----------------------------------------------------------------------===//
+/// Dataflow Directional Tag Classes. These are used for tag dispatching
+/// within the dataflow solver/transfer functions to determine what direction
+/// a dataflow analysis flows.
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+namespace dataflow {
+ struct forward_analysis_tag {};
+ struct backward_analysis_tag {};
+} // end namespace dataflow
+
+//===----------------------------------------------------------------------===//
+/// DataflowValues. Container class to store dataflow values for a CFG.
+//===----------------------------------------------------------------------===//
+
+template <typename ValueTypes,
+ typename _AnalysisDirTag = dataflow::forward_analysis_tag >
+class DataflowValues {
+
+ //===--------------------------------------------------------------------===//
+ // Type declarations.
+ //===--------------------------------------------------------------------===//
+
+public:
+ typedef typename ValueTypes::ValTy ValTy;
+ typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy;
+ typedef _AnalysisDirTag AnalysisDirTag;
+ typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy;
+ typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy;
+ typedef llvm::DenseMap<const Stmt*, ValTy> StmtDataMapTy;
+
+ //===--------------------------------------------------------------------===//
+ // Predicates.
+ //===--------------------------------------------------------------------===//
+
+public:
+ /// isForwardAnalysis - Returns true if the dataflow values are computed
+ /// from a forward analysis.
+ bool isForwardAnalysis() { return isForwardAnalysis(AnalysisDirTag()); }
+
+ /// isBackwardAnalysis - Returns true if the dataflow values are computed
+ /// from a backward analysis.
+ bool isBackwardAnalysis() { return !isForwardAnalysis(); }
+
+private:
+ bool isForwardAnalysis(dataflow::forward_analysis_tag) { return true; }
+ bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; }
+
+ //===--------------------------------------------------------------------===//
+ // Initialization and accessors methods.
+ //===--------------------------------------------------------------------===//
+
+public:
+ DataflowValues() : StmtDataMap(NULL) {}
+ ~DataflowValues() { delete StmtDataMap; }
+
+ /// InitializeValues - Invoked by the solver to initialize state needed for
+ /// dataflow analysis. This method is usually specialized by subclasses.
+ void InitializeValues(const CFG& cfg) {}
+
+
+ /// getEdgeData - Retrieves the dataflow values associated with a
+ /// CFG edge.
+ ValTy& getEdgeData(const BlockEdge &E) {
+ typename EdgeDataMapTy::iterator I = EdgeDataMap.find(E);
+ assert (I != EdgeDataMap.end() && "No data associated with Edge.");
+ return I->second;
+ }
+
+ const ValTy& getEdgeData(const BlockEdge &E) const {
+ return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E);
+ }
+
+ /// getBlockData - Retrieves the dataflow values associated with a
+ /// specified CFGBlock. If the dataflow analysis is a forward analysis,
+ /// this data is associated with the END of the block. If the analysis
+ /// is a backwards analysis, it is associated with the ENTRY of the block.
+ ValTy& getBlockData(const CFGBlock *B) {
+ typename BlockDataMapTy::iterator I = BlockDataMap.find(B);
+ assert (I != BlockDataMap.end() && "No data associated with block.");
+ return I->second;
+ }
+
+ const ValTy& getBlockData(const CFGBlock *B) const {
+ return const_cast<DataflowValues*>(this)->getBlockData(B);
+ }
+
+ /// getStmtData - Retrieves the dataflow values associated with a
+ /// specified Stmt. If the dataflow analysis is a forward analysis,
+ /// this data corresponds to the point immediately before a Stmt.
+ /// If the analysis is a backwards analysis, it is associated with
+ /// the point after a Stmt. This data is only computed for block-level
+ /// expressions, and only when requested when the analysis is executed.
+ ValTy& getStmtData(const Stmt *S) {
+ assert (StmtDataMap && "Dataflow values were not computed for statements.");
+ typename StmtDataMapTy::iterator I = StmtDataMap->find(S);
+ assert (I != StmtDataMap->end() && "No data associated with statement.");
+ return I->second;
+ }
+
+ const ValTy& getStmtData(const Stmt *S) const {
+ return const_cast<DataflowValues*>(this)->getStmtData(S);
+ }
+
+ /// getEdgeDataMap - Retrieves the internal map between CFG edges and
+ /// dataflow values. Usually used by a dataflow solver to compute
+ /// values for blocks.
+ EdgeDataMapTy& getEdgeDataMap() { return EdgeDataMap; }
+ const EdgeDataMapTy& getEdgeDataMap() const { return EdgeDataMap; }
+
+ /// getBlockDataMap - Retrieves the internal map between CFGBlocks and
+ /// dataflow values. If the dataflow analysis operates in the forward
+ /// direction, the values correspond to the dataflow values at the start
+ /// of the block. Otherwise, for a backward analysis, the values correpsond
+ /// to the dataflow values at the end of the block.
+ BlockDataMapTy& getBlockDataMap() { return BlockDataMap; }
+ const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; }
+
+ /// getStmtDataMap - Retrieves the internal map between Stmts and
+ /// dataflow values.
+ StmtDataMapTy& getStmtDataMap() {
+ if (!StmtDataMap) StmtDataMap = new StmtDataMapTy();
+ return *StmtDataMap;
+ }
+
+ const StmtDataMapTy& getStmtDataMap() const {
+ return const_cast<DataflowValues*>(this)->getStmtDataMap();
+ }
+
+ /// getAnalysisData - Retrieves the meta data associated with a
+ /// dataflow analysis for analyzing a particular CFG.
+ /// This is typically consumed by transfer function code (via the solver).
+ /// This can also be used by subclasses to interpret the dataflow values.
+ AnalysisDataTy& getAnalysisData() { return AnalysisData; }
+ const AnalysisDataTy& getAnalysisData() const { return AnalysisData; }
+
+ //===--------------------------------------------------------------------===//
+ // Internal data.
+ //===--------------------------------------------------------------------===//
+
+protected:
+ EdgeDataMapTy EdgeDataMap;
+ BlockDataMapTy BlockDataMap;
+ StmtDataMapTy* StmtDataMap;
+ AnalysisDataTy AnalysisData;
+};
+
+} // end namespace clang
+#endif
diff --git a/clang-r353983/include/clang/Analysis/ProgramPoint.h b/clang-r353983/include/clang/Analysis/ProgramPoint.h
new file mode 100644
index 00000000..623f5dc7
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/ProgramPoint.h
@@ -0,0 +1,782 @@
+//==- ProgramPoint.h - Program Points for Path-Sensitive Analysis --*- C++ -*-//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the interface ProgramPoint, which identifies a
+// distinct location in a function.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H
+#define LLVM_CLANG_ANALYSIS_PROGRAMPOINT_H
+
+#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Analysis/CFG.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/DataTypes.h"
+#include <cassert>
+#include <string>
+#include <utility>
+
+namespace clang {
+
+class AnalysisDeclContext;
+class FunctionDecl;
+class LocationContext;
+
+/// ProgramPoints can be "tagged" as representing points specific to a given
+/// analysis entity. Tags are abstract annotations, with an associated
+/// description and potentially other information.
+class ProgramPointTag {
+public:
+ ProgramPointTag(void *tagKind = nullptr) : TagKind(tagKind) {}
+ virtual ~ProgramPointTag();
+ virtual StringRef getTagDescription() const = 0;
+
+protected:
+ /// Used to implement 'isKind' in subclasses.
+ const void *getTagKind() { return TagKind; }
+
+private:
+ const void *TagKind;
+};
+
+class SimpleProgramPointTag : public ProgramPointTag {
+ std::string Desc;
+public:
+ SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg);
+ StringRef getTagDescription() const override;
+};
+
+class ProgramPoint {
+public:
+ enum Kind { BlockEdgeKind,
+ BlockEntranceKind,
+ BlockExitKind,
+ PreStmtKind,
+ PreStmtPurgeDeadSymbolsKind,
+ PostStmtPurgeDeadSymbolsKind,
+ PostStmtKind,
+ PreLoadKind,
+ PostLoadKind,
+ PreStoreKind,
+ PostStoreKind,
+ PostConditionKind,
+ PostLValueKind,
+ PostAllocatorCallKind,
+ MinPostStmtKind = PostStmtKind,
+ MaxPostStmtKind = PostAllocatorCallKind,
+ PostInitializerKind,
+ CallEnterKind,
+ CallExitBeginKind,
+ CallExitEndKind,
+ FunctionExitKind,
+ PreImplicitCallKind,
+ PostImplicitCallKind,
+ MinImplicitCallKind = PreImplicitCallKind,
+ MaxImplicitCallKind = PostImplicitCallKind,
+ LoopExitKind,
+ EpsilonKind};
+
+private:
+ const void *Data1;
+ llvm::PointerIntPair<const void *, 2, unsigned> Data2;
+
+ // The LocationContext could be NULL to allow ProgramPoint to be used in
+ // context insensitive analysis.
+ llvm::PointerIntPair<const LocationContext *, 2, unsigned> L;
+
+ llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag;
+
+protected:
+ ProgramPoint() = default;
+ ProgramPoint(const void *P,
+ Kind k,
+ const LocationContext *l,
+ const ProgramPointTag *tag = nullptr)
+ : Data1(P),
+ Data2(nullptr, (((unsigned) k) >> 0) & 0x3),
+ L(l, (((unsigned) k) >> 2) & 0x3),
+ Tag(tag, (((unsigned) k) >> 4) & 0x3) {
+ assert(getKind() == k);
+ assert(getLocationContext() == l);
+ assert(getData1() == P);
+ }
+
+ ProgramPoint(const void *P1,
+ const void *P2,
+ Kind k,
+ const LocationContext *l,
+ const ProgramPointTag *tag = nullptr)
+ : Data1(P1),
+ Data2(P2, (((unsigned) k) >> 0) & 0x3),
+ L(l, (((unsigned) k) >> 2) & 0x3),
+ Tag(tag, (((unsigned) k) >> 4) & 0x3) {}
+
+protected:
+ const void *getData1() const { return Data1; }
+ const void *getData2() const { return Data2.getPointer(); }
+ void setData2(const void *d) { Data2.setPointer(d); }
+
+public:
+ /// Create a new ProgramPoint object that is the same as the original
+ /// except for using the specified tag value.
+ ProgramPoint withTag(const ProgramPointTag *tag) const {
+ return ProgramPoint(getData1(), getData2(), getKind(),
+ getLocationContext(), tag);
+ }
+
+ /// Convert to the specified ProgramPoint type, asserting that this
+ /// ProgramPoint is of the desired type.
+ template<typename T>
+ T castAs() const {
+ assert(T::isKind(*this));
+ T t;
+ ProgramPoint& PP = t;
+ PP = *this;
+ return t;
+ }
+
+ /// Convert to the specified ProgramPoint type, returning None if this
+ /// ProgramPoint is not of the desired type.
+ template<typename T>
+ Optional<T> getAs() const {
+ if (!T::isKind(*this))
+ return None;
+ T t;
+ ProgramPoint& PP = t;
+ PP = *this;
+ return t;
+ }
+
+ Kind getKind() const {
+ unsigned x = Tag.getInt();
+ x <<= 2;
+ x |= L.getInt();
+ x <<= 2;
+ x |= Data2.getInt();
+ return (Kind) x;
+ }
+
+ /// Is this a program point corresponding to purge/removal of dead
+ /// symbols and bindings.
+ bool isPurgeKind() {
+ Kind K = getKind();
+ return (K == PostStmtPurgeDeadSymbolsKind ||
+ K == PreStmtPurgeDeadSymbolsKind);
+ }
+
+ const ProgramPointTag *getTag() const { return Tag.getPointer(); }
+
+ const LocationContext *getLocationContext() const {
+ return L.getPointer();
+ }
+
+ const StackFrameContext *getStackFrame() const {
+ return getLocationContext()->getStackFrame();
+ }
+
+ // For use with DenseMap. This hash is probably slow.
+ unsigned getHashValue() const {
+ llvm::FoldingSetNodeID ID;
+ Profile(ID);
+ return ID.ComputeHash();
+ }
+
+ bool operator==(const ProgramPoint & RHS) const {
+ return Data1 == RHS.Data1 &&
+ Data2 == RHS.Data2 &&
+ L == RHS.L &&
+ Tag == RHS.Tag;
+ }
+
+ bool operator!=(const ProgramPoint &RHS) const {
+ return Data1 != RHS.Data1 ||
+ Data2 != RHS.Data2 ||
+ L != RHS.L ||
+ Tag != RHS.Tag;
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddInteger((unsigned) getKind());
+ ID.AddPointer(getData1());
+ ID.AddPointer(getData2());
+ ID.AddPointer(getLocationContext());
+ ID.AddPointer(getTag());
+ }
+
+ void print(StringRef CR, llvm::raw_ostream &Out) const;
+
+ LLVM_DUMP_METHOD void dump() const;
+
+ static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
+ const LocationContext *LC,
+ const ProgramPointTag *tag);
+};
+
+class BlockEntrance : public ProgramPoint {
+public:
+ BlockEntrance(const CFGBlock *B, const LocationContext *L,
+ const ProgramPointTag *tag = nullptr)
+ : ProgramPoint(B, BlockEntranceKind, L, tag) {
+ assert(B && "BlockEntrance requires non-null block");
+ }
+
+ const CFGBlock *getBlock() const {
+ return reinterpret_cast<const CFGBlock*>(getData1());
+ }
+
+ Optional<CFGElement> getFirstElement() const {
+ const CFGBlock *B = getBlock();
+ return B->empty() ? Optional<CFGElement>() : B->front();
+ }
+
+private:
+ friend class ProgramPoint;
+ BlockEntrance() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == BlockEntranceKind;
+ }
+};
+
+class BlockExit : public ProgramPoint {
+public:
+ BlockExit(const CFGBlock *B, const LocationContext *L)
+ : ProgramPoint(B, BlockExitKind, L) {}
+
+ const CFGBlock *getBlock() const {
+ return reinterpret_cast<const CFGBlock*>(getData1());
+ }
+
+ const Stmt *getTerminator() const {
+ return getBlock()->getTerminator();
+ }
+
+private:
+ friend class ProgramPoint;
+ BlockExit() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == BlockExitKind;
+ }
+};
+
+class StmtPoint : public ProgramPoint {
+public:
+ StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L,
+ const ProgramPointTag *tag)
+ : ProgramPoint(S, p2, k, L, tag) {
+ assert(S);
+ }
+
+ const Stmt *getStmt() const { return (const Stmt*) getData1(); }
+
+ template <typename T>
+ const T* getStmtAs() const { return dyn_cast<T>(getStmt()); }
+
+protected:
+ StmtPoint() = default;
+private:
+ friend class ProgramPoint;
+ static bool isKind(const ProgramPoint &Location) {
+ unsigned k = Location.getKind();
+ return k >= PreStmtKind && k <= MaxPostStmtKind;
+ }
+};
+
+
+class PreStmt : public StmtPoint {
+public:
+ PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag,
+ const Stmt *SubStmt = nullptr)
+ : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {}
+
+ const Stmt *getSubStmt() const { return (const Stmt*) getData2(); }
+
+private:
+ friend class ProgramPoint;
+ PreStmt() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PreStmtKind;
+ }
+};
+
+class PostStmt : public StmtPoint {
+protected:
+ PostStmt() = default;
+ PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L,
+ const ProgramPointTag *tag = nullptr)
+ : StmtPoint(S, data, k, L, tag) {}
+
+public:
+ explicit PostStmt(const Stmt *S, Kind k, const LocationContext *L,
+ const ProgramPointTag *tag = nullptr)
+ : StmtPoint(S, nullptr, k, L, tag) {}
+
+ explicit PostStmt(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = nullptr)
+ : StmtPoint(S, nullptr, PostStmtKind, L, tag) {}
+
+private:
+ friend class ProgramPoint;
+ static bool isKind(const ProgramPoint &Location) {
+ unsigned k = Location.getKind();
+ return k >= MinPostStmtKind && k <= MaxPostStmtKind;
+ }
+};
+
+class FunctionExitPoint : public ProgramPoint {
+public:
+ explicit FunctionExitPoint(const ReturnStmt *S,
+ const LocationContext *LC,
+ const ProgramPointTag *tag = nullptr)
+ : ProgramPoint(S, FunctionExitKind, LC, tag) {}
+
+ const CFGBlock *getBlock() const {
+ return &getLocationContext()->getCFG()->getExit();
+ }
+
+ const ReturnStmt *getStmt() const {
+ return reinterpret_cast<const ReturnStmt *>(getData1());
+ }
+
+private:
+ friend class ProgramPoint;
+ FunctionExitPoint() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == FunctionExitKind;
+ }
+};
+
+// PostCondition represents the post program point of a branch condition.
+class PostCondition : public PostStmt {
+public:
+ PostCondition(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = nullptr)
+ : PostStmt(S, PostConditionKind, L, tag) {}
+
+private:
+ friend class ProgramPoint;
+ PostCondition() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostConditionKind;
+ }
+};
+
+class LocationCheck : public StmtPoint {
+protected:
+ LocationCheck() = default;
+ LocationCheck(const Stmt *S, const LocationContext *L,
+ ProgramPoint::Kind K, const ProgramPointTag *tag)
+ : StmtPoint(S, nullptr, K, L, tag) {}
+
+private:
+ friend class ProgramPoint;
+ static bool isKind(const ProgramPoint &location) {
+ unsigned k = location.getKind();
+ return k == PreLoadKind || k == PreStoreKind;
+ }
+};
+
+class PreLoad : public LocationCheck {
+public:
+ PreLoad(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = nullptr)
+ : LocationCheck(S, L, PreLoadKind, tag) {}
+
+private:
+ friend class ProgramPoint;
+ PreLoad() = default;
+ static bool isKind(const ProgramPoint &location) {
+ return location.getKind() == PreLoadKind;
+ }
+};
+
+class PreStore : public LocationCheck {
+public:
+ PreStore(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = nullptr)
+ : LocationCheck(S, L, PreStoreKind, tag) {}
+
+private:
+ friend class ProgramPoint;
+ PreStore() = default;
+ static bool isKind(const ProgramPoint &location) {
+ return location.getKind() == PreStoreKind;
+ }
+};
+
+class PostLoad : public PostStmt {
+public:
+ PostLoad(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = nullptr)
+ : PostStmt(S, PostLoadKind, L, tag) {}
+
+private:
+ friend class ProgramPoint;
+ PostLoad() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostLoadKind;
+ }
+};
+
+/// Represents a program point after a store evaluation.
+class PostStore : public PostStmt {
+public:
+ /// Construct the post store point.
+ /// \param Loc can be used to store the information about the location
+ /// used in the form it was uttered in the code.
+ PostStore(const Stmt *S, const LocationContext *L, const void *Loc,
+ const ProgramPointTag *tag = nullptr)
+ : PostStmt(S, PostStoreKind, L, tag) {
+ assert(getData2() == nullptr);
+ setData2(Loc);
+ }
+
+ /// Returns the information about the location used in the store,
+ /// how it was uttered in the code.
+ const void *getLocationValue() const {
+ return getData2();
+ }
+
+private:
+ friend class ProgramPoint;
+ PostStore() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostStoreKind;
+ }
+};
+
+class PostLValue : public PostStmt {
+public:
+ PostLValue(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = nullptr)
+ : PostStmt(S, PostLValueKind, L, tag) {}
+
+private:
+ friend class ProgramPoint;
+ PostLValue() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostLValueKind;
+ }
+};
+
+/// Represents a point after we ran remove dead bindings BEFORE
+/// processing the given statement.
+class PreStmtPurgeDeadSymbols : public StmtPoint {
+public:
+ PreStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = nullptr)
+ : StmtPoint(S, nullptr, PreStmtPurgeDeadSymbolsKind, L, tag) { }
+
+private:
+ friend class ProgramPoint;
+ PreStmtPurgeDeadSymbols() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PreStmtPurgeDeadSymbolsKind;
+ }
+};
+
+/// Represents a point after we ran remove dead bindings AFTER
+/// processing the given statement.
+class PostStmtPurgeDeadSymbols : public StmtPoint {
+public:
+ PostStmtPurgeDeadSymbols(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *tag = nullptr)
+ : StmtPoint(S, nullptr, PostStmtPurgeDeadSymbolsKind, L, tag) { }
+
+private:
+ friend class ProgramPoint;
+ PostStmtPurgeDeadSymbols() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostStmtPurgeDeadSymbolsKind;
+ }
+};
+
+class BlockEdge : public ProgramPoint {
+public:
+ BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L)
+ : ProgramPoint(B1, B2, BlockEdgeKind, L) {
+ assert(B1 && "BlockEdge: source block must be non-null");
+ assert(B2 && "BlockEdge: destination block must be non-null");
+ }
+
+ const CFGBlock *getSrc() const {
+ return static_cast<const CFGBlock*>(getData1());
+ }
+
+ const CFGBlock *getDst() const {
+ return static_cast<const CFGBlock*>(getData2());
+ }
+
+private:
+ friend class ProgramPoint;
+ BlockEdge() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == BlockEdgeKind;
+ }
+};
+
+class PostInitializer : public ProgramPoint {
+public:
+ /// Construct a PostInitializer point that represents a location after
+ /// CXXCtorInitializer expression evaluation.
+ ///
+ /// \param I The initializer.
+ /// \param Loc The location of the field being initialized.
+ PostInitializer(const CXXCtorInitializer *I,
+ const void *Loc,
+ const LocationContext *L)
+ : ProgramPoint(I, Loc, PostInitializerKind, L) {}
+
+ const CXXCtorInitializer *getInitializer() const {
+ return static_cast<const CXXCtorInitializer *>(getData1());
+ }
+
+ /// Returns the location of the field.
+ const void *getLocationValue() const {
+ return getData2();
+ }
+
+private:
+ friend class ProgramPoint;
+ PostInitializer() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostInitializerKind;
+ }
+};
+
+/// Represents an implicit call event.
+///
+/// The nearest statement is provided for diagnostic purposes.
+class ImplicitCallPoint : public ProgramPoint {
+public:
+ ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K,
+ const LocationContext *L, const ProgramPointTag *Tag)
+ : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {}
+
+ const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); }
+ SourceLocation getLocation() const {
+ return SourceLocation::getFromPtrEncoding(getData1());
+ }
+
+protected:
+ ImplicitCallPoint() = default;
+private:
+ friend class ProgramPoint;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() >= MinImplicitCallKind &&
+ Location.getKind() <= MaxImplicitCallKind;
+ }
+};
+
+/// Represents a program point just before an implicit call event.
+///
+/// Explicit calls will appear as PreStmt program points.
+class PreImplicitCall : public ImplicitCallPoint {
+public:
+ PreImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L,
+ const ProgramPointTag *Tag = nullptr)
+ : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {}
+
+private:
+ friend class ProgramPoint;
+ PreImplicitCall() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PreImplicitCallKind;
+ }
+};
+
+/// Represents a program point just after an implicit call event.
+///
+/// Explicit calls will appear as PostStmt program points.
+class PostImplicitCall : public ImplicitCallPoint {
+public:
+ PostImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L,
+ const ProgramPointTag *Tag = nullptr)
+ : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {}
+
+private:
+ friend class ProgramPoint;
+ PostImplicitCall() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostImplicitCallKind;
+ }
+};
+
+class PostAllocatorCall : public StmtPoint {
+public:
+ PostAllocatorCall(const Stmt *S, const LocationContext *L,
+ const ProgramPointTag *Tag = nullptr)
+ : StmtPoint(S, nullptr, PostAllocatorCallKind, L, Tag) {}
+
+private:
+ friend class ProgramPoint;
+ PostAllocatorCall() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostAllocatorCallKind;
+ }
+};
+
+/// Represents a point when we begin processing an inlined call.
+/// CallEnter uses the caller's location context.
+class CallEnter : public ProgramPoint {
+public:
+ CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx,
+ const LocationContext *callerCtx)
+ : ProgramPoint(stmt, calleeCtx, CallEnterKind, callerCtx, nullptr) {}
+
+ const Stmt *getCallExpr() const {
+ return static_cast<const Stmt *>(getData1());
+ }
+
+ const StackFrameContext *getCalleeContext() const {
+ return static_cast<const StackFrameContext *>(getData2());
+ }
+
+ /// Returns the entry block in the CFG for the entered function.
+ const CFGBlock *getEntry() const {
+ const StackFrameContext *CalleeCtx = getCalleeContext();
+ const CFG *CalleeCFG = CalleeCtx->getCFG();
+ return &(CalleeCFG->getEntry());
+ }
+
+private:
+ friend class ProgramPoint;
+ CallEnter() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == CallEnterKind;
+ }
+};
+
+/// Represents a point when we start the call exit sequence (for inlined call).
+///
+/// The call exit is simulated with a sequence of nodes, which occur between
+/// CallExitBegin and CallExitEnd. The following operations occur between the
+/// two program points:
+/// - CallExitBegin
+/// - Bind the return value
+/// - Run Remove dead bindings (to clean up the dead symbols from the callee).
+/// - CallExitEnd
+class CallExitBegin : public ProgramPoint {
+public:
+ // CallExitBegin uses the callee's location context.
+ CallExitBegin(const StackFrameContext *L, const ReturnStmt *RS)
+ : ProgramPoint(RS, CallExitBeginKind, L, nullptr) { }
+
+ const ReturnStmt *getReturnStmt() const {
+ return static_cast<const ReturnStmt *>(getData1());
+ }
+
+private:
+ friend class ProgramPoint;
+ CallExitBegin() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == CallExitBeginKind;
+ }
+};
+
+/// Represents a point when we finish the call exit sequence (for inlined call).
+/// \sa CallExitBegin
+class CallExitEnd : public ProgramPoint {
+public:
+ // CallExitEnd uses the caller's location context.
+ CallExitEnd(const StackFrameContext *CalleeCtx,
+ const LocationContext *CallerCtx)
+ : ProgramPoint(CalleeCtx, CallExitEndKind, CallerCtx, nullptr) {}
+
+ const StackFrameContext *getCalleeContext() const {
+ return static_cast<const StackFrameContext *>(getData1());
+ }
+
+private:
+ friend class ProgramPoint;
+ CallExitEnd() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == CallExitEndKind;
+ }
+};
+
+/// Represents a point when we exit a loop.
+/// When this ProgramPoint is encountered we can be sure that the symbolic
+/// execution of the corresponding LoopStmt is finished on the given path.
+/// Note: It is possible to encounter a LoopExit element when we haven't even
+/// encountered the loop itself. At the current state not all loop exits will
+/// result in a LoopExit program point.
+class LoopExit : public ProgramPoint {
+public:
+ LoopExit(const Stmt *LoopStmt, const LocationContext *LC)
+ : ProgramPoint(LoopStmt, nullptr, LoopExitKind, LC) {}
+
+ const Stmt *getLoopStmt() const {
+ return static_cast<const Stmt *>(getData1());
+ }
+
+private:
+ friend class ProgramPoint;
+ LoopExit() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == LoopExitKind;
+ }
+};
+
+/// This is a meta program point, which should be skipped by all the diagnostic
+/// reasoning etc.
+class EpsilonPoint : public ProgramPoint {
+public:
+ EpsilonPoint(const LocationContext *L, const void *Data1,
+ const void *Data2 = nullptr,
+ const ProgramPointTag *tag = nullptr)
+ : ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {}
+
+ const void *getData() const { return getData1(); }
+
+private:
+ friend class ProgramPoint;
+ EpsilonPoint() = default;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == EpsilonKind;
+ }
+};
+
+} // end namespace clang
+
+
+namespace llvm { // Traits specialization for DenseMap
+
+template <> struct DenseMapInfo<clang::ProgramPoint> {
+
+static inline clang::ProgramPoint getEmptyKey() {
+ uintptr_t x =
+ reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7;
+ return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), nullptr);
+}
+
+static inline clang::ProgramPoint getTombstoneKey() {
+ uintptr_t x =
+ reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7;
+ return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), nullptr);
+}
+
+static unsigned getHashValue(const clang::ProgramPoint &Loc) {
+ return Loc.getHashValue();
+}
+
+static bool isEqual(const clang::ProgramPoint &L,
+ const clang::ProgramPoint &R) {
+ return L == R;
+}
+
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/clang-r353983/include/clang/Analysis/RetainSummaryManager.h b/clang-r353983/include/clang/Analysis/RetainSummaryManager.h
new file mode 100644
index 00000000..6acefb56
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/RetainSummaryManager.h
@@ -0,0 +1,767 @@
+//=== RetainSummaryManager.h - Summaries for reference counting ---*- C++ -*--//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines summaries implementation for retain counting, which
+// implements a reference count checker for Core Foundation and Cocoa
+// on (Mac OS X).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_RETAINSUMMARY_MANAGER_H
+#define LLVM_CLANG_ANALYSIS_RETAINSUMMARY_MANAGER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/AnyCall.h"
+#include "clang/Analysis/SelectorExtras.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace clang;
+
+namespace clang {
+namespace ento {
+
+/// Determines the object kind of a tracked object.
+enum class ObjKind {
+ /// Indicates that the tracked object is a CF object.
+ CF,
+
+ /// Indicates that the tracked object is an Objective-C object.
+ ObjC,
+
+ /// Indicates that the tracked object could be a CF or Objective-C object.
+ AnyObj,
+
+ /// Indicates that the tracked object is a generalized object.
+ Generalized,
+
+ /// Indicates that the tracking object is a descendant of a
+ /// referenced-counted OSObject, used in the Darwin kernel.
+ OS
+};
+
+enum ArgEffectKind {
+ /// There is no effect.
+ DoNothing,
+
+ /// The argument is treated as if an -autorelease message had been sent to
+ /// the referenced object.
+ Autorelease,
+
+ /// The argument is treated as if the referenced object was deallocated.
+ Dealloc,
+
+ /// The argument has its reference count decreased by 1.
+ DecRef,
+
+ /// The argument has its reference count decreased by 1 to model
+ /// a transferred bridge cast under ARC.
+ DecRefBridgedTransferred,
+
+ /// The argument has its reference count increased by 1.
+ IncRef,
+
+ /// The argument is a pointer to a retain-counted object; on exit, the new
+ /// value of the pointer is a +0 value.
+ UnretainedOutParameter,
+
+ /// The argument is a pointer to a retain-counted object; on exit, the new
+ /// value of the pointer is a +1 value.
+ RetainedOutParameter,
+
+ /// The argument is a pointer to a retain-counted object; on exit, the new
+ /// value of the pointer is a +1 value iff the return code is zero.
+ RetainedOutParameterOnZero,
+
+ /// The argument is a pointer to a retain-counted object; on exit, the new
+ /// value of the pointer is a +1 value iff the return code is non-zero.
+ RetainedOutParameterOnNonZero,
+
+ /// The argument is treated as potentially escaping, meaning that
+ /// even when its reference count hits 0 it should be treated as still
+ /// possibly being alive as someone else *may* be holding onto the object.
+ MayEscape,
+
+ /// All typestate tracking of the object ceases. This is usually employed
+ /// when the effect of the call is completely unknown.
+ StopTracking,
+
+ /// All typestate tracking of the object ceases. Unlike StopTracking,
+ /// this is also enforced when the method body is inlined.
+ ///
+ /// In some cases, we obtain a better summary for this checker
+ /// by looking at the call site than by inlining the function.
+ /// Signifies that we should stop tracking the symbol even if
+ /// the function is inlined.
+ StopTrackingHard,
+
+ /// Performs the combined functionality of DecRef and StopTrackingHard.
+ ///
+ /// The models the effect that the called function decrements the reference
+ /// count of the argument and all typestate tracking on that argument
+ /// should cease.
+ DecRefAndStopTrackingHard,
+};
+
+/// An ArgEffect summarizes the retain count behavior on an argument or receiver
+/// to a function or method.
+class ArgEffect {
+ ArgEffectKind K;
+ ObjKind O;
+public:
+ explicit ArgEffect(ArgEffectKind K = DoNothing, ObjKind O = ObjKind::AnyObj)
+ : K(K), O(O) {}
+
+ ArgEffectKind getKind() const { return K; }
+ ObjKind getObjKind() const { return O; }
+
+ ArgEffect withKind(ArgEffectKind NewK) {
+ return ArgEffect(NewK, O);
+ }
+
+ bool operator==(const ArgEffect &Other) const {
+ return K == Other.K && O == Other.O;
+ }
+};
+
+/// RetEffect summarizes a call's retain/release behavior with respect
+/// to its return value.
+class RetEffect {
+public:
+ enum Kind {
+ /// Indicates that no retain count information is tracked for
+ /// the return value.
+ NoRet,
+
+ /// Indicates that the returned value is an owned (+1) symbol.
+ OwnedSymbol,
+
+ /// Indicates that the returned value is an object with retain count
+ /// semantics but that it is not owned (+0). This is the default
+ /// for getters, etc.
+ NotOwnedSymbol,
+
+ /// Indicates that the return value is an owned object when the
+ /// receiver is also a tracked object.
+ OwnedWhenTrackedReceiver,
+
+ // Treat this function as returning a non-tracked symbol even if
+ // the function has been inlined. This is used where the call
+ // site summary is more precise than the summary indirectly produced
+ // by inlining the function
+ NoRetHard
+ };
+
+private:
+ Kind K;
+ ObjKind O;
+
+ RetEffect(Kind k, ObjKind o = ObjKind::AnyObj) : K(k), O(o) {}
+
+public:
+ Kind getKind() const { return K; }
+
+ ObjKind getObjKind() const { return O; }
+
+ bool isOwned() const {
+ return K == OwnedSymbol || K == OwnedWhenTrackedReceiver;
+ }
+
+ bool notOwned() const {
+ return K == NotOwnedSymbol;
+ }
+
+ bool operator==(const RetEffect &Other) const {
+ return K == Other.K && O == Other.O;
+ }
+
+ static RetEffect MakeOwnedWhenTrackedReceiver() {
+ return RetEffect(OwnedWhenTrackedReceiver, ObjKind::ObjC);
+ }
+
+ static RetEffect MakeOwned(ObjKind o) {
+ return RetEffect(OwnedSymbol, o);
+ }
+ static RetEffect MakeNotOwned(ObjKind o) {
+ return RetEffect(NotOwnedSymbol, o);
+ }
+ static RetEffect MakeNoRet() {
+ return RetEffect(NoRet);
+ }
+ static RetEffect MakeNoRetHard() {
+ return RetEffect(NoRetHard);
+ }
+};
+
+/// A key identifying a summary.
+class ObjCSummaryKey {
+ IdentifierInfo* II;
+ Selector S;
+public:
+ ObjCSummaryKey(IdentifierInfo* ii, Selector s)
+ : II(ii), S(s) {}
+
+ ObjCSummaryKey(const ObjCInterfaceDecl *d, Selector s)
+ : II(d ? d->getIdentifier() : nullptr), S(s) {}
+
+ ObjCSummaryKey(Selector s)
+ : II(nullptr), S(s) {}
+
+ IdentifierInfo *getIdentifier() const { return II; }
+ Selector getSelector() const { return S; }
+};
+
+} // end namespace ento
+} // end namespace clang
+
+using namespace ento;
+
+namespace llvm {
+
+//===----------------------------------------------------------------------===//
+// Adapters for FoldingSet.
+//===----------------------------------------------------------------------===//
+template <> struct FoldingSetTrait<ArgEffect> {
+static inline void Profile(const ArgEffect X, FoldingSetNodeID &ID) {
+ ID.AddInteger((unsigned) X.getKind());
+ ID.AddInteger((unsigned) X.getObjKind());
+}
+};
+template <> struct FoldingSetTrait<RetEffect> {
+ static inline void Profile(const RetEffect &X, FoldingSetNodeID &ID) {
+ ID.AddInteger((unsigned) X.getKind());
+ ID.AddInteger((unsigned) X.getObjKind());
+}
+};
+
+template <> struct DenseMapInfo<ObjCSummaryKey> {
+ static inline ObjCSummaryKey getEmptyKey() {
+ return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getEmptyKey(),
+ DenseMapInfo<Selector>::getEmptyKey());
+ }
+
+ static inline ObjCSummaryKey getTombstoneKey() {
+ return ObjCSummaryKey(DenseMapInfo<IdentifierInfo*>::getTombstoneKey(),
+ DenseMapInfo<Selector>::getTombstoneKey());
+ }
+
+ static unsigned getHashValue(const ObjCSummaryKey &V) {
+ typedef std::pair<IdentifierInfo*, Selector> PairTy;
+ return DenseMapInfo<PairTy>::getHashValue(PairTy(V.getIdentifier(),
+ V.getSelector()));
+ }
+
+ static bool isEqual(const ObjCSummaryKey& LHS, const ObjCSummaryKey& RHS) {
+ return LHS.getIdentifier() == RHS.getIdentifier() &&
+ LHS.getSelector() == RHS.getSelector();
+ }
+
+};
+
+} // end llvm namespace
+
+
+namespace clang {
+namespace ento {
+
+/// ArgEffects summarizes the effects of a function/method call on all of
+/// its arguments.
+typedef llvm::ImmutableMap<unsigned, ArgEffect> ArgEffects;
+
+/// Summary for a function with respect to ownership changes.
+class RetainSummary {
+ /// Args - a map of (index, ArgEffect) pairs, where index
+ /// specifies the argument (starting from 0). This can be sparsely
+ /// populated; arguments with no entry in Args use 'DefaultArgEffect'.
+ ArgEffects Args;
+
+ /// DefaultArgEffect - The default ArgEffect to apply to arguments that
+ /// do not have an entry in Args.
+ ArgEffect DefaultArgEffect;
+
+ /// Receiver - If this summary applies to an Objective-C message expression,
+ /// this is the effect applied to the state of the receiver.
+ ArgEffect Receiver;
+
+ /// Effect on "this" pointer - applicable only to C++ method calls.
+ ArgEffect This;
+
+ /// Ret - The effect on the return value. Used to indicate if the
+ /// function/method call returns a new tracked symbol.
+ RetEffect Ret;
+
+public:
+ RetainSummary(ArgEffects A,
+ RetEffect R,
+ ArgEffect defaultEff,
+ ArgEffect ReceiverEff,
+ ArgEffect ThisEff)
+ : Args(A), DefaultArgEffect(defaultEff), Receiver(ReceiverEff),
+ This(ThisEff), Ret(R) {}
+
+ /// getArg - Return the argument effect on the argument specified by
+ /// idx (starting from 0).
+ ArgEffect getArg(unsigned idx) const {
+ if (const ArgEffect *AE = Args.lookup(idx))
+ return *AE;
+
+ return DefaultArgEffect;
+ }
+
+ void addArg(ArgEffects::Factory &af, unsigned idx, ArgEffect e) {
+ Args = af.add(Args, idx, e);
+ }
+
+ /// setDefaultArgEffect - Set the default argument effect.
+ void setDefaultArgEffect(ArgEffect E) {
+ DefaultArgEffect = E;
+ }
+
+ /// getRetEffect - Returns the effect on the return value of the call.
+ RetEffect getRetEffect() const { return Ret; }
+
+ /// setRetEffect - Set the effect of the return value of the call.
+ void setRetEffect(RetEffect E) { Ret = E; }
+
+
+ /// Sets the effect on the receiver of the message.
+ void setReceiverEffect(ArgEffect e) { Receiver = e; }
+
+ /// getReceiverEffect - Returns the effect on the receiver of the call.
+ /// This is only meaningful if the summary applies to an ObjCMessageExpr*.
+ ArgEffect getReceiverEffect() const { return Receiver; }
+
+ /// \return the effect on the "this" receiver of the method call.
+ /// This is only meaningful if the summary applies to CXXMethodDecl*.
+ ArgEffect getThisEffect() const { return This; }
+
+ ArgEffect getDefaultEffect() const { return DefaultArgEffect; }
+
+ /// Set the effect of the method on "this".
+ void setThisEffect(ArgEffect e) { This = e; }
+
+ bool isNoop() const {
+ return Ret == RetEffect::MakeNoRet() && Receiver.getKind() == DoNothing
+ && DefaultArgEffect.getKind() == MayEscape && This.getKind() == DoNothing
+ && Args.isEmpty();
+ }
+
+ /// Test if two retain summaries are identical. Note that merely equivalent
+ /// summaries are not necessarily identical (for example, if an explicit
+ /// argument effect matches the default effect).
+ bool operator==(const RetainSummary &Other) const {
+ return Args == Other.Args && DefaultArgEffect == Other.DefaultArgEffect &&
+ Receiver == Other.Receiver && This == Other.This && Ret == Other.Ret;
+ }
+
+ /// Profile this summary for inclusion in a FoldingSet.
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.Add(Args);
+ ID.Add(DefaultArgEffect);
+ ID.Add(Receiver);
+ ID.Add(This);
+ ID.Add(Ret);
+ }
+
+ /// A retain summary is simple if it has no ArgEffects other than the default.
+ bool isSimple() const {
+ return Args.isEmpty();
+ }
+
+ ArgEffects getArgEffects() const { return Args; }
+
+private:
+ ArgEffect getDefaultArgEffect() const { return DefaultArgEffect; }
+
+ friend class RetainSummaryManager;
+};
+
+class ObjCSummaryCache {
+ typedef llvm::DenseMap<ObjCSummaryKey, const RetainSummary *> MapTy;
+ MapTy M;
+public:
+ ObjCSummaryCache() {}
+
+ const RetainSummary * find(const ObjCInterfaceDecl *D, Selector S) {
+ // Do a lookup with the (D,S) pair. If we find a match return
+ // the iterator.
+ ObjCSummaryKey K(D, S);
+ MapTy::iterator I = M.find(K);
+
+ if (I != M.end())
+ return I->second;
+ if (!D)
+ return nullptr;
+
+ // Walk the super chain. If we find a hit with a parent, we'll end
+ // up returning that summary. We actually allow that key (null,S), as
+ // we cache summaries for the null ObjCInterfaceDecl* to allow us to
+ // generate initial summaries without having to worry about NSObject
+ // being declared.
+ // FIXME: We may change this at some point.
+ for (ObjCInterfaceDecl *C=D->getSuperClass() ;; C=C->getSuperClass()) {
+ if ((I = M.find(ObjCSummaryKey(C, S))) != M.end())
+ break;
+
+ if (!C)
+ return nullptr;
+ }
+
+ // Cache the summary with original key to make the next lookup faster
+ // and return the iterator.
+ const RetainSummary *Summ = I->second;
+ M[K] = Summ;
+ return Summ;
+ }
+
+ const RetainSummary *find(IdentifierInfo* II, Selector S) {
+ // FIXME: Class method lookup. Right now we don't have a good way
+ // of going between IdentifierInfo* and the class hierarchy.
+ MapTy::iterator I = M.find(ObjCSummaryKey(II, S));
+
+ if (I == M.end())
+ I = M.find(ObjCSummaryKey(S));
+
+ return I == M.end() ? nullptr : I->second;
+ }
+
+ const RetainSummary *& operator[](ObjCSummaryKey K) {
+ return M[K];
+ }
+
+ const RetainSummary *& operator[](Selector S) {
+ return M[ ObjCSummaryKey(S) ];
+ }
+};
+
+class RetainSummaryTemplate;
+
+class RetainSummaryManager {
+ typedef llvm::DenseMap<const FunctionDecl*, const RetainSummary *>
+ FuncSummariesTy;
+
+ typedef ObjCSummaryCache ObjCMethodSummariesTy;
+
+ typedef llvm::FoldingSetNodeWrapper<RetainSummary> CachedSummaryNode;
+
+ /// Ctx - The ASTContext object for the analyzed ASTs.
+ ASTContext &Ctx;
+
+ /// Records whether or not the analyzed code runs in ARC mode.
+ const bool ARCEnabled;
+
+ /// Track Objective-C and CoreFoundation objects.
+ const bool TrackObjCAndCFObjects;
+
+ /// Track sublcasses of OSObject.
+ const bool TrackOSObjects;
+
+ /// FuncSummaries - A map from FunctionDecls to summaries.
+ FuncSummariesTy FuncSummaries;
+
+ /// ObjCClassMethodSummaries - A map from selectors (for instance methods)
+ /// to summaries.
+ ObjCMethodSummariesTy ObjCClassMethodSummaries;
+
+ /// ObjCMethodSummaries - A map from selectors to summaries.
+ ObjCMethodSummariesTy ObjCMethodSummaries;
+
+ /// BPAlloc - A BumpPtrAllocator used for allocating summaries, ArgEffects,
+ /// and all other data used by the checker.
+ llvm::BumpPtrAllocator BPAlloc;
+
+ /// AF - A factory for ArgEffects objects.
+ ArgEffects::Factory AF;
+
+ /// ObjCAllocRetE - Default return effect for methods returning Objective-C
+ /// objects.
+ RetEffect ObjCAllocRetE;
+
+ /// ObjCInitRetE - Default return effect for init methods returning
+ /// Objective-C objects.
+ RetEffect ObjCInitRetE;
+
+ /// SimpleSummaries - Used for uniquing summaries that don't have special
+ /// effects.
+ llvm::FoldingSet<CachedSummaryNode> SimpleSummaries;
+
+ /// Create an OS object at +1.
+ const RetainSummary *getOSSummaryCreateRule(const FunctionDecl *FD);
+
+ /// Get an OS object at +0.
+ const RetainSummary *getOSSummaryGetRule(const FunctionDecl *FD);
+
+ /// Increment the reference count on OS object.
+ const RetainSummary *getOSSummaryRetainRule(const FunctionDecl *FD);
+
+ /// Decrement the reference count on OS object.
+ const RetainSummary *getOSSummaryReleaseRule(const FunctionDecl *FD);
+
+ /// Free the OS object.
+ const RetainSummary *getOSSummaryFreeRule(const FunctionDecl *FD);
+
+ const RetainSummary *getUnarySummary(const FunctionType* FT,
+ ArgEffectKind AE);
+
+ const RetainSummary *getCFSummaryCreateRule(const FunctionDecl *FD);
+ const RetainSummary *getCFSummaryGetRule(const FunctionDecl *FD);
+ const RetainSummary *getCFCreateGetRuleSummary(const FunctionDecl *FD);
+
+ const RetainSummary *getPersistentSummary(const RetainSummary &OldSumm);
+
+ const RetainSummary *
+ getPersistentSummary(RetEffect RetEff, ArgEffects ScratchArgs,
+ ArgEffect ReceiverEff = ArgEffect(DoNothing),
+ ArgEffect DefaultEff = ArgEffect(MayEscape),
+ ArgEffect ThisEff = ArgEffect(DoNothing)) {
+ RetainSummary Summ(ScratchArgs, RetEff, DefaultEff, ReceiverEff, ThisEff);
+ return getPersistentSummary(Summ);
+ }
+
+ const RetainSummary *getDoNothingSummary() {
+ return getPersistentSummary(RetEffect::MakeNoRet(),
+ ArgEffects(AF.getEmptyMap()),
+ ArgEffect(DoNothing), ArgEffect(DoNothing));
+ }
+
+ const RetainSummary *getDefaultSummary() {
+ return getPersistentSummary(RetEffect::MakeNoRet(),
+ ArgEffects(AF.getEmptyMap()),
+ ArgEffect(DoNothing), ArgEffect(MayEscape));
+ }
+
+ const RetainSummary *getPersistentStopSummary() {
+ return getPersistentSummary(
+ RetEffect::MakeNoRet(), ArgEffects(AF.getEmptyMap()),
+ ArgEffect(StopTracking), ArgEffect(StopTracking));
+ }
+
+ void InitializeClassMethodSummaries();
+ void InitializeMethodSummaries();
+
+ void addNSObjectClsMethSummary(Selector S, const RetainSummary *Summ) {
+ ObjCClassMethodSummaries[S] = Summ;
+ }
+
+ void addNSObjectMethSummary(Selector S, const RetainSummary *Summ) {
+ ObjCMethodSummaries[S] = Summ;
+ }
+
+ void addClassMethSummary(const char* Cls, const char* name,
+ const RetainSummary *Summ, bool isNullary = true) {
+ IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
+ Selector S = isNullary ? GetNullarySelector(name, Ctx)
+ : GetUnarySelector(name, Ctx);
+ ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
+ }
+
+ void addInstMethSummary(const char* Cls, const char* nullaryName,
+ const RetainSummary *Summ) {
+ IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
+ Selector S = GetNullarySelector(nullaryName, Ctx);
+ ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
+ }
+
+ template <typename... Keywords>
+ void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy &Summaries,
+ const RetainSummary *Summ, Keywords *... Kws) {
+ Selector S = getKeywordSelector(Ctx, Kws...);
+ Summaries[ObjCSummaryKey(ClsII, S)] = Summ;
+ }
+
+ template <typename... Keywords>
+ void addInstMethSummary(const char *Cls, const RetainSummary *Summ,
+ Keywords *... Kws) {
+ addMethodSummary(&Ctx.Idents.get(Cls), ObjCMethodSummaries, Summ, Kws...);
+ }
+
+ template <typename... Keywords>
+ void addClsMethSummary(const char *Cls, const RetainSummary *Summ,
+ Keywords *... Kws) {
+ addMethodSummary(&Ctx.Idents.get(Cls), ObjCClassMethodSummaries, Summ,
+ Kws...);
+ }
+
+ template <typename... Keywords>
+ void addClsMethSummary(IdentifierInfo *II, const RetainSummary *Summ,
+ Keywords *... Kws) {
+ addMethodSummary(II, ObjCClassMethodSummaries, Summ, Kws...);
+ }
+
+ const RetainSummary * generateSummary(const FunctionDecl *FD,
+ bool &AllowAnnotations);
+
+ /// Return a summary for OSObject, or nullptr if not found.
+ const RetainSummary *getSummaryForOSObject(const FunctionDecl *FD,
+ StringRef FName, QualType RetTy);
+
+ /// Return a summary for Objective-C or CF object, or nullptr if not found.
+ const RetainSummary *getSummaryForObjCOrCFObject(
+ const FunctionDecl *FD,
+ StringRef FName,
+ QualType RetTy,
+ const FunctionType *FT,
+ bool &AllowAnnotations);
+
+ /// Apply the annotation of {@code pd} in function {@code FD}
+ /// to the resulting summary stored in out-parameter {@code Template}.
+ /// \return whether an annotation was applied.
+ bool applyParamAnnotationEffect(const ParmVarDecl *pd, unsigned parm_idx,
+ const NamedDecl *FD,
+ RetainSummaryTemplate &Template);
+
+public:
+ RetainSummaryManager(ASTContext &ctx, bool trackObjCAndCFObjects,
+ bool trackOSObjects)
+ : Ctx(ctx), ARCEnabled((bool)Ctx.getLangOpts().ObjCAutoRefCount),
+ TrackObjCAndCFObjects(trackObjCAndCFObjects),
+ TrackOSObjects(trackOSObjects), AF(BPAlloc),
+ ObjCAllocRetE(ARCEnabled ? RetEffect::MakeNotOwned(ObjKind::ObjC)
+ : RetEffect::MakeOwned(ObjKind::ObjC)),
+ ObjCInitRetE(ARCEnabled ? RetEffect::MakeNotOwned(ObjKind::ObjC)
+ : RetEffect::MakeOwnedWhenTrackedReceiver()) {
+ InitializeClassMethodSummaries();
+ InitializeMethodSummaries();
+ }
+
+ enum class BehaviorSummary {
+ // Function does not return.
+ NoOp,
+
+ // Function returns the first argument.
+ Identity,
+
+ // Function returns "this" argument.
+ IdentityThis,
+
+ // Function either returns zero, or the input parameter.
+ IdentityOrZero
+ };
+
+ Optional<BehaviorSummary> canEval(const CallExpr *CE, const FunctionDecl *FD,
+ bool &hasTrustedImplementationAnnotation);
+
+ /// \return Whether the type corresponds to a known smart pointer
+ /// implementation (that is, everything about it is inlineable).
+ static bool isKnownSmartPointer(QualType QT);
+
+ bool isTrustedReferenceCountImplementation(const Decl *FD);
+
+ const RetainSummary *getSummary(AnyCall C,
+ bool HasNonZeroCallbackArg=false,
+ bool IsReceiverUnconsumedSelf=false,
+ QualType ReceiverType={});
+
+ RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
+
+private:
+
+ /// getMethodSummary - This version of getMethodSummary is used to query
+ /// the summary for the current method being analyzed.
+ const RetainSummary *getMethodSummary(const ObjCMethodDecl *MD);
+
+ const RetainSummary *getFunctionSummary(const FunctionDecl *FD);
+
+ const RetainSummary *getMethodSummary(Selector S, const ObjCInterfaceDecl *ID,
+ const ObjCMethodDecl *MD,
+ QualType RetTy,
+ ObjCMethodSummariesTy &CachedSummaries);
+
+ const RetainSummary *
+ getInstanceMethodSummary(const ObjCMessageExpr *ME, QualType ReceiverType);
+
+ const RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME);
+
+ const RetainSummary *getStandardMethodSummary(const ObjCMethodDecl *MD,
+ Selector S, QualType RetTy);
+
+ /// Determine if there is a special return effect for this function or method.
+ Optional<RetEffect> getRetEffectFromAnnotations(QualType RetTy,
+ const Decl *D);
+
+ void updateSummaryFromAnnotations(const RetainSummary *&Summ,
+ const ObjCMethodDecl *MD);
+
+ void updateSummaryFromAnnotations(const RetainSummary *&Summ,
+ const FunctionDecl *FD);
+
+ const RetainSummary *updateSummaryForNonZeroCallbackArg(const RetainSummary *S,
+ AnyCall &C);
+
+ /// Special case '[super init];' and '[self init];'
+ ///
+ /// Even though calling '[super init]' without assigning the result to self
+ /// and checking if the parent returns 'nil' is a bad pattern, it is common.
+ /// Additionally, our Self Init checker already warns about it. To avoid
+ /// overwhelming the user with messages from both checkers, we model the case
+ /// of '[super init]' in cases when it is not consumed by another expression
+ /// as if the call preserves the value of 'self'; essentially, assuming it can
+ /// never fail and return 'nil'.
+ /// Note, we don't want to just stop tracking the value since we want the
+ /// RetainCount checker to report leaks and use-after-free if SelfInit checker
+ /// is turned off.
+ void updateSummaryForReceiverUnconsumedSelf(const RetainSummary *&S);
+
+ /// Set argument types for arguments which are not doing anything.
+ void updateSummaryForArgumentTypes(const AnyCall &C, const RetainSummary *&RS);
+
+ /// Determine whether a declaration {@code D} of correspondent type (return
+ /// type for functions/methods) {@code QT} has any of the given attributes,
+ /// provided they pass necessary validation checks AND tracking the given
+ /// attribute is enabled.
+ /// Returns the object kind corresponding to the present attribute, or None,
+ /// if none of the specified attributes are present.
+ /// Crashes if passed an attribute which is not explicitly handled.
+ template <class T>
+ Optional<ObjKind> hasAnyEnabledAttrOf(const Decl *D, QualType QT);
+
+ template <class T1, class T2, class... Others>
+ Optional<ObjKind> hasAnyEnabledAttrOf(const Decl *D, QualType QT);
+
+ friend class RetainSummaryTemplate;
+};
+
+
+// Used to avoid allocating long-term (BPAlloc'd) memory for default retain
+// summaries. If a function or method looks like it has a default summary, but
+// it has annotations, the annotations are added to the stack-based template
+// and then copied into managed memory.
+class RetainSummaryTemplate {
+ RetainSummaryManager &Manager;
+ const RetainSummary *&RealSummary;
+ RetainSummary ScratchSummary;
+ bool Accessed;
+public:
+ RetainSummaryTemplate(const RetainSummary *&real, RetainSummaryManager &mgr)
+ : Manager(mgr), RealSummary(real), ScratchSummary(*real), Accessed(false) {}
+
+ ~RetainSummaryTemplate() {
+ if (Accessed)
+ RealSummary = Manager.getPersistentSummary(ScratchSummary);
+ }
+
+ RetainSummary &operator*() {
+ Accessed = true;
+ return ScratchSummary;
+ }
+
+ RetainSummary *operator->() {
+ Accessed = true;
+ return &ScratchSummary;
+ }
+};
+
+} // end namespace ento
+} // end namespace clang
+
+#endif
diff --git a/clang-r353983/include/clang/Analysis/SelectorExtras.h b/clang-r353983/include/clang/Analysis/SelectorExtras.h
new file mode 100644
index 00000000..d26e9159
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/SelectorExtras.h
@@ -0,0 +1,36 @@
+//=== SelectorExtras.h - Helpers for checkers using selectors -----*- C++ -*-=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_ANALYSIS_SELECTOREXTRAS_H
+#define LLVM_CLANG_LIB_ANALYSIS_SELECTOREXTRAS_H
+
+#include "clang/AST/ASTContext.h"
+
+namespace clang {
+
+template <typename... IdentifierInfos>
+static inline Selector getKeywordSelector(ASTContext &Ctx,
+ IdentifierInfos *... IIs) {
+ static_assert(sizeof...(IdentifierInfos),
+ "keyword selectors must have at least one argument");
+ SmallVector<IdentifierInfo *, 10> II({&Ctx.Idents.get(IIs)...});
+
+ return Ctx.Selectors.getSelector(II.size(), &II[0]);
+}
+
+template <typename... IdentifierInfos>
+static inline void lazyInitKeywordSelector(Selector &Sel, ASTContext &Ctx,
+ IdentifierInfos *... IIs) {
+ if (!Sel.isNull())
+ return;
+ Sel = getKeywordSelector(Ctx, IIs...);
+}
+
+} // end namespace clang
+
+#endif
diff --git a/clang-r353983/include/clang/Analysis/Support/BumpVector.h b/clang-r353983/include/clang/Analysis/Support/BumpVector.h
new file mode 100644
index 00000000..74092dab
--- /dev/null
+++ b/clang-r353983/include/clang/Analysis/Support/BumpVector.h
@@ -0,0 +1,256 @@
+//===- BumpVector.h - Vector-like ADT that uses bump allocation -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides BumpVector, a vector-like ADT whose contents are
+// allocated from a BumpPtrAllocator.
+//
+//===----------------------------------------------------------------------===//
+
+// FIXME: Most of this is copy-and-paste from SmallVector.h. We can
+// refactor this core logic into something common that is shared between
+// the two. The main thing that is different is the allocation strategy.
+
+#ifndef LLVM_CLANG_ANALYSIS_SUPPORT_BUMPVECTOR_H
+#define LLVM_CLANG_ANALYSIS_SUPPORT_BUMPVECTOR_H
+
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/Support/Allocator.h"
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+
+namespace clang {
+
+class BumpVectorContext {
+ llvm::PointerIntPair<llvm::BumpPtrAllocator*, 1> Alloc;
+
+public:
+ /// Construct a new BumpVectorContext that creates a new BumpPtrAllocator
+ /// and destroys it when the BumpVectorContext object is destroyed.
+ BumpVectorContext() : Alloc(new llvm::BumpPtrAllocator(), 1) {}
+
+ BumpVectorContext(BumpVectorContext &&Other) : Alloc(Other.Alloc) {
+ Other.Alloc.setInt(false);
+ Other.Alloc.setPointer(nullptr);
+ }
+
+ /// Construct a new BumpVectorContext that reuses an existing
+ /// BumpPtrAllocator. This BumpPtrAllocator is not destroyed when the
+ /// BumpVectorContext object is destroyed.
+ BumpVectorContext(llvm::BumpPtrAllocator &A) : Alloc(&A, 0) {}
+
+ ~BumpVectorContext() {
+ if (Alloc.getInt())
+ delete Alloc.getPointer();
+ }
+
+ llvm::BumpPtrAllocator &getAllocator() { return *Alloc.getPointer(); }
+};
+
+template<typename T>
+class BumpVector {
+ T *Begin = nullptr;
+ T *End = nullptr;
+ T *Capacity = nullptr;
+
+public:
+ // Default ctor - Initialize to empty.
+ explicit BumpVector(BumpVectorContext &C, unsigned N) {
+ reserve(C, N);
+ }
+
+ ~BumpVector() {
+ if (std::is_class<T>::value) {
+ // Destroy the constructed elements in the vector.
+ destroy_range(Begin, End);
+ }
+ }
+
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ using value_type = T;
+ using iterator = T *;
+ using const_iterator = const T *;
+
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+
+ using reference = T &;
+ using const_reference = const T &;
+ using pointer = T *;
+ using const_pointer = const T *;
+
+ // forward iterator creation methods.
+ iterator begin() { return Begin; }
+ const_iterator begin() const { return Begin; }
+ iterator end() { return End; }
+ const_iterator end() const { return End; }
+
+ // reverse iterator creation methods.
+ reverse_iterator rbegin() { return reverse_iterator(end()); }
+ const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
+ reverse_iterator rend() { return reverse_iterator(begin()); }
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(begin());
+ }
+
+ bool empty() const { return Begin == End; }
+ size_type size() const { return End-Begin; }
+
+ reference operator[](unsigned idx) {
+ assert(Begin + idx < End);
+ return Begin[idx];
+ }
+ const_reference operator[](unsigned idx) const {
+ assert(Begin + idx < End);
+ return Begin[idx];
+ }
+
+ reference front() {
+ return begin()[0];
+ }
+ const_reference front() const {
+ return begin()[0];
+ }
+
+ reference back() {
+ return end()[-1];
+ }
+ const_reference back() const {
+ return end()[-1];
+ }
+
+ void pop_back() {
+ --End;
+ End->~T();
+ }
+
+ T pop_back_val() {
+ T Result = back();
+ pop_back();
+ return Result;
+ }
+
+ void clear() {
+ if (std::is_class<T>::value) {
+ destroy_range(Begin, End);
+ }
+ End = Begin;
+ }
+
+ /// data - Return a pointer to the vector's buffer, even if empty().
+ pointer data() {
+ return pointer(Begin);
+ }
+
+ /// data - Return a pointer to the vector's buffer, even if empty().
+ const_pointer data() const {
+ return const_pointer(Begin);
+ }
+
+ void push_back(const_reference Elt, BumpVectorContext &C) {
+ if (End < Capacity) {
+ Retry:
+ new (End) T(Elt);
+ ++End;
+ return;
+ }
+ grow(C);
+ goto Retry;
+ }
+
+ /// insert - Insert some number of copies of element into a position. Return
+ /// iterator to position after last inserted copy.
+ iterator insert(iterator I, size_t Cnt, const_reference E,
+ BumpVectorContext &C) {
+ assert(I >= Begin && I <= End && "Iterator out of bounds.");
+ if (End + Cnt <= Capacity) {
+ Retry:
+ move_range_right(I, End, Cnt);
+ construct_range(I, I + Cnt, E);
+ End += Cnt;
+ return I + Cnt;
+ }
+ ptrdiff_t D = I - Begin;
+ grow(C, size() + Cnt);
+ I = Begin + D;
+ goto Retry;
+ }
+
+ void reserve(BumpVectorContext &C, unsigned N) {
+ if (unsigned(Capacity-Begin) < N)
+ grow(C, N);
+ }
+
+ /// capacity - Return the total number of elements in the currently allocated
+ /// buffer.
+ size_t capacity() const { return Capacity - Begin; }
+
+private:
+ /// grow - double the size of the allocated memory, guaranteeing space for at
+ /// least one more element or MinSize if specified.
+ void grow(BumpVectorContext &C, size_type MinSize = 1);
+
+ void construct_range(T *S, T *E, const T &Elt) {
+ for (; S != E; ++S)
+ new (S) T(Elt);
+ }
+
+ void destroy_range(T *S, T *E) {
+ while (S != E) {
+ --E;
+ E->~T();
+ }
+ }
+
+ void move_range_right(T *S, T *E, size_t D) {
+ for (T *I = E + D - 1, *IL = S + D - 1; I != IL; --I) {
+ --E;
+ new (I) T(*E);
+ E->~T();
+ }
+ }
+};
+
+// Define this out-of-line to dissuade the C++ compiler from inlining it.
+template <typename T>
+void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) {
+ size_t CurCapacity = Capacity-Begin;
+ size_t CurSize = size();
+ size_t NewCapacity = 2*CurCapacity;
+ if (NewCapacity < MinSize)
+ NewCapacity = MinSize;
+
+ // Allocate the memory from the BumpPtrAllocator.
+ T *NewElts = C.getAllocator().template Allocate<T>(NewCapacity);
+
+ // Copy the elements over.
+ if (Begin != End) {
+ if (std::is_class<T>::value) {
+ std::uninitialized_copy(Begin, End, NewElts);
+ // Destroy the original elements.
+ destroy_range(Begin, End);
+ } else {
+ // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove).
+ memcpy(NewElts, Begin, CurSize * sizeof(T));
+ }
+ }
+
+ // For now, leak 'Begin'. We can add it back to a freelist in
+ // BumpVectorContext.
+ Begin = NewElts;
+ End = NewElts+CurSize;
+ Capacity = Begin+NewCapacity;
+}
+
+} // namespace clang
+
+#endif // LLVM_CLANG_ANALYSIS_SUPPORT_BUMPVECTOR_H