ParentMapContext.cpp 16 KB

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