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 ⤅
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