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