xref: /freebsd/contrib/llvm-project/clang/include/clang/Analysis/FlowSensitive/ASTOps.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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