clang 20.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
14#include "clang/AST/ASTLambda.h"
16#include "clang/AST/Decl.h"
17#include "clang/AST/DeclBase.h"
18#include "clang/AST/DeclCXX.h"
19#include "clang/AST/Expr.h"
20#include "clang/AST/ExprCXX.h"
21#include "clang/AST/Stmt.h"
22#include "clang/AST/Type.h"
24#include "clang/Basic/LLVM.h"
25#include "llvm/ADT/DenseSet.h"
26#include "llvm/ADT/STLExtras.h"
27#include <cassert>
28#include <iterator>
29#include <vector>
30
31#define DEBUG_TYPE "dataflow"
32
33namespace clang::dataflow {
34
36 const Expr *Current = &E;
37 const Expr *Last = nullptr;
38 while (Current != Last) {
39 Last = Current;
40 if (auto *EWC = dyn_cast<ExprWithCleanups>(Current)) {
41 Current = EWC->getSubExpr();
42 assert(Current != nullptr);
43 }
44 if (auto *CE = dyn_cast<ConstantExpr>(Current)) {
45 Current = CE->getSubExpr();
46 assert(Current != nullptr);
47 }
48 Current = Current->IgnoreParens();
49 assert(Current != nullptr);
50 }
51 return *Current;
52}
53
55 if (auto *E = dyn_cast<Expr>(&S))
56 return ignoreCFGOmittedNodes(*E);
57 return S;
58}
59
60// FIXME: Does not precisely handle non-virtual diamond inheritance. A single
61// field decl will be modeled for all instances of the inherited field.
65 return;
66
67 for (const FieldDecl *Field : Type->getAsRecordDecl()->fields())
68 Fields.insert(Field);
69 if (auto *CXXRecord = Type->getAsCXXRecordDecl())
70 for (const CXXBaseSpecifier &Base : CXXRecord->bases())
71 getFieldsFromClassHierarchy(Base.getType(), Fields);
72}
73
74/// Gets the set of all fields in the type.
76 FieldSet Fields;
78 return Fields;
79}
80
81bool containsSameFields(const FieldSet &Fields,
82 const RecordStorageLocation::FieldToLoc &FieldLocs) {
83 if (Fields.size() != FieldLocs.size())
84 return false;
85 for ([[maybe_unused]] auto [Field, Loc] : FieldLocs)
86 if (!Fields.contains(cast_or_null<FieldDecl>(Field)))
87 return false;
88 return true;
89}
90
91/// Returns the fields of a `RecordDecl` that are initialized by an
92/// `InitListExpr` or `CXXParenListInitExpr`, in the order in which they appear
93/// in `InitListExpr::inits()` / `CXXParenListInitExpr::getInitExprs()`.
94/// `InitList->getType()` must be a record type.
95template <class InitListT>
96static std::vector<const FieldDecl *>
97getFieldsForInitListExpr(const InitListT *InitList) {
98 const RecordDecl *RD = InitList->getType()->getAsRecordDecl();
99 assert(RD != nullptr);
100
101 std::vector<const FieldDecl *> Fields;
102
103 if (InitList->getType()->isUnionType()) {
104 if (const FieldDecl *Field = InitList->getInitializedFieldInUnion())
105 Fields.push_back(Field);
106 return Fields;
107 }
108
109 // Unnamed bitfields are only used for padding and do not appear in
110 // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s
111 // field list, and we thus need to remove them before mapping inits to
112 // fields to avoid mapping inits to the wrongs fields.
113 llvm::copy_if(
114 RD->fields(), std::back_inserter(Fields),
115 [](const FieldDecl *Field) { return !Field->isUnnamedBitField(); });
116 return Fields;
117}
118
120 : RecordInitListHelper(InitList->getType(),
121 getFieldsForInitListExpr(InitList),
122 InitList->inits()) {}
123
125 const CXXParenListInitExpr *ParenInitList)
126 : RecordInitListHelper(ParenInitList->getType(),
127 getFieldsForInitListExpr(ParenInitList),
128 ParenInitList->getInitExprs()) {}
129
131 QualType Ty, std::vector<const FieldDecl *> Fields,
132 ArrayRef<Expr *> Inits) {
133 auto *RD = Ty->getAsCXXRecordDecl();
134 assert(RD != nullptr);
135
136 // Unions initialized with an empty initializer list need special treatment.
137 // For structs/classes initialized with an empty initializer list, Clang
138 // puts `ImplicitValueInitExpr`s in `InitListExpr::inits()`, but for unions,
139 // it doesn't do this -- so we create an `ImplicitValueInitExpr` ourselves.
140 SmallVector<Expr *> InitsForUnion;
141 if (Ty->isUnionType() && Inits.empty()) {
142 assert(Fields.size() <= 1);
143 if (!Fields.empty()) {
144 ImplicitValueInitForUnion.emplace(Fields.front()->getType());
145 InitsForUnion.push_back(&*ImplicitValueInitForUnion);
146 }
147 Inits = InitsForUnion;
148 }
149
150 size_t InitIdx = 0;
151
152 assert(Fields.size() + RD->getNumBases() == Inits.size());
153 for (const CXXBaseSpecifier &Base : RD->bases()) {
154 assert(InitIdx < Inits.size());
155 Expr *Init = Inits[InitIdx++];
156 BaseInits.emplace_back(&Base, Init);
157 }
158
159 assert(Fields.size() == Inits.size() - InitIdx);
160 for (const FieldDecl *Field : Fields) {
161 assert(InitIdx < Inits.size());
162 Expr *Init = Inits[InitIdx++];
163 FieldInits.emplace_back(Field, Init);
164 }
165}
166
167static void insertIfGlobal(const Decl &D,
168 llvm::DenseSet<const VarDecl *> &Globals) {
169 if (auto *V = dyn_cast<VarDecl>(&D))
170 if (V->hasGlobalStorage())
171 Globals.insert(V);
172}
173
174static void insertIfLocal(const Decl &D,
175 llvm::DenseSet<const VarDecl *> &Locals) {
176 if (auto *V = dyn_cast<VarDecl>(&D))
177 if (V->hasLocalStorage() && !isa<ParmVarDecl>(V))
178 Locals.insert(V);
179}
180
181static void insertIfFunction(const Decl &D,
182 llvm::DenseSet<const FunctionDecl *> &Funcs) {
183 if (auto *FD = dyn_cast<FunctionDecl>(&D))
184 Funcs.insert(FD);
185}
186
188 // Use getCalleeDecl instead of getMethodDecl in order to handle
189 // pointer-to-member calls.
190 const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(C.getCalleeDecl());
191 if (!MethodDecl)
192 return nullptr;
193 auto *Body = dyn_cast_or_null<CompoundStmt>(MethodDecl->getBody());
194 if (!Body || Body->size() != 1)
195 return nullptr;
196 if (auto *RS = dyn_cast<ReturnStmt>(*Body->body_begin()))
197 if (auto *Return = RS->getRetValue())
198 return dyn_cast<MemberExpr>(Return->IgnoreParenImpCasts());
199 return nullptr;
200}
201
203public:
205 : Referenced(Referenced) {}
206
208 for (const CXXCtorInitializer *Init : Ctor->inits()) {
209 if (Init->isMemberInitializer()) {
210 Referenced.Fields.insert(Init->getMember());
211 } else if (Init->isIndirectMemberInitializer()) {
212 for (const auto *I : Init->getIndirectMember()->chain())
213 Referenced.Fields.insert(cast<FieldDecl>(I));
214 }
215
216 Expr *InitExpr = Init->getInit();
217
218 // Also collect declarations referenced in `InitExpr`.
219 TraverseStmt(InitExpr);
220
221 // If this is a `CXXDefaultInitExpr`, also collect declarations referenced
222 // within the default expression.
223 if (auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(InitExpr))
224 TraverseStmt(DefaultInit->getExpr());
225 }
226 }
227
228 bool VisitDecl(Decl *D) override {
229 insertIfGlobal(*D, Referenced.Globals);
230 insertIfLocal(*D, Referenced.Locals);
231 insertIfFunction(*D, Referenced.Functions);
232 return true;
233 }
234
236 insertIfGlobal(*E->getDecl(), Referenced.Globals);
237 insertIfLocal(*E->getDecl(), Referenced.Locals);
238 insertIfFunction(*E->getDecl(), Referenced.Functions);
239 return true;
240 }
241
243 // If this is a method that returns a member variable but does nothing else,
244 // model the field of the return value.
246 if (const auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl()))
247 Referenced.Fields.insert(FD);
248 return true;
249 }
250
251 bool VisitMemberExpr(MemberExpr *E) override {
252 // FIXME: should we be using `E->getFoundDecl()`?
253 const ValueDecl *VD = E->getMemberDecl();
254 insertIfGlobal(*VD, Referenced.Globals);
255 insertIfFunction(*VD, Referenced.Functions);
256 if (const auto *FD = dyn_cast<FieldDecl>(VD))
257 Referenced.Fields.insert(FD);
258 return true;
259 }
260
261 bool VisitInitListExpr(InitListExpr *InitList) override {
262 if (InitList->getType()->isRecordType())
263 for (const auto *FD : getFieldsForInitListExpr(InitList))
264 Referenced.Fields.insert(FD);
265 return true;
266 }
267
268 bool VisitCXXParenListInitExpr(CXXParenListInitExpr *ParenInitList) override {
269 if (ParenInitList->getType()->isRecordType())
270 for (const auto *FD : getFieldsForInitListExpr(ParenInitList))
271 Referenced.Fields.insert(FD);
272 return true;
273 }
274
275private:
276 ReferencedDecls &Referenced;
277};
278
282 Visitor.TraverseStmt(FD.getBody());
283 if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&FD))
284 Visitor.traverseConstructorInits(CtorDecl);
285
286 // If analyzing a lambda call operator, collect all captures of parameters (of
287 // the surrounding function). This collects them even if they are not
288 // referenced in the body of the lambda call operator. Non-parameter local
289 // variables that are captured are already collected into
290 // `ReferencedDecls.Locals` when traversing the call operator body, but we
291 // collect parameters here to avoid needing to check at each referencing node
292 // whether the parameter is a lambda capture from a surrounding function or is
293 // a parameter of the current function. If it becomes necessary to limit this
294 // set to the parameters actually referenced in the body, alternative
295 // optimizations can be implemented to minimize duplicative work.
296 if (const auto *Method = dyn_cast<CXXMethodDecl>(&FD);
297 Method && isLambdaCallOperator(Method)) {
298 for (const auto &Capture : Method->getParent()->captures()) {
299 if (Capture.capturesVariable()) {
300 if (const auto *Param =
301 dyn_cast<ParmVarDecl>(Capture.getCapturedVar())) {
302 Result.LambdaCapturedParams.insert(Param);
303 }
304 }
305 }
306 }
307
308 return Result;
309}
310
314 Visitor.TraverseStmt(const_cast<Stmt *>(&S));
315 return Result;
316}
317
318} // namespace clang::dataflow
#define V(N, I)
Definition: ASTContext.h:3443
This file provides some common utility functions for processing Lambda related AST Constructs.
const Decl * D
Expr * E
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.
SourceLocation Loc
Definition: SemaObjC.cpp:759
C Language Family Type Representation.
Represents a base class of a C++ class.
Definition: DeclCXX.h:146
Represents a C++ constructor within a class.
Definition: DeclCXX.h:2553
Represents a C++ base or member initializer.
Definition: DeclCXX.h:2318
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:4960
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1265
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
virtual bool TraverseStmt(Stmt *S)
Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...
This represents one expression.
Definition: Expr.h:110
QualType getType() const
Definition: Expr.h:142
Represents a member of a struct/union/class.
Definition: Decl.h:3033
Represents a function declaration or definition.
Definition: Decl.h:1935
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition: Decl.cpp:3243
Describes an C or C++ initializer list.
Definition: Expr.h:5088
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3236
A (possibly-)qualified type.
Definition: Type.h:929
Represents a struct/union/class.
Definition: Decl.h:4148
field_range fields() const
Definition: Decl.h:4354
Stmt - This represents one statement.
Definition: Stmt.h:84
The base class of the type hierarchy.
Definition: Type.h:1828
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1916
bool isDependentType() const
Whether this type is a dependent type, meaning that its definition somehow depends on a template para...
Definition: Type.h:2706
bool isIncompleteType(NamedDecl **Def=nullptr) const
Types are partitioned into 3 broad categories (C99 6.2.5p1): object types, function types,...
Definition: Type.cpp:2396
bool isRecordType() const
Definition: Type.h:8286
bool isUnionType() const
Definition: Type.cpp:704
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition: Type.cpp:1920
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:671
Specialization of RecursiveASTVisitor that visits those nodes that are relevant to the dataflow analy...
Definition: ASTOps.h:92
Helper class for initialization of a record with an InitListExpr.
Definition: ASTOps.h:57
RecordInitListHelper(const InitListExpr *InitList)
Definition: ASTOps.cpp:119
llvm::DenseMap< const ValueDecl *, StorageLocation * > FieldToLoc
bool VisitCXXParenListInitExpr(CXXParenListInitExpr *ParenInitList) override
Definition: ASTOps.cpp:268
bool VisitInitListExpr(InitListExpr *InitList) override
Definition: ASTOps.cpp:261
bool VisitMemberExpr(MemberExpr *E) override
Definition: ASTOps.cpp:251
bool VisitDeclRefExpr(DeclRefExpr *E) override
Definition: ASTOps.cpp:235
void traverseConstructorInits(const CXXConstructorDecl *Ctor)
Definition: ASTOps.cpp:207
bool VisitCXXMemberCallExpr(CXXMemberCallExpr *C) override
Definition: ASTOps.cpp:242
ReferencedDeclsVisitor(ReferencedDecls &Referenced)
Definition: ASTOps.cpp:204
bool VisitDecl(Decl *D) override
Definition: ASTOps.cpp:228
Dataflow Directional Tag Classes.
Definition: AdornedCFG.h:29
static void getFieldsFromClassHierarchy(QualType Type, FieldSet &Fields)
Definition: ASTOps.cpp:62
static void insertIfFunction(const Decl &D, llvm::DenseSet< const FunctionDecl * > &Funcs)
Definition: ASTOps.cpp:181
static MemberExpr * getMemberForAccessor(const CXXMemberCallExpr &C)
Definition: ASTOps.cpp:187
ReferencedDecls getReferencedDecls(const FunctionDecl &FD)
Returns declarations that are declared in or referenced from FD.
Definition: ASTOps.cpp:279
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:97
const Expr & ignoreCFGOmittedNodes(const Expr &E)
Skip past nodes that the CFG does not emit.
Definition: ASTOps.cpp:35
FieldSet getObjectFields(QualType Type)
Returns the set of all fields in the type.
Definition: ASTOps.cpp:75
static void insertIfGlobal(const Decl &D, llvm::DenseSet< const VarDecl * > &Globals)
Definition: ASTOps.cpp:167
static void insertIfLocal(const Decl &D, llvm::DenseSet< const VarDecl * > &Locals)
Definition: ASTOps.cpp:174
bool containsSameFields(const FieldSet &Fields, const RecordStorageLocation::FieldToLoc &FieldLocs)
Returns whether Fields and FieldLocs contain the same fields.
Definition: ASTOps.cpp:81
bool isLambdaCallOperator(const CXXMethodDecl *MD)
Definition: ASTLambda.h:27
@ 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:137
llvm::DenseSet< const VarDecl * > Globals
All variables with static storage duration, notably including static member variables and static vari...
Definition: ASTOps.h:142
llvm::DenseSet< const VarDecl * > Locals
Local variables, not including parameters or static variables declared within a function.
Definition: ASTOps.h:145
llvm::DenseSet< const FunctionDecl * > Functions
Free functions and member functions which are referenced (but not necessarily called).
Definition: ASTOps.h:148
FieldSet Fields
Non-static member variables.
Definition: ASTOps.h:139