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