Mercurial > hg > CbC > CbC_llvm
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 ⤅ | 444 ParentMap ⤅ |
308 llvm::SmallVector<DynTypedNode, 16> ParentStack; | 445 llvm::SmallVector<DynTypedNode, 16> ParentStack; |
309 }; | 446 }; |