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 
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 
32 namespace clang::dataflow {
33 
34 const Expr &ignoreCFGOmittedNodes(const Expr &E) {
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 
53 const Stmt &ignoreCFGOmittedNodes(const Stmt &S) {
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.
63  !Type->isRecordType())
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 
80 bool 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.
94 template <class InitListT>
95 static std::vector<const FieldDecl *>
96 getFieldsForInitListExpr(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  if (const FieldDecl *Field = InitList->getInitializedFieldInUnion())
104  Fields.push_back(Field);
105  return Fields;
106  }
107 
108  // Unnamed bitfields are only used for padding and do not appear in
109  // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s
110  // field list, and we thus need to remove them before mapping inits to
111  // fields to avoid mapping inits to the wrongs fields.
112  llvm::copy_if(
113  RD->fields(), std::back_inserter(Fields),
114  [](const FieldDecl *Field) { return !Field->isUnnamedBitField(); });
115  return Fields;
116 }
117 
119  : RecordInitListHelper(InitList->getType(),
120  getFieldsForInitListExpr(InitList),
121  InitList->inits()) {}
122 
124  const CXXParenListInitExpr *ParenInitList)
125  : RecordInitListHelper(ParenInitList->getType(),
126  getFieldsForInitListExpr(ParenInitList),
127  ParenInitList->getInitExprs()) {}
128 
130  QualType Ty, std::vector<const FieldDecl *> Fields,
131  ArrayRef<Expr *> Inits) {
132  auto *RD = Ty->getAsCXXRecordDecl();
133  assert(RD != nullptr);
134 
135  // Unions initialized with an empty initializer list need special treatment.
136  // For structs/classes initialized with an empty initializer list, Clang
137  // puts `ImplicitValueInitExpr`s in `InitListExpr::inits()`, but for unions,
138  // it doesn't do this -- so we create an `ImplicitValueInitExpr` ourselves.
139  SmallVector<Expr *> InitsForUnion;
140  if (Ty->isUnionType() && Inits.empty()) {
141  assert(Fields.size() <= 1);
142  if (!Fields.empty()) {
143  ImplicitValueInitForUnion.emplace(Fields.front()->getType());
144  InitsForUnion.push_back(&*ImplicitValueInitForUnion);
145  }
146  Inits = InitsForUnion;
147  }
148 
149  size_t InitIdx = 0;
150 
151  assert(Fields.size() + RD->getNumBases() == Inits.size());
152  for (const CXXBaseSpecifier &Base : RD->bases()) {
153  assert(InitIdx < Inits.size());
154  Expr *Init = Inits[InitIdx++];
155  BaseInits.emplace_back(&Base, Init);
156  }
157 
158  assert(Fields.size() == Inits.size() - InitIdx);
159  for (const FieldDecl *Field : Fields) {
160  assert(InitIdx < Inits.size());
161  Expr *Init = Inits[InitIdx++];
162  FieldInits.emplace_back(Field, Init);
163  }
164 }
165 
166 static void insertIfGlobal(const Decl &D,
167  llvm::DenseSet<const VarDecl *> &Globals) {
168  if (auto *V = dyn_cast<VarDecl>(&D))
169  if (V->hasGlobalStorage())
170  Globals.insert(V);
171 }
172 
173 static void insertIfFunction(const Decl &D,
174  llvm::DenseSet<const FunctionDecl *> &Funcs) {
175  if (auto *FD = dyn_cast<FunctionDecl>(&D))
176  Funcs.insert(FD);
177 }
178 
180  // Use getCalleeDecl instead of getMethodDecl in order to handle
181  // pointer-to-member calls.
182  const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(C.getCalleeDecl());
183  if (!MethodDecl)
184  return nullptr;
185  auto *Body = dyn_cast_or_null<CompoundStmt>(MethodDecl->getBody());
186  if (!Body || Body->size() != 1)
187  return nullptr;
188  if (auto *RS = dyn_cast<ReturnStmt>(*Body->body_begin()))
189  if (auto *Return = RS->getRetValue())
190  return dyn_cast<MemberExpr>(Return->IgnoreParenImpCasts());
191  return nullptr;
192 }
193 
195  : public AnalysisASTVisitor<ReferencedDeclsVisitor> {
196 public:
198  : Referenced(Referenced) {}
199 
201  for (const CXXCtorInitializer *Init : Ctor->inits()) {
202  if (Init->isMemberInitializer()) {
203  Referenced.Fields.insert(Init->getMember());
204  } else if (Init->isIndirectMemberInitializer()) {
205  for (const auto *I : Init->getIndirectMember()->chain())
206  Referenced.Fields.insert(cast<FieldDecl>(I));
207  }
208 
209  Expr *InitExpr = Init->getInit();
210 
211  // Also collect declarations referenced in `InitExpr`.
212  TraverseStmt(InitExpr);
213 
214  // If this is a `CXXDefaultInitExpr`, also collect declarations referenced
215  // within the default expression.
216  if (auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(InitExpr))
217  TraverseStmt(DefaultInit->getExpr());
218  }
219  }
220 
221  bool VisitDecl(Decl *D) {
222  insertIfGlobal(*D, Referenced.Globals);
223  insertIfFunction(*D, Referenced.Functions);
224  return true;
225  }
226 
228  insertIfGlobal(*E->getDecl(), Referenced.Globals);
229  insertIfFunction(*E->getDecl(), Referenced.Functions);
230  return true;
231  }
232 
234  // If this is a method that returns a member variable but does nothing else,
235  // model the field of the return value.
236  if (MemberExpr *E = getMemberForAccessor(*C))
237  if (const auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl()))
238  Referenced.Fields.insert(FD);
239  return true;
240  }
241 
243  // FIXME: should we be using `E->getFoundDecl()`?
244  const ValueDecl *VD = E->getMemberDecl();
245  insertIfGlobal(*VD, Referenced.Globals);
246  insertIfFunction(*VD, Referenced.Functions);
247  if (const auto *FD = dyn_cast<FieldDecl>(VD))
248  Referenced.Fields.insert(FD);
249  return true;
250  }
251 
252  bool VisitInitListExpr(InitListExpr *InitList) {
253  if (InitList->getType()->isRecordType())
254  for (const auto *FD : getFieldsForInitListExpr(InitList))
255  Referenced.Fields.insert(FD);
256  return true;
257  }
258 
260  if (ParenInitList->getType()->isRecordType())
261  for (const auto *FD : getFieldsForInitListExpr(ParenInitList))
262  Referenced.Fields.insert(FD);
263  return true;
264  }
265 
266 private:
267  ReferencedDecls &Referenced;
268 };
269 
271  ReferencedDecls Result;
272  ReferencedDeclsVisitor Visitor(Result);
273  Visitor.TraverseStmt(FD.getBody());
274  if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&FD))
275  Visitor.TraverseConstructorInits(CtorDecl);
276 
277  return Result;
278 }
279 
281  ReferencedDecls Result;
282  ReferencedDeclsVisitor Visitor(Result);
283  Visitor.TraverseStmt(const_cast<Stmt *>(&S));
284  return Result;
285 }
286 
287 } // namespace clang::dataflow
#define V(N, I)
Definition: ASTContext.h:3346
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:2539
Represents a C++ base or member initializer.
Definition: DeclCXX.h:2304
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:4953
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
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:3031
Represents a function declaration or definition.
Definition: Decl.h:1933
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition: Decl.cpp:3228
Describes an C or C++ initializer list.
Definition: Expr.h:5070
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3239
A (possibly-)qualified type.
Definition: Type.h:941
Represents a struct/union/class.
Definition: Decl.h:4146
field_range fields() const
Definition: Decl.h:4352
bool TraverseStmt(Stmt *S, DataRecursionQueue *Queue=nullptr)
Recursively visit a statement or expression, by dispatching to Traverse*() based on the argument's dy...
Stmt - This represents one statement.
Definition: Stmt.h:84
The base class of the type hierarchy.
Definition: Type.h:1829
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1882
bool isDependentType() const
Whether this type is a dependent type, meaning that its definition somehow depends on a template para...
Definition: Type.h:2701
bool isIncompleteType(NamedDecl **Def=nullptr) const
Types are partitioned into 3 broad categories (C99 6.2.5p1): object types, function types,...
Definition: Type.cpp:2362
bool isRecordType() const
Definition: Type.h:8113
bool isUnionType() const
Definition: Type.cpp:671
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition: Type.cpp:1886
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:668
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:56
RecordInitListHelper(const InitListExpr *InitList)
Definition: ASTOps.cpp:118
llvm::DenseMap< const ValueDecl *, StorageLocation * > FieldToLoc
bool VisitCXXParenListInitExpr(CXXParenListInitExpr *ParenInitList)
Definition: ASTOps.cpp:259
bool VisitMemberExpr(MemberExpr *E)
Definition: ASTOps.cpp:242
void TraverseConstructorInits(const CXXConstructorDecl *Ctor)
Definition: ASTOps.cpp:200
bool VisitCXXMemberCallExpr(CXXMemberCallExpr *C)
Definition: ASTOps.cpp:233
bool VisitDeclRefExpr(DeclRefExpr *E)
Definition: ASTOps.cpp:227
bool VisitInitListExpr(InitListExpr *InitList)
Definition: ASTOps.cpp:252
ReferencedDeclsVisitor(ReferencedDecls &Referenced)
Definition: ASTOps.cpp:197
Dataflow Directional Tag Classes.
Definition: AdornedCFG.h:29
static void getFieldsFromClassHierarchy(QualType Type, FieldSet &Fields)
Definition: ASTOps.cpp:61
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
static MemberExpr * getMemberForAccessor(const CXXMemberCallExpr &C)
Definition: ASTOps.cpp:179
static void insertIfFunction(const Decl &D, llvm::DenseSet< const FunctionDecl * > &Funcs)
Definition: ASTOps.cpp:173
ReferencedDecls getReferencedDecls(const FunctionDecl &FD)
Returns declarations that are declared in or referenced from FD.
Definition: ASTOps.cpp:270
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:166
bool containsSameFields(const FieldSet &Fields, const RecordStorageLocation::FieldToLoc &FieldLocs)
Returns whether Fields and FieldLocs contain the same fields.
Definition: ASTOps.cpp:80
bool Init(InterpState &S, CodePtr OpPC)
Definition: Interp.h:1745
A collection of several types of declarations, all referenced from the same function.
Definition: ASTOps.h:136
llvm::DenseSet< const VarDecl * > Globals
All variables with static storage duration, notably including static member variables and static vari...
Definition: ASTOps.h:141
llvm::DenseSet< const FunctionDecl * > Functions
Free functions and member functions which are referenced (but not necessarily called).
Definition: ASTOps.h:144
FieldSet Fields
Non-static member variables.
Definition: ASTOps.h:138