19ec8c961SSamira Bazuzi //===-- ASTOps.cc -------------------------------*- C++ -*-===// 29ec8c961SSamira Bazuzi // 39ec8c961SSamira Bazuzi // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 49ec8c961SSamira Bazuzi // See https://llvm.org/LICENSE.txt for license information. 59ec8c961SSamira Bazuzi // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 69ec8c961SSamira Bazuzi // 79ec8c961SSamira Bazuzi //===----------------------------------------------------------------------===// 89ec8c961SSamira Bazuzi // 99ec8c961SSamira Bazuzi // Operations on AST nodes that are used in flow-sensitive analysis. 109ec8c961SSamira Bazuzi // 119ec8c961SSamira Bazuzi //===----------------------------------------------------------------------===// 129ec8c961SSamira Bazuzi 139ec8c961SSamira Bazuzi #include "clang/Analysis/FlowSensitive/ASTOps.h" 14*198fb5edSSamira Bazuzi #include "clang/AST/ASTLambda.h" 159ec8c961SSamira Bazuzi #include "clang/AST/ComputeDependence.h" 169ec8c961SSamira Bazuzi #include "clang/AST/Decl.h" 179ec8c961SSamira Bazuzi #include "clang/AST/DeclBase.h" 189ec8c961SSamira Bazuzi #include "clang/AST/DeclCXX.h" 199ec8c961SSamira Bazuzi #include "clang/AST/Expr.h" 209ec8c961SSamira Bazuzi #include "clang/AST/ExprCXX.h" 219ec8c961SSamira Bazuzi #include "clang/AST/Stmt.h" 229ec8c961SSamira Bazuzi #include "clang/AST/Type.h" 239ec8c961SSamira Bazuzi #include "clang/Analysis/FlowSensitive/StorageLocation.h" 249ec8c961SSamira Bazuzi #include "clang/Basic/LLVM.h" 259ec8c961SSamira Bazuzi #include "llvm/ADT/DenseSet.h" 269ec8c961SSamira Bazuzi #include "llvm/ADT/STLExtras.h" 279ec8c961SSamira Bazuzi #include <cassert> 289ec8c961SSamira Bazuzi #include <iterator> 299ec8c961SSamira Bazuzi #include <vector> 309ec8c961SSamira Bazuzi 319ec8c961SSamira Bazuzi #define DEBUG_TYPE "dataflow" 329ec8c961SSamira Bazuzi 339ec8c961SSamira Bazuzi namespace clang::dataflow { 349ec8c961SSamira Bazuzi 359ec8c961SSamira Bazuzi const Expr &ignoreCFGOmittedNodes(const Expr &E) { 369ec8c961SSamira Bazuzi const Expr *Current = &E; 37c70f0583Smartinboehme const Expr *Last = nullptr; 38c70f0583Smartinboehme while (Current != Last) { 39c70f0583Smartinboehme Last = Current; 409ec8c961SSamira Bazuzi if (auto *EWC = dyn_cast<ExprWithCleanups>(Current)) { 419ec8c961SSamira Bazuzi Current = EWC->getSubExpr(); 429ec8c961SSamira Bazuzi assert(Current != nullptr); 439ec8c961SSamira Bazuzi } 44c70f0583Smartinboehme if (auto *CE = dyn_cast<ConstantExpr>(Current)) { 45c70f0583Smartinboehme Current = CE->getSubExpr(); 46c70f0583Smartinboehme assert(Current != nullptr); 47c70f0583Smartinboehme } 489ec8c961SSamira Bazuzi Current = Current->IgnoreParens(); 499ec8c961SSamira Bazuzi assert(Current != nullptr); 50c70f0583Smartinboehme } 519ec8c961SSamira Bazuzi return *Current; 529ec8c961SSamira Bazuzi } 539ec8c961SSamira Bazuzi 549ec8c961SSamira Bazuzi const Stmt &ignoreCFGOmittedNodes(const Stmt &S) { 559ec8c961SSamira Bazuzi if (auto *E = dyn_cast<Expr>(&S)) 569ec8c961SSamira Bazuzi return ignoreCFGOmittedNodes(*E); 579ec8c961SSamira Bazuzi return S; 589ec8c961SSamira Bazuzi } 599ec8c961SSamira Bazuzi 609ec8c961SSamira Bazuzi // FIXME: Does not precisely handle non-virtual diamond inheritance. A single 619ec8c961SSamira Bazuzi // field decl will be modeled for all instances of the inherited field. 629ec8c961SSamira Bazuzi static void getFieldsFromClassHierarchy(QualType Type, FieldSet &Fields) { 639ec8c961SSamira Bazuzi if (Type->isIncompleteType() || Type->isDependentType() || 649ec8c961SSamira Bazuzi !Type->isRecordType()) 659ec8c961SSamira Bazuzi return; 669ec8c961SSamira Bazuzi 679ec8c961SSamira Bazuzi for (const FieldDecl *Field : Type->getAsRecordDecl()->fields()) 689ec8c961SSamira Bazuzi Fields.insert(Field); 699ec8c961SSamira Bazuzi if (auto *CXXRecord = Type->getAsCXXRecordDecl()) 709ec8c961SSamira Bazuzi for (const CXXBaseSpecifier &Base : CXXRecord->bases()) 719ec8c961SSamira Bazuzi getFieldsFromClassHierarchy(Base.getType(), Fields); 729ec8c961SSamira Bazuzi } 739ec8c961SSamira Bazuzi 749ec8c961SSamira Bazuzi /// Gets the set of all fields in the type. 759ec8c961SSamira Bazuzi FieldSet getObjectFields(QualType Type) { 769ec8c961SSamira Bazuzi FieldSet Fields; 779ec8c961SSamira Bazuzi getFieldsFromClassHierarchy(Type, Fields); 789ec8c961SSamira Bazuzi return Fields; 799ec8c961SSamira Bazuzi } 809ec8c961SSamira Bazuzi 819ec8c961SSamira Bazuzi bool containsSameFields(const FieldSet &Fields, 829ec8c961SSamira Bazuzi const RecordStorageLocation::FieldToLoc &FieldLocs) { 839ec8c961SSamira Bazuzi if (Fields.size() != FieldLocs.size()) 849ec8c961SSamira Bazuzi return false; 859ec8c961SSamira Bazuzi for ([[maybe_unused]] auto [Field, Loc] : FieldLocs) 869ec8c961SSamira Bazuzi if (!Fields.contains(cast_or_null<FieldDecl>(Field))) 879ec8c961SSamira Bazuzi return false; 889ec8c961SSamira Bazuzi return true; 899ec8c961SSamira Bazuzi } 909ec8c961SSamira Bazuzi 919ec8c961SSamira Bazuzi /// Returns the fields of a `RecordDecl` that are initialized by an 92ca7d9442Smartinboehme /// `InitListExpr` or `CXXParenListInitExpr`, in the order in which they appear 93ca7d9442Smartinboehme /// in `InitListExpr::inits()` / `CXXParenListInitExpr::getInitExprs()`. 94ca7d9442Smartinboehme /// `InitList->getType()` must be a record type. 95ca7d9442Smartinboehme template <class InitListT> 969ec8c961SSamira Bazuzi static std::vector<const FieldDecl *> 97ca7d9442Smartinboehme getFieldsForInitListExpr(const InitListT *InitList) { 989ec8c961SSamira Bazuzi const RecordDecl *RD = InitList->getType()->getAsRecordDecl(); 999ec8c961SSamira Bazuzi assert(RD != nullptr); 1009ec8c961SSamira Bazuzi 1019ec8c961SSamira Bazuzi std::vector<const FieldDecl *> Fields; 1029ec8c961SSamira Bazuzi 1039ec8c961SSamira Bazuzi if (InitList->getType()->isUnionType()) { 104275196d8Smartinboehme if (const FieldDecl *Field = InitList->getInitializedFieldInUnion()) 105275196d8Smartinboehme Fields.push_back(Field); 1069ec8c961SSamira Bazuzi return Fields; 1079ec8c961SSamira Bazuzi } 1089ec8c961SSamira Bazuzi 1099ec8c961SSamira Bazuzi // Unnamed bitfields are only used for padding and do not appear in 1109ec8c961SSamira Bazuzi // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s 1119ec8c961SSamira Bazuzi // field list, and we thus need to remove them before mapping inits to 1129ec8c961SSamira Bazuzi // fields to avoid mapping inits to the wrongs fields. 1139ec8c961SSamira Bazuzi llvm::copy_if( 1149ec8c961SSamira Bazuzi RD->fields(), std::back_inserter(Fields), 1153d56ea05STimm Baeder [](const FieldDecl *Field) { return !Field->isUnnamedBitField(); }); 1169ec8c961SSamira Bazuzi return Fields; 1179ec8c961SSamira Bazuzi } 1189ec8c961SSamira Bazuzi 119ca7d9442Smartinboehme RecordInitListHelper::RecordInitListHelper(const InitListExpr *InitList) 120ca7d9442Smartinboehme : RecordInitListHelper(InitList->getType(), 121ca7d9442Smartinboehme getFieldsForInitListExpr(InitList), 122ca7d9442Smartinboehme InitList->inits()) {} 1239ec8c961SSamira Bazuzi 124ca7d9442Smartinboehme RecordInitListHelper::RecordInitListHelper( 125ca7d9442Smartinboehme const CXXParenListInitExpr *ParenInitList) 126ca7d9442Smartinboehme : RecordInitListHelper(ParenInitList->getType(), 127ca7d9442Smartinboehme getFieldsForInitListExpr(ParenInitList), 128ca7d9442Smartinboehme ParenInitList->getInitExprs()) {} 129ca7d9442Smartinboehme 130ca7d9442Smartinboehme RecordInitListHelper::RecordInitListHelper( 131ca7d9442Smartinboehme QualType Ty, std::vector<const FieldDecl *> Fields, 132ca7d9442Smartinboehme ArrayRef<Expr *> Inits) { 133ca7d9442Smartinboehme auto *RD = Ty->getAsCXXRecordDecl(); 134ca7d9442Smartinboehme assert(RD != nullptr); 1359ec8c961SSamira Bazuzi 1369ec8c961SSamira Bazuzi // Unions initialized with an empty initializer list need special treatment. 1379ec8c961SSamira Bazuzi // For structs/classes initialized with an empty initializer list, Clang 1389ec8c961SSamira Bazuzi // puts `ImplicitValueInitExpr`s in `InitListExpr::inits()`, but for unions, 1399ec8c961SSamira Bazuzi // it doesn't do this -- so we create an `ImplicitValueInitExpr` ourselves. 1409ec8c961SSamira Bazuzi SmallVector<Expr *> InitsForUnion; 141ca7d9442Smartinboehme if (Ty->isUnionType() && Inits.empty()) { 142275196d8Smartinboehme assert(Fields.size() <= 1); 143275196d8Smartinboehme if (!Fields.empty()) { 1449ec8c961SSamira Bazuzi ImplicitValueInitForUnion.emplace(Fields.front()->getType()); 1459ec8c961SSamira Bazuzi InitsForUnion.push_back(&*ImplicitValueInitForUnion); 146275196d8Smartinboehme } 1479ec8c961SSamira Bazuzi Inits = InitsForUnion; 1489ec8c961SSamira Bazuzi } 1499ec8c961SSamira Bazuzi 1509ec8c961SSamira Bazuzi size_t InitIdx = 0; 1519ec8c961SSamira Bazuzi 1529ec8c961SSamira Bazuzi assert(Fields.size() + RD->getNumBases() == Inits.size()); 1539ec8c961SSamira Bazuzi for (const CXXBaseSpecifier &Base : RD->bases()) { 1549ec8c961SSamira Bazuzi assert(InitIdx < Inits.size()); 1559ec8c961SSamira Bazuzi Expr *Init = Inits[InitIdx++]; 1569ec8c961SSamira Bazuzi BaseInits.emplace_back(&Base, Init); 1579ec8c961SSamira Bazuzi } 1589ec8c961SSamira Bazuzi 1599ec8c961SSamira Bazuzi assert(Fields.size() == Inits.size() - InitIdx); 1609ec8c961SSamira Bazuzi for (const FieldDecl *Field : Fields) { 1619ec8c961SSamira Bazuzi assert(InitIdx < Inits.size()); 1629ec8c961SSamira Bazuzi Expr *Init = Inits[InitIdx++]; 1639ec8c961SSamira Bazuzi FieldInits.emplace_back(Field, Init); 1649ec8c961SSamira Bazuzi } 1659ec8c961SSamira Bazuzi } 1669ec8c961SSamira Bazuzi 1679ec8c961SSamira Bazuzi static void insertIfGlobal(const Decl &D, 1689ec8c961SSamira Bazuzi llvm::DenseSet<const VarDecl *> &Globals) { 1699ec8c961SSamira Bazuzi if (auto *V = dyn_cast<VarDecl>(&D)) 1709ec8c961SSamira Bazuzi if (V->hasGlobalStorage()) 1719ec8c961SSamira Bazuzi Globals.insert(V); 1729ec8c961SSamira Bazuzi } 1739ec8c961SSamira Bazuzi 1742575ea6eSSamira Bazuzi static void insertIfLocal(const Decl &D, 1752575ea6eSSamira Bazuzi llvm::DenseSet<const VarDecl *> &Locals) { 1762575ea6eSSamira Bazuzi if (auto *V = dyn_cast<VarDecl>(&D)) 1772575ea6eSSamira Bazuzi if (V->hasLocalStorage() && !isa<ParmVarDecl>(V)) 1782575ea6eSSamira Bazuzi Locals.insert(V); 1792575ea6eSSamira Bazuzi } 1802575ea6eSSamira Bazuzi 1819ec8c961SSamira Bazuzi static void insertIfFunction(const Decl &D, 1829ec8c961SSamira Bazuzi llvm::DenseSet<const FunctionDecl *> &Funcs) { 1839ec8c961SSamira Bazuzi if (auto *FD = dyn_cast<FunctionDecl>(&D)) 1849ec8c961SSamira Bazuzi Funcs.insert(FD); 1859ec8c961SSamira Bazuzi } 1869ec8c961SSamira Bazuzi 1879ec8c961SSamira Bazuzi static MemberExpr *getMemberForAccessor(const CXXMemberCallExpr &C) { 1889ec8c961SSamira Bazuzi // Use getCalleeDecl instead of getMethodDecl in order to handle 1899ec8c961SSamira Bazuzi // pointer-to-member calls. 1909ec8c961SSamira Bazuzi const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(C.getCalleeDecl()); 1919ec8c961SSamira Bazuzi if (!MethodDecl) 1929ec8c961SSamira Bazuzi return nullptr; 1939ec8c961SSamira Bazuzi auto *Body = dyn_cast_or_null<CompoundStmt>(MethodDecl->getBody()); 1949ec8c961SSamira Bazuzi if (!Body || Body->size() != 1) 1959ec8c961SSamira Bazuzi return nullptr; 1969ec8c961SSamira Bazuzi if (auto *RS = dyn_cast<ReturnStmt>(*Body->body_begin())) 1979ec8c961SSamira Bazuzi if (auto *Return = RS->getRetValue()) 1989ec8c961SSamira Bazuzi return dyn_cast<MemberExpr>(Return->IgnoreParenImpCasts()); 1999ec8c961SSamira Bazuzi return nullptr; 2009ec8c961SSamira Bazuzi } 2019ec8c961SSamira Bazuzi 202dde802b1SSirraide class ReferencedDeclsVisitor : public AnalysisASTVisitor { 2035161a3f6Smartinboehme public: 2045161a3f6Smartinboehme ReferencedDeclsVisitor(ReferencedDecls &Referenced) 2055161a3f6Smartinboehme : Referenced(Referenced) {} 2065161a3f6Smartinboehme 207dde802b1SSirraide void traverseConstructorInits(const CXXConstructorDecl *Ctor) { 2085161a3f6Smartinboehme for (const CXXCtorInitializer *Init : Ctor->inits()) { 2095161a3f6Smartinboehme if (Init->isMemberInitializer()) { 2105161a3f6Smartinboehme Referenced.Fields.insert(Init->getMember()); 2115161a3f6Smartinboehme } else if (Init->isIndirectMemberInitializer()) { 2125161a3f6Smartinboehme for (const auto *I : Init->getIndirectMember()->chain()) 2135161a3f6Smartinboehme Referenced.Fields.insert(cast<FieldDecl>(I)); 2149ec8c961SSamira Bazuzi } 2159ec8c961SSamira Bazuzi 2165161a3f6Smartinboehme Expr *InitExpr = Init->getInit(); 2179ec8c961SSamira Bazuzi 2185161a3f6Smartinboehme // Also collect declarations referenced in `InitExpr`. 2195161a3f6Smartinboehme TraverseStmt(InitExpr); 2205161a3f6Smartinboehme 2215161a3f6Smartinboehme // If this is a `CXXDefaultInitExpr`, also collect declarations referenced 2225161a3f6Smartinboehme // within the default expression. 2235161a3f6Smartinboehme if (auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(InitExpr)) 2245161a3f6Smartinboehme TraverseStmt(DefaultInit->getExpr()); 2255161a3f6Smartinboehme } 2265161a3f6Smartinboehme } 2275161a3f6Smartinboehme 228dde802b1SSirraide bool VisitDecl(Decl *D) override { 2295161a3f6Smartinboehme insertIfGlobal(*D, Referenced.Globals); 2302575ea6eSSamira Bazuzi insertIfLocal(*D, Referenced.Locals); 2315161a3f6Smartinboehme insertIfFunction(*D, Referenced.Functions); 2325161a3f6Smartinboehme return true; 2335161a3f6Smartinboehme } 2345161a3f6Smartinboehme 235dde802b1SSirraide bool VisitDeclRefExpr(DeclRefExpr *E) override { 2369ec8c961SSamira Bazuzi insertIfGlobal(*E->getDecl(), Referenced.Globals); 2372575ea6eSSamira Bazuzi insertIfLocal(*E->getDecl(), Referenced.Locals); 2389ec8c961SSamira Bazuzi insertIfFunction(*E->getDecl(), Referenced.Functions); 2395161a3f6Smartinboehme return true; 2405161a3f6Smartinboehme } 2415161a3f6Smartinboehme 242dde802b1SSirraide bool VisitCXXMemberCallExpr(CXXMemberCallExpr *C) override { 2439ec8c961SSamira Bazuzi // If this is a method that returns a member variable but does nothing else, 2449ec8c961SSamira Bazuzi // model the field of the return value. 2459ec8c961SSamira Bazuzi if (MemberExpr *E = getMemberForAccessor(*C)) 2469ec8c961SSamira Bazuzi if (const auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) 2479ec8c961SSamira Bazuzi Referenced.Fields.insert(FD); 2485161a3f6Smartinboehme return true; 2495161a3f6Smartinboehme } 2505161a3f6Smartinboehme 251dde802b1SSirraide bool VisitMemberExpr(MemberExpr *E) override { 2529ec8c961SSamira Bazuzi // FIXME: should we be using `E->getFoundDecl()`? 2539ec8c961SSamira Bazuzi const ValueDecl *VD = E->getMemberDecl(); 2549ec8c961SSamira Bazuzi insertIfGlobal(*VD, Referenced.Globals); 2559ec8c961SSamira Bazuzi insertIfFunction(*VD, Referenced.Functions); 2569ec8c961SSamira Bazuzi if (const auto *FD = dyn_cast<FieldDecl>(VD)) 2579ec8c961SSamira Bazuzi Referenced.Fields.insert(FD); 2585161a3f6Smartinboehme return true; 2595161a3f6Smartinboehme } 2605161a3f6Smartinboehme 261dde802b1SSirraide bool VisitInitListExpr(InitListExpr *InitList) override { 2629ec8c961SSamira Bazuzi if (InitList->getType()->isRecordType()) 2639ec8c961SSamira Bazuzi for (const auto *FD : getFieldsForInitListExpr(InitList)) 2649ec8c961SSamira Bazuzi Referenced.Fields.insert(FD); 2655161a3f6Smartinboehme return true; 2665161a3f6Smartinboehme } 2675161a3f6Smartinboehme 268dde802b1SSirraide bool VisitCXXParenListInitExpr(CXXParenListInitExpr *ParenInitList) override { 269ca7d9442Smartinboehme if (ParenInitList->getType()->isRecordType()) 270ca7d9442Smartinboehme for (const auto *FD : getFieldsForInitListExpr(ParenInitList)) 271ca7d9442Smartinboehme Referenced.Fields.insert(FD); 2725161a3f6Smartinboehme return true; 2739ec8c961SSamira Bazuzi } 2745161a3f6Smartinboehme 2755161a3f6Smartinboehme private: 2765161a3f6Smartinboehme ReferencedDecls &Referenced; 2775161a3f6Smartinboehme }; 2789ec8c961SSamira Bazuzi 2799ec8c961SSamira Bazuzi ReferencedDecls getReferencedDecls(const FunctionDecl &FD) { 2809ec8c961SSamira Bazuzi ReferencedDecls Result; 2815161a3f6Smartinboehme ReferencedDeclsVisitor Visitor(Result); 2825161a3f6Smartinboehme Visitor.TraverseStmt(FD.getBody()); 2835161a3f6Smartinboehme if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&FD)) 284dde802b1SSirraide Visitor.traverseConstructorInits(CtorDecl); 2859ec8c961SSamira Bazuzi 286*198fb5edSSamira Bazuzi // If analyzing a lambda call operator, collect all captures of parameters (of 287*198fb5edSSamira Bazuzi // the surrounding function). This collects them even if they are not 288*198fb5edSSamira Bazuzi // referenced in the body of the lambda call operator. Non-parameter local 289*198fb5edSSamira Bazuzi // variables that are captured are already collected into 290*198fb5edSSamira Bazuzi // `ReferencedDecls.Locals` when traversing the call operator body, but we 291*198fb5edSSamira Bazuzi // collect parameters here to avoid needing to check at each referencing node 292*198fb5edSSamira Bazuzi // whether the parameter is a lambda capture from a surrounding function or is 293*198fb5edSSamira Bazuzi // a parameter of the current function. If it becomes necessary to limit this 294*198fb5edSSamira Bazuzi // set to the parameters actually referenced in the body, alternative 295*198fb5edSSamira Bazuzi // optimizations can be implemented to minimize duplicative work. 296*198fb5edSSamira Bazuzi if (const auto *Method = dyn_cast<CXXMethodDecl>(&FD); 297*198fb5edSSamira Bazuzi Method && isLambdaCallOperator(Method)) { 298*198fb5edSSamira Bazuzi for (const auto &Capture : Method->getParent()->captures()) { 299*198fb5edSSamira Bazuzi if (Capture.capturesVariable()) { 300*198fb5edSSamira Bazuzi if (const auto *Param = 301*198fb5edSSamira Bazuzi dyn_cast<ParmVarDecl>(Capture.getCapturedVar())) { 302*198fb5edSSamira Bazuzi Result.LambdaCapturedParams.insert(Param); 303*198fb5edSSamira Bazuzi } 304*198fb5edSSamira Bazuzi } 305*198fb5edSSamira Bazuzi } 306*198fb5edSSamira Bazuzi } 307*198fb5edSSamira Bazuzi 3089ec8c961SSamira Bazuzi return Result; 3099ec8c961SSamira Bazuzi } 3109ec8c961SSamira Bazuzi 311d634b233SSamira Bazuzi ReferencedDecls getReferencedDecls(const Stmt &S) { 312d634b233SSamira Bazuzi ReferencedDecls Result; 3135161a3f6Smartinboehme ReferencedDeclsVisitor Visitor(Result); 3145161a3f6Smartinboehme Visitor.TraverseStmt(const_cast<Stmt *>(&S)); 315d634b233SSamira Bazuzi return Result; 316d634b233SSamira Bazuzi } 317d634b233SSamira Bazuzi 3189ec8c961SSamira Bazuzi } // namespace clang::dataflow 319