1 //===-- ASTOps.h -------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Operations on AST nodes that are used in flow-sensitive analysis. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H 14 #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H 15 16 #include "clang/AST/Decl.h" 17 #include "clang/AST/Expr.h" 18 #include "clang/AST/RecursiveASTVisitor.h" 19 #include "clang/AST/Type.h" 20 #include "clang/Analysis/FlowSensitive/StorageLocation.h" 21 #include "llvm/ADT/DenseSet.h" 22 #include "llvm/ADT/SetVector.h" 23 24 namespace clang { 25 namespace dataflow { 26 27 /// Skip past nodes that the CFG does not emit. These nodes are invisible to 28 /// flow-sensitive analysis, and should be ignored as they will effectively not 29 /// exist. 30 /// 31 /// * `ParenExpr` - The CFG takes the operator precedence into account, but 32 /// otherwise omits the node afterwards. 33 /// 34 /// * `ExprWithCleanups` - The CFG will generate the appropriate calls to 35 /// destructors and then omit the node. 36 /// 37 const Expr &ignoreCFGOmittedNodes(const Expr &E); 38 const Stmt &ignoreCFGOmittedNodes(const Stmt &S); 39 40 /// A set of `FieldDecl *`. Use `SmallSetVector` to guarantee deterministic 41 /// iteration order. 42 using FieldSet = llvm::SmallSetVector<const FieldDecl *, 4>; 43 44 /// Returns the set of all fields in the type. 45 FieldSet getObjectFields(QualType Type); 46 47 /// Returns whether `Fields` and `FieldLocs` contain the same fields. 48 bool containsSameFields(const FieldSet &Fields, 49 const RecordStorageLocation::FieldToLoc &FieldLocs); 50 51 /// Helper class for initialization of a record with an `InitListExpr`. 52 /// `InitListExpr::inits()` contains the initializers for both the base classes 53 /// and the fields of the record; this helper class separates these out into two 54 /// different lists. In addition, it deals with special cases associated with 55 /// unions. 56 class RecordInitListHelper { 57 public: 58 // `InitList` must have record type. 59 RecordInitListHelper(const InitListExpr *InitList); 60 RecordInitListHelper(const CXXParenListInitExpr *ParenInitList); 61 62 // Base classes with their associated initializer expressions. base_inits()63 ArrayRef<std::pair<const CXXBaseSpecifier *, Expr *>> base_inits() const { 64 return BaseInits; 65 } 66 67 // Fields with their associated initializer expressions. field_inits()68 ArrayRef<std::pair<const FieldDecl *, Expr *>> field_inits() const { 69 return FieldInits; 70 } 71 72 private: 73 RecordInitListHelper(QualType Ty, std::vector<const FieldDecl *> Fields, 74 ArrayRef<Expr *> Inits); 75 76 SmallVector<std::pair<const CXXBaseSpecifier *, Expr *>> BaseInits; 77 SmallVector<std::pair<const FieldDecl *, Expr *>> FieldInits; 78 79 // We potentially synthesize an `ImplicitValueInitExpr` for unions. It's a 80 // member variable because we store a pointer to it in `FieldInits`. 81 std::optional<ImplicitValueInitExpr> ImplicitValueInitForUnion; 82 }; 83 84 /// Specialization of `RecursiveASTVisitor` that visits those nodes that are 85 /// relevant to the dataflow analysis; generally, these are the ones that also 86 /// appear in the CFG. 87 /// To start the traversal, call `TraverseStmt()` on the statement or body of 88 /// the function to analyze. Don't call `TraverseDecl()` on the function itself; 89 /// this won't work as `TraverseDecl()` contains code to avoid traversing nested 90 /// functions. 91 template <class Derived> 92 class AnalysisASTVisitor : public RecursiveASTVisitor<Derived> { 93 public: shouldVisitImplicitCode()94 bool shouldVisitImplicitCode() { return true; } 95 shouldVisitLambdaBody()96 bool shouldVisitLambdaBody() const { return false; } 97 TraverseDecl(Decl * D)98 bool TraverseDecl(Decl *D) { 99 // Don't traverse nested record or function declarations. 100 // - We won't be analyzing code contained in these anyway 101 // - We don't model fields that are used only in these nested declaration, 102 // so trying to propagate a result object to initializers of such fields 103 // would cause an error. 104 if (isa_and_nonnull<RecordDecl>(D) || isa_and_nonnull<FunctionDecl>(D)) 105 return true; 106 107 return RecursiveASTVisitor<Derived>::TraverseDecl(D); 108 } 109 110 // Don't traverse expressions in unevaluated contexts, as we don't model 111 // fields that are only used in these. 112 // Note: The operand of the `noexcept` operator is an unevaluated operand, but 113 // nevertheless it appears in the Clang CFG, so we don't exclude it here. TraverseDecltypeTypeLoc(DecltypeTypeLoc)114 bool TraverseDecltypeTypeLoc(DecltypeTypeLoc) { return true; } TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc)115 bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc) { return true; } TraverseCXXTypeidExpr(CXXTypeidExpr * TIE)116 bool TraverseCXXTypeidExpr(CXXTypeidExpr *TIE) { 117 if (TIE->isPotentiallyEvaluated()) 118 return RecursiveASTVisitor<Derived>::TraverseCXXTypeidExpr(TIE); 119 return true; 120 } TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *)121 bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *) { 122 return true; 123 } 124 TraverseBindingDecl(BindingDecl * BD)125 bool TraverseBindingDecl(BindingDecl *BD) { 126 // `RecursiveASTVisitor` doesn't traverse holding variables for 127 // `BindingDecl`s by itself, so we need to tell it to. 128 if (VarDecl *HoldingVar = BD->getHoldingVar()) 129 TraverseDecl(HoldingVar); 130 return RecursiveASTVisitor<Derived>::TraverseBindingDecl(BD); 131 } 132 }; 133 134 /// A collection of several types of declarations, all referenced from the same 135 /// function. 136 struct ReferencedDecls { 137 /// Non-static member variables. 138 FieldSet Fields; 139 /// All variables with static storage duration, notably including static 140 /// member variables and static variables declared within a function. 141 llvm::DenseSet<const VarDecl *> Globals; 142 /// Free functions and member functions which are referenced (but not 143 /// necessarily called). 144 llvm::DenseSet<const FunctionDecl *> Functions; 145 }; 146 147 /// Returns declarations that are declared in or referenced from `FD`. 148 ReferencedDecls getReferencedDecls(const FunctionDecl &FD); 149 150 /// Returns declarations that are declared in or referenced from `S`. 151 ReferencedDecls getReferencedDecls(const Stmt &S); 152 153 } // namespace dataflow 154 } // namespace clang 155 156 #endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H 157