diff options
Diffstat (limited to 'clang-r353983/include/clang/Analysis')
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 |
