xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/ParentMapContext.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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 
52fe6060f1SDimitry Andric template <typename T, typename... U>
53fe6060f1SDimitry Andric std::tuple<bool, DynTypedNodeList, const T *, const U *...>
54fe6060f1SDimitry Andric matchParents(const DynTypedNodeList &NodeList,
55fe6060f1SDimitry Andric              ParentMapContext::ParentMap *ParentMap);
56fe6060f1SDimitry Andric 
57fe6060f1SDimitry Andric template <typename, typename...> struct MatchParents;
58fe6060f1SDimitry Andric 
595ffd83dbSDimitry Andric class ParentMapContext::ParentMap {
60fe6060f1SDimitry Andric 
61fe6060f1SDimitry Andric   template <typename, typename...> friend struct ::MatchParents;
62fe6060f1SDimitry Andric 
635ffd83dbSDimitry Andric   /// Contains parents of a node.
645ffd83dbSDimitry Andric   using ParentVector = llvm::SmallVector<DynTypedNode, 2>;
655ffd83dbSDimitry Andric 
665ffd83dbSDimitry Andric   /// Maps from a node to its parents. This is used for nodes that have
675ffd83dbSDimitry Andric   /// pointer identity only, which are more common and we can save space by
685ffd83dbSDimitry Andric   /// only storing a unique pointer to them.
695ffd83dbSDimitry Andric   using ParentMapPointers =
705ffd83dbSDimitry Andric       llvm::DenseMap<const void *,
715ffd83dbSDimitry Andric                      llvm::PointerUnion<const Decl *, const Stmt *,
725ffd83dbSDimitry Andric                                         DynTypedNode *, ParentVector *>>;
735ffd83dbSDimitry Andric 
745ffd83dbSDimitry Andric   /// Parent map for nodes without pointer identity. We store a full
755ffd83dbSDimitry Andric   /// DynTypedNode for all keys.
765ffd83dbSDimitry Andric   using ParentMapOtherNodes =
775ffd83dbSDimitry Andric       llvm::DenseMap<DynTypedNode,
785ffd83dbSDimitry Andric                      llvm::PointerUnion<const Decl *, const Stmt *,
795ffd83dbSDimitry Andric                                         DynTypedNode *, ParentVector *>>;
805ffd83dbSDimitry Andric 
815ffd83dbSDimitry Andric   ParentMapPointers PointerParents;
825ffd83dbSDimitry Andric   ParentMapOtherNodes OtherParents;
835ffd83dbSDimitry Andric   class ASTVisitor;
845ffd83dbSDimitry Andric 
855ffd83dbSDimitry Andric   static DynTypedNode
865ffd83dbSDimitry Andric   getSingleDynTypedNodeFromParentMap(ParentMapPointers::mapped_type U) {
875ffd83dbSDimitry Andric     if (const auto *D = U.dyn_cast<const Decl *>())
885ffd83dbSDimitry Andric       return DynTypedNode::create(*D);
895ffd83dbSDimitry Andric     if (const auto *S = U.dyn_cast<const Stmt *>())
905ffd83dbSDimitry Andric       return DynTypedNode::create(*S);
915ffd83dbSDimitry Andric     return *U.get<DynTypedNode *>();
925ffd83dbSDimitry Andric   }
935ffd83dbSDimitry Andric 
945ffd83dbSDimitry Andric   template <typename NodeTy, typename MapTy>
955ffd83dbSDimitry Andric   static DynTypedNodeList getDynNodeFromMap(const NodeTy &Node,
965ffd83dbSDimitry Andric                                                         const MapTy &Map) {
975ffd83dbSDimitry Andric     auto I = Map.find(Node);
985ffd83dbSDimitry Andric     if (I == Map.end()) {
995ffd83dbSDimitry Andric       return llvm::ArrayRef<DynTypedNode>();
1005ffd83dbSDimitry Andric     }
1015ffd83dbSDimitry Andric     if (const auto *V = I->second.template dyn_cast<ParentVector *>()) {
102*bdd1243dSDimitry Andric       return llvm::ArrayRef(*V);
1035ffd83dbSDimitry Andric     }
1045ffd83dbSDimitry Andric     return getSingleDynTypedNodeFromParentMap(I->second);
1055ffd83dbSDimitry Andric   }
1065ffd83dbSDimitry Andric 
1075ffd83dbSDimitry Andric public:
1085ffd83dbSDimitry Andric   ParentMap(ASTContext &Ctx);
1095ffd83dbSDimitry Andric   ~ParentMap() {
1105ffd83dbSDimitry Andric     for (const auto &Entry : PointerParents) {
1115ffd83dbSDimitry Andric       if (Entry.second.is<DynTypedNode *>()) {
1125ffd83dbSDimitry Andric         delete Entry.second.get<DynTypedNode *>();
1135ffd83dbSDimitry Andric       } else if (Entry.second.is<ParentVector *>()) {
1145ffd83dbSDimitry Andric         delete Entry.second.get<ParentVector *>();
1155ffd83dbSDimitry Andric       }
1165ffd83dbSDimitry Andric     }
1175ffd83dbSDimitry Andric     for (const auto &Entry : OtherParents) {
1185ffd83dbSDimitry Andric       if (Entry.second.is<DynTypedNode *>()) {
1195ffd83dbSDimitry Andric         delete Entry.second.get<DynTypedNode *>();
1205ffd83dbSDimitry Andric       } else if (Entry.second.is<ParentVector *>()) {
1215ffd83dbSDimitry Andric         delete Entry.second.get<ParentVector *>();
1225ffd83dbSDimitry Andric       }
1235ffd83dbSDimitry Andric     }
1245ffd83dbSDimitry Andric   }
1255ffd83dbSDimitry Andric 
1265ffd83dbSDimitry Andric   DynTypedNodeList getParents(TraversalKind TK, const DynTypedNode &Node) {
1275ffd83dbSDimitry Andric     if (Node.getNodeKind().hasPointerIdentity()) {
1285ffd83dbSDimitry Andric       auto ParentList =
1295ffd83dbSDimitry Andric           getDynNodeFromMap(Node.getMemoizationData(), PointerParents);
130fe6060f1SDimitry Andric       if (ParentList.size() > 0 && TK == TK_IgnoreUnlessSpelledInSource) {
131fe6060f1SDimitry Andric 
132fe6060f1SDimitry Andric         const auto *ChildExpr = Node.get<Expr>();
133fe6060f1SDimitry Andric 
134fe6060f1SDimitry Andric         {
135fe6060f1SDimitry Andric           // Don't match explicit node types because different stdlib
136fe6060f1SDimitry Andric           // implementations implement this in different ways and have
137fe6060f1SDimitry Andric           // different intermediate nodes.
138fe6060f1SDimitry Andric           // Look up 4 levels for a cxxRewrittenBinaryOperator as that is
139fe6060f1SDimitry Andric           // enough for the major stdlib implementations.
140fe6060f1SDimitry Andric           auto RewrittenBinOpParentsList = ParentList;
141fe6060f1SDimitry Andric           int I = 0;
142fe6060f1SDimitry Andric           while (ChildExpr && RewrittenBinOpParentsList.size() == 1 &&
143fe6060f1SDimitry Andric                  I++ < 4) {
144fe6060f1SDimitry Andric             const auto *S = RewrittenBinOpParentsList[0].get<Stmt>();
145fe6060f1SDimitry Andric             if (!S)
146fe6060f1SDimitry Andric               break;
147fe6060f1SDimitry Andric 
148fe6060f1SDimitry Andric             const auto *RWBO = dyn_cast<CXXRewrittenBinaryOperator>(S);
149fe6060f1SDimitry Andric             if (!RWBO) {
150fe6060f1SDimitry Andric               RewrittenBinOpParentsList = getDynNodeFromMap(S, PointerParents);
151fe6060f1SDimitry Andric               continue;
152fe6060f1SDimitry Andric             }
153fe6060f1SDimitry Andric             if (RWBO->getLHS()->IgnoreUnlessSpelledInSource() != ChildExpr &&
154fe6060f1SDimitry Andric                 RWBO->getRHS()->IgnoreUnlessSpelledInSource() != ChildExpr)
155fe6060f1SDimitry Andric               break;
156fe6060f1SDimitry Andric             return DynTypedNode::create(*RWBO);
157fe6060f1SDimitry Andric           }
158fe6060f1SDimitry Andric         }
159fe6060f1SDimitry Andric 
160fe6060f1SDimitry Andric         const auto *ParentExpr = ParentList[0].get<Expr>();
161fe6060f1SDimitry Andric         if (ParentExpr && ChildExpr)
162fe6060f1SDimitry Andric           return AscendIgnoreUnlessSpelledInSource(ParentExpr, ChildExpr);
163fe6060f1SDimitry Andric 
164fe6060f1SDimitry Andric         {
165fe6060f1SDimitry Andric           auto AncestorNodes =
166fe6060f1SDimitry Andric               matchParents<DeclStmt, CXXForRangeStmt>(ParentList, this);
167fe6060f1SDimitry Andric           if (std::get<bool>(AncestorNodes) &&
168fe6060f1SDimitry Andric               std::get<const CXXForRangeStmt *>(AncestorNodes)
169fe6060f1SDimitry Andric                       ->getLoopVarStmt() ==
170fe6060f1SDimitry Andric                   std::get<const DeclStmt *>(AncestorNodes))
171fe6060f1SDimitry Andric             return std::get<DynTypedNodeList>(AncestorNodes);
172fe6060f1SDimitry Andric         }
173fe6060f1SDimitry Andric         {
174fe6060f1SDimitry Andric           auto AncestorNodes = matchParents<VarDecl, DeclStmt, CXXForRangeStmt>(
175fe6060f1SDimitry Andric               ParentList, this);
176fe6060f1SDimitry Andric           if (std::get<bool>(AncestorNodes) &&
177fe6060f1SDimitry Andric               std::get<const CXXForRangeStmt *>(AncestorNodes)
178fe6060f1SDimitry Andric                       ->getRangeStmt() ==
179fe6060f1SDimitry Andric                   std::get<const DeclStmt *>(AncestorNodes))
180fe6060f1SDimitry Andric             return std::get<DynTypedNodeList>(AncestorNodes);
181fe6060f1SDimitry Andric         }
182fe6060f1SDimitry Andric         {
183fe6060f1SDimitry Andric           auto AncestorNodes =
184fe6060f1SDimitry Andric               matchParents<CXXMethodDecl, CXXRecordDecl, LambdaExpr>(ParentList,
185fe6060f1SDimitry Andric                                                                      this);
186fe6060f1SDimitry Andric           if (std::get<bool>(AncestorNodes))
187fe6060f1SDimitry Andric             return std::get<DynTypedNodeList>(AncestorNodes);
188fe6060f1SDimitry Andric         }
189fe6060f1SDimitry Andric         {
190fe6060f1SDimitry Andric           auto AncestorNodes =
191fe6060f1SDimitry Andric               matchParents<FunctionTemplateDecl, CXXRecordDecl, LambdaExpr>(
192fe6060f1SDimitry Andric                   ParentList, this);
193fe6060f1SDimitry Andric           if (std::get<bool>(AncestorNodes))
194fe6060f1SDimitry Andric             return std::get<DynTypedNodeList>(AncestorNodes);
195fe6060f1SDimitry Andric         }
1965ffd83dbSDimitry Andric       }
1975ffd83dbSDimitry Andric       return ParentList;
1985ffd83dbSDimitry Andric     }
1995ffd83dbSDimitry Andric     return getDynNodeFromMap(Node, OtherParents);
2005ffd83dbSDimitry Andric   }
2015ffd83dbSDimitry Andric 
2025ffd83dbSDimitry Andric   DynTypedNodeList AscendIgnoreUnlessSpelledInSource(const Expr *E,
2035ffd83dbSDimitry Andric                                                      const Expr *Child) {
2045ffd83dbSDimitry Andric 
2055ffd83dbSDimitry Andric     auto ShouldSkip = [](const Expr *E, const Expr *Child) {
2065ffd83dbSDimitry Andric       if (isa<ImplicitCastExpr>(E))
2075ffd83dbSDimitry Andric         return true;
2085ffd83dbSDimitry Andric 
2095ffd83dbSDimitry Andric       if (isa<FullExpr>(E))
2105ffd83dbSDimitry Andric         return true;
2115ffd83dbSDimitry Andric 
2125ffd83dbSDimitry Andric       if (isa<MaterializeTemporaryExpr>(E))
2135ffd83dbSDimitry Andric         return true;
2145ffd83dbSDimitry Andric 
2155ffd83dbSDimitry Andric       if (isa<CXXBindTemporaryExpr>(E))
2165ffd83dbSDimitry Andric         return true;
2175ffd83dbSDimitry Andric 
2185ffd83dbSDimitry Andric       if (isa<ParenExpr>(E))
2195ffd83dbSDimitry Andric         return true;
2205ffd83dbSDimitry Andric 
2215ffd83dbSDimitry Andric       if (isa<ExprWithCleanups>(E))
2225ffd83dbSDimitry Andric         return true;
2235ffd83dbSDimitry Andric 
2245ffd83dbSDimitry Andric       auto SR = Child->getSourceRange();
2255ffd83dbSDimitry Andric 
226e8d8bef9SDimitry Andric       if (const auto *C = dyn_cast<CXXFunctionalCastExpr>(E)) {
227e8d8bef9SDimitry Andric         if (C->getSourceRange() == SR)
228e8d8bef9SDimitry Andric           return true;
229e8d8bef9SDimitry Andric       }
230e8d8bef9SDimitry Andric 
2315ffd83dbSDimitry Andric       if (const auto *C = dyn_cast<CXXConstructExpr>(E)) {
232e8d8bef9SDimitry Andric         if (C->getSourceRange() == SR || C->isElidable())
2335ffd83dbSDimitry Andric           return true;
2345ffd83dbSDimitry Andric       }
2355ffd83dbSDimitry Andric 
2365ffd83dbSDimitry Andric       if (const auto *C = dyn_cast<CXXMemberCallExpr>(E)) {
2375ffd83dbSDimitry Andric         if (C->getSourceRange() == SR)
2385ffd83dbSDimitry Andric           return true;
2395ffd83dbSDimitry Andric       }
2405ffd83dbSDimitry Andric 
2415ffd83dbSDimitry Andric       if (const auto *C = dyn_cast<MemberExpr>(E)) {
2425ffd83dbSDimitry Andric         if (C->getSourceRange() == SR)
2435ffd83dbSDimitry Andric           return true;
2445ffd83dbSDimitry Andric       }
2455ffd83dbSDimitry Andric       return false;
2465ffd83dbSDimitry Andric     };
2475ffd83dbSDimitry Andric 
2485ffd83dbSDimitry Andric     while (ShouldSkip(E, Child)) {
2495ffd83dbSDimitry Andric       auto It = PointerParents.find(E);
2505ffd83dbSDimitry Andric       if (It == PointerParents.end())
2515ffd83dbSDimitry Andric         break;
2525ffd83dbSDimitry Andric       const auto *S = It->second.dyn_cast<const Stmt *>();
2535ffd83dbSDimitry Andric       if (!S) {
2545ffd83dbSDimitry Andric         if (auto *Vec = It->second.dyn_cast<ParentVector *>())
255*bdd1243dSDimitry Andric           return llvm::ArrayRef(*Vec);
2565ffd83dbSDimitry Andric         return getSingleDynTypedNodeFromParentMap(It->second);
2575ffd83dbSDimitry Andric       }
2585ffd83dbSDimitry Andric       const auto *P = dyn_cast<Expr>(S);
2595ffd83dbSDimitry Andric       if (!P)
2605ffd83dbSDimitry Andric         return DynTypedNode::create(*S);
2615ffd83dbSDimitry Andric       Child = E;
2625ffd83dbSDimitry Andric       E = P;
2635ffd83dbSDimitry Andric     }
2645ffd83dbSDimitry Andric     return DynTypedNode::create(*E);
2655ffd83dbSDimitry Andric   }
2665ffd83dbSDimitry Andric };
2675ffd83dbSDimitry Andric 
268fe6060f1SDimitry Andric template <typename T, typename... U> struct MatchParents {
269fe6060f1SDimitry Andric   static std::tuple<bool, DynTypedNodeList, const T *, const U *...>
270fe6060f1SDimitry Andric   match(const DynTypedNodeList &NodeList,
271fe6060f1SDimitry Andric         ParentMapContext::ParentMap *ParentMap) {
272fe6060f1SDimitry Andric     if (const auto *TypedNode = NodeList[0].get<T>()) {
273fe6060f1SDimitry Andric       auto NextParentList =
274fe6060f1SDimitry Andric           ParentMap->getDynNodeFromMap(TypedNode, ParentMap->PointerParents);
275fe6060f1SDimitry Andric       if (NextParentList.size() == 1) {
276fe6060f1SDimitry Andric         auto TailTuple = MatchParents<U...>::match(NextParentList, ParentMap);
277fe6060f1SDimitry Andric         if (std::get<bool>(TailTuple)) {
278*bdd1243dSDimitry Andric           return std::apply(
279*bdd1243dSDimitry Andric               [TypedNode](bool, DynTypedNodeList NodeList, auto... TupleTail) {
280*bdd1243dSDimitry Andric                 return std::make_tuple(true, NodeList, TypedNode, TupleTail...);
281*bdd1243dSDimitry Andric               },
282*bdd1243dSDimitry Andric               TailTuple);
283fe6060f1SDimitry Andric         }
284fe6060f1SDimitry Andric       }
285fe6060f1SDimitry Andric     }
286fe6060f1SDimitry Andric     return std::tuple_cat(std::make_tuple(false, NodeList),
287fe6060f1SDimitry Andric                           std::tuple<const T *, const U *...>());
288fe6060f1SDimitry Andric   }
289fe6060f1SDimitry Andric };
290fe6060f1SDimitry Andric 
291fe6060f1SDimitry Andric template <typename T> struct MatchParents<T> {
292fe6060f1SDimitry Andric   static std::tuple<bool, DynTypedNodeList, const T *>
293fe6060f1SDimitry Andric   match(const DynTypedNodeList &NodeList,
294fe6060f1SDimitry Andric         ParentMapContext::ParentMap *ParentMap) {
295fe6060f1SDimitry Andric     if (const auto *TypedNode = NodeList[0].get<T>()) {
296fe6060f1SDimitry Andric       auto NextParentList =
297fe6060f1SDimitry Andric           ParentMap->getDynNodeFromMap(TypedNode, ParentMap->PointerParents);
298fe6060f1SDimitry Andric       if (NextParentList.size() == 1)
299fe6060f1SDimitry Andric         return std::make_tuple(true, NodeList, TypedNode);
300fe6060f1SDimitry Andric     }
301fe6060f1SDimitry Andric     return std::make_tuple(false, NodeList, nullptr);
302fe6060f1SDimitry Andric   }
303fe6060f1SDimitry Andric };
304fe6060f1SDimitry Andric 
305fe6060f1SDimitry Andric template <typename T, typename... U>
306fe6060f1SDimitry Andric std::tuple<bool, DynTypedNodeList, const T *, const U *...>
307fe6060f1SDimitry Andric matchParents(const DynTypedNodeList &NodeList,
308fe6060f1SDimitry Andric              ParentMapContext::ParentMap *ParentMap) {
309fe6060f1SDimitry Andric   return MatchParents<T, U...>::match(NodeList, ParentMap);
310fe6060f1SDimitry Andric }
311fe6060f1SDimitry Andric 
3125ffd83dbSDimitry Andric /// Template specializations to abstract away from pointers and TypeLocs.
3135ffd83dbSDimitry Andric /// @{
3145ffd83dbSDimitry Andric template <typename T> static DynTypedNode createDynTypedNode(const T &Node) {
3155ffd83dbSDimitry Andric   return DynTypedNode::create(*Node);
3165ffd83dbSDimitry Andric }
3175ffd83dbSDimitry Andric template <> DynTypedNode createDynTypedNode(const TypeLoc &Node) {
3185ffd83dbSDimitry Andric   return DynTypedNode::create(Node);
3195ffd83dbSDimitry Andric }
3205ffd83dbSDimitry Andric template <>
3215ffd83dbSDimitry Andric DynTypedNode createDynTypedNode(const NestedNameSpecifierLoc &Node) {
3225ffd83dbSDimitry Andric   return DynTypedNode::create(Node);
3235ffd83dbSDimitry Andric }
32481ad6265SDimitry Andric template <> DynTypedNode createDynTypedNode(const ObjCProtocolLoc &Node) {
32581ad6265SDimitry Andric   return DynTypedNode::create(Node);
32681ad6265SDimitry Andric }
3275ffd83dbSDimitry Andric /// @}
3285ffd83dbSDimitry Andric 
3295ffd83dbSDimitry Andric /// A \c RecursiveASTVisitor that builds a map from nodes to their
3305ffd83dbSDimitry Andric /// parents as defined by the \c RecursiveASTVisitor.
3315ffd83dbSDimitry Andric ///
3325ffd83dbSDimitry Andric /// Note that the relationship described here is purely in terms of AST
3335ffd83dbSDimitry Andric /// traversal - there are other relationships (for example declaration context)
3345ffd83dbSDimitry Andric /// in the AST that are better modeled by special matchers.
3355ffd83dbSDimitry Andric class ParentMapContext::ParentMap::ASTVisitor
3365ffd83dbSDimitry Andric     : public RecursiveASTVisitor<ASTVisitor> {
3375ffd83dbSDimitry Andric public:
3385ffd83dbSDimitry Andric   ASTVisitor(ParentMap &Map) : Map(Map) {}
3395ffd83dbSDimitry Andric 
3405ffd83dbSDimitry Andric private:
3415ffd83dbSDimitry Andric   friend class RecursiveASTVisitor<ASTVisitor>;
3425ffd83dbSDimitry Andric 
3435ffd83dbSDimitry Andric   using VisitorBase = RecursiveASTVisitor<ASTVisitor>;
3445ffd83dbSDimitry Andric 
3455ffd83dbSDimitry Andric   bool shouldVisitTemplateInstantiations() const { return true; }
3465ffd83dbSDimitry Andric 
3475ffd83dbSDimitry Andric   bool shouldVisitImplicitCode() const { return true; }
3485ffd83dbSDimitry Andric 
349e8d8bef9SDimitry Andric   /// Record the parent of the node we're visiting.
350e8d8bef9SDimitry Andric   /// MapNode is the child, the parent is on top of ParentStack.
351e8d8bef9SDimitry Andric   /// Parents is the parent storage (either PointerParents or OtherParents).
352e8d8bef9SDimitry Andric   template <typename MapNodeTy, typename MapTy>
353e8d8bef9SDimitry Andric   void addParent(MapNodeTy MapNode, MapTy *Parents) {
354e8d8bef9SDimitry Andric     if (ParentStack.empty())
355e8d8bef9SDimitry Andric       return;
356e8d8bef9SDimitry Andric 
3575ffd83dbSDimitry Andric     // FIXME: Currently we add the same parent multiple times, but only
3585ffd83dbSDimitry Andric     // when no memoization data is available for the type.
3595ffd83dbSDimitry Andric     // For example when we visit all subexpressions of template
3605ffd83dbSDimitry Andric     // instantiations; this is suboptimal, but benign: the only way to
3615ffd83dbSDimitry Andric     // visit those is with hasAncestor / hasParent, and those do not create
3625ffd83dbSDimitry Andric     // new matches.
3635ffd83dbSDimitry Andric     // The plan is to enable DynTypedNode to be storable in a map or hash
3645ffd83dbSDimitry Andric     // map. The main problem there is to implement hash functions /
3655ffd83dbSDimitry Andric     // comparison operators for all types that DynTypedNode supports that
3665ffd83dbSDimitry Andric     // do not have pointer identity.
3675ffd83dbSDimitry Andric     auto &NodeOrVector = (*Parents)[MapNode];
3685ffd83dbSDimitry Andric     if (NodeOrVector.isNull()) {
3695ffd83dbSDimitry Andric       if (const auto *D = ParentStack.back().get<Decl>())
3705ffd83dbSDimitry Andric         NodeOrVector = D;
3715ffd83dbSDimitry Andric       else if (const auto *S = ParentStack.back().get<Stmt>())
3725ffd83dbSDimitry Andric         NodeOrVector = S;
3735ffd83dbSDimitry Andric       else
3745ffd83dbSDimitry Andric         NodeOrVector = new DynTypedNode(ParentStack.back());
3755ffd83dbSDimitry Andric     } else {
3765ffd83dbSDimitry Andric       if (!NodeOrVector.template is<ParentVector *>()) {
3775ffd83dbSDimitry Andric         auto *Vector = new ParentVector(
3785ffd83dbSDimitry Andric             1, getSingleDynTypedNodeFromParentMap(NodeOrVector));
3795ffd83dbSDimitry Andric         delete NodeOrVector.template dyn_cast<DynTypedNode *>();
3805ffd83dbSDimitry Andric         NodeOrVector = Vector;
3815ffd83dbSDimitry Andric       }
3825ffd83dbSDimitry Andric 
3835ffd83dbSDimitry Andric       auto *Vector = NodeOrVector.template get<ParentVector *>();
3845ffd83dbSDimitry Andric       // Skip duplicates for types that have memoization data.
3855ffd83dbSDimitry Andric       // We must check that the type has memoization data before calling
386349cc55cSDimitry Andric       // llvm::is_contained() because DynTypedNode::operator== can't compare all
3875ffd83dbSDimitry Andric       // types.
3885ffd83dbSDimitry Andric       bool Found = ParentStack.back().getMemoizationData() &&
389349cc55cSDimitry Andric                    llvm::is_contained(*Vector, ParentStack.back());
3905ffd83dbSDimitry Andric       if (!Found)
3915ffd83dbSDimitry Andric         Vector->push_back(ParentStack.back());
3925ffd83dbSDimitry Andric     }
3935ffd83dbSDimitry Andric   }
394e8d8bef9SDimitry Andric 
39581ad6265SDimitry Andric   template <typename T> static bool isNull(T Node) { return !Node; }
39681ad6265SDimitry Andric   static bool isNull(ObjCProtocolLoc Node) { return false; }
39781ad6265SDimitry Andric 
398e8d8bef9SDimitry Andric   template <typename T, typename MapNodeTy, typename BaseTraverseFn,
399e8d8bef9SDimitry Andric             typename MapTy>
400e8d8bef9SDimitry Andric   bool TraverseNode(T Node, MapNodeTy MapNode, BaseTraverseFn BaseTraverse,
401e8d8bef9SDimitry Andric                     MapTy *Parents) {
40281ad6265SDimitry Andric     if (isNull(Node))
403e8d8bef9SDimitry Andric       return true;
404e8d8bef9SDimitry Andric     addParent(MapNode, Parents);
4055ffd83dbSDimitry Andric     ParentStack.push_back(createDynTypedNode(Node));
4065ffd83dbSDimitry Andric     bool Result = BaseTraverse();
4075ffd83dbSDimitry Andric     ParentStack.pop_back();
4085ffd83dbSDimitry Andric     return Result;
4095ffd83dbSDimitry Andric   }
4105ffd83dbSDimitry Andric 
4115ffd83dbSDimitry Andric   bool TraverseDecl(Decl *DeclNode) {
4125ffd83dbSDimitry Andric     return TraverseNode(
4135ffd83dbSDimitry Andric         DeclNode, DeclNode, [&] { return VisitorBase::TraverseDecl(DeclNode); },
4145ffd83dbSDimitry Andric         &Map.PointerParents);
4155ffd83dbSDimitry Andric   }
4165ffd83dbSDimitry Andric   bool TraverseTypeLoc(TypeLoc TypeLocNode) {
4175ffd83dbSDimitry Andric     return TraverseNode(
4185ffd83dbSDimitry Andric         TypeLocNode, DynTypedNode::create(TypeLocNode),
4195ffd83dbSDimitry Andric         [&] { return VisitorBase::TraverseTypeLoc(TypeLocNode); },
4205ffd83dbSDimitry Andric         &Map.OtherParents);
4215ffd83dbSDimitry Andric   }
4225ffd83dbSDimitry Andric   bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode) {
4235ffd83dbSDimitry Andric     return TraverseNode(
4245ffd83dbSDimitry Andric         NNSLocNode, DynTypedNode::create(NNSLocNode),
4255ffd83dbSDimitry Andric         [&] { return VisitorBase::TraverseNestedNameSpecifierLoc(NNSLocNode); },
4265ffd83dbSDimitry Andric         &Map.OtherParents);
4275ffd83dbSDimitry Andric   }
428349cc55cSDimitry Andric   bool TraverseAttr(Attr *AttrNode) {
429349cc55cSDimitry Andric     return TraverseNode(
430349cc55cSDimitry Andric         AttrNode, AttrNode, [&] { return VisitorBase::TraverseAttr(AttrNode); },
431349cc55cSDimitry Andric         &Map.PointerParents);
432349cc55cSDimitry Andric   }
43381ad6265SDimitry Andric   bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLocNode) {
43481ad6265SDimitry Andric     return TraverseNode(
43581ad6265SDimitry Andric         ProtocolLocNode, DynTypedNode::create(ProtocolLocNode),
43681ad6265SDimitry Andric         [&] { return VisitorBase::TraverseObjCProtocolLoc(ProtocolLocNode); },
43781ad6265SDimitry Andric         &Map.OtherParents);
43881ad6265SDimitry Andric   }
4395ffd83dbSDimitry Andric 
440e8d8bef9SDimitry Andric   // Using generic TraverseNode for Stmt would prevent data-recursion.
441e8d8bef9SDimitry Andric   bool dataTraverseStmtPre(Stmt *StmtNode) {
442e8d8bef9SDimitry Andric     addParent(StmtNode, &Map.PointerParents);
443e8d8bef9SDimitry Andric     ParentStack.push_back(DynTypedNode::create(*StmtNode));
444e8d8bef9SDimitry Andric     return true;
445e8d8bef9SDimitry Andric   }
446e8d8bef9SDimitry Andric   bool dataTraverseStmtPost(Stmt *StmtNode) {
447e8d8bef9SDimitry Andric     ParentStack.pop_back();
448e8d8bef9SDimitry Andric     return true;
449e8d8bef9SDimitry Andric   }
450e8d8bef9SDimitry Andric 
4515ffd83dbSDimitry Andric   ParentMap &Map;
4525ffd83dbSDimitry Andric   llvm::SmallVector<DynTypedNode, 16> ParentStack;
4535ffd83dbSDimitry Andric };
4545ffd83dbSDimitry Andric 
4555ffd83dbSDimitry Andric ParentMapContext::ParentMap::ParentMap(ASTContext &Ctx) {
4565ffd83dbSDimitry Andric   ASTVisitor(*this).TraverseAST(Ctx);
4575ffd83dbSDimitry Andric }
4585ffd83dbSDimitry Andric 
4595ffd83dbSDimitry Andric DynTypedNodeList ParentMapContext::getParents(const DynTypedNode &Node) {
4605ffd83dbSDimitry Andric   if (!Parents)
4615ffd83dbSDimitry Andric     // We build the parent map for the traversal scope (usually whole TU), as
4625ffd83dbSDimitry Andric     // hasAncestor can escape any subtree.
4635ffd83dbSDimitry Andric     Parents = std::make_unique<ParentMap>(ASTCtx);
4645ffd83dbSDimitry Andric   return Parents->getParents(getTraversalKind(), Node);
4655ffd83dbSDimitry Andric }
466