xref: /llvm-project/clang/lib/Analysis/FlowSensitive/ASTOps.cpp (revision 198fb5ed4ac7d096da03ea4a0a27832d18b1350f)
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 
13 #include "clang/Analysis/FlowSensitive/ASTOps.h"
14 #include "clang/AST/ASTLambda.h"
15 #include "clang/AST/ComputeDependence.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"
23 #include "clang/Analysis/FlowSensitive/StorageLocation.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 
33 namespace clang::dataflow {
34 
35 const Expr &ignoreCFGOmittedNodes(const Expr &E) {
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 
54 const Stmt &ignoreCFGOmittedNodes(const Stmt &S) {
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.
62 static void getFieldsFromClassHierarchy(QualType Type, FieldSet &Fields) {
63   if (Type->isIncompleteType() || Type->isDependentType() ||
64       !Type->isRecordType())
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.
75 FieldSet getObjectFields(QualType Type) {
76   FieldSet Fields;
77   getFieldsFromClassHierarchy(Type, Fields);
78   return Fields;
79 }
80 
81 bool 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.
95 template <class InitListT>
96 static std::vector<const FieldDecl *>
97 getFieldsForInitListExpr(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 
119 RecordInitListHelper::RecordInitListHelper(const InitListExpr *InitList)
120     : RecordInitListHelper(InitList->getType(),
121                            getFieldsForInitListExpr(InitList),
122                            InitList->inits()) {}
123 
124 RecordInitListHelper::RecordInitListHelper(
125     const CXXParenListInitExpr *ParenInitList)
126     : RecordInitListHelper(ParenInitList->getType(),
127                            getFieldsForInitListExpr(ParenInitList),
128                            ParenInitList->getInitExprs()) {}
129 
130 RecordInitListHelper::RecordInitListHelper(
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 
167 static 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 
174 static 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 
181 static 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 
187 static MemberExpr *getMemberForAccessor(const CXXMemberCallExpr &C) {
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 
202 class ReferencedDeclsVisitor : public AnalysisASTVisitor {
203 public:
204   ReferencedDeclsVisitor(ReferencedDecls &Referenced)
205       : Referenced(Referenced) {}
206 
207   void traverseConstructorInits(const CXXConstructorDecl *Ctor) {
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 
235   bool VisitDeclRefExpr(DeclRefExpr *E) override {
236     insertIfGlobal(*E->getDecl(), Referenced.Globals);
237     insertIfLocal(*E->getDecl(), Referenced.Locals);
238     insertIfFunction(*E->getDecl(), Referenced.Functions);
239     return true;
240   }
241 
242   bool VisitCXXMemberCallExpr(CXXMemberCallExpr *C) override {
243     // If this is a method that returns a member variable but does nothing else,
244     // model the field of the return value.
245     if (MemberExpr *E = getMemberForAccessor(*C))
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 
275 private:
276   ReferencedDecls &Referenced;
277 };
278 
279 ReferencedDecls getReferencedDecls(const FunctionDecl &FD) {
280   ReferencedDecls Result;
281   ReferencedDeclsVisitor Visitor(Result);
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 
311 ReferencedDecls getReferencedDecls(const Stmt &S) {
312   ReferencedDecls Result;
313   ReferencedDeclsVisitor Visitor(Result);
314   Visitor.TraverseStmt(const_cast<Stmt *>(&S));
315   return Result;
316 }
317 
318 } // namespace clang::dataflow
319