blob: b73b32774b53f39214db27eb7257b4fd1f720b28 [file] [log] [blame]
Reid Kleckner8a81daa2019-12-09 17:03:47 -08001//===- ParentMapContext.cpp - Map of parents using DynTypedNode -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Similar to ParentMap.cpp, but generalizes to non-Stmt nodes, which can have
10// multiple parents.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/AST/ParentMapContext.h"
15#include "clang/AST/RecursiveASTVisitor.h"
16#include "clang/AST/Decl.h"
17#include "clang/AST/Expr.h"
18#include "clang/AST/TemplateBase.h"
19
20using namespace clang;
21
22ParentMapContext::ParentMapContext(ASTContext &Ctx) : ASTCtx(Ctx) {}
23
24ParentMapContext::~ParentMapContext() = default;
25
Stephen Kellyf29204d2020-01-24 23:46:54 +000026void ParentMapContext::clear() { Parents.reset(); }
Reid Kleckner8a81daa2019-12-09 17:03:47 -080027
28const Expr *ParentMapContext::traverseIgnored(const Expr *E) const {
29 return traverseIgnored(const_cast<Expr *>(E));
30}
31
32Expr *ParentMapContext::traverseIgnored(Expr *E) const {
33 if (!E)
34 return nullptr;
35
36 switch (Traversal) {
Reid Klecknercd625112020-02-12 11:34:13 -080037 case TK_AsIs:
Reid Kleckner8a81daa2019-12-09 17:03:47 -080038 return E;
Reid Klecknercd625112020-02-12 11:34:13 -080039 case TK_IgnoreImplicitCastsAndParentheses:
Reid Kleckner8a81daa2019-12-09 17:03:47 -080040 return E->IgnoreParenImpCasts();
Reid Klecknercd625112020-02-12 11:34:13 -080041 case TK_IgnoreUnlessSpelledInSource:
Reid Kleckner8a81daa2019-12-09 17:03:47 -080042 return E->IgnoreUnlessSpelledInSource();
43 }
44 llvm_unreachable("Invalid Traversal type!");
45}
46
Reid Klecknercd625112020-02-12 11:34:13 -080047DynTypedNode ParentMapContext::traverseIgnored(const DynTypedNode &N) const {
Reid Kleckner8a81daa2019-12-09 17:03:47 -080048 if (const auto *E = N.get<Expr>()) {
Reid Klecknercd625112020-02-12 11:34:13 -080049 return DynTypedNode::create(*traverseIgnored(E));
Reid Kleckner8a81daa2019-12-09 17:03:47 -080050 }
51 return N;
52}
53
54class ParentMapContext::ParentMap {
55 /// Contains parents of a node.
Reid Klecknercd625112020-02-12 11:34:13 -080056 using ParentVector = llvm::SmallVector<DynTypedNode, 2>;
Reid Kleckner8a81daa2019-12-09 17:03:47 -080057
58 /// Maps from a node to its parents. This is used for nodes that have
59 /// pointer identity only, which are more common and we can save space by
60 /// only storing a unique pointer to them.
Reid Klecknercd625112020-02-12 11:34:13 -080061 using ParentMapPointers =
62 llvm::DenseMap<const void *,
63 llvm::PointerUnion<const Decl *, const Stmt *,
64 DynTypedNode *, ParentVector *>>;
Reid Kleckner8a81daa2019-12-09 17:03:47 -080065
66 /// Parent map for nodes without pointer identity. We store a full
67 /// DynTypedNode for all keys.
Reid Klecknercd625112020-02-12 11:34:13 -080068 using ParentMapOtherNodes =
69 llvm::DenseMap<DynTypedNode,
70 llvm::PointerUnion<const Decl *, const Stmt *,
71 DynTypedNode *, ParentVector *>>;
Reid Kleckner8a81daa2019-12-09 17:03:47 -080072
73 ParentMapPointers PointerParents;
74 ParentMapOtherNodes OtherParents;
75 class ASTVisitor;
76
Reid Klecknercd625112020-02-12 11:34:13 -080077 static DynTypedNode
Reid Kleckner8a81daa2019-12-09 17:03:47 -080078 getSingleDynTypedNodeFromParentMap(ParentMapPointers::mapped_type U) {
79 if (const auto *D = U.dyn_cast<const Decl *>())
Reid Klecknercd625112020-02-12 11:34:13 -080080 return DynTypedNode::create(*D);
Reid Kleckner8a81daa2019-12-09 17:03:47 -080081 if (const auto *S = U.dyn_cast<const Stmt *>())
Reid Klecknercd625112020-02-12 11:34:13 -080082 return DynTypedNode::create(*S);
83 return *U.get<DynTypedNode *>();
Reid Kleckner8a81daa2019-12-09 17:03:47 -080084 }
85
86 template <typename NodeTy, typename MapTy>
87 static DynTypedNodeList getDynNodeFromMap(const NodeTy &Node,
88 const MapTy &Map) {
89 auto I = Map.find(Node);
90 if (I == Map.end()) {
Reid Klecknercd625112020-02-12 11:34:13 -080091 return llvm::ArrayRef<DynTypedNode>();
Reid Kleckner8a81daa2019-12-09 17:03:47 -080092 }
93 if (const auto *V = I->second.template dyn_cast<ParentVector *>()) {
94 return llvm::makeArrayRef(*V);
95 }
96 return getSingleDynTypedNodeFromParentMap(I->second);
97 }
98
99public:
100 ParentMap(ASTContext &Ctx);
101 ~ParentMap() {
102 for (const auto &Entry : PointerParents) {
Reid Klecknercd625112020-02-12 11:34:13 -0800103 if (Entry.second.is<DynTypedNode *>()) {
104 delete Entry.second.get<DynTypedNode *>();
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800105 } else if (Entry.second.is<ParentVector *>()) {
106 delete Entry.second.get<ParentVector *>();
107 }
108 }
109 for (const auto &Entry : OtherParents) {
Reid Klecknercd625112020-02-12 11:34:13 -0800110 if (Entry.second.is<DynTypedNode *>()) {
111 delete Entry.second.get<DynTypedNode *>();
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800112 } else if (Entry.second.is<ParentVector *>()) {
113 delete Entry.second.get<ParentVector *>();
114 }
115 }
116 }
117
Reid Klecknercd625112020-02-12 11:34:13 -0800118 DynTypedNodeList getParents(TraversalKind TK, const DynTypedNode &Node) {
Stephen Kellyf29204d2020-01-24 23:46:54 +0000119 if (Node.getNodeKind().hasPointerIdentity()) {
120 auto ParentList =
121 getDynNodeFromMap(Node.getMemoizationData(), PointerParents);
Reid Klecknercd625112020-02-12 11:34:13 -0800122 if (ParentList.size() == 1 && TK == TK_IgnoreUnlessSpelledInSource) {
Stephen Kellyf29204d2020-01-24 23:46:54 +0000123 const auto *E = ParentList[0].get<Expr>();
124 const auto *Child = Node.get<Expr>();
125 if (E && Child)
126 return AscendIgnoreUnlessSpelledInSource(E, Child);
127 }
128 return ParentList;
129 }
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800130 return getDynNodeFromMap(Node, OtherParents);
131 }
Stephen Kellyf29204d2020-01-24 23:46:54 +0000132
Stephen Kelly0a57d142020-01-27 11:16:50 +0000133 DynTypedNodeList AscendIgnoreUnlessSpelledInSource(const Expr *E,
134 const Expr *Child) {
Stephen Kellyf29204d2020-01-24 23:46:54 +0000135
136 auto ShouldSkip = [](const Expr *E, const Expr *Child) {
137 if (isa<ImplicitCastExpr>(E))
138 return true;
139
140 if (isa<FullExpr>(E))
141 return true;
142
143 if (isa<MaterializeTemporaryExpr>(E))
144 return true;
145
146 if (isa<CXXBindTemporaryExpr>(E))
147 return true;
148
149 if (isa<ParenExpr>(E))
150 return true;
151
152 if (isa<ExprWithCleanups>(E))
153 return true;
154
155 auto SR = Child->getSourceRange();
156
157 if (const auto *C = dyn_cast<CXXConstructExpr>(E)) {
158 if (C->getSourceRange() == SR || !isa<CXXTemporaryObjectExpr>(C))
159 return true;
160 }
161
162 if (const auto *C = dyn_cast<CXXMemberCallExpr>(E)) {
163 if (C->getSourceRange() == SR)
164 return true;
165 }
166
167 if (const auto *C = dyn_cast<MemberExpr>(E)) {
168 if (C->getSourceRange() == SR)
169 return true;
170 }
171 return false;
172 };
173
174 while (ShouldSkip(E, Child)) {
175 auto It = PointerParents.find(E);
176 if (It == PointerParents.end())
177 break;
178 const auto *S = It->second.dyn_cast<const Stmt *>();
Stephen Kelly0a57d142020-01-27 11:16:50 +0000179 if (!S) {
180 if (auto *Vec = It->second.dyn_cast<ParentVector *>())
181 return llvm::makeArrayRef(*Vec);
Stephen Kellyf29204d2020-01-24 23:46:54 +0000182 return getSingleDynTypedNodeFromParentMap(It->second);
Stephen Kelly0a57d142020-01-27 11:16:50 +0000183 }
Stephen Kellyf29204d2020-01-24 23:46:54 +0000184 const auto *P = dyn_cast<Expr>(S);
185 if (!P)
Reid Klecknercd625112020-02-12 11:34:13 -0800186 return DynTypedNode::create(*S);
Stephen Kellyf29204d2020-01-24 23:46:54 +0000187 Child = E;
188 E = P;
189 }
Reid Klecknercd625112020-02-12 11:34:13 -0800190 return DynTypedNode::create(*E);
Stephen Kellyf29204d2020-01-24 23:46:54 +0000191 }
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800192};
193
194/// Template specializations to abstract away from pointers and TypeLocs.
195/// @{
Reid Klecknercd625112020-02-12 11:34:13 -0800196template <typename T> static DynTypedNode createDynTypedNode(const T &Node) {
197 return DynTypedNode::create(*Node);
198}
199template <> DynTypedNode createDynTypedNode(const TypeLoc &Node) {
200 return DynTypedNode::create(Node);
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800201}
202template <>
Reid Klecknercd625112020-02-12 11:34:13 -0800203DynTypedNode createDynTypedNode(const NestedNameSpecifierLoc &Node) {
204 return DynTypedNode::create(Node);
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800205}
206/// @}
207
208/// A \c RecursiveASTVisitor that builds a map from nodes to their
209/// parents as defined by the \c RecursiveASTVisitor.
210///
211/// Note that the relationship described here is purely in terms of AST
212/// traversal - there are other relationships (for example declaration context)
213/// in the AST that are better modeled by special matchers.
214///
215/// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.
216class ParentMapContext::ParentMap::ASTVisitor
217 : public RecursiveASTVisitor<ASTVisitor> {
218public:
Stephen Kellyf29204d2020-01-24 23:46:54 +0000219 ASTVisitor(ParentMap &Map) : Map(Map) {}
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800220
221private:
222 friend class RecursiveASTVisitor<ASTVisitor>;
223
224 using VisitorBase = RecursiveASTVisitor<ASTVisitor>;
225
226 bool shouldVisitTemplateInstantiations() const { return true; }
227
228 bool shouldVisitImplicitCode() const { return true; }
229
230 template <typename T, typename MapNodeTy, typename BaseTraverseFn,
231 typename MapTy>
232 bool TraverseNode(T Node, MapNodeTy MapNode, BaseTraverseFn BaseTraverse,
233 MapTy *Parents) {
234 if (!Node)
235 return true;
236 if (ParentStack.size() > 0) {
237 // FIXME: Currently we add the same parent multiple times, but only
238 // when no memoization data is available for the type.
239 // For example when we visit all subexpressions of template
240 // instantiations; this is suboptimal, but benign: the only way to
241 // visit those is with hasAncestor / hasParent, and those do not create
242 // new matches.
243 // The plan is to enable DynTypedNode to be storable in a map or hash
244 // map. The main problem there is to implement hash functions /
245 // comparison operators for all types that DynTypedNode supports that
246 // do not have pointer identity.
247 auto &NodeOrVector = (*Parents)[MapNode];
248 if (NodeOrVector.isNull()) {
249 if (const auto *D = ParentStack.back().get<Decl>())
250 NodeOrVector = D;
251 else if (const auto *S = ParentStack.back().get<Stmt>())
252 NodeOrVector = S;
253 else
Reid Klecknercd625112020-02-12 11:34:13 -0800254 NodeOrVector = new DynTypedNode(ParentStack.back());
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800255 } else {
256 if (!NodeOrVector.template is<ParentVector *>()) {
257 auto *Vector = new ParentVector(
258 1, getSingleDynTypedNodeFromParentMap(NodeOrVector));
Reid Klecknercd625112020-02-12 11:34:13 -0800259 delete NodeOrVector.template dyn_cast<DynTypedNode *>();
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800260 NodeOrVector = Vector;
261 }
262
263 auto *Vector = NodeOrVector.template get<ParentVector *>();
264 // Skip duplicates for types that have memoization data.
265 // We must check that the type has memoization data before calling
266 // std::find() because DynTypedNode::operator== can't compare all
267 // types.
268 bool Found = ParentStack.back().getMemoizationData() &&
269 std::find(Vector->begin(), Vector->end(),
270 ParentStack.back()) != Vector->end();
271 if (!Found)
272 Vector->push_back(ParentStack.back());
273 }
274 }
275 ParentStack.push_back(createDynTypedNode(Node));
276 bool Result = BaseTraverse();
277 ParentStack.pop_back();
278 return Result;
279 }
280
281 bool TraverseDecl(Decl *DeclNode) {
282 return TraverseNode(
283 DeclNode, DeclNode, [&] { return VisitorBase::TraverseDecl(DeclNode); },
284 &Map.PointerParents);
285 }
286
287 bool TraverseStmt(Stmt *StmtNode) {
Stephen Kellyf29204d2020-01-24 23:46:54 +0000288 return TraverseNode(StmtNode, StmtNode,
289 [&] { return VisitorBase::TraverseStmt(StmtNode); },
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800290 &Map.PointerParents);
291 }
292
293 bool TraverseTypeLoc(TypeLoc TypeLocNode) {
294 return TraverseNode(
Reid Klecknercd625112020-02-12 11:34:13 -0800295 TypeLocNode, DynTypedNode::create(TypeLocNode),
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800296 [&] { return VisitorBase::TraverseTypeLoc(TypeLocNode); },
297 &Map.OtherParents);
298 }
299
300 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode) {
301 return TraverseNode(
Reid Klecknercd625112020-02-12 11:34:13 -0800302 NNSLocNode, DynTypedNode::create(NNSLocNode),
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800303 [&] { return VisitorBase::TraverseNestedNameSpecifierLoc(NNSLocNode); },
304 &Map.OtherParents);
305 }
306
307 ParentMap &Map;
Reid Klecknercd625112020-02-12 11:34:13 -0800308 llvm::SmallVector<DynTypedNode, 16> ParentStack;
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800309};
310
311ParentMapContext::ParentMap::ParentMap(ASTContext &Ctx) {
Stephen Kellyf29204d2020-01-24 23:46:54 +0000312 ASTVisitor(*this).TraverseAST(Ctx);
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800313}
314
Reid Klecknercd625112020-02-12 11:34:13 -0800315DynTypedNodeList ParentMapContext::getParents(const DynTypedNode &Node) {
Stephen Kellyf29204d2020-01-24 23:46:54 +0000316 if (!Parents)
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800317 // We build the parent map for the traversal scope (usually whole TU), as
318 // hasAncestor can escape any subtree.
Stephen Kellyf29204d2020-01-24 23:46:54 +0000319 Parents = std::make_unique<ParentMap>(ASTCtx);
320 return Parents->getParents(getTraversalKind(), Node);
Reid Kleckner8a81daa2019-12-09 17:03:47 -0800321}