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
24namespace clang {
25namespace 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///
37const Expr &ignoreCFGOmittedNodes(const Expr &E);
38const Stmt &ignoreCFGOmittedNodes(const Stmt &S);
39
40/// A set of `FieldDecl *`. Use `SmallSetVector` to guarantee deterministic
41/// iteration order.
42using FieldSet = llvm::SmallSetVector<const FieldDecl *, 4>;
43
44/// Returns the set of all fields in the type.
45FieldSet getObjectFields(QualType Type);
46
47/// Returns whether `Fields` and `FieldLocs` contain the same fields.
48bool 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.
56class RecordInitListHelper {
57public:
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.
63 ArrayRef<std::pair<const CXXBaseSpecifier *, Expr *>> base_inits() const {
64 return BaseInits;
65 }
66
67 // Fields with their associated initializer expressions.
68 ArrayRef<std::pair<const FieldDecl *, Expr *>> field_inits() const {
69 return FieldInits;
70 }
71
72private:
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.
91template <class Derived>
92class AnalysisASTVisitor : public RecursiveASTVisitor<Derived> {
93public:
94 bool shouldVisitImplicitCode() { return true; }
95
96 bool shouldVisitLambdaBody() const { return false; }
97
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>(Val: D) || isa_and_nonnull<FunctionDecl>(Val: 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.
114 bool TraverseDecltypeTypeLoc(DecltypeTypeLoc) { return true; }
115 bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc) { return true; }
116 bool TraverseCXXTypeidExpr(CXXTypeidExpr *TIE) {
117 if (TIE->isPotentiallyEvaluated())
118 return RecursiveASTVisitor<Derived>::TraverseCXXTypeidExpr(TIE);
119 return true;
120 }
121 bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *) {
122 return true;
123 }
124
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(D: 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.
136struct 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`.
148ReferencedDecls getReferencedDecls(const FunctionDecl &FD);
149
150/// Returns declarations that are declared in or referenced from `S`.
151ReferencedDecls getReferencedDecls(const Stmt &S);
152
153} // namespace dataflow
154} // namespace clang
155
156#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H
157