xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/ASTOps.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===-- ASTOps.cc -------------------------------*- C++ -*-===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric //  Operations on AST nodes that are used in flow-sensitive analysis.
10*0fca6ea1SDimitry Andric //
11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
12*0fca6ea1SDimitry Andric 
13*0fca6ea1SDimitry Andric #include "clang/Analysis/FlowSensitive/ASTOps.h"
14*0fca6ea1SDimitry Andric #include "clang/AST/ComputeDependence.h"
15*0fca6ea1SDimitry Andric #include "clang/AST/Decl.h"
16*0fca6ea1SDimitry Andric #include "clang/AST/DeclBase.h"
17*0fca6ea1SDimitry Andric #include "clang/AST/DeclCXX.h"
18*0fca6ea1SDimitry Andric #include "clang/AST/Expr.h"
19*0fca6ea1SDimitry Andric #include "clang/AST/ExprCXX.h"
20*0fca6ea1SDimitry Andric #include "clang/AST/Stmt.h"
21*0fca6ea1SDimitry Andric #include "clang/AST/Type.h"
22*0fca6ea1SDimitry Andric #include "clang/Analysis/FlowSensitive/StorageLocation.h"
23*0fca6ea1SDimitry Andric #include "clang/Basic/LLVM.h"
24*0fca6ea1SDimitry Andric #include "llvm/ADT/DenseSet.h"
25*0fca6ea1SDimitry Andric #include "llvm/ADT/STLExtras.h"
26*0fca6ea1SDimitry Andric #include <cassert>
27*0fca6ea1SDimitry Andric #include <iterator>
28*0fca6ea1SDimitry Andric #include <vector>
29*0fca6ea1SDimitry Andric 
30*0fca6ea1SDimitry Andric #define DEBUG_TYPE "dataflow"
31*0fca6ea1SDimitry Andric 
32*0fca6ea1SDimitry Andric namespace clang::dataflow {
33*0fca6ea1SDimitry Andric 
34*0fca6ea1SDimitry Andric const Expr &ignoreCFGOmittedNodes(const Expr &E) {
35*0fca6ea1SDimitry Andric   const Expr *Current = &E;
36*0fca6ea1SDimitry Andric   const Expr *Last = nullptr;
37*0fca6ea1SDimitry Andric   while (Current != Last) {
38*0fca6ea1SDimitry Andric     Last = Current;
39*0fca6ea1SDimitry Andric     if (auto *EWC = dyn_cast<ExprWithCleanups>(Current)) {
40*0fca6ea1SDimitry Andric       Current = EWC->getSubExpr();
41*0fca6ea1SDimitry Andric       assert(Current != nullptr);
42*0fca6ea1SDimitry Andric     }
43*0fca6ea1SDimitry Andric     if (auto *CE = dyn_cast<ConstantExpr>(Current)) {
44*0fca6ea1SDimitry Andric       Current = CE->getSubExpr();
45*0fca6ea1SDimitry Andric       assert(Current != nullptr);
46*0fca6ea1SDimitry Andric     }
47*0fca6ea1SDimitry Andric     Current = Current->IgnoreParens();
48*0fca6ea1SDimitry Andric     assert(Current != nullptr);
49*0fca6ea1SDimitry Andric   }
50*0fca6ea1SDimitry Andric   return *Current;
51*0fca6ea1SDimitry Andric }
52*0fca6ea1SDimitry Andric 
53*0fca6ea1SDimitry Andric const Stmt &ignoreCFGOmittedNodes(const Stmt &S) {
54*0fca6ea1SDimitry Andric   if (auto *E = dyn_cast<Expr>(&S))
55*0fca6ea1SDimitry Andric     return ignoreCFGOmittedNodes(*E);
56*0fca6ea1SDimitry Andric   return S;
57*0fca6ea1SDimitry Andric }
58*0fca6ea1SDimitry Andric 
59*0fca6ea1SDimitry Andric // FIXME: Does not precisely handle non-virtual diamond inheritance. A single
60*0fca6ea1SDimitry Andric // field decl will be modeled for all instances of the inherited field.
61*0fca6ea1SDimitry Andric static void getFieldsFromClassHierarchy(QualType Type, FieldSet &Fields) {
62*0fca6ea1SDimitry Andric   if (Type->isIncompleteType() || Type->isDependentType() ||
63*0fca6ea1SDimitry Andric       !Type->isRecordType())
64*0fca6ea1SDimitry Andric     return;
65*0fca6ea1SDimitry Andric 
66*0fca6ea1SDimitry Andric   for (const FieldDecl *Field : Type->getAsRecordDecl()->fields())
67*0fca6ea1SDimitry Andric     Fields.insert(Field);
68*0fca6ea1SDimitry Andric   if (auto *CXXRecord = Type->getAsCXXRecordDecl())
69*0fca6ea1SDimitry Andric     for (const CXXBaseSpecifier &Base : CXXRecord->bases())
70*0fca6ea1SDimitry Andric       getFieldsFromClassHierarchy(Base.getType(), Fields);
71*0fca6ea1SDimitry Andric }
72*0fca6ea1SDimitry Andric 
73*0fca6ea1SDimitry Andric /// Gets the set of all fields in the type.
74*0fca6ea1SDimitry Andric FieldSet getObjectFields(QualType Type) {
75*0fca6ea1SDimitry Andric   FieldSet Fields;
76*0fca6ea1SDimitry Andric   getFieldsFromClassHierarchy(Type, Fields);
77*0fca6ea1SDimitry Andric   return Fields;
78*0fca6ea1SDimitry Andric }
79*0fca6ea1SDimitry Andric 
80*0fca6ea1SDimitry Andric bool containsSameFields(const FieldSet &Fields,
81*0fca6ea1SDimitry Andric                         const RecordStorageLocation::FieldToLoc &FieldLocs) {
82*0fca6ea1SDimitry Andric   if (Fields.size() != FieldLocs.size())
83*0fca6ea1SDimitry Andric     return false;
84*0fca6ea1SDimitry Andric   for ([[maybe_unused]] auto [Field, Loc] : FieldLocs)
85*0fca6ea1SDimitry Andric     if (!Fields.contains(cast_or_null<FieldDecl>(Field)))
86*0fca6ea1SDimitry Andric       return false;
87*0fca6ea1SDimitry Andric   return true;
88*0fca6ea1SDimitry Andric }
89*0fca6ea1SDimitry Andric 
90*0fca6ea1SDimitry Andric /// Returns the fields of a `RecordDecl` that are initialized by an
91*0fca6ea1SDimitry Andric /// `InitListExpr` or `CXXParenListInitExpr`, in the order in which they appear
92*0fca6ea1SDimitry Andric /// in `InitListExpr::inits()` / `CXXParenListInitExpr::getInitExprs()`.
93*0fca6ea1SDimitry Andric /// `InitList->getType()` must be a record type.
94*0fca6ea1SDimitry Andric template <class InitListT>
95*0fca6ea1SDimitry Andric static std::vector<const FieldDecl *>
96*0fca6ea1SDimitry Andric getFieldsForInitListExpr(const InitListT *InitList) {
97*0fca6ea1SDimitry Andric   const RecordDecl *RD = InitList->getType()->getAsRecordDecl();
98*0fca6ea1SDimitry Andric   assert(RD != nullptr);
99*0fca6ea1SDimitry Andric 
100*0fca6ea1SDimitry Andric   std::vector<const FieldDecl *> Fields;
101*0fca6ea1SDimitry Andric 
102*0fca6ea1SDimitry Andric   if (InitList->getType()->isUnionType()) {
103*0fca6ea1SDimitry Andric     if (const FieldDecl *Field = InitList->getInitializedFieldInUnion())
104*0fca6ea1SDimitry Andric       Fields.push_back(Field);
105*0fca6ea1SDimitry Andric     return Fields;
106*0fca6ea1SDimitry Andric   }
107*0fca6ea1SDimitry Andric 
108*0fca6ea1SDimitry Andric   // Unnamed bitfields are only used for padding and do not appear in
109*0fca6ea1SDimitry Andric   // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s
110*0fca6ea1SDimitry Andric   // field list, and we thus need to remove them before mapping inits to
111*0fca6ea1SDimitry Andric   // fields to avoid mapping inits to the wrongs fields.
112*0fca6ea1SDimitry Andric   llvm::copy_if(
113*0fca6ea1SDimitry Andric       RD->fields(), std::back_inserter(Fields),
114*0fca6ea1SDimitry Andric       [](const FieldDecl *Field) { return !Field->isUnnamedBitField(); });
115*0fca6ea1SDimitry Andric   return Fields;
116*0fca6ea1SDimitry Andric }
117*0fca6ea1SDimitry Andric 
118*0fca6ea1SDimitry Andric RecordInitListHelper::RecordInitListHelper(const InitListExpr *InitList)
119*0fca6ea1SDimitry Andric     : RecordInitListHelper(InitList->getType(),
120*0fca6ea1SDimitry Andric                            getFieldsForInitListExpr(InitList),
121*0fca6ea1SDimitry Andric                            InitList->inits()) {}
122*0fca6ea1SDimitry Andric 
123*0fca6ea1SDimitry Andric RecordInitListHelper::RecordInitListHelper(
124*0fca6ea1SDimitry Andric     const CXXParenListInitExpr *ParenInitList)
125*0fca6ea1SDimitry Andric     : RecordInitListHelper(ParenInitList->getType(),
126*0fca6ea1SDimitry Andric                            getFieldsForInitListExpr(ParenInitList),
127*0fca6ea1SDimitry Andric                            ParenInitList->getInitExprs()) {}
128*0fca6ea1SDimitry Andric 
129*0fca6ea1SDimitry Andric RecordInitListHelper::RecordInitListHelper(
130*0fca6ea1SDimitry Andric     QualType Ty, std::vector<const FieldDecl *> Fields,
131*0fca6ea1SDimitry Andric     ArrayRef<Expr *> Inits) {
132*0fca6ea1SDimitry Andric   auto *RD = Ty->getAsCXXRecordDecl();
133*0fca6ea1SDimitry Andric   assert(RD != nullptr);
134*0fca6ea1SDimitry Andric 
135*0fca6ea1SDimitry Andric   // Unions initialized with an empty initializer list need special treatment.
136*0fca6ea1SDimitry Andric   // For structs/classes initialized with an empty initializer list, Clang
137*0fca6ea1SDimitry Andric   // puts `ImplicitValueInitExpr`s in `InitListExpr::inits()`, but for unions,
138*0fca6ea1SDimitry Andric   // it doesn't do this -- so we create an `ImplicitValueInitExpr` ourselves.
139*0fca6ea1SDimitry Andric   SmallVector<Expr *> InitsForUnion;
140*0fca6ea1SDimitry Andric   if (Ty->isUnionType() && Inits.empty()) {
141*0fca6ea1SDimitry Andric     assert(Fields.size() <= 1);
142*0fca6ea1SDimitry Andric     if (!Fields.empty()) {
143*0fca6ea1SDimitry Andric       ImplicitValueInitForUnion.emplace(Fields.front()->getType());
144*0fca6ea1SDimitry Andric       InitsForUnion.push_back(&*ImplicitValueInitForUnion);
145*0fca6ea1SDimitry Andric     }
146*0fca6ea1SDimitry Andric     Inits = InitsForUnion;
147*0fca6ea1SDimitry Andric   }
148*0fca6ea1SDimitry Andric 
149*0fca6ea1SDimitry Andric   size_t InitIdx = 0;
150*0fca6ea1SDimitry Andric 
151*0fca6ea1SDimitry Andric   assert(Fields.size() + RD->getNumBases() == Inits.size());
152*0fca6ea1SDimitry Andric   for (const CXXBaseSpecifier &Base : RD->bases()) {
153*0fca6ea1SDimitry Andric     assert(InitIdx < Inits.size());
154*0fca6ea1SDimitry Andric     Expr *Init = Inits[InitIdx++];
155*0fca6ea1SDimitry Andric     BaseInits.emplace_back(&Base, Init);
156*0fca6ea1SDimitry Andric   }
157*0fca6ea1SDimitry Andric 
158*0fca6ea1SDimitry Andric   assert(Fields.size() == Inits.size() - InitIdx);
159*0fca6ea1SDimitry Andric   for (const FieldDecl *Field : Fields) {
160*0fca6ea1SDimitry Andric     assert(InitIdx < Inits.size());
161*0fca6ea1SDimitry Andric     Expr *Init = Inits[InitIdx++];
162*0fca6ea1SDimitry Andric     FieldInits.emplace_back(Field, Init);
163*0fca6ea1SDimitry Andric   }
164*0fca6ea1SDimitry Andric }
165*0fca6ea1SDimitry Andric 
166*0fca6ea1SDimitry Andric static void insertIfGlobal(const Decl &D,
167*0fca6ea1SDimitry Andric                            llvm::DenseSet<const VarDecl *> &Globals) {
168*0fca6ea1SDimitry Andric   if (auto *V = dyn_cast<VarDecl>(&D))
169*0fca6ea1SDimitry Andric     if (V->hasGlobalStorage())
170*0fca6ea1SDimitry Andric       Globals.insert(V);
171*0fca6ea1SDimitry Andric }
172*0fca6ea1SDimitry Andric 
173*0fca6ea1SDimitry Andric static void insertIfFunction(const Decl &D,
174*0fca6ea1SDimitry Andric                              llvm::DenseSet<const FunctionDecl *> &Funcs) {
175*0fca6ea1SDimitry Andric   if (auto *FD = dyn_cast<FunctionDecl>(&D))
176*0fca6ea1SDimitry Andric     Funcs.insert(FD);
177*0fca6ea1SDimitry Andric }
178*0fca6ea1SDimitry Andric 
179*0fca6ea1SDimitry Andric static MemberExpr *getMemberForAccessor(const CXXMemberCallExpr &C) {
180*0fca6ea1SDimitry Andric   // Use getCalleeDecl instead of getMethodDecl in order to handle
181*0fca6ea1SDimitry Andric   // pointer-to-member calls.
182*0fca6ea1SDimitry Andric   const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(C.getCalleeDecl());
183*0fca6ea1SDimitry Andric   if (!MethodDecl)
184*0fca6ea1SDimitry Andric     return nullptr;
185*0fca6ea1SDimitry Andric   auto *Body = dyn_cast_or_null<CompoundStmt>(MethodDecl->getBody());
186*0fca6ea1SDimitry Andric   if (!Body || Body->size() != 1)
187*0fca6ea1SDimitry Andric     return nullptr;
188*0fca6ea1SDimitry Andric   if (auto *RS = dyn_cast<ReturnStmt>(*Body->body_begin()))
189*0fca6ea1SDimitry Andric     if (auto *Return = RS->getRetValue())
190*0fca6ea1SDimitry Andric       return dyn_cast<MemberExpr>(Return->IgnoreParenImpCasts());
191*0fca6ea1SDimitry Andric   return nullptr;
192*0fca6ea1SDimitry Andric }
193*0fca6ea1SDimitry Andric 
194*0fca6ea1SDimitry Andric class ReferencedDeclsVisitor
195*0fca6ea1SDimitry Andric     : public AnalysisASTVisitor<ReferencedDeclsVisitor> {
196*0fca6ea1SDimitry Andric public:
197*0fca6ea1SDimitry Andric   ReferencedDeclsVisitor(ReferencedDecls &Referenced)
198*0fca6ea1SDimitry Andric       : Referenced(Referenced) {}
199*0fca6ea1SDimitry Andric 
200*0fca6ea1SDimitry Andric   void TraverseConstructorInits(const CXXConstructorDecl *Ctor) {
201*0fca6ea1SDimitry Andric     for (const CXXCtorInitializer *Init : Ctor->inits()) {
202*0fca6ea1SDimitry Andric       if (Init->isMemberInitializer()) {
203*0fca6ea1SDimitry Andric         Referenced.Fields.insert(Init->getMember());
204*0fca6ea1SDimitry Andric       } else if (Init->isIndirectMemberInitializer()) {
205*0fca6ea1SDimitry Andric         for (const auto *I : Init->getIndirectMember()->chain())
206*0fca6ea1SDimitry Andric           Referenced.Fields.insert(cast<FieldDecl>(I));
207*0fca6ea1SDimitry Andric       }
208*0fca6ea1SDimitry Andric 
209*0fca6ea1SDimitry Andric       Expr *InitExpr = Init->getInit();
210*0fca6ea1SDimitry Andric 
211*0fca6ea1SDimitry Andric       // Also collect declarations referenced in `InitExpr`.
212*0fca6ea1SDimitry Andric       TraverseStmt(InitExpr);
213*0fca6ea1SDimitry Andric 
214*0fca6ea1SDimitry Andric       // If this is a `CXXDefaultInitExpr`, also collect declarations referenced
215*0fca6ea1SDimitry Andric       // within the default expression.
216*0fca6ea1SDimitry Andric       if (auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(InitExpr))
217*0fca6ea1SDimitry Andric         TraverseStmt(DefaultInit->getExpr());
218*0fca6ea1SDimitry Andric     }
219*0fca6ea1SDimitry Andric   }
220*0fca6ea1SDimitry Andric 
221*0fca6ea1SDimitry Andric   bool VisitDecl(Decl *D) {
222*0fca6ea1SDimitry Andric     insertIfGlobal(*D, Referenced.Globals);
223*0fca6ea1SDimitry Andric     insertIfFunction(*D, Referenced.Functions);
224*0fca6ea1SDimitry Andric     return true;
225*0fca6ea1SDimitry Andric   }
226*0fca6ea1SDimitry Andric 
227*0fca6ea1SDimitry Andric   bool VisitDeclRefExpr(DeclRefExpr *E) {
228*0fca6ea1SDimitry Andric     insertIfGlobal(*E->getDecl(), Referenced.Globals);
229*0fca6ea1SDimitry Andric     insertIfFunction(*E->getDecl(), Referenced.Functions);
230*0fca6ea1SDimitry Andric     return true;
231*0fca6ea1SDimitry Andric   }
232*0fca6ea1SDimitry Andric 
233*0fca6ea1SDimitry Andric   bool VisitCXXMemberCallExpr(CXXMemberCallExpr *C) {
234*0fca6ea1SDimitry Andric     // If this is a method that returns a member variable but does nothing else,
235*0fca6ea1SDimitry Andric     // model the field of the return value.
236*0fca6ea1SDimitry Andric     if (MemberExpr *E = getMemberForAccessor(*C))
237*0fca6ea1SDimitry Andric       if (const auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl()))
238*0fca6ea1SDimitry Andric         Referenced.Fields.insert(FD);
239*0fca6ea1SDimitry Andric     return true;
240*0fca6ea1SDimitry Andric   }
241*0fca6ea1SDimitry Andric 
242*0fca6ea1SDimitry Andric   bool VisitMemberExpr(MemberExpr *E) {
243*0fca6ea1SDimitry Andric     // FIXME: should we be using `E->getFoundDecl()`?
244*0fca6ea1SDimitry Andric     const ValueDecl *VD = E->getMemberDecl();
245*0fca6ea1SDimitry Andric     insertIfGlobal(*VD, Referenced.Globals);
246*0fca6ea1SDimitry Andric     insertIfFunction(*VD, Referenced.Functions);
247*0fca6ea1SDimitry Andric     if (const auto *FD = dyn_cast<FieldDecl>(VD))
248*0fca6ea1SDimitry Andric       Referenced.Fields.insert(FD);
249*0fca6ea1SDimitry Andric     return true;
250*0fca6ea1SDimitry Andric   }
251*0fca6ea1SDimitry Andric 
252*0fca6ea1SDimitry Andric   bool VisitInitListExpr(InitListExpr *InitList) {
253*0fca6ea1SDimitry Andric     if (InitList->getType()->isRecordType())
254*0fca6ea1SDimitry Andric       for (const auto *FD : getFieldsForInitListExpr(InitList))
255*0fca6ea1SDimitry Andric         Referenced.Fields.insert(FD);
256*0fca6ea1SDimitry Andric     return true;
257*0fca6ea1SDimitry Andric   }
258*0fca6ea1SDimitry Andric 
259*0fca6ea1SDimitry Andric   bool VisitCXXParenListInitExpr(CXXParenListInitExpr *ParenInitList) {
260*0fca6ea1SDimitry Andric     if (ParenInitList->getType()->isRecordType())
261*0fca6ea1SDimitry Andric       for (const auto *FD : getFieldsForInitListExpr(ParenInitList))
262*0fca6ea1SDimitry Andric         Referenced.Fields.insert(FD);
263*0fca6ea1SDimitry Andric     return true;
264*0fca6ea1SDimitry Andric   }
265*0fca6ea1SDimitry Andric 
266*0fca6ea1SDimitry Andric private:
267*0fca6ea1SDimitry Andric   ReferencedDecls &Referenced;
268*0fca6ea1SDimitry Andric };
269*0fca6ea1SDimitry Andric 
270*0fca6ea1SDimitry Andric ReferencedDecls getReferencedDecls(const FunctionDecl &FD) {
271*0fca6ea1SDimitry Andric   ReferencedDecls Result;
272*0fca6ea1SDimitry Andric   ReferencedDeclsVisitor Visitor(Result);
273*0fca6ea1SDimitry Andric   Visitor.TraverseStmt(FD.getBody());
274*0fca6ea1SDimitry Andric   if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&FD))
275*0fca6ea1SDimitry Andric     Visitor.TraverseConstructorInits(CtorDecl);
276*0fca6ea1SDimitry Andric 
277*0fca6ea1SDimitry Andric   return Result;
278*0fca6ea1SDimitry Andric }
279*0fca6ea1SDimitry Andric 
280*0fca6ea1SDimitry Andric ReferencedDecls getReferencedDecls(const Stmt &S) {
281*0fca6ea1SDimitry Andric   ReferencedDecls Result;
282*0fca6ea1SDimitry Andric   ReferencedDeclsVisitor Visitor(Result);
283*0fca6ea1SDimitry Andric   Visitor.TraverseStmt(const_cast<Stmt *>(&S));
284*0fca6ea1SDimitry Andric   return Result;
285*0fca6ea1SDimitry Andric }
286*0fca6ea1SDimitry Andric 
287*0fca6ea1SDimitry Andric } // namespace clang::dataflow
288