clang 19.0.0git
ASTOps.cpp
Go to the documentation of this file.
1//===-- ASTOps.cc -------------------------------*- 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
15#include "clang/AST/Decl.h"
16#include "clang/AST/DeclBase.h"
17#include "clang/AST/DeclCXX.h"
18#include "clang/AST/Expr.h"
19#include "clang/AST/ExprCXX.h"
20#include "clang/AST/Stmt.h"
21#include "clang/AST/Type.h"
23#include "clang/Basic/LLVM.h"
24#include "llvm/ADT/DenseSet.h"
25#include "llvm/ADT/STLExtras.h"
26#include <cassert>
27#include <iterator>
28#include <vector>
29
30#define DEBUG_TYPE "dataflow"
31
32namespace clang::dataflow {
33
35 const Expr *Current = &E;
36 const Expr *Last = nullptr;
37 while (Current != Last) {
38 Last = Current;
39 if (auto *EWC = dyn_cast<ExprWithCleanups>(Current)) {
40 Current = EWC->getSubExpr();
41 assert(Current != nullptr);
42 }
43 if (auto *CE = dyn_cast<ConstantExpr>(Current)) {
44 Current = CE->getSubExpr();
45 assert(Current != nullptr);
46 }
47 Current = Current->IgnoreParens();
48 assert(Current != nullptr);
49 }
50 return *Current;
51}
52
54 if (auto *E = dyn_cast<Expr>(&S))
55 return ignoreCFGOmittedNodes(*E);
56 return S;
57}
58
59// FIXME: Does not precisely handle non-virtual diamond inheritance. A single
60// field decl will be modeled for all instances of the inherited field.
64 return;
65
66 for (const FieldDecl *Field : Type->getAsRecordDecl()->fields())
67 Fields.insert(Field);
68 if (auto *CXXRecord = Type->getAsCXXRecordDecl())
69 for (const CXXBaseSpecifier &Base : CXXRecord->bases())
70 getFieldsFromClassHierarchy(Base.getType(), Fields);
71}
72
73/// Gets the set of all fields in the type.
75 FieldSet Fields;
77 return Fields;
78}
79
80bool containsSameFields(const FieldSet &Fields,
81 const RecordStorageLocation::FieldToLoc &FieldLocs) {
82 if (Fields.size() != FieldLocs.size())
83 return false;
84 for ([[maybe_unused]] auto [Field, Loc] : FieldLocs)
85 if (!Fields.contains(cast_or_null<FieldDecl>(Field)))
86 return false;
87 return true;
88}
89
90/// Returns the fields of a `RecordDecl` that are initialized by an
91/// `InitListExpr` or `CXXParenListInitExpr`, in the order in which they appear
92/// in `InitListExpr::inits()` / `CXXParenListInitExpr::getInitExprs()`.
93/// `InitList->getType()` must be a record type.
94template <class InitListT>
95static std::vector<const FieldDecl *>
96getFieldsForInitListExpr(const InitListT *InitList) {
97 const RecordDecl *RD = InitList->getType()->getAsRecordDecl();
98 assert(RD != nullptr);
99
100 std::vector<const FieldDecl *> Fields;
101
102 if (InitList->getType()->isUnionType()) {
103 Fields.push_back(InitList->getInitializedFieldInUnion());
104 return Fields;
105 }
106
107 // Unnamed bitfields are only used for padding and do not appear in
108 // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s
109 // field list, and we thus need to remove them before mapping inits to
110 // fields to avoid mapping inits to the wrongs fields.
111 llvm::copy_if(
112 RD->fields(), std::back_inserter(Fields),
113 [](const FieldDecl *Field) { return !Field->isUnnamedBitField(); });
114 return Fields;
115}
116
118 : RecordInitListHelper(InitList->getType(),
119 getFieldsForInitListExpr(InitList),
120 InitList->inits()) {}
121
123 const CXXParenListInitExpr *ParenInitList)
124 : RecordInitListHelper(ParenInitList->getType(),
125 getFieldsForInitListExpr(ParenInitList),
126 ParenInitList->getInitExprs()) {}
127
129 QualType Ty, std::vector<const FieldDecl *> Fields,
130 ArrayRef<Expr *> Inits) {
131 auto *RD = Ty->getAsCXXRecordDecl();
132 assert(RD != nullptr);
133
134 // Unions initialized with an empty initializer list need special treatment.
135 // For structs/classes initialized with an empty initializer list, Clang
136 // puts `ImplicitValueInitExpr`s in `InitListExpr::inits()`, but for unions,
137 // it doesn't do this -- so we create an `ImplicitValueInitExpr` ourselves.
138 SmallVector<Expr *> InitsForUnion;
139 if (Ty->isUnionType() && Inits.empty()) {
140 assert(Fields.size() == 1);
141 ImplicitValueInitForUnion.emplace(Fields.front()->getType());
142 InitsForUnion.push_back(&*ImplicitValueInitForUnion);
143 Inits = InitsForUnion;
144 }
145
146 size_t InitIdx = 0;
147
148 assert(Fields.size() + RD->getNumBases() == Inits.size());
149 for (const CXXBaseSpecifier &Base : RD->bases()) {
150 assert(InitIdx < Inits.size());
151 Expr *Init = Inits[InitIdx++];
152 BaseInits.emplace_back(&Base, Init);
153 }
154
155 assert(Fields.size() == Inits.size() - InitIdx);
156 for (const FieldDecl *Field : Fields) {
157 assert(InitIdx < Inits.size());
158 Expr *Init = Inits[InitIdx++];
159 FieldInits.emplace_back(Field, Init);
160 }
161}
162
163static void insertIfGlobal(const Decl &D,
165 if (auto *V = dyn_cast<VarDecl>(&D))
166 if (V->hasGlobalStorage())
167 Globals.insert(V);
168}
169
170static void insertIfFunction(const Decl &D,
172 if (auto *FD = dyn_cast<FunctionDecl>(&D))
173 Funcs.insert(FD);
174}
175
177 // Use getCalleeDecl instead of getMethodDecl in order to handle
178 // pointer-to-member calls.
179 const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(C.getCalleeDecl());
180 if (!MethodDecl)
181 return nullptr;
182 auto *Body = dyn_cast_or_null<CompoundStmt>(MethodDecl->getBody());
183 if (!Body || Body->size() != 1)
184 return nullptr;
185 if (auto *RS = dyn_cast<ReturnStmt>(*Body->body_begin()))
186 if (auto *Return = RS->getRetValue())
187 return dyn_cast<MemberExpr>(Return->IgnoreParenImpCasts());
188 return nullptr;
189}
190
191static void getReferencedDecls(const Decl &D, ReferencedDecls &Referenced) {
192 insertIfGlobal(D, Referenced.Globals);
193 insertIfFunction(D, Referenced.Functions);
194 if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D))
195 for (const auto *B : Decomp->bindings())
196 if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding()))
197 // FIXME: should we be using `E->getFoundDecl()`?
198 if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
199 Referenced.Fields.insert(FD);
200}
201
202/// Traverses `S` and inserts into `Referenced` any declarations that are
203/// declared in or referenced from sub-statements.
204static void getReferencedDecls(const Stmt &S, ReferencedDecls &Referenced) {
205 for (auto *Child : S.children())
206 if (Child != nullptr)
207 getReferencedDecls(*Child, Referenced);
208 if (const auto *DefaultArg = dyn_cast<CXXDefaultArgExpr>(&S))
209 getReferencedDecls(*DefaultArg->getExpr(), Referenced);
210 if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(&S))
211 getReferencedDecls(*DefaultInit->getExpr(), Referenced);
212
213 if (auto *DS = dyn_cast<DeclStmt>(&S)) {
214 if (DS->isSingleDecl())
215 getReferencedDecls(*DS->getSingleDecl(), Referenced);
216 else
217 for (auto *D : DS->getDeclGroup())
218 getReferencedDecls(*D, Referenced);
219 } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
220 insertIfGlobal(*E->getDecl(), Referenced.Globals);
221 insertIfFunction(*E->getDecl(), Referenced.Functions);
222 } else if (const auto *C = dyn_cast<CXXMemberCallExpr>(&S)) {
223 // If this is a method that returns a member variable but does nothing else,
224 // model the field of the return value.
226 if (const auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl()))
227 Referenced.Fields.insert(FD);
228 } else if (auto *E = dyn_cast<MemberExpr>(&S)) {
229 // FIXME: should we be using `E->getFoundDecl()`?
230 const ValueDecl *VD = E->getMemberDecl();
231 insertIfGlobal(*VD, Referenced.Globals);
232 insertIfFunction(*VD, Referenced.Functions);
233 if (const auto *FD = dyn_cast<FieldDecl>(VD))
234 Referenced.Fields.insert(FD);
235 } else if (auto *InitList = dyn_cast<InitListExpr>(&S)) {
236 if (InitList->getType()->isRecordType())
237 for (const auto *FD : getFieldsForInitListExpr(InitList))
238 Referenced.Fields.insert(FD);
239 } else if (auto *ParenInitList = dyn_cast<CXXParenListInitExpr>(&S)) {
240 if (ParenInitList->getType()->isRecordType())
241 for (const auto *FD : getFieldsForInitListExpr(ParenInitList))
242 Referenced.Fields.insert(FD);
243 }
244}
245
248 // Look for global variable and field references in the
249 // constructor-initializers.
250 if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&FD)) {
251 for (const auto *Init : CtorDecl->inits()) {
252 if (Init->isMemberInitializer()) {
253 Result.Fields.insert(Init->getMember());
254 } else if (Init->isIndirectMemberInitializer()) {
255 for (const auto *I : Init->getIndirectMember()->chain())
256 Result.Fields.insert(cast<FieldDecl>(I));
257 }
258 const Expr *E = Init->getInit();
259 assert(E != nullptr);
261 }
262 // Add all fields mentioned in default member initializers.
263 for (const FieldDecl *F : CtorDecl->getParent()->fields())
264 if (const auto *I = F->getInClassInitializer())
266 }
268
269 return Result;
270}
271
275 return Result;
276}
277
278} // namespace clang::dataflow
#define V(N, I)
Definition: ASTContext.h:3284
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
C Language Family Type Representation.
Represents a base class of a C++ class.
Definition: DeclCXX.h:146
Represents a call to a member function that may be written either with member call syntax (e....
Definition: ExprCXX.h:176
Represents a list-initialization with parenthesis.
Definition: ExprCXX.h:4922
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
This represents one expression.
Definition: Expr.h:110
Represents a member of a struct/union/class.
Definition: Decl.h:3058
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition: Decl.h:3271
Represents a function declaration or definition.
Definition: Decl.h:1971
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition: Decl.cpp:3236
Describes an C or C++ initializer list.
Definition: Expr.h:4847
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3172
A (possibly-)qualified type.
Definition: Type.h:940
Represents a struct/union/class.
Definition: Decl.h:4169
field_range fields() const
Definition: Decl.h:4375
Stmt - This represents one statement.
Definition: Stmt.h:84
The base class of the type hierarchy.
Definition: Type.h:1813
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1870
bool isDependentType() const
Whether this type is a dependent type, meaning that its definition somehow depends on a template para...
Definition: Type.h:2653
bool isIncompleteType(NamedDecl **Def=nullptr) const
Types are partitioned into 3 broad categories (C99 6.2.5p1): object types, function types,...
Definition: Type.cpp:2350
bool isRecordType() const
Definition: Type.h:7706
bool isUnionType() const
Definition: Type.cpp:660
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition: Type.cpp:1874
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:706
Helper class for initialization of a record with an InitListExpr.
Definition: ASTOps.h:55
RecordInitListHelper(const InitListExpr *InitList)
Definition: ASTOps.cpp:117
llvm::DenseMap< const ValueDecl *, StorageLocation * > FieldToLoc
Dataflow Directional Tag Classes.
Definition: AdornedCFG.h:28
static void getFieldsFromClassHierarchy(QualType Type, FieldSet &Fields)
Definition: ASTOps.cpp:61
static void insertIfFunction(const Decl &D, llvm::DenseSet< const FunctionDecl * > &Funcs)
Definition: ASTOps.cpp:170
static MemberExpr * getMemberForAccessor(const CXXMemberCallExpr &C)
Definition: ASTOps.cpp:176
ReferencedDecls getReferencedDecls(const FunctionDecl &FD)
Returns declarations that are declared in or referenced from FD.
Definition: ASTOps.cpp:246
static std::vector< const FieldDecl * > getFieldsForInitListExpr(const InitListT *InitList)
Returns the fields of a RecordDecl that are initialized by an InitListExpr or CXXParenListInitExpr,...
Definition: ASTOps.cpp:96
const Expr & ignoreCFGOmittedNodes(const Expr &E)
Skip past nodes that the CFG does not emit.
Definition: ASTOps.cpp:34
FieldSet getObjectFields(QualType Type)
Returns the set of all fields in the type.
Definition: ASTOps.cpp:74
static void insertIfGlobal(const Decl &D, llvm::DenseSet< const VarDecl * > &Globals)
Definition: ASTOps.cpp:163
bool containsSameFields(const FieldSet &Fields, const RecordStorageLocation::FieldToLoc &FieldLocs)
Returns whether Fields and FieldLocs contain the same fields.
Definition: ASTOps.cpp:80
@ Result
The result type of a method or function.
A collection of several types of declarations, all referenced from the same function.
Definition: ASTOps.h:85
llvm::DenseSet< const VarDecl * > Globals
All variables with static storage duration, notably including static member variables and static vari...
Definition: ASTOps.h:90
llvm::DenseSet< const FunctionDecl * > Functions
Free functions and member functions which are referenced (but not necessarily called).
Definition: ASTOps.h:93
FieldSet Fields
Non-static member variables.
Definition: ASTOps.h:87