15ffd83dbSDimitry Andric //===- ParentMapContext.cpp - Map of parents using DynTypedNode -*- C++ -*-===// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric // 95ffd83dbSDimitry Andric // Similar to ParentMap.cpp, but generalizes to non-Stmt nodes, which can have 105ffd83dbSDimitry Andric // multiple parents. 115ffd83dbSDimitry Andric // 125ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 135ffd83dbSDimitry Andric 145ffd83dbSDimitry Andric #include "clang/AST/ParentMapContext.h" 155ffd83dbSDimitry Andric #include "clang/AST/RecursiveASTVisitor.h" 165ffd83dbSDimitry Andric #include "clang/AST/Decl.h" 175ffd83dbSDimitry Andric #include "clang/AST/Expr.h" 185ffd83dbSDimitry Andric #include "clang/AST/TemplateBase.h" 195ffd83dbSDimitry Andric 205ffd83dbSDimitry Andric using namespace clang; 215ffd83dbSDimitry Andric 225ffd83dbSDimitry Andric ParentMapContext::ParentMapContext(ASTContext &Ctx) : ASTCtx(Ctx) {} 235ffd83dbSDimitry Andric 245ffd83dbSDimitry Andric ParentMapContext::~ParentMapContext() = default; 255ffd83dbSDimitry Andric 265ffd83dbSDimitry Andric void ParentMapContext::clear() { Parents.reset(); } 275ffd83dbSDimitry Andric 285ffd83dbSDimitry Andric const Expr *ParentMapContext::traverseIgnored(const Expr *E) const { 295ffd83dbSDimitry Andric return traverseIgnored(const_cast<Expr *>(E)); 305ffd83dbSDimitry Andric } 315ffd83dbSDimitry Andric 325ffd83dbSDimitry Andric Expr *ParentMapContext::traverseIgnored(Expr *E) const { 335ffd83dbSDimitry Andric if (!E) 345ffd83dbSDimitry Andric return nullptr; 355ffd83dbSDimitry Andric 365ffd83dbSDimitry Andric switch (Traversal) { 375ffd83dbSDimitry Andric case TK_AsIs: 385ffd83dbSDimitry Andric return E; 395ffd83dbSDimitry Andric case TK_IgnoreUnlessSpelledInSource: 405ffd83dbSDimitry Andric return E->IgnoreUnlessSpelledInSource(); 415ffd83dbSDimitry Andric } 425ffd83dbSDimitry Andric llvm_unreachable("Invalid Traversal type!"); 435ffd83dbSDimitry Andric } 445ffd83dbSDimitry Andric 455ffd83dbSDimitry Andric DynTypedNode ParentMapContext::traverseIgnored(const DynTypedNode &N) const { 465ffd83dbSDimitry Andric if (const auto *E = N.get<Expr>()) { 475ffd83dbSDimitry Andric return DynTypedNode::create(*traverseIgnored(E)); 485ffd83dbSDimitry Andric } 495ffd83dbSDimitry Andric return N; 505ffd83dbSDimitry Andric } 515ffd83dbSDimitry Andric 525ffd83dbSDimitry Andric class ParentMapContext::ParentMap { 535ffd83dbSDimitry Andric /// Contains parents of a node. 545ffd83dbSDimitry Andric using ParentVector = llvm::SmallVector<DynTypedNode, 2>; 555ffd83dbSDimitry Andric 565ffd83dbSDimitry Andric /// Maps from a node to its parents. This is used for nodes that have 575ffd83dbSDimitry Andric /// pointer identity only, which are more common and we can save space by 585ffd83dbSDimitry Andric /// only storing a unique pointer to them. 595ffd83dbSDimitry Andric using ParentMapPointers = 605ffd83dbSDimitry Andric llvm::DenseMap<const void *, 615ffd83dbSDimitry Andric llvm::PointerUnion<const Decl *, const Stmt *, 625ffd83dbSDimitry Andric DynTypedNode *, ParentVector *>>; 635ffd83dbSDimitry Andric 645ffd83dbSDimitry Andric /// Parent map for nodes without pointer identity. We store a full 655ffd83dbSDimitry Andric /// DynTypedNode for all keys. 665ffd83dbSDimitry Andric using ParentMapOtherNodes = 675ffd83dbSDimitry Andric llvm::DenseMap<DynTypedNode, 685ffd83dbSDimitry Andric llvm::PointerUnion<const Decl *, const Stmt *, 695ffd83dbSDimitry Andric DynTypedNode *, ParentVector *>>; 705ffd83dbSDimitry Andric 715ffd83dbSDimitry Andric ParentMapPointers PointerParents; 725ffd83dbSDimitry Andric ParentMapOtherNodes OtherParents; 735ffd83dbSDimitry Andric class ASTVisitor; 745ffd83dbSDimitry Andric 755ffd83dbSDimitry Andric static DynTypedNode 765ffd83dbSDimitry Andric getSingleDynTypedNodeFromParentMap(ParentMapPointers::mapped_type U) { 775ffd83dbSDimitry Andric if (const auto *D = U.dyn_cast<const Decl *>()) 785ffd83dbSDimitry Andric return DynTypedNode::create(*D); 795ffd83dbSDimitry Andric if (const auto *S = U.dyn_cast<const Stmt *>()) 805ffd83dbSDimitry Andric return DynTypedNode::create(*S); 815ffd83dbSDimitry Andric return *U.get<DynTypedNode *>(); 825ffd83dbSDimitry Andric } 835ffd83dbSDimitry Andric 845ffd83dbSDimitry Andric template <typename NodeTy, typename MapTy> 855ffd83dbSDimitry Andric static DynTypedNodeList getDynNodeFromMap(const NodeTy &Node, 865ffd83dbSDimitry Andric const MapTy &Map) { 875ffd83dbSDimitry Andric auto I = Map.find(Node); 885ffd83dbSDimitry Andric if (I == Map.end()) { 895ffd83dbSDimitry Andric return llvm::ArrayRef<DynTypedNode>(); 905ffd83dbSDimitry Andric } 915ffd83dbSDimitry Andric if (const auto *V = I->second.template dyn_cast<ParentVector *>()) { 925ffd83dbSDimitry Andric return llvm::makeArrayRef(*V); 935ffd83dbSDimitry Andric } 945ffd83dbSDimitry Andric return getSingleDynTypedNodeFromParentMap(I->second); 955ffd83dbSDimitry Andric } 965ffd83dbSDimitry Andric 975ffd83dbSDimitry Andric public: 985ffd83dbSDimitry Andric ParentMap(ASTContext &Ctx); 995ffd83dbSDimitry Andric ~ParentMap() { 1005ffd83dbSDimitry Andric for (const auto &Entry : PointerParents) { 1015ffd83dbSDimitry Andric if (Entry.second.is<DynTypedNode *>()) { 1025ffd83dbSDimitry Andric delete Entry.second.get<DynTypedNode *>(); 1035ffd83dbSDimitry Andric } else if (Entry.second.is<ParentVector *>()) { 1045ffd83dbSDimitry Andric delete Entry.second.get<ParentVector *>(); 1055ffd83dbSDimitry Andric } 1065ffd83dbSDimitry Andric } 1075ffd83dbSDimitry Andric for (const auto &Entry : OtherParents) { 1085ffd83dbSDimitry Andric if (Entry.second.is<DynTypedNode *>()) { 1095ffd83dbSDimitry Andric delete Entry.second.get<DynTypedNode *>(); 1105ffd83dbSDimitry Andric } else if (Entry.second.is<ParentVector *>()) { 1115ffd83dbSDimitry Andric delete Entry.second.get<ParentVector *>(); 1125ffd83dbSDimitry Andric } 1135ffd83dbSDimitry Andric } 1145ffd83dbSDimitry Andric } 1155ffd83dbSDimitry Andric 1165ffd83dbSDimitry Andric DynTypedNodeList getParents(TraversalKind TK, const DynTypedNode &Node) { 1175ffd83dbSDimitry Andric if (Node.getNodeKind().hasPointerIdentity()) { 1185ffd83dbSDimitry Andric auto ParentList = 1195ffd83dbSDimitry Andric getDynNodeFromMap(Node.getMemoizationData(), PointerParents); 1205ffd83dbSDimitry Andric if (ParentList.size() == 1 && TK == TK_IgnoreUnlessSpelledInSource) { 1215ffd83dbSDimitry Andric const auto *E = ParentList[0].get<Expr>(); 1225ffd83dbSDimitry Andric const auto *Child = Node.get<Expr>(); 1235ffd83dbSDimitry Andric if (E && Child) 1245ffd83dbSDimitry Andric return AscendIgnoreUnlessSpelledInSource(E, Child); 1255ffd83dbSDimitry Andric } 1265ffd83dbSDimitry Andric return ParentList; 1275ffd83dbSDimitry Andric } 1285ffd83dbSDimitry Andric return getDynNodeFromMap(Node, OtherParents); 1295ffd83dbSDimitry Andric } 1305ffd83dbSDimitry Andric 1315ffd83dbSDimitry Andric DynTypedNodeList AscendIgnoreUnlessSpelledInSource(const Expr *E, 1325ffd83dbSDimitry Andric const Expr *Child) { 1335ffd83dbSDimitry Andric 1345ffd83dbSDimitry Andric auto ShouldSkip = [](const Expr *E, const Expr *Child) { 1355ffd83dbSDimitry Andric if (isa<ImplicitCastExpr>(E)) 1365ffd83dbSDimitry Andric return true; 1375ffd83dbSDimitry Andric 1385ffd83dbSDimitry Andric if (isa<FullExpr>(E)) 1395ffd83dbSDimitry Andric return true; 1405ffd83dbSDimitry Andric 1415ffd83dbSDimitry Andric if (isa<MaterializeTemporaryExpr>(E)) 1425ffd83dbSDimitry Andric return true; 1435ffd83dbSDimitry Andric 1445ffd83dbSDimitry Andric if (isa<CXXBindTemporaryExpr>(E)) 1455ffd83dbSDimitry Andric return true; 1465ffd83dbSDimitry Andric 1475ffd83dbSDimitry Andric if (isa<ParenExpr>(E)) 1485ffd83dbSDimitry Andric return true; 1495ffd83dbSDimitry Andric 1505ffd83dbSDimitry Andric if (isa<ExprWithCleanups>(E)) 1515ffd83dbSDimitry Andric return true; 1525ffd83dbSDimitry Andric 1535ffd83dbSDimitry Andric auto SR = Child->getSourceRange(); 1545ffd83dbSDimitry Andric 155*e8d8bef9SDimitry Andric if (const auto *C = dyn_cast<CXXFunctionalCastExpr>(E)) { 156*e8d8bef9SDimitry Andric if (C->getSourceRange() == SR) 157*e8d8bef9SDimitry Andric return true; 158*e8d8bef9SDimitry Andric } 159*e8d8bef9SDimitry Andric 1605ffd83dbSDimitry Andric if (const auto *C = dyn_cast<CXXConstructExpr>(E)) { 161*e8d8bef9SDimitry Andric if (C->getSourceRange() == SR || C->isElidable()) 1625ffd83dbSDimitry Andric return true; 1635ffd83dbSDimitry Andric } 1645ffd83dbSDimitry Andric 1655ffd83dbSDimitry Andric if (const auto *C = dyn_cast<CXXMemberCallExpr>(E)) { 1665ffd83dbSDimitry Andric if (C->getSourceRange() == SR) 1675ffd83dbSDimitry Andric return true; 1685ffd83dbSDimitry Andric } 1695ffd83dbSDimitry Andric 1705ffd83dbSDimitry Andric if (const auto *C = dyn_cast<MemberExpr>(E)) { 1715ffd83dbSDimitry Andric if (C->getSourceRange() == SR) 1725ffd83dbSDimitry Andric return true; 1735ffd83dbSDimitry Andric } 1745ffd83dbSDimitry Andric return false; 1755ffd83dbSDimitry Andric }; 1765ffd83dbSDimitry Andric 1775ffd83dbSDimitry Andric while (ShouldSkip(E, Child)) { 1785ffd83dbSDimitry Andric auto It = PointerParents.find(E); 1795ffd83dbSDimitry Andric if (It == PointerParents.end()) 1805ffd83dbSDimitry Andric break; 1815ffd83dbSDimitry Andric const auto *S = It->second.dyn_cast<const Stmt *>(); 1825ffd83dbSDimitry Andric if (!S) { 1835ffd83dbSDimitry Andric if (auto *Vec = It->second.dyn_cast<ParentVector *>()) 1845ffd83dbSDimitry Andric return llvm::makeArrayRef(*Vec); 1855ffd83dbSDimitry Andric return getSingleDynTypedNodeFromParentMap(It->second); 1865ffd83dbSDimitry Andric } 1875ffd83dbSDimitry Andric const auto *P = dyn_cast<Expr>(S); 1885ffd83dbSDimitry Andric if (!P) 1895ffd83dbSDimitry Andric return DynTypedNode::create(*S); 1905ffd83dbSDimitry Andric Child = E; 1915ffd83dbSDimitry Andric E = P; 1925ffd83dbSDimitry Andric } 1935ffd83dbSDimitry Andric return DynTypedNode::create(*E); 1945ffd83dbSDimitry Andric } 1955ffd83dbSDimitry Andric }; 1965ffd83dbSDimitry Andric 1975ffd83dbSDimitry Andric /// Template specializations to abstract away from pointers and TypeLocs. 1985ffd83dbSDimitry Andric /// @{ 1995ffd83dbSDimitry Andric template <typename T> static DynTypedNode createDynTypedNode(const T &Node) { 2005ffd83dbSDimitry Andric return DynTypedNode::create(*Node); 2015ffd83dbSDimitry Andric } 2025ffd83dbSDimitry Andric template <> DynTypedNode createDynTypedNode(const TypeLoc &Node) { 2035ffd83dbSDimitry Andric return DynTypedNode::create(Node); 2045ffd83dbSDimitry Andric } 2055ffd83dbSDimitry Andric template <> 2065ffd83dbSDimitry Andric DynTypedNode createDynTypedNode(const NestedNameSpecifierLoc &Node) { 2075ffd83dbSDimitry Andric return DynTypedNode::create(Node); 2085ffd83dbSDimitry Andric } 2095ffd83dbSDimitry Andric /// @} 2105ffd83dbSDimitry Andric 2115ffd83dbSDimitry Andric /// A \c RecursiveASTVisitor that builds a map from nodes to their 2125ffd83dbSDimitry Andric /// parents as defined by the \c RecursiveASTVisitor. 2135ffd83dbSDimitry Andric /// 2145ffd83dbSDimitry Andric /// Note that the relationship described here is purely in terms of AST 2155ffd83dbSDimitry Andric /// traversal - there are other relationships (for example declaration context) 2165ffd83dbSDimitry Andric /// in the AST that are better modeled by special matchers. 2175ffd83dbSDimitry Andric class ParentMapContext::ParentMap::ASTVisitor 2185ffd83dbSDimitry Andric : public RecursiveASTVisitor<ASTVisitor> { 2195ffd83dbSDimitry Andric public: 2205ffd83dbSDimitry Andric ASTVisitor(ParentMap &Map) : Map(Map) {} 2215ffd83dbSDimitry Andric 2225ffd83dbSDimitry Andric private: 2235ffd83dbSDimitry Andric friend class RecursiveASTVisitor<ASTVisitor>; 2245ffd83dbSDimitry Andric 2255ffd83dbSDimitry Andric using VisitorBase = RecursiveASTVisitor<ASTVisitor>; 2265ffd83dbSDimitry Andric 2275ffd83dbSDimitry Andric bool shouldVisitTemplateInstantiations() const { return true; } 2285ffd83dbSDimitry Andric 2295ffd83dbSDimitry Andric bool shouldVisitImplicitCode() const { return true; } 2305ffd83dbSDimitry Andric 231*e8d8bef9SDimitry Andric /// Record the parent of the node we're visiting. 232*e8d8bef9SDimitry Andric /// MapNode is the child, the parent is on top of ParentStack. 233*e8d8bef9SDimitry Andric /// Parents is the parent storage (either PointerParents or OtherParents). 234*e8d8bef9SDimitry Andric template <typename MapNodeTy, typename MapTy> 235*e8d8bef9SDimitry Andric void addParent(MapNodeTy MapNode, MapTy *Parents) { 236*e8d8bef9SDimitry Andric if (ParentStack.empty()) 237*e8d8bef9SDimitry Andric return; 238*e8d8bef9SDimitry Andric 2395ffd83dbSDimitry Andric // FIXME: Currently we add the same parent multiple times, but only 2405ffd83dbSDimitry Andric // when no memoization data is available for the type. 2415ffd83dbSDimitry Andric // For example when we visit all subexpressions of template 2425ffd83dbSDimitry Andric // instantiations; this is suboptimal, but benign: the only way to 2435ffd83dbSDimitry Andric // visit those is with hasAncestor / hasParent, and those do not create 2445ffd83dbSDimitry Andric // new matches. 2455ffd83dbSDimitry Andric // The plan is to enable DynTypedNode to be storable in a map or hash 2465ffd83dbSDimitry Andric // map. The main problem there is to implement hash functions / 2475ffd83dbSDimitry Andric // comparison operators for all types that DynTypedNode supports that 2485ffd83dbSDimitry Andric // do not have pointer identity. 2495ffd83dbSDimitry Andric auto &NodeOrVector = (*Parents)[MapNode]; 2505ffd83dbSDimitry Andric if (NodeOrVector.isNull()) { 2515ffd83dbSDimitry Andric if (const auto *D = ParentStack.back().get<Decl>()) 2525ffd83dbSDimitry Andric NodeOrVector = D; 2535ffd83dbSDimitry Andric else if (const auto *S = ParentStack.back().get<Stmt>()) 2545ffd83dbSDimitry Andric NodeOrVector = S; 2555ffd83dbSDimitry Andric else 2565ffd83dbSDimitry Andric NodeOrVector = new DynTypedNode(ParentStack.back()); 2575ffd83dbSDimitry Andric } else { 2585ffd83dbSDimitry Andric if (!NodeOrVector.template is<ParentVector *>()) { 2595ffd83dbSDimitry Andric auto *Vector = new ParentVector( 2605ffd83dbSDimitry Andric 1, getSingleDynTypedNodeFromParentMap(NodeOrVector)); 2615ffd83dbSDimitry Andric delete NodeOrVector.template dyn_cast<DynTypedNode *>(); 2625ffd83dbSDimitry Andric NodeOrVector = Vector; 2635ffd83dbSDimitry Andric } 2645ffd83dbSDimitry Andric 2655ffd83dbSDimitry Andric auto *Vector = NodeOrVector.template get<ParentVector *>(); 2665ffd83dbSDimitry Andric // Skip duplicates for types that have memoization data. 2675ffd83dbSDimitry Andric // We must check that the type has memoization data before calling 2685ffd83dbSDimitry Andric // std::find() because DynTypedNode::operator== can't compare all 2695ffd83dbSDimitry Andric // types. 2705ffd83dbSDimitry Andric bool Found = ParentStack.back().getMemoizationData() && 2715ffd83dbSDimitry Andric std::find(Vector->begin(), Vector->end(), 2725ffd83dbSDimitry Andric ParentStack.back()) != Vector->end(); 2735ffd83dbSDimitry Andric if (!Found) 2745ffd83dbSDimitry Andric Vector->push_back(ParentStack.back()); 2755ffd83dbSDimitry Andric } 2765ffd83dbSDimitry Andric } 277*e8d8bef9SDimitry Andric 278*e8d8bef9SDimitry Andric template <typename T, typename MapNodeTy, typename BaseTraverseFn, 279*e8d8bef9SDimitry Andric typename MapTy> 280*e8d8bef9SDimitry Andric bool TraverseNode(T Node, MapNodeTy MapNode, BaseTraverseFn BaseTraverse, 281*e8d8bef9SDimitry Andric MapTy *Parents) { 282*e8d8bef9SDimitry Andric if (!Node) 283*e8d8bef9SDimitry Andric return true; 284*e8d8bef9SDimitry Andric addParent(MapNode, Parents); 2855ffd83dbSDimitry Andric ParentStack.push_back(createDynTypedNode(Node)); 2865ffd83dbSDimitry Andric bool Result = BaseTraverse(); 2875ffd83dbSDimitry Andric ParentStack.pop_back(); 2885ffd83dbSDimitry Andric return Result; 2895ffd83dbSDimitry Andric } 2905ffd83dbSDimitry Andric 2915ffd83dbSDimitry Andric bool TraverseDecl(Decl *DeclNode) { 2925ffd83dbSDimitry Andric return TraverseNode( 2935ffd83dbSDimitry Andric DeclNode, DeclNode, [&] { return VisitorBase::TraverseDecl(DeclNode); }, 2945ffd83dbSDimitry Andric &Map.PointerParents); 2955ffd83dbSDimitry Andric } 2965ffd83dbSDimitry Andric bool TraverseTypeLoc(TypeLoc TypeLocNode) { 2975ffd83dbSDimitry Andric return TraverseNode( 2985ffd83dbSDimitry Andric TypeLocNode, DynTypedNode::create(TypeLocNode), 2995ffd83dbSDimitry Andric [&] { return VisitorBase::TraverseTypeLoc(TypeLocNode); }, 3005ffd83dbSDimitry Andric &Map.OtherParents); 3015ffd83dbSDimitry Andric } 3025ffd83dbSDimitry Andric bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode) { 3035ffd83dbSDimitry Andric return TraverseNode( 3045ffd83dbSDimitry Andric NNSLocNode, DynTypedNode::create(NNSLocNode), 3055ffd83dbSDimitry Andric [&] { return VisitorBase::TraverseNestedNameSpecifierLoc(NNSLocNode); }, 3065ffd83dbSDimitry Andric &Map.OtherParents); 3075ffd83dbSDimitry Andric } 3085ffd83dbSDimitry Andric 309*e8d8bef9SDimitry Andric // Using generic TraverseNode for Stmt would prevent data-recursion. 310*e8d8bef9SDimitry Andric bool dataTraverseStmtPre(Stmt *StmtNode) { 311*e8d8bef9SDimitry Andric addParent(StmtNode, &Map.PointerParents); 312*e8d8bef9SDimitry Andric ParentStack.push_back(DynTypedNode::create(*StmtNode)); 313*e8d8bef9SDimitry Andric return true; 314*e8d8bef9SDimitry Andric } 315*e8d8bef9SDimitry Andric bool dataTraverseStmtPost(Stmt *StmtNode) { 316*e8d8bef9SDimitry Andric ParentStack.pop_back(); 317*e8d8bef9SDimitry Andric return true; 318*e8d8bef9SDimitry Andric } 319*e8d8bef9SDimitry Andric 3205ffd83dbSDimitry Andric ParentMap ⤅ 3215ffd83dbSDimitry Andric llvm::SmallVector<DynTypedNode, 16> ParentStack; 3225ffd83dbSDimitry Andric }; 3235ffd83dbSDimitry Andric 3245ffd83dbSDimitry Andric ParentMapContext::ParentMap::ParentMap(ASTContext &Ctx) { 3255ffd83dbSDimitry Andric ASTVisitor(*this).TraverseAST(Ctx); 3265ffd83dbSDimitry Andric } 3275ffd83dbSDimitry Andric 3285ffd83dbSDimitry Andric DynTypedNodeList ParentMapContext::getParents(const DynTypedNode &Node) { 3295ffd83dbSDimitry Andric if (!Parents) 3305ffd83dbSDimitry Andric // We build the parent map for the traversal scope (usually whole TU), as 3315ffd83dbSDimitry Andric // hasAncestor can escape any subtree. 3325ffd83dbSDimitry Andric Parents = std::make_unique<ParentMap>(ASTCtx); 3335ffd83dbSDimitry Andric return Parents->getParents(getTraversalKind(), Node); 3345ffd83dbSDimitry Andric } 335