xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/ParentMapContext.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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.
64*0fca6ea1SDimitry Andric   class ParentVector {
65*0fca6ea1SDimitry Andric   public:
66*0fca6ea1SDimitry Andric     ParentVector() = default;
67*0fca6ea1SDimitry Andric     explicit ParentVector(size_t N, const DynTypedNode &Value) {
68*0fca6ea1SDimitry Andric       Items.reserve(N);
69*0fca6ea1SDimitry Andric       for (; N > 0; --N)
70*0fca6ea1SDimitry Andric         push_back(Value);
71*0fca6ea1SDimitry Andric     }
72*0fca6ea1SDimitry Andric     bool contains(const DynTypedNode &Value) {
73*0fca6ea1SDimitry Andric       return Seen.contains(Value);
74*0fca6ea1SDimitry Andric     }
75*0fca6ea1SDimitry Andric     void push_back(const DynTypedNode &Value) {
76*0fca6ea1SDimitry Andric       if (!Value.getMemoizationData() || Seen.insert(Value).second)
77*0fca6ea1SDimitry Andric         Items.push_back(Value);
78*0fca6ea1SDimitry Andric     }
79*0fca6ea1SDimitry Andric     llvm::ArrayRef<DynTypedNode> view() const { return Items; }
80*0fca6ea1SDimitry Andric   private:
81*0fca6ea1SDimitry Andric     llvm::SmallVector<DynTypedNode, 2> Items;
82*0fca6ea1SDimitry Andric     llvm::SmallDenseSet<DynTypedNode, 2> Seen;
83*0fca6ea1SDimitry Andric   };
845ffd83dbSDimitry Andric 
855ffd83dbSDimitry Andric   /// Maps from a node to its parents. This is used for nodes that have
865ffd83dbSDimitry Andric   /// pointer identity only, which are more common and we can save space by
875ffd83dbSDimitry Andric   /// only storing a unique pointer to them.
885ffd83dbSDimitry Andric   using ParentMapPointers =
895ffd83dbSDimitry Andric       llvm::DenseMap<const void *,
905ffd83dbSDimitry Andric                      llvm::PointerUnion<const Decl *, const Stmt *,
915ffd83dbSDimitry Andric                                         DynTypedNode *, ParentVector *>>;
925ffd83dbSDimitry Andric 
935ffd83dbSDimitry Andric   /// Parent map for nodes without pointer identity. We store a full
945ffd83dbSDimitry Andric   /// DynTypedNode for all keys.
955ffd83dbSDimitry Andric   using ParentMapOtherNodes =
965ffd83dbSDimitry Andric       llvm::DenseMap<DynTypedNode,
975ffd83dbSDimitry Andric                      llvm::PointerUnion<const Decl *, const Stmt *,
985ffd83dbSDimitry Andric                                         DynTypedNode *, ParentVector *>>;
995ffd83dbSDimitry Andric 
1005ffd83dbSDimitry Andric   ParentMapPointers PointerParents;
1015ffd83dbSDimitry Andric   ParentMapOtherNodes OtherParents;
1025ffd83dbSDimitry Andric   class ASTVisitor;
1035ffd83dbSDimitry Andric 
1045ffd83dbSDimitry Andric   static DynTypedNode
1055ffd83dbSDimitry Andric   getSingleDynTypedNodeFromParentMap(ParentMapPointers::mapped_type U) {
1065ffd83dbSDimitry Andric     if (const auto *D = U.dyn_cast<const Decl *>())
1075ffd83dbSDimitry Andric       return DynTypedNode::create(*D);
1085ffd83dbSDimitry Andric     if (const auto *S = U.dyn_cast<const Stmt *>())
1095ffd83dbSDimitry Andric       return DynTypedNode::create(*S);
1105ffd83dbSDimitry Andric     return *U.get<DynTypedNode *>();
1115ffd83dbSDimitry Andric   }
1125ffd83dbSDimitry Andric 
1135ffd83dbSDimitry Andric   template <typename NodeTy, typename MapTy>
1145ffd83dbSDimitry Andric   static DynTypedNodeList getDynNodeFromMap(const NodeTy &Node,
1155ffd83dbSDimitry Andric                                                         const MapTy &Map) {
1165ffd83dbSDimitry Andric     auto I = Map.find(Node);
1175ffd83dbSDimitry Andric     if (I == Map.end()) {
1185ffd83dbSDimitry Andric       return llvm::ArrayRef<DynTypedNode>();
1195ffd83dbSDimitry Andric     }
1205ffd83dbSDimitry Andric     if (const auto *V = I->second.template dyn_cast<ParentVector *>()) {
121*0fca6ea1SDimitry Andric       return V->view();
1225ffd83dbSDimitry Andric     }
1235ffd83dbSDimitry Andric     return getSingleDynTypedNodeFromParentMap(I->second);
1245ffd83dbSDimitry Andric   }
1255ffd83dbSDimitry Andric 
1265ffd83dbSDimitry Andric public:
1275ffd83dbSDimitry Andric   ParentMap(ASTContext &Ctx);
1285ffd83dbSDimitry Andric   ~ParentMap() {
1295ffd83dbSDimitry Andric     for (const auto &Entry : PointerParents) {
1305ffd83dbSDimitry Andric       if (Entry.second.is<DynTypedNode *>()) {
1315ffd83dbSDimitry Andric         delete Entry.second.get<DynTypedNode *>();
1325ffd83dbSDimitry Andric       } else if (Entry.second.is<ParentVector *>()) {
1335ffd83dbSDimitry Andric         delete Entry.second.get<ParentVector *>();
1345ffd83dbSDimitry Andric       }
1355ffd83dbSDimitry Andric     }
1365ffd83dbSDimitry Andric     for (const auto &Entry : OtherParents) {
1375ffd83dbSDimitry Andric       if (Entry.second.is<DynTypedNode *>()) {
1385ffd83dbSDimitry Andric         delete Entry.second.get<DynTypedNode *>();
1395ffd83dbSDimitry Andric       } else if (Entry.second.is<ParentVector *>()) {
1405ffd83dbSDimitry Andric         delete Entry.second.get<ParentVector *>();
1415ffd83dbSDimitry Andric       }
1425ffd83dbSDimitry Andric     }
1435ffd83dbSDimitry Andric   }
1445ffd83dbSDimitry Andric 
1455ffd83dbSDimitry Andric   DynTypedNodeList getParents(TraversalKind TK, const DynTypedNode &Node) {
1465ffd83dbSDimitry Andric     if (Node.getNodeKind().hasPointerIdentity()) {
1475ffd83dbSDimitry Andric       auto ParentList =
1485ffd83dbSDimitry Andric           getDynNodeFromMap(Node.getMemoizationData(), PointerParents);
149fe6060f1SDimitry Andric       if (ParentList.size() > 0 && TK == TK_IgnoreUnlessSpelledInSource) {
150fe6060f1SDimitry Andric 
151fe6060f1SDimitry Andric         const auto *ChildExpr = Node.get<Expr>();
152fe6060f1SDimitry Andric 
153fe6060f1SDimitry Andric         {
154fe6060f1SDimitry Andric           // Don't match explicit node types because different stdlib
155fe6060f1SDimitry Andric           // implementations implement this in different ways and have
156fe6060f1SDimitry Andric           // different intermediate nodes.
157fe6060f1SDimitry Andric           // Look up 4 levels for a cxxRewrittenBinaryOperator as that is
158fe6060f1SDimitry Andric           // enough for the major stdlib implementations.
159fe6060f1SDimitry Andric           auto RewrittenBinOpParentsList = ParentList;
160fe6060f1SDimitry Andric           int I = 0;
161fe6060f1SDimitry Andric           while (ChildExpr && RewrittenBinOpParentsList.size() == 1 &&
162fe6060f1SDimitry Andric                  I++ < 4) {
163fe6060f1SDimitry Andric             const auto *S = RewrittenBinOpParentsList[0].get<Stmt>();
164fe6060f1SDimitry Andric             if (!S)
165fe6060f1SDimitry Andric               break;
166fe6060f1SDimitry Andric 
167fe6060f1SDimitry Andric             const auto *RWBO = dyn_cast<CXXRewrittenBinaryOperator>(S);
168fe6060f1SDimitry Andric             if (!RWBO) {
169fe6060f1SDimitry Andric               RewrittenBinOpParentsList = getDynNodeFromMap(S, PointerParents);
170fe6060f1SDimitry Andric               continue;
171fe6060f1SDimitry Andric             }
172fe6060f1SDimitry Andric             if (RWBO->getLHS()->IgnoreUnlessSpelledInSource() != ChildExpr &&
173fe6060f1SDimitry Andric                 RWBO->getRHS()->IgnoreUnlessSpelledInSource() != ChildExpr)
174fe6060f1SDimitry Andric               break;
175fe6060f1SDimitry Andric             return DynTypedNode::create(*RWBO);
176fe6060f1SDimitry Andric           }
177fe6060f1SDimitry Andric         }
178fe6060f1SDimitry Andric 
179fe6060f1SDimitry Andric         const auto *ParentExpr = ParentList[0].get<Expr>();
180fe6060f1SDimitry Andric         if (ParentExpr && ChildExpr)
181fe6060f1SDimitry Andric           return AscendIgnoreUnlessSpelledInSource(ParentExpr, ChildExpr);
182fe6060f1SDimitry Andric 
183fe6060f1SDimitry Andric         {
184fe6060f1SDimitry Andric           auto AncestorNodes =
185fe6060f1SDimitry Andric               matchParents<DeclStmt, CXXForRangeStmt>(ParentList, this);
186fe6060f1SDimitry Andric           if (std::get<bool>(AncestorNodes) &&
187fe6060f1SDimitry Andric               std::get<const CXXForRangeStmt *>(AncestorNodes)
188fe6060f1SDimitry Andric                       ->getLoopVarStmt() ==
189fe6060f1SDimitry Andric                   std::get<const DeclStmt *>(AncestorNodes))
190fe6060f1SDimitry Andric             return std::get<DynTypedNodeList>(AncestorNodes);
191fe6060f1SDimitry Andric         }
192fe6060f1SDimitry Andric         {
193fe6060f1SDimitry Andric           auto AncestorNodes = matchParents<VarDecl, DeclStmt, CXXForRangeStmt>(
194fe6060f1SDimitry Andric               ParentList, this);
195fe6060f1SDimitry Andric           if (std::get<bool>(AncestorNodes) &&
196fe6060f1SDimitry Andric               std::get<const CXXForRangeStmt *>(AncestorNodes)
197fe6060f1SDimitry Andric                       ->getRangeStmt() ==
198fe6060f1SDimitry Andric                   std::get<const DeclStmt *>(AncestorNodes))
199fe6060f1SDimitry Andric             return std::get<DynTypedNodeList>(AncestorNodes);
200fe6060f1SDimitry Andric         }
201fe6060f1SDimitry Andric         {
202fe6060f1SDimitry Andric           auto AncestorNodes =
203fe6060f1SDimitry Andric               matchParents<CXXMethodDecl, CXXRecordDecl, LambdaExpr>(ParentList,
204fe6060f1SDimitry Andric                                                                      this);
205fe6060f1SDimitry Andric           if (std::get<bool>(AncestorNodes))
206fe6060f1SDimitry Andric             return std::get<DynTypedNodeList>(AncestorNodes);
207fe6060f1SDimitry Andric         }
208fe6060f1SDimitry Andric         {
209fe6060f1SDimitry Andric           auto AncestorNodes =
210fe6060f1SDimitry Andric               matchParents<FunctionTemplateDecl, CXXRecordDecl, LambdaExpr>(
211fe6060f1SDimitry Andric                   ParentList, this);
212fe6060f1SDimitry Andric           if (std::get<bool>(AncestorNodes))
213fe6060f1SDimitry Andric             return std::get<DynTypedNodeList>(AncestorNodes);
214fe6060f1SDimitry Andric         }
2155ffd83dbSDimitry Andric       }
2165ffd83dbSDimitry Andric       return ParentList;
2175ffd83dbSDimitry Andric     }
2185ffd83dbSDimitry Andric     return getDynNodeFromMap(Node, OtherParents);
2195ffd83dbSDimitry Andric   }
2205ffd83dbSDimitry Andric 
2215ffd83dbSDimitry Andric   DynTypedNodeList AscendIgnoreUnlessSpelledInSource(const Expr *E,
2225ffd83dbSDimitry Andric                                                      const Expr *Child) {
2235ffd83dbSDimitry Andric 
2245ffd83dbSDimitry Andric     auto ShouldSkip = [](const Expr *E, const Expr *Child) {
2255ffd83dbSDimitry Andric       if (isa<ImplicitCastExpr>(E))
2265ffd83dbSDimitry Andric         return true;
2275ffd83dbSDimitry Andric 
2285ffd83dbSDimitry Andric       if (isa<FullExpr>(E))
2295ffd83dbSDimitry Andric         return true;
2305ffd83dbSDimitry Andric 
2315ffd83dbSDimitry Andric       if (isa<MaterializeTemporaryExpr>(E))
2325ffd83dbSDimitry Andric         return true;
2335ffd83dbSDimitry Andric 
2345ffd83dbSDimitry Andric       if (isa<CXXBindTemporaryExpr>(E))
2355ffd83dbSDimitry Andric         return true;
2365ffd83dbSDimitry Andric 
2375ffd83dbSDimitry Andric       if (isa<ParenExpr>(E))
2385ffd83dbSDimitry Andric         return true;
2395ffd83dbSDimitry Andric 
2405ffd83dbSDimitry Andric       if (isa<ExprWithCleanups>(E))
2415ffd83dbSDimitry Andric         return true;
2425ffd83dbSDimitry Andric 
2435ffd83dbSDimitry Andric       auto SR = Child->getSourceRange();
2445ffd83dbSDimitry Andric 
245e8d8bef9SDimitry Andric       if (const auto *C = dyn_cast<CXXFunctionalCastExpr>(E)) {
246e8d8bef9SDimitry Andric         if (C->getSourceRange() == SR)
247e8d8bef9SDimitry Andric           return true;
248e8d8bef9SDimitry Andric       }
249e8d8bef9SDimitry Andric 
2505ffd83dbSDimitry Andric       if (const auto *C = dyn_cast<CXXConstructExpr>(E)) {
251e8d8bef9SDimitry Andric         if (C->getSourceRange() == SR || C->isElidable())
2525ffd83dbSDimitry Andric           return true;
2535ffd83dbSDimitry Andric       }
2545ffd83dbSDimitry Andric 
2555ffd83dbSDimitry Andric       if (const auto *C = dyn_cast<CXXMemberCallExpr>(E)) {
2565ffd83dbSDimitry Andric         if (C->getSourceRange() == SR)
2575ffd83dbSDimitry Andric           return true;
2585ffd83dbSDimitry Andric       }
2595ffd83dbSDimitry Andric 
2605ffd83dbSDimitry Andric       if (const auto *C = dyn_cast<MemberExpr>(E)) {
2615ffd83dbSDimitry Andric         if (C->getSourceRange() == SR)
2625ffd83dbSDimitry Andric           return true;
2635ffd83dbSDimitry Andric       }
2645ffd83dbSDimitry Andric       return false;
2655ffd83dbSDimitry Andric     };
2665ffd83dbSDimitry Andric 
2675ffd83dbSDimitry Andric     while (ShouldSkip(E, Child)) {
2685ffd83dbSDimitry Andric       auto It = PointerParents.find(E);
2695ffd83dbSDimitry Andric       if (It == PointerParents.end())
2705ffd83dbSDimitry Andric         break;
2715ffd83dbSDimitry Andric       const auto *S = It->second.dyn_cast<const Stmt *>();
2725ffd83dbSDimitry Andric       if (!S) {
2735ffd83dbSDimitry Andric         if (auto *Vec = It->second.dyn_cast<ParentVector *>())
274*0fca6ea1SDimitry Andric           return Vec->view();
2755ffd83dbSDimitry Andric         return getSingleDynTypedNodeFromParentMap(It->second);
2765ffd83dbSDimitry Andric       }
2775ffd83dbSDimitry Andric       const auto *P = dyn_cast<Expr>(S);
2785ffd83dbSDimitry Andric       if (!P)
2795ffd83dbSDimitry Andric         return DynTypedNode::create(*S);
2805ffd83dbSDimitry Andric       Child = E;
2815ffd83dbSDimitry Andric       E = P;
2825ffd83dbSDimitry Andric     }
2835ffd83dbSDimitry Andric     return DynTypedNode::create(*E);
2845ffd83dbSDimitry Andric   }
2855ffd83dbSDimitry Andric };
2865ffd83dbSDimitry Andric 
287fe6060f1SDimitry Andric template <typename T, typename... U> struct MatchParents {
288fe6060f1SDimitry Andric   static std::tuple<bool, DynTypedNodeList, const T *, const U *...>
289fe6060f1SDimitry Andric   match(const DynTypedNodeList &NodeList,
290fe6060f1SDimitry Andric         ParentMapContext::ParentMap *ParentMap) {
291fe6060f1SDimitry Andric     if (const auto *TypedNode = NodeList[0].get<T>()) {
292fe6060f1SDimitry Andric       auto NextParentList =
293fe6060f1SDimitry Andric           ParentMap->getDynNodeFromMap(TypedNode, ParentMap->PointerParents);
294fe6060f1SDimitry Andric       if (NextParentList.size() == 1) {
295fe6060f1SDimitry Andric         auto TailTuple = MatchParents<U...>::match(NextParentList, ParentMap);
296fe6060f1SDimitry Andric         if (std::get<bool>(TailTuple)) {
297bdd1243dSDimitry Andric           return std::apply(
298bdd1243dSDimitry Andric               [TypedNode](bool, DynTypedNodeList NodeList, auto... TupleTail) {
299bdd1243dSDimitry Andric                 return std::make_tuple(true, NodeList, TypedNode, TupleTail...);
300bdd1243dSDimitry Andric               },
301bdd1243dSDimitry Andric               TailTuple);
302fe6060f1SDimitry Andric         }
303fe6060f1SDimitry Andric       }
304fe6060f1SDimitry Andric     }
305fe6060f1SDimitry Andric     return std::tuple_cat(std::make_tuple(false, NodeList),
306fe6060f1SDimitry Andric                           std::tuple<const T *, const U *...>());
307fe6060f1SDimitry Andric   }
308fe6060f1SDimitry Andric };
309fe6060f1SDimitry Andric 
310fe6060f1SDimitry Andric template <typename T> struct MatchParents<T> {
311fe6060f1SDimitry Andric   static std::tuple<bool, DynTypedNodeList, const T *>
312fe6060f1SDimitry Andric   match(const DynTypedNodeList &NodeList,
313fe6060f1SDimitry Andric         ParentMapContext::ParentMap *ParentMap) {
314fe6060f1SDimitry Andric     if (const auto *TypedNode = NodeList[0].get<T>()) {
315fe6060f1SDimitry Andric       auto NextParentList =
316fe6060f1SDimitry Andric           ParentMap->getDynNodeFromMap(TypedNode, ParentMap->PointerParents);
317fe6060f1SDimitry Andric       if (NextParentList.size() == 1)
318fe6060f1SDimitry Andric         return std::make_tuple(true, NodeList, TypedNode);
319fe6060f1SDimitry Andric     }
320fe6060f1SDimitry Andric     return std::make_tuple(false, NodeList, nullptr);
321fe6060f1SDimitry Andric   }
322fe6060f1SDimitry Andric };
323fe6060f1SDimitry Andric 
324fe6060f1SDimitry Andric template <typename T, typename... U>
325fe6060f1SDimitry Andric std::tuple<bool, DynTypedNodeList, const T *, const U *...>
326fe6060f1SDimitry Andric matchParents(const DynTypedNodeList &NodeList,
327fe6060f1SDimitry Andric              ParentMapContext::ParentMap *ParentMap) {
328fe6060f1SDimitry Andric   return MatchParents<T, U...>::match(NodeList, ParentMap);
329fe6060f1SDimitry Andric }
330fe6060f1SDimitry Andric 
3315ffd83dbSDimitry Andric /// Template specializations to abstract away from pointers and TypeLocs.
3325ffd83dbSDimitry Andric /// @{
3335ffd83dbSDimitry Andric template <typename T> static DynTypedNode createDynTypedNode(const T &Node) {
3345ffd83dbSDimitry Andric   return DynTypedNode::create(*Node);
3355ffd83dbSDimitry Andric }
3365ffd83dbSDimitry Andric template <> DynTypedNode createDynTypedNode(const TypeLoc &Node) {
3375ffd83dbSDimitry Andric   return DynTypedNode::create(Node);
3385ffd83dbSDimitry Andric }
3395ffd83dbSDimitry Andric template <>
3405ffd83dbSDimitry Andric DynTypedNode createDynTypedNode(const NestedNameSpecifierLoc &Node) {
3415ffd83dbSDimitry Andric   return DynTypedNode::create(Node);
3425ffd83dbSDimitry Andric }
34381ad6265SDimitry Andric template <> DynTypedNode createDynTypedNode(const ObjCProtocolLoc &Node) {
34481ad6265SDimitry Andric   return DynTypedNode::create(Node);
34581ad6265SDimitry Andric }
3465ffd83dbSDimitry Andric /// @}
3475ffd83dbSDimitry Andric 
3485ffd83dbSDimitry Andric /// A \c RecursiveASTVisitor that builds a map from nodes to their
3495ffd83dbSDimitry Andric /// parents as defined by the \c RecursiveASTVisitor.
3505ffd83dbSDimitry Andric ///
3515ffd83dbSDimitry Andric /// Note that the relationship described here is purely in terms of AST
3525ffd83dbSDimitry Andric /// traversal - there are other relationships (for example declaration context)
3535ffd83dbSDimitry Andric /// in the AST that are better modeled by special matchers.
3545ffd83dbSDimitry Andric class ParentMapContext::ParentMap::ASTVisitor
3555ffd83dbSDimitry Andric     : public RecursiveASTVisitor<ASTVisitor> {
3565ffd83dbSDimitry Andric public:
3575ffd83dbSDimitry Andric   ASTVisitor(ParentMap &Map) : Map(Map) {}
3585ffd83dbSDimitry Andric 
3595ffd83dbSDimitry Andric private:
3605ffd83dbSDimitry Andric   friend class RecursiveASTVisitor<ASTVisitor>;
3615ffd83dbSDimitry Andric 
3625ffd83dbSDimitry Andric   using VisitorBase = RecursiveASTVisitor<ASTVisitor>;
3635ffd83dbSDimitry Andric 
3645ffd83dbSDimitry Andric   bool shouldVisitTemplateInstantiations() const { return true; }
3655ffd83dbSDimitry Andric 
3665ffd83dbSDimitry Andric   bool shouldVisitImplicitCode() const { return true; }
3675ffd83dbSDimitry Andric 
368e8d8bef9SDimitry Andric   /// Record the parent of the node we're visiting.
369e8d8bef9SDimitry Andric   /// MapNode is the child, the parent is on top of ParentStack.
370e8d8bef9SDimitry Andric   /// Parents is the parent storage (either PointerParents or OtherParents).
371e8d8bef9SDimitry Andric   template <typename MapNodeTy, typename MapTy>
372e8d8bef9SDimitry Andric   void addParent(MapNodeTy MapNode, MapTy *Parents) {
373e8d8bef9SDimitry Andric     if (ParentStack.empty())
374e8d8bef9SDimitry Andric       return;
375e8d8bef9SDimitry Andric 
3765ffd83dbSDimitry Andric     // FIXME: Currently we add the same parent multiple times, but only
3775ffd83dbSDimitry Andric     // when no memoization data is available for the type.
3785ffd83dbSDimitry Andric     // For example when we visit all subexpressions of template
3795ffd83dbSDimitry Andric     // instantiations; this is suboptimal, but benign: the only way to
3805ffd83dbSDimitry Andric     // visit those is with hasAncestor / hasParent, and those do not create
3815ffd83dbSDimitry Andric     // new matches.
3825ffd83dbSDimitry Andric     // The plan is to enable DynTypedNode to be storable in a map or hash
3835ffd83dbSDimitry Andric     // map. The main problem there is to implement hash functions /
3845ffd83dbSDimitry Andric     // comparison operators for all types that DynTypedNode supports that
3855ffd83dbSDimitry Andric     // do not have pointer identity.
3865ffd83dbSDimitry Andric     auto &NodeOrVector = (*Parents)[MapNode];
3875ffd83dbSDimitry Andric     if (NodeOrVector.isNull()) {
3885ffd83dbSDimitry Andric       if (const auto *D = ParentStack.back().get<Decl>())
3895ffd83dbSDimitry Andric         NodeOrVector = D;
3905ffd83dbSDimitry Andric       else if (const auto *S = ParentStack.back().get<Stmt>())
3915ffd83dbSDimitry Andric         NodeOrVector = S;
3925ffd83dbSDimitry Andric       else
3935ffd83dbSDimitry Andric         NodeOrVector = new DynTypedNode(ParentStack.back());
3945ffd83dbSDimitry Andric     } else {
3955ffd83dbSDimitry Andric       if (!NodeOrVector.template is<ParentVector *>()) {
3965ffd83dbSDimitry Andric         auto *Vector = new ParentVector(
3975ffd83dbSDimitry Andric             1, getSingleDynTypedNodeFromParentMap(NodeOrVector));
3985ffd83dbSDimitry Andric         delete NodeOrVector.template dyn_cast<DynTypedNode *>();
3995ffd83dbSDimitry Andric         NodeOrVector = Vector;
4005ffd83dbSDimitry Andric       }
4015ffd83dbSDimitry Andric 
4025ffd83dbSDimitry Andric       auto *Vector = NodeOrVector.template get<ParentVector *>();
4035ffd83dbSDimitry Andric       // Skip duplicates for types that have memoization data.
4045ffd83dbSDimitry Andric       // We must check that the type has memoization data before calling
405349cc55cSDimitry Andric       // llvm::is_contained() because DynTypedNode::operator== can't compare all
4065ffd83dbSDimitry Andric       // types.
4075ffd83dbSDimitry Andric       bool Found = ParentStack.back().getMemoizationData() &&
408349cc55cSDimitry Andric                    llvm::is_contained(*Vector, ParentStack.back());
4095ffd83dbSDimitry Andric       if (!Found)
4105ffd83dbSDimitry Andric         Vector->push_back(ParentStack.back());
4115ffd83dbSDimitry Andric     }
4125ffd83dbSDimitry Andric   }
413e8d8bef9SDimitry Andric 
41481ad6265SDimitry Andric   template <typename T> static bool isNull(T Node) { return !Node; }
41581ad6265SDimitry Andric   static bool isNull(ObjCProtocolLoc Node) { return false; }
41681ad6265SDimitry Andric 
417e8d8bef9SDimitry Andric   template <typename T, typename MapNodeTy, typename BaseTraverseFn,
418e8d8bef9SDimitry Andric             typename MapTy>
419e8d8bef9SDimitry Andric   bool TraverseNode(T Node, MapNodeTy MapNode, BaseTraverseFn BaseTraverse,
420e8d8bef9SDimitry Andric                     MapTy *Parents) {
42181ad6265SDimitry Andric     if (isNull(Node))
422e8d8bef9SDimitry Andric       return true;
423e8d8bef9SDimitry Andric     addParent(MapNode, Parents);
4245ffd83dbSDimitry Andric     ParentStack.push_back(createDynTypedNode(Node));
4255ffd83dbSDimitry Andric     bool Result = BaseTraverse();
4265ffd83dbSDimitry Andric     ParentStack.pop_back();
4275ffd83dbSDimitry Andric     return Result;
4285ffd83dbSDimitry Andric   }
4295ffd83dbSDimitry Andric 
4305ffd83dbSDimitry Andric   bool TraverseDecl(Decl *DeclNode) {
4315ffd83dbSDimitry Andric     return TraverseNode(
4325ffd83dbSDimitry Andric         DeclNode, DeclNode, [&] { return VisitorBase::TraverseDecl(DeclNode); },
4335ffd83dbSDimitry Andric         &Map.PointerParents);
4345ffd83dbSDimitry Andric   }
4355ffd83dbSDimitry Andric   bool TraverseTypeLoc(TypeLoc TypeLocNode) {
4365ffd83dbSDimitry Andric     return TraverseNode(
4375ffd83dbSDimitry Andric         TypeLocNode, DynTypedNode::create(TypeLocNode),
4385ffd83dbSDimitry Andric         [&] { return VisitorBase::TraverseTypeLoc(TypeLocNode); },
4395ffd83dbSDimitry Andric         &Map.OtherParents);
4405ffd83dbSDimitry Andric   }
4415ffd83dbSDimitry Andric   bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode) {
4425ffd83dbSDimitry Andric     return TraverseNode(
4435ffd83dbSDimitry Andric         NNSLocNode, DynTypedNode::create(NNSLocNode),
4445ffd83dbSDimitry Andric         [&] { return VisitorBase::TraverseNestedNameSpecifierLoc(NNSLocNode); },
4455ffd83dbSDimitry Andric         &Map.OtherParents);
4465ffd83dbSDimitry Andric   }
447349cc55cSDimitry Andric   bool TraverseAttr(Attr *AttrNode) {
448349cc55cSDimitry Andric     return TraverseNode(
449349cc55cSDimitry Andric         AttrNode, AttrNode, [&] { return VisitorBase::TraverseAttr(AttrNode); },
450349cc55cSDimitry Andric         &Map.PointerParents);
451349cc55cSDimitry Andric   }
45281ad6265SDimitry Andric   bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLocNode) {
45381ad6265SDimitry Andric     return TraverseNode(
45481ad6265SDimitry Andric         ProtocolLocNode, DynTypedNode::create(ProtocolLocNode),
45581ad6265SDimitry Andric         [&] { return VisitorBase::TraverseObjCProtocolLoc(ProtocolLocNode); },
45681ad6265SDimitry Andric         &Map.OtherParents);
45781ad6265SDimitry Andric   }
4585ffd83dbSDimitry Andric 
459e8d8bef9SDimitry Andric   // Using generic TraverseNode for Stmt would prevent data-recursion.
460e8d8bef9SDimitry Andric   bool dataTraverseStmtPre(Stmt *StmtNode) {
461e8d8bef9SDimitry Andric     addParent(StmtNode, &Map.PointerParents);
462e8d8bef9SDimitry Andric     ParentStack.push_back(DynTypedNode::create(*StmtNode));
463e8d8bef9SDimitry Andric     return true;
464e8d8bef9SDimitry Andric   }
465e8d8bef9SDimitry Andric   bool dataTraverseStmtPost(Stmt *StmtNode) {
466e8d8bef9SDimitry Andric     ParentStack.pop_back();
467e8d8bef9SDimitry Andric     return true;
468e8d8bef9SDimitry Andric   }
469e8d8bef9SDimitry Andric 
4705ffd83dbSDimitry Andric   ParentMap &Map;
4715ffd83dbSDimitry Andric   llvm::SmallVector<DynTypedNode, 16> ParentStack;
4725ffd83dbSDimitry Andric };
4735ffd83dbSDimitry Andric 
4745ffd83dbSDimitry Andric ParentMapContext::ParentMap::ParentMap(ASTContext &Ctx) {
4755ffd83dbSDimitry Andric   ASTVisitor(*this).TraverseAST(Ctx);
4765ffd83dbSDimitry Andric }
4775ffd83dbSDimitry Andric 
4785ffd83dbSDimitry Andric DynTypedNodeList ParentMapContext::getParents(const DynTypedNode &Node) {
4795ffd83dbSDimitry Andric   if (!Parents)
4805ffd83dbSDimitry Andric     // We build the parent map for the traversal scope (usually whole TU), as
4815ffd83dbSDimitry Andric     // hasAncestor can escape any subtree.
4825ffd83dbSDimitry Andric     Parents = std::make_unique<ParentMap>(ASTCtx);
4835ffd83dbSDimitry Andric   return Parents->getParents(getTraversalKind(), Node);
4845ffd83dbSDimitry Andric }
485