comparison clang/lib/AST/ParentMapContext.cpp @ 207:2e18cbf3894f

LLVM12
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 08 Jun 2021 06:07:14 +0900
parents 0572611fdcc8
children c4bab56944e8
comparison
equal deleted inserted replaced
173:0572611fdcc8 207:2e18cbf3894f
34 return nullptr; 34 return nullptr;
35 35
36 switch (Traversal) { 36 switch (Traversal) {
37 case TK_AsIs: 37 case TK_AsIs:
38 return E; 38 return E;
39 case TK_IgnoreImplicitCastsAndParentheses:
40 return E->IgnoreParenImpCasts();
41 case TK_IgnoreUnlessSpelledInSource: 39 case TK_IgnoreUnlessSpelledInSource:
42 return E->IgnoreUnlessSpelledInSource(); 40 return E->IgnoreUnlessSpelledInSource();
43 } 41 }
44 llvm_unreachable("Invalid Traversal type!"); 42 llvm_unreachable("Invalid Traversal type!");
45 } 43 }
49 return DynTypedNode::create(*traverseIgnored(E)); 47 return DynTypedNode::create(*traverseIgnored(E));
50 } 48 }
51 return N; 49 return N;
52 } 50 }
53 51
52 template <typename T, typename... U>
53 std::tuple<bool, DynTypedNodeList, const T *, const U *...>
54 matchParents(const DynTypedNodeList &NodeList,
55 ParentMapContext::ParentMap *ParentMap);
56
57 template <typename, typename...> struct MatchParents;
58
54 class ParentMapContext::ParentMap { 59 class ParentMapContext::ParentMap {
60
61 template <typename, typename...> friend struct ::MatchParents;
62
55 /// Contains parents of a node. 63 /// Contains parents of a node.
56 using ParentVector = llvm::SmallVector<DynTypedNode, 2>; 64 using ParentVector = llvm::SmallVector<DynTypedNode, 2>;
57 65
58 /// Maps from a node to its parents. This is used for nodes that have 66 /// 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 67 /// pointer identity only, which are more common and we can save space by
117 125
118 DynTypedNodeList getParents(TraversalKind TK, const DynTypedNode &Node) { 126 DynTypedNodeList getParents(TraversalKind TK, const DynTypedNode &Node) {
119 if (Node.getNodeKind().hasPointerIdentity()) { 127 if (Node.getNodeKind().hasPointerIdentity()) {
120 auto ParentList = 128 auto ParentList =
121 getDynNodeFromMap(Node.getMemoizationData(), PointerParents); 129 getDynNodeFromMap(Node.getMemoizationData(), PointerParents);
122 if (ParentList.size() == 1 && TK == TK_IgnoreUnlessSpelledInSource) { 130 if (ParentList.size() > 0 && TK == TK_IgnoreUnlessSpelledInSource) {
123 const auto *E = ParentList[0].get<Expr>(); 131
124 const auto *Child = Node.get<Expr>(); 132 const auto *ChildExpr = Node.get<Expr>();
125 if (E && Child) 133
126 return AscendIgnoreUnlessSpelledInSource(E, Child); 134 {
135 // Don't match explicit node types because different stdlib
136 // implementations implement this in different ways and have
137 // different intermediate nodes.
138 // Look up 4 levels for a cxxRewrittenBinaryOperator as that is
139 // enough for the major stdlib implementations.
140 auto RewrittenBinOpParentsList = ParentList;
141 int I = 0;
142 while (ChildExpr && RewrittenBinOpParentsList.size() == 1 &&
143 I++ < 4) {
144 const auto *S = RewrittenBinOpParentsList[0].get<Stmt>();
145 if (!S)
146 break;
147
148 const auto *RWBO = dyn_cast<CXXRewrittenBinaryOperator>(S);
149 if (!RWBO) {
150 RewrittenBinOpParentsList = getDynNodeFromMap(S, PointerParents);
151 continue;
152 }
153 if (RWBO->getLHS()->IgnoreUnlessSpelledInSource() != ChildExpr &&
154 RWBO->getRHS()->IgnoreUnlessSpelledInSource() != ChildExpr)
155 break;
156 return DynTypedNode::create(*RWBO);
157 }
158 }
159
160 const auto *ParentExpr = ParentList[0].get<Expr>();
161 if (ParentExpr && ChildExpr)
162 return AscendIgnoreUnlessSpelledInSource(ParentExpr, ChildExpr);
163
164 {
165 auto AncestorNodes =
166 matchParents<DeclStmt, CXXForRangeStmt>(ParentList, this);
167 if (std::get<bool>(AncestorNodes) &&
168 std::get<const CXXForRangeStmt *>(AncestorNodes)
169 ->getLoopVarStmt() ==
170 std::get<const DeclStmt *>(AncestorNodes))
171 return std::get<DynTypedNodeList>(AncestorNodes);
172 }
173 {
174 auto AncestorNodes = matchParents<VarDecl, DeclStmt, CXXForRangeStmt>(
175 ParentList, this);
176 if (std::get<bool>(AncestorNodes) &&
177 std::get<const CXXForRangeStmt *>(AncestorNodes)
178 ->getRangeStmt() ==
179 std::get<const DeclStmt *>(AncestorNodes))
180 return std::get<DynTypedNodeList>(AncestorNodes);
181 }
182 {
183 auto AncestorNodes =
184 matchParents<CXXMethodDecl, CXXRecordDecl, LambdaExpr>(ParentList,
185 this);
186 if (std::get<bool>(AncestorNodes))
187 return std::get<DynTypedNodeList>(AncestorNodes);
188 }
189 {
190 auto AncestorNodes =
191 matchParents<FunctionTemplateDecl, CXXRecordDecl, LambdaExpr>(
192 ParentList, this);
193 if (std::get<bool>(AncestorNodes))
194 return std::get<DynTypedNodeList>(AncestorNodes);
195 }
127 } 196 }
128 return ParentList; 197 return ParentList;
129 } 198 }
130 return getDynNodeFromMap(Node, OtherParents); 199 return getDynNodeFromMap(Node, OtherParents);
131 } 200 }
152 if (isa<ExprWithCleanups>(E)) 221 if (isa<ExprWithCleanups>(E))
153 return true; 222 return true;
154 223
155 auto SR = Child->getSourceRange(); 224 auto SR = Child->getSourceRange();
156 225
226 if (const auto *C = dyn_cast<CXXFunctionalCastExpr>(E)) {
227 if (C->getSourceRange() == SR)
228 return true;
229 }
230
157 if (const auto *C = dyn_cast<CXXConstructExpr>(E)) { 231 if (const auto *C = dyn_cast<CXXConstructExpr>(E)) {
158 if (C->getSourceRange() == SR || !isa<CXXTemporaryObjectExpr>(C)) 232 if (C->getSourceRange() == SR || C->isElidable())
159 return true; 233 return true;
160 } 234 }
161 235
162 if (const auto *C = dyn_cast<CXXMemberCallExpr>(E)) { 236 if (const auto *C = dyn_cast<CXXMemberCallExpr>(E)) {
163 if (C->getSourceRange() == SR) 237 if (C->getSourceRange() == SR)
189 } 263 }
190 return DynTypedNode::create(*E); 264 return DynTypedNode::create(*E);
191 } 265 }
192 }; 266 };
193 267
268 template <typename Tuple, std::size_t... Is>
269 auto tuple_pop_front_impl(const Tuple &tuple, std::index_sequence<Is...>) {
270 return std::make_tuple(std::get<1 + Is>(tuple)...);
271 }
272
273 template <typename Tuple> auto tuple_pop_front(const Tuple &tuple) {
274 return tuple_pop_front_impl(
275 tuple, std::make_index_sequence<std::tuple_size<Tuple>::value - 1>());
276 }
277
278 template <typename T, typename... U> struct MatchParents {
279 static std::tuple<bool, DynTypedNodeList, const T *, const U *...>
280 match(const DynTypedNodeList &NodeList,
281 ParentMapContext::ParentMap *ParentMap) {
282 if (const auto *TypedNode = NodeList[0].get<T>()) {
283 auto NextParentList =
284 ParentMap->getDynNodeFromMap(TypedNode, ParentMap->PointerParents);
285 if (NextParentList.size() == 1) {
286 auto TailTuple = MatchParents<U...>::match(NextParentList, ParentMap);
287 if (std::get<bool>(TailTuple)) {
288 return std::tuple_cat(
289 std::make_tuple(true, std::get<DynTypedNodeList>(TailTuple),
290 TypedNode),
291 tuple_pop_front(tuple_pop_front(TailTuple)));
292 }
293 }
294 }
295 return std::tuple_cat(std::make_tuple(false, NodeList),
296 std::tuple<const T *, const U *...>());
297 }
298 };
299
300 template <typename T> struct MatchParents<T> {
301 static std::tuple<bool, DynTypedNodeList, const T *>
302 match(const DynTypedNodeList &NodeList,
303 ParentMapContext::ParentMap *ParentMap) {
304 if (const auto *TypedNode = NodeList[0].get<T>()) {
305 auto NextParentList =
306 ParentMap->getDynNodeFromMap(TypedNode, ParentMap->PointerParents);
307 if (NextParentList.size() == 1)
308 return std::make_tuple(true, NodeList, TypedNode);
309 }
310 return std::make_tuple(false, NodeList, nullptr);
311 }
312 };
313
314 template <typename T, typename... U>
315 std::tuple<bool, DynTypedNodeList, const T *, const U *...>
316 matchParents(const DynTypedNodeList &NodeList,
317 ParentMapContext::ParentMap *ParentMap) {
318 return MatchParents<T, U...>::match(NodeList, ParentMap);
319 }
320
194 /// Template specializations to abstract away from pointers and TypeLocs. 321 /// Template specializations to abstract away from pointers and TypeLocs.
195 /// @{ 322 /// @{
196 template <typename T> static DynTypedNode createDynTypedNode(const T &Node) { 323 template <typename T> static DynTypedNode createDynTypedNode(const T &Node) {
197 return DynTypedNode::create(*Node); 324 return DynTypedNode::create(*Node);
198 } 325 }
209 /// parents as defined by the \c RecursiveASTVisitor. 336 /// parents as defined by the \c RecursiveASTVisitor.
210 /// 337 ///
211 /// Note that the relationship described here is purely in terms of AST 338 /// Note that the relationship described here is purely in terms of AST
212 /// traversal - there are other relationships (for example declaration context) 339 /// traversal - there are other relationships (for example declaration context)
213 /// in the AST that are better modeled by special matchers. 340 /// 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.
216 class ParentMapContext::ParentMap::ASTVisitor 341 class ParentMapContext::ParentMap::ASTVisitor
217 : public RecursiveASTVisitor<ASTVisitor> { 342 : public RecursiveASTVisitor<ASTVisitor> {
218 public: 343 public:
219 ASTVisitor(ParentMap &Map) : Map(Map) {} 344 ASTVisitor(ParentMap &Map) : Map(Map) {}
220 345
224 using VisitorBase = RecursiveASTVisitor<ASTVisitor>; 349 using VisitorBase = RecursiveASTVisitor<ASTVisitor>;
225 350
226 bool shouldVisitTemplateInstantiations() const { return true; } 351 bool shouldVisitTemplateInstantiations() const { return true; }
227 352
228 bool shouldVisitImplicitCode() const { return true; } 353 bool shouldVisitImplicitCode() const { return true; }
354
355 /// Record the parent of the node we're visiting.
356 /// MapNode is the child, the parent is on top of ParentStack.
357 /// Parents is the parent storage (either PointerParents or OtherParents).
358 template <typename MapNodeTy, typename MapTy>
359 void addParent(MapNodeTy MapNode, MapTy *Parents) {
360 if (ParentStack.empty())
361 return;
362
363 // FIXME: Currently we add the same parent multiple times, but only
364 // when no memoization data is available for the type.
365 // For example when we visit all subexpressions of template
366 // instantiations; this is suboptimal, but benign: the only way to
367 // visit those is with hasAncestor / hasParent, and those do not create
368 // new matches.
369 // The plan is to enable DynTypedNode to be storable in a map or hash
370 // map. The main problem there is to implement hash functions /
371 // comparison operators for all types that DynTypedNode supports that
372 // do not have pointer identity.
373 auto &NodeOrVector = (*Parents)[MapNode];
374 if (NodeOrVector.isNull()) {
375 if (const auto *D = ParentStack.back().get<Decl>())
376 NodeOrVector = D;
377 else if (const auto *S = ParentStack.back().get<Stmt>())
378 NodeOrVector = S;
379 else
380 NodeOrVector = new DynTypedNode(ParentStack.back());
381 } else {
382 if (!NodeOrVector.template is<ParentVector *>()) {
383 auto *Vector = new ParentVector(
384 1, getSingleDynTypedNodeFromParentMap(NodeOrVector));
385 delete NodeOrVector.template dyn_cast<DynTypedNode *>();
386 NodeOrVector = Vector;
387 }
388
389 auto *Vector = NodeOrVector.template get<ParentVector *>();
390 // Skip duplicates for types that have memoization data.
391 // We must check that the type has memoization data before calling
392 // std::find() because DynTypedNode::operator== can't compare all
393 // types.
394 bool Found = ParentStack.back().getMemoizationData() &&
395 std::find(Vector->begin(), Vector->end(),
396 ParentStack.back()) != Vector->end();
397 if (!Found)
398 Vector->push_back(ParentStack.back());
399 }
400 }
229 401
230 template <typename T, typename MapNodeTy, typename BaseTraverseFn, 402 template <typename T, typename MapNodeTy, typename BaseTraverseFn,
231 typename MapTy> 403 typename MapTy>
232 bool TraverseNode(T Node, MapNodeTy MapNode, BaseTraverseFn BaseTraverse, 404 bool TraverseNode(T Node, MapNodeTy MapNode, BaseTraverseFn BaseTraverse,
233 MapTy *Parents) { 405 MapTy *Parents) {
234 if (!Node) 406 if (!Node)
235 return true; 407 return true;
236 if (ParentStack.size() > 0) { 408 addParent(MapNode, Parents);
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
254 NodeOrVector = new DynTypedNode(ParentStack.back());
255 } else {
256 if (!NodeOrVector.template is<ParentVector *>()) {
257 auto *Vector = new ParentVector(
258 1, getSingleDynTypedNodeFromParentMap(NodeOrVector));
259 delete NodeOrVector.template dyn_cast<DynTypedNode *>();
260 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)); 409 ParentStack.push_back(createDynTypedNode(Node));
276 bool Result = BaseTraverse(); 410 bool Result = BaseTraverse();
277 ParentStack.pop_back(); 411 ParentStack.pop_back();
278 return Result; 412 return Result;
279 } 413 }
281 bool TraverseDecl(Decl *DeclNode) { 415 bool TraverseDecl(Decl *DeclNode) {
282 return TraverseNode( 416 return TraverseNode(
283 DeclNode, DeclNode, [&] { return VisitorBase::TraverseDecl(DeclNode); }, 417 DeclNode, DeclNode, [&] { return VisitorBase::TraverseDecl(DeclNode); },
284 &Map.PointerParents); 418 &Map.PointerParents);
285 } 419 }
286
287 bool TraverseStmt(Stmt *StmtNode) {
288 return TraverseNode(StmtNode, StmtNode,
289 [&] { return VisitorBase::TraverseStmt(StmtNode); },
290 &Map.PointerParents);
291 }
292
293 bool TraverseTypeLoc(TypeLoc TypeLocNode) { 420 bool TraverseTypeLoc(TypeLoc TypeLocNode) {
294 return TraverseNode( 421 return TraverseNode(
295 TypeLocNode, DynTypedNode::create(TypeLocNode), 422 TypeLocNode, DynTypedNode::create(TypeLocNode),
296 [&] { return VisitorBase::TraverseTypeLoc(TypeLocNode); }, 423 [&] { return VisitorBase::TraverseTypeLoc(TypeLocNode); },
297 &Map.OtherParents); 424 &Map.OtherParents);
298 } 425 }
299
300 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode) { 426 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode) {
301 return TraverseNode( 427 return TraverseNode(
302 NNSLocNode, DynTypedNode::create(NNSLocNode), 428 NNSLocNode, DynTypedNode::create(NNSLocNode),
303 [&] { return VisitorBase::TraverseNestedNameSpecifierLoc(NNSLocNode); }, 429 [&] { return VisitorBase::TraverseNestedNameSpecifierLoc(NNSLocNode); },
304 &Map.OtherParents); 430 &Map.OtherParents);
431 }
432
433 // Using generic TraverseNode for Stmt would prevent data-recursion.
434 bool dataTraverseStmtPre(Stmt *StmtNode) {
435 addParent(StmtNode, &Map.PointerParents);
436 ParentStack.push_back(DynTypedNode::create(*StmtNode));
437 return true;
438 }
439 bool dataTraverseStmtPost(Stmt *StmtNode) {
440 ParentStack.pop_back();
441 return true;
305 } 442 }
306 443
307 ParentMap &Map; 444 ParentMap &Map;
308 llvm::SmallVector<DynTypedNode, 16> ParentStack; 445 llvm::SmallVector<DynTypedNode, 16> ParentStack;
309 }; 446 };