xref: /openbsd-src/gnu/llvm/clang/lib/AST/ParentMapContext.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1ec727ea7Spatrick //===- ParentMapContext.cpp - Map of parents using DynTypedNode -*- C++ -*-===//
2ec727ea7Spatrick //
3ec727ea7Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ec727ea7Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ec727ea7Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ec727ea7Spatrick //
7ec727ea7Spatrick //===----------------------------------------------------------------------===//
8ec727ea7Spatrick //
9ec727ea7Spatrick // Similar to ParentMap.cpp, but generalizes to non-Stmt nodes, which can have
10ec727ea7Spatrick // multiple parents.
11ec727ea7Spatrick //
12ec727ea7Spatrick //===----------------------------------------------------------------------===//
13ec727ea7Spatrick 
14ec727ea7Spatrick #include "clang/AST/ParentMapContext.h"
15ec727ea7Spatrick #include "clang/AST/RecursiveASTVisitor.h"
16ec727ea7Spatrick #include "clang/AST/Decl.h"
17ec727ea7Spatrick #include "clang/AST/Expr.h"
18ec727ea7Spatrick #include "clang/AST/TemplateBase.h"
19ec727ea7Spatrick 
20ec727ea7Spatrick using namespace clang;
21ec727ea7Spatrick 
ParentMapContext(ASTContext & Ctx)22ec727ea7Spatrick ParentMapContext::ParentMapContext(ASTContext &Ctx) : ASTCtx(Ctx) {}
23ec727ea7Spatrick 
24ec727ea7Spatrick ParentMapContext::~ParentMapContext() = default;
25ec727ea7Spatrick 
clear()26ec727ea7Spatrick void ParentMapContext::clear() { Parents.reset(); }
27ec727ea7Spatrick 
traverseIgnored(const Expr * E) const28ec727ea7Spatrick const Expr *ParentMapContext::traverseIgnored(const Expr *E) const {
29ec727ea7Spatrick   return traverseIgnored(const_cast<Expr *>(E));
30ec727ea7Spatrick }
31ec727ea7Spatrick 
traverseIgnored(Expr * E) const32ec727ea7Spatrick Expr *ParentMapContext::traverseIgnored(Expr *E) const {
33ec727ea7Spatrick   if (!E)
34ec727ea7Spatrick     return nullptr;
35ec727ea7Spatrick 
36ec727ea7Spatrick   switch (Traversal) {
37ec727ea7Spatrick   case TK_AsIs:
38ec727ea7Spatrick     return E;
39ec727ea7Spatrick   case TK_IgnoreUnlessSpelledInSource:
40ec727ea7Spatrick     return E->IgnoreUnlessSpelledInSource();
41ec727ea7Spatrick   }
42ec727ea7Spatrick   llvm_unreachable("Invalid Traversal type!");
43ec727ea7Spatrick }
44ec727ea7Spatrick 
traverseIgnored(const DynTypedNode & N) const45ec727ea7Spatrick DynTypedNode ParentMapContext::traverseIgnored(const DynTypedNode &N) const {
46ec727ea7Spatrick   if (const auto *E = N.get<Expr>()) {
47ec727ea7Spatrick     return DynTypedNode::create(*traverseIgnored(E));
48ec727ea7Spatrick   }
49ec727ea7Spatrick   return N;
50ec727ea7Spatrick }
51ec727ea7Spatrick 
52a9ac8606Spatrick template <typename T, typename... U>
53a9ac8606Spatrick std::tuple<bool, DynTypedNodeList, const T *, const U *...>
54a9ac8606Spatrick matchParents(const DynTypedNodeList &NodeList,
55a9ac8606Spatrick              ParentMapContext::ParentMap *ParentMap);
56a9ac8606Spatrick 
57a9ac8606Spatrick template <typename, typename...> struct MatchParents;
58a9ac8606Spatrick 
59ec727ea7Spatrick class ParentMapContext::ParentMap {
60a9ac8606Spatrick 
61a9ac8606Spatrick   template <typename, typename...> friend struct ::MatchParents;
62a9ac8606Spatrick 
63ec727ea7Spatrick   /// Contains parents of a node.
64ec727ea7Spatrick   using ParentVector = llvm::SmallVector<DynTypedNode, 2>;
65ec727ea7Spatrick 
66ec727ea7Spatrick   /// Maps from a node to its parents. This is used for nodes that have
67ec727ea7Spatrick   /// pointer identity only, which are more common and we can save space by
68ec727ea7Spatrick   /// only storing a unique pointer to them.
69ec727ea7Spatrick   using ParentMapPointers =
70ec727ea7Spatrick       llvm::DenseMap<const void *,
71ec727ea7Spatrick                      llvm::PointerUnion<const Decl *, const Stmt *,
72ec727ea7Spatrick                                         DynTypedNode *, ParentVector *>>;
73ec727ea7Spatrick 
74ec727ea7Spatrick   /// Parent map for nodes without pointer identity. We store a full
75ec727ea7Spatrick   /// DynTypedNode for all keys.
76ec727ea7Spatrick   using ParentMapOtherNodes =
77ec727ea7Spatrick       llvm::DenseMap<DynTypedNode,
78ec727ea7Spatrick                      llvm::PointerUnion<const Decl *, const Stmt *,
79ec727ea7Spatrick                                         DynTypedNode *, ParentVector *>>;
80ec727ea7Spatrick 
81ec727ea7Spatrick   ParentMapPointers PointerParents;
82ec727ea7Spatrick   ParentMapOtherNodes OtherParents;
83ec727ea7Spatrick   class ASTVisitor;
84ec727ea7Spatrick 
85ec727ea7Spatrick   static DynTypedNode
getSingleDynTypedNodeFromParentMap(ParentMapPointers::mapped_type U)86ec727ea7Spatrick   getSingleDynTypedNodeFromParentMap(ParentMapPointers::mapped_type U) {
87ec727ea7Spatrick     if (const auto *D = U.dyn_cast<const Decl *>())
88ec727ea7Spatrick       return DynTypedNode::create(*D);
89ec727ea7Spatrick     if (const auto *S = U.dyn_cast<const Stmt *>())
90ec727ea7Spatrick       return DynTypedNode::create(*S);
91ec727ea7Spatrick     return *U.get<DynTypedNode *>();
92ec727ea7Spatrick   }
93ec727ea7Spatrick 
94ec727ea7Spatrick   template <typename NodeTy, typename MapTy>
getDynNodeFromMap(const NodeTy & Node,const MapTy & Map)95ec727ea7Spatrick   static DynTypedNodeList getDynNodeFromMap(const NodeTy &Node,
96ec727ea7Spatrick                                                         const MapTy &Map) {
97ec727ea7Spatrick     auto I = Map.find(Node);
98ec727ea7Spatrick     if (I == Map.end()) {
99ec727ea7Spatrick       return llvm::ArrayRef<DynTypedNode>();
100ec727ea7Spatrick     }
101ec727ea7Spatrick     if (const auto *V = I->second.template dyn_cast<ParentVector *>()) {
102*12c85518Srobert       return llvm::ArrayRef(*V);
103ec727ea7Spatrick     }
104ec727ea7Spatrick     return getSingleDynTypedNodeFromParentMap(I->second);
105ec727ea7Spatrick   }
106ec727ea7Spatrick 
107ec727ea7Spatrick public:
108ec727ea7Spatrick   ParentMap(ASTContext &Ctx);
~ParentMap()109ec727ea7Spatrick   ~ParentMap() {
110ec727ea7Spatrick     for (const auto &Entry : PointerParents) {
111ec727ea7Spatrick       if (Entry.second.is<DynTypedNode *>()) {
112ec727ea7Spatrick         delete Entry.second.get<DynTypedNode *>();
113ec727ea7Spatrick       } else if (Entry.second.is<ParentVector *>()) {
114ec727ea7Spatrick         delete Entry.second.get<ParentVector *>();
115ec727ea7Spatrick       }
116ec727ea7Spatrick     }
117ec727ea7Spatrick     for (const auto &Entry : OtherParents) {
118ec727ea7Spatrick       if (Entry.second.is<DynTypedNode *>()) {
119ec727ea7Spatrick         delete Entry.second.get<DynTypedNode *>();
120ec727ea7Spatrick       } else if (Entry.second.is<ParentVector *>()) {
121ec727ea7Spatrick         delete Entry.second.get<ParentVector *>();
122ec727ea7Spatrick       }
123ec727ea7Spatrick     }
124ec727ea7Spatrick   }
125ec727ea7Spatrick 
getParents(TraversalKind TK,const DynTypedNode & Node)126ec727ea7Spatrick   DynTypedNodeList getParents(TraversalKind TK, const DynTypedNode &Node) {
127ec727ea7Spatrick     if (Node.getNodeKind().hasPointerIdentity()) {
128ec727ea7Spatrick       auto ParentList =
129ec727ea7Spatrick           getDynNodeFromMap(Node.getMemoizationData(), PointerParents);
130a9ac8606Spatrick       if (ParentList.size() > 0 && TK == TK_IgnoreUnlessSpelledInSource) {
131a9ac8606Spatrick 
132a9ac8606Spatrick         const auto *ChildExpr = Node.get<Expr>();
133a9ac8606Spatrick 
134a9ac8606Spatrick         {
135a9ac8606Spatrick           // Don't match explicit node types because different stdlib
136a9ac8606Spatrick           // implementations implement this in different ways and have
137a9ac8606Spatrick           // different intermediate nodes.
138a9ac8606Spatrick           // Look up 4 levels for a cxxRewrittenBinaryOperator as that is
139a9ac8606Spatrick           // enough for the major stdlib implementations.
140a9ac8606Spatrick           auto RewrittenBinOpParentsList = ParentList;
141a9ac8606Spatrick           int I = 0;
142a9ac8606Spatrick           while (ChildExpr && RewrittenBinOpParentsList.size() == 1 &&
143a9ac8606Spatrick                  I++ < 4) {
144a9ac8606Spatrick             const auto *S = RewrittenBinOpParentsList[0].get<Stmt>();
145a9ac8606Spatrick             if (!S)
146a9ac8606Spatrick               break;
147a9ac8606Spatrick 
148a9ac8606Spatrick             const auto *RWBO = dyn_cast<CXXRewrittenBinaryOperator>(S);
149a9ac8606Spatrick             if (!RWBO) {
150a9ac8606Spatrick               RewrittenBinOpParentsList = getDynNodeFromMap(S, PointerParents);
151a9ac8606Spatrick               continue;
152a9ac8606Spatrick             }
153a9ac8606Spatrick             if (RWBO->getLHS()->IgnoreUnlessSpelledInSource() != ChildExpr &&
154a9ac8606Spatrick                 RWBO->getRHS()->IgnoreUnlessSpelledInSource() != ChildExpr)
155a9ac8606Spatrick               break;
156a9ac8606Spatrick             return DynTypedNode::create(*RWBO);
157a9ac8606Spatrick           }
158a9ac8606Spatrick         }
159a9ac8606Spatrick 
160a9ac8606Spatrick         const auto *ParentExpr = ParentList[0].get<Expr>();
161a9ac8606Spatrick         if (ParentExpr && ChildExpr)
162a9ac8606Spatrick           return AscendIgnoreUnlessSpelledInSource(ParentExpr, ChildExpr);
163a9ac8606Spatrick 
164a9ac8606Spatrick         {
165a9ac8606Spatrick           auto AncestorNodes =
166a9ac8606Spatrick               matchParents<DeclStmt, CXXForRangeStmt>(ParentList, this);
167a9ac8606Spatrick           if (std::get<bool>(AncestorNodes) &&
168a9ac8606Spatrick               std::get<const CXXForRangeStmt *>(AncestorNodes)
169a9ac8606Spatrick                       ->getLoopVarStmt() ==
170a9ac8606Spatrick                   std::get<const DeclStmt *>(AncestorNodes))
171a9ac8606Spatrick             return std::get<DynTypedNodeList>(AncestorNodes);
172a9ac8606Spatrick         }
173a9ac8606Spatrick         {
174a9ac8606Spatrick           auto AncestorNodes = matchParents<VarDecl, DeclStmt, CXXForRangeStmt>(
175a9ac8606Spatrick               ParentList, this);
176a9ac8606Spatrick           if (std::get<bool>(AncestorNodes) &&
177a9ac8606Spatrick               std::get<const CXXForRangeStmt *>(AncestorNodes)
178a9ac8606Spatrick                       ->getRangeStmt() ==
179a9ac8606Spatrick                   std::get<const DeclStmt *>(AncestorNodes))
180a9ac8606Spatrick             return std::get<DynTypedNodeList>(AncestorNodes);
181a9ac8606Spatrick         }
182a9ac8606Spatrick         {
183a9ac8606Spatrick           auto AncestorNodes =
184a9ac8606Spatrick               matchParents<CXXMethodDecl, CXXRecordDecl, LambdaExpr>(ParentList,
185a9ac8606Spatrick                                                                      this);
186a9ac8606Spatrick           if (std::get<bool>(AncestorNodes))
187a9ac8606Spatrick             return std::get<DynTypedNodeList>(AncestorNodes);
188a9ac8606Spatrick         }
189a9ac8606Spatrick         {
190a9ac8606Spatrick           auto AncestorNodes =
191a9ac8606Spatrick               matchParents<FunctionTemplateDecl, CXXRecordDecl, LambdaExpr>(
192a9ac8606Spatrick                   ParentList, this);
193a9ac8606Spatrick           if (std::get<bool>(AncestorNodes))
194a9ac8606Spatrick             return std::get<DynTypedNodeList>(AncestorNodes);
195a9ac8606Spatrick         }
196ec727ea7Spatrick       }
197ec727ea7Spatrick       return ParentList;
198ec727ea7Spatrick     }
199ec727ea7Spatrick     return getDynNodeFromMap(Node, OtherParents);
200ec727ea7Spatrick   }
201ec727ea7Spatrick 
AscendIgnoreUnlessSpelledInSource(const Expr * E,const Expr * Child)202ec727ea7Spatrick   DynTypedNodeList AscendIgnoreUnlessSpelledInSource(const Expr *E,
203ec727ea7Spatrick                                                      const Expr *Child) {
204ec727ea7Spatrick 
205ec727ea7Spatrick     auto ShouldSkip = [](const Expr *E, const Expr *Child) {
206ec727ea7Spatrick       if (isa<ImplicitCastExpr>(E))
207ec727ea7Spatrick         return true;
208ec727ea7Spatrick 
209ec727ea7Spatrick       if (isa<FullExpr>(E))
210ec727ea7Spatrick         return true;
211ec727ea7Spatrick 
212ec727ea7Spatrick       if (isa<MaterializeTemporaryExpr>(E))
213ec727ea7Spatrick         return true;
214ec727ea7Spatrick 
215ec727ea7Spatrick       if (isa<CXXBindTemporaryExpr>(E))
216ec727ea7Spatrick         return true;
217ec727ea7Spatrick 
218ec727ea7Spatrick       if (isa<ParenExpr>(E))
219ec727ea7Spatrick         return true;
220ec727ea7Spatrick 
221ec727ea7Spatrick       if (isa<ExprWithCleanups>(E))
222ec727ea7Spatrick         return true;
223ec727ea7Spatrick 
224ec727ea7Spatrick       auto SR = Child->getSourceRange();
225ec727ea7Spatrick 
226a9ac8606Spatrick       if (const auto *C = dyn_cast<CXXFunctionalCastExpr>(E)) {
227a9ac8606Spatrick         if (C->getSourceRange() == SR)
228a9ac8606Spatrick           return true;
229a9ac8606Spatrick       }
230a9ac8606Spatrick 
231ec727ea7Spatrick       if (const auto *C = dyn_cast<CXXConstructExpr>(E)) {
232a9ac8606Spatrick         if (C->getSourceRange() == SR || C->isElidable())
233ec727ea7Spatrick           return true;
234ec727ea7Spatrick       }
235ec727ea7Spatrick 
236ec727ea7Spatrick       if (const auto *C = dyn_cast<CXXMemberCallExpr>(E)) {
237ec727ea7Spatrick         if (C->getSourceRange() == SR)
238ec727ea7Spatrick           return true;
239ec727ea7Spatrick       }
240ec727ea7Spatrick 
241ec727ea7Spatrick       if (const auto *C = dyn_cast<MemberExpr>(E)) {
242ec727ea7Spatrick         if (C->getSourceRange() == SR)
243ec727ea7Spatrick           return true;
244ec727ea7Spatrick       }
245ec727ea7Spatrick       return false;
246ec727ea7Spatrick     };
247ec727ea7Spatrick 
248ec727ea7Spatrick     while (ShouldSkip(E, Child)) {
249ec727ea7Spatrick       auto It = PointerParents.find(E);
250ec727ea7Spatrick       if (It == PointerParents.end())
251ec727ea7Spatrick         break;
252ec727ea7Spatrick       const auto *S = It->second.dyn_cast<const Stmt *>();
253ec727ea7Spatrick       if (!S) {
254ec727ea7Spatrick         if (auto *Vec = It->second.dyn_cast<ParentVector *>())
255*12c85518Srobert           return llvm::ArrayRef(*Vec);
256ec727ea7Spatrick         return getSingleDynTypedNodeFromParentMap(It->second);
257ec727ea7Spatrick       }
258ec727ea7Spatrick       const auto *P = dyn_cast<Expr>(S);
259ec727ea7Spatrick       if (!P)
260ec727ea7Spatrick         return DynTypedNode::create(*S);
261ec727ea7Spatrick       Child = E;
262ec727ea7Spatrick       E = P;
263ec727ea7Spatrick     }
264ec727ea7Spatrick     return DynTypedNode::create(*E);
265ec727ea7Spatrick   }
266ec727ea7Spatrick };
267ec727ea7Spatrick 
268a9ac8606Spatrick template <typename T, typename... U> struct MatchParents {
269a9ac8606Spatrick   static std::tuple<bool, DynTypedNodeList, const T *, const U *...>
matchMatchParents270a9ac8606Spatrick   match(const DynTypedNodeList &NodeList,
271a9ac8606Spatrick         ParentMapContext::ParentMap *ParentMap) {
272a9ac8606Spatrick     if (const auto *TypedNode = NodeList[0].get<T>()) {
273a9ac8606Spatrick       auto NextParentList =
274a9ac8606Spatrick           ParentMap->getDynNodeFromMap(TypedNode, ParentMap->PointerParents);
275a9ac8606Spatrick       if (NextParentList.size() == 1) {
276a9ac8606Spatrick         auto TailTuple = MatchParents<U...>::match(NextParentList, ParentMap);
277a9ac8606Spatrick         if (std::get<bool>(TailTuple)) {
278*12c85518Srobert           return std::apply(
279*12c85518Srobert               [TypedNode](bool, DynTypedNodeList NodeList, auto... TupleTail) {
280*12c85518Srobert                 return std::make_tuple(true, NodeList, TypedNode, TupleTail...);
281*12c85518Srobert               },
282*12c85518Srobert               TailTuple);
283a9ac8606Spatrick         }
284a9ac8606Spatrick       }
285a9ac8606Spatrick     }
286a9ac8606Spatrick     return std::tuple_cat(std::make_tuple(false, NodeList),
287a9ac8606Spatrick                           std::tuple<const T *, const U *...>());
288a9ac8606Spatrick   }
289a9ac8606Spatrick };
290a9ac8606Spatrick 
291a9ac8606Spatrick template <typename T> struct MatchParents<T> {
292a9ac8606Spatrick   static std::tuple<bool, DynTypedNodeList, const T *>
matchMatchParents293a9ac8606Spatrick   match(const DynTypedNodeList &NodeList,
294a9ac8606Spatrick         ParentMapContext::ParentMap *ParentMap) {
295a9ac8606Spatrick     if (const auto *TypedNode = NodeList[0].get<T>()) {
296a9ac8606Spatrick       auto NextParentList =
297a9ac8606Spatrick           ParentMap->getDynNodeFromMap(TypedNode, ParentMap->PointerParents);
298a9ac8606Spatrick       if (NextParentList.size() == 1)
299a9ac8606Spatrick         return std::make_tuple(true, NodeList, TypedNode);
300a9ac8606Spatrick     }
301a9ac8606Spatrick     return std::make_tuple(false, NodeList, nullptr);
302a9ac8606Spatrick   }
303a9ac8606Spatrick };
304a9ac8606Spatrick 
305a9ac8606Spatrick template <typename T, typename... U>
306a9ac8606Spatrick std::tuple<bool, DynTypedNodeList, const T *, const U *...>
matchParents(const DynTypedNodeList & NodeList,ParentMapContext::ParentMap * ParentMap)307a9ac8606Spatrick matchParents(const DynTypedNodeList &NodeList,
308a9ac8606Spatrick              ParentMapContext::ParentMap *ParentMap) {
309a9ac8606Spatrick   return MatchParents<T, U...>::match(NodeList, ParentMap);
310a9ac8606Spatrick }
311a9ac8606Spatrick 
312ec727ea7Spatrick /// Template specializations to abstract away from pointers and TypeLocs.
313ec727ea7Spatrick /// @{
createDynTypedNode(const T & Node)314ec727ea7Spatrick template <typename T> static DynTypedNode createDynTypedNode(const T &Node) {
315ec727ea7Spatrick   return DynTypedNode::create(*Node);
316ec727ea7Spatrick }
createDynTypedNode(const TypeLoc & Node)317ec727ea7Spatrick template <> DynTypedNode createDynTypedNode(const TypeLoc &Node) {
318ec727ea7Spatrick   return DynTypedNode::create(Node);
319ec727ea7Spatrick }
320ec727ea7Spatrick template <>
createDynTypedNode(const NestedNameSpecifierLoc & Node)321ec727ea7Spatrick DynTypedNode createDynTypedNode(const NestedNameSpecifierLoc &Node) {
322ec727ea7Spatrick   return DynTypedNode::create(Node);
323ec727ea7Spatrick }
createDynTypedNode(const ObjCProtocolLoc & Node)324*12c85518Srobert template <> DynTypedNode createDynTypedNode(const ObjCProtocolLoc &Node) {
325*12c85518Srobert   return DynTypedNode::create(Node);
326*12c85518Srobert }
327ec727ea7Spatrick /// @}
328ec727ea7Spatrick 
329ec727ea7Spatrick /// A \c RecursiveASTVisitor that builds a map from nodes to their
330ec727ea7Spatrick /// parents as defined by the \c RecursiveASTVisitor.
331ec727ea7Spatrick ///
332ec727ea7Spatrick /// Note that the relationship described here is purely in terms of AST
333ec727ea7Spatrick /// traversal - there are other relationships (for example declaration context)
334ec727ea7Spatrick /// in the AST that are better modeled by special matchers.
335ec727ea7Spatrick class ParentMapContext::ParentMap::ASTVisitor
336ec727ea7Spatrick     : public RecursiveASTVisitor<ASTVisitor> {
337ec727ea7Spatrick public:
ASTVisitor(ParentMap & Map)338ec727ea7Spatrick   ASTVisitor(ParentMap &Map) : Map(Map) {}
339ec727ea7Spatrick 
340ec727ea7Spatrick private:
341ec727ea7Spatrick   friend class RecursiveASTVisitor<ASTVisitor>;
342ec727ea7Spatrick 
343ec727ea7Spatrick   using VisitorBase = RecursiveASTVisitor<ASTVisitor>;
344ec727ea7Spatrick 
shouldVisitTemplateInstantiations() const345ec727ea7Spatrick   bool shouldVisitTemplateInstantiations() const { return true; }
346ec727ea7Spatrick 
shouldVisitImplicitCode() const347ec727ea7Spatrick   bool shouldVisitImplicitCode() const { return true; }
348ec727ea7Spatrick 
349a9ac8606Spatrick   /// Record the parent of the node we're visiting.
350a9ac8606Spatrick   /// MapNode is the child, the parent is on top of ParentStack.
351a9ac8606Spatrick   /// Parents is the parent storage (either PointerParents or OtherParents).
352a9ac8606Spatrick   template <typename MapNodeTy, typename MapTy>
addParent(MapNodeTy MapNode,MapTy * Parents)353a9ac8606Spatrick   void addParent(MapNodeTy MapNode, MapTy *Parents) {
354a9ac8606Spatrick     if (ParentStack.empty())
355a9ac8606Spatrick       return;
356a9ac8606Spatrick 
357ec727ea7Spatrick     // FIXME: Currently we add the same parent multiple times, but only
358ec727ea7Spatrick     // when no memoization data is available for the type.
359ec727ea7Spatrick     // For example when we visit all subexpressions of template
360ec727ea7Spatrick     // instantiations; this is suboptimal, but benign: the only way to
361ec727ea7Spatrick     // visit those is with hasAncestor / hasParent, and those do not create
362ec727ea7Spatrick     // new matches.
363ec727ea7Spatrick     // The plan is to enable DynTypedNode to be storable in a map or hash
364ec727ea7Spatrick     // map. The main problem there is to implement hash functions /
365ec727ea7Spatrick     // comparison operators for all types that DynTypedNode supports that
366ec727ea7Spatrick     // do not have pointer identity.
367ec727ea7Spatrick     auto &NodeOrVector = (*Parents)[MapNode];
368ec727ea7Spatrick     if (NodeOrVector.isNull()) {
369ec727ea7Spatrick       if (const auto *D = ParentStack.back().get<Decl>())
370ec727ea7Spatrick         NodeOrVector = D;
371ec727ea7Spatrick       else if (const auto *S = ParentStack.back().get<Stmt>())
372ec727ea7Spatrick         NodeOrVector = S;
373ec727ea7Spatrick       else
374ec727ea7Spatrick         NodeOrVector = new DynTypedNode(ParentStack.back());
375ec727ea7Spatrick     } else {
376ec727ea7Spatrick       if (!NodeOrVector.template is<ParentVector *>()) {
377ec727ea7Spatrick         auto *Vector = new ParentVector(
378ec727ea7Spatrick             1, getSingleDynTypedNodeFromParentMap(NodeOrVector));
379ec727ea7Spatrick         delete NodeOrVector.template dyn_cast<DynTypedNode *>();
380ec727ea7Spatrick         NodeOrVector = Vector;
381ec727ea7Spatrick       }
382ec727ea7Spatrick 
383ec727ea7Spatrick       auto *Vector = NodeOrVector.template get<ParentVector *>();
384ec727ea7Spatrick       // Skip duplicates for types that have memoization data.
385ec727ea7Spatrick       // We must check that the type has memoization data before calling
386*12c85518Srobert       // llvm::is_contained() because DynTypedNode::operator== can't compare all
387ec727ea7Spatrick       // types.
388ec727ea7Spatrick       bool Found = ParentStack.back().getMemoizationData() &&
389*12c85518Srobert                    llvm::is_contained(*Vector, ParentStack.back());
390ec727ea7Spatrick       if (!Found)
391ec727ea7Spatrick         Vector->push_back(ParentStack.back());
392ec727ea7Spatrick     }
393ec727ea7Spatrick   }
394a9ac8606Spatrick 
isNull(T Node)395*12c85518Srobert   template <typename T> static bool isNull(T Node) { return !Node; }
isNull(ObjCProtocolLoc Node)396*12c85518Srobert   static bool isNull(ObjCProtocolLoc Node) { return false; }
397*12c85518Srobert 
398a9ac8606Spatrick   template <typename T, typename MapNodeTy, typename BaseTraverseFn,
399a9ac8606Spatrick             typename MapTy>
TraverseNode(T Node,MapNodeTy MapNode,BaseTraverseFn BaseTraverse,MapTy * Parents)400a9ac8606Spatrick   bool TraverseNode(T Node, MapNodeTy MapNode, BaseTraverseFn BaseTraverse,
401a9ac8606Spatrick                     MapTy *Parents) {
402*12c85518Srobert     if (isNull(Node))
403a9ac8606Spatrick       return true;
404a9ac8606Spatrick     addParent(MapNode, Parents);
405ec727ea7Spatrick     ParentStack.push_back(createDynTypedNode(Node));
406ec727ea7Spatrick     bool Result = BaseTraverse();
407ec727ea7Spatrick     ParentStack.pop_back();
408ec727ea7Spatrick     return Result;
409ec727ea7Spatrick   }
410ec727ea7Spatrick 
TraverseDecl(Decl * DeclNode)411ec727ea7Spatrick   bool TraverseDecl(Decl *DeclNode) {
412ec727ea7Spatrick     return TraverseNode(
413ec727ea7Spatrick         DeclNode, DeclNode, [&] { return VisitorBase::TraverseDecl(DeclNode); },
414ec727ea7Spatrick         &Map.PointerParents);
415ec727ea7Spatrick   }
TraverseTypeLoc(TypeLoc TypeLocNode)416ec727ea7Spatrick   bool TraverseTypeLoc(TypeLoc TypeLocNode) {
417ec727ea7Spatrick     return TraverseNode(
418ec727ea7Spatrick         TypeLocNode, DynTypedNode::create(TypeLocNode),
419ec727ea7Spatrick         [&] { return VisitorBase::TraverseTypeLoc(TypeLocNode); },
420ec727ea7Spatrick         &Map.OtherParents);
421ec727ea7Spatrick   }
TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode)422ec727ea7Spatrick   bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode) {
423ec727ea7Spatrick     return TraverseNode(
424ec727ea7Spatrick         NNSLocNode, DynTypedNode::create(NNSLocNode),
425ec727ea7Spatrick         [&] { return VisitorBase::TraverseNestedNameSpecifierLoc(NNSLocNode); },
426ec727ea7Spatrick         &Map.OtherParents);
427ec727ea7Spatrick   }
TraverseAttr(Attr * AttrNode)428*12c85518Srobert   bool TraverseAttr(Attr *AttrNode) {
429*12c85518Srobert     return TraverseNode(
430*12c85518Srobert         AttrNode, AttrNode, [&] { return VisitorBase::TraverseAttr(AttrNode); },
431*12c85518Srobert         &Map.PointerParents);
432*12c85518Srobert   }
TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLocNode)433*12c85518Srobert   bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLocNode) {
434*12c85518Srobert     return TraverseNode(
435*12c85518Srobert         ProtocolLocNode, DynTypedNode::create(ProtocolLocNode),
436*12c85518Srobert         [&] { return VisitorBase::TraverseObjCProtocolLoc(ProtocolLocNode); },
437*12c85518Srobert         &Map.OtherParents);
438*12c85518Srobert   }
439ec727ea7Spatrick 
440a9ac8606Spatrick   // Using generic TraverseNode for Stmt would prevent data-recursion.
dataTraverseStmtPre(Stmt * StmtNode)441a9ac8606Spatrick   bool dataTraverseStmtPre(Stmt *StmtNode) {
442a9ac8606Spatrick     addParent(StmtNode, &Map.PointerParents);
443a9ac8606Spatrick     ParentStack.push_back(DynTypedNode::create(*StmtNode));
444a9ac8606Spatrick     return true;
445a9ac8606Spatrick   }
dataTraverseStmtPost(Stmt * StmtNode)446a9ac8606Spatrick   bool dataTraverseStmtPost(Stmt *StmtNode) {
447a9ac8606Spatrick     ParentStack.pop_back();
448a9ac8606Spatrick     return true;
449a9ac8606Spatrick   }
450a9ac8606Spatrick 
451ec727ea7Spatrick   ParentMap &Map;
452ec727ea7Spatrick   llvm::SmallVector<DynTypedNode, 16> ParentStack;
453ec727ea7Spatrick };
454ec727ea7Spatrick 
ParentMap(ASTContext & Ctx)455ec727ea7Spatrick ParentMapContext::ParentMap::ParentMap(ASTContext &Ctx) {
456ec727ea7Spatrick   ASTVisitor(*this).TraverseAST(Ctx);
457ec727ea7Spatrick }
458ec727ea7Spatrick 
getParents(const DynTypedNode & Node)459ec727ea7Spatrick DynTypedNodeList ParentMapContext::getParents(const DynTypedNode &Node) {
460ec727ea7Spatrick   if (!Parents)
461ec727ea7Spatrick     // We build the parent map for the traversal scope (usually whole TU), as
462ec727ea7Spatrick     // hasAncestor can escape any subtree.
463ec727ea7Spatrick     Parents = std::make_unique<ParentMap>(ASTCtx);
464ec727ea7Spatrick   return Parents->getParents(getTraversalKind(), Node);
465ec727ea7Spatrick }
466