xref: /openbsd-src/gnu/llvm/clang/lib/AST/ParentMap.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===--- ParentMap.cpp - Mappings from Stmts to their Parents ---*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick //  This file defines the ParentMap class.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick 
13e5dd7070Spatrick #include "clang/AST/ParentMap.h"
14e5dd7070Spatrick #include "clang/AST/Decl.h"
15e5dd7070Spatrick #include "clang/AST/Expr.h"
16e5dd7070Spatrick #include "clang/AST/ExprCXX.h"
17e5dd7070Spatrick #include "clang/AST/StmtObjC.h"
18e5dd7070Spatrick #include "llvm/ADT/DenseMap.h"
19e5dd7070Spatrick 
20e5dd7070Spatrick using namespace clang;
21e5dd7070Spatrick 
22e5dd7070Spatrick typedef llvm::DenseMap<Stmt*, Stmt*> MapTy;
23e5dd7070Spatrick 
24e5dd7070Spatrick enum OpaqueValueMode {
25e5dd7070Spatrick   OV_Transparent,
26e5dd7070Spatrick   OV_Opaque
27e5dd7070Spatrick };
28e5dd7070Spatrick 
BuildParentMap(MapTy & M,Stmt * S,OpaqueValueMode OVMode=OV_Transparent)29e5dd7070Spatrick static void BuildParentMap(MapTy& M, Stmt* S,
30e5dd7070Spatrick                            OpaqueValueMode OVMode = OV_Transparent) {
31e5dd7070Spatrick   if (!S)
32e5dd7070Spatrick     return;
33e5dd7070Spatrick 
34e5dd7070Spatrick   switch (S->getStmtClass()) {
35e5dd7070Spatrick   case Stmt::PseudoObjectExprClass: {
36e5dd7070Spatrick     PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S);
37e5dd7070Spatrick 
38*12c85518Srobert     if (OVMode == OV_Opaque && M[POE->getSyntacticForm()])
39*12c85518Srobert       break;
40*12c85518Srobert 
41e5dd7070Spatrick     // If we are rebuilding the map, clear out any existing state.
42e5dd7070Spatrick     if (M[POE->getSyntacticForm()])
43e5dd7070Spatrick       for (Stmt *SubStmt : S->children())
44e5dd7070Spatrick         M[SubStmt] = nullptr;
45e5dd7070Spatrick 
46e5dd7070Spatrick     M[POE->getSyntacticForm()] = S;
47e5dd7070Spatrick     BuildParentMap(M, POE->getSyntacticForm(), OV_Transparent);
48e5dd7070Spatrick 
49e5dd7070Spatrick     for (PseudoObjectExpr::semantics_iterator I = POE->semantics_begin(),
50e5dd7070Spatrick                                               E = POE->semantics_end();
51e5dd7070Spatrick          I != E; ++I) {
52e5dd7070Spatrick       M[*I] = S;
53e5dd7070Spatrick       BuildParentMap(M, *I, OV_Opaque);
54e5dd7070Spatrick     }
55e5dd7070Spatrick     break;
56e5dd7070Spatrick   }
57e5dd7070Spatrick   case Stmt::BinaryConditionalOperatorClass: {
58e5dd7070Spatrick     assert(OVMode == OV_Transparent && "Should not appear alongside OVEs");
59e5dd7070Spatrick     BinaryConditionalOperator *BCO = cast<BinaryConditionalOperator>(S);
60e5dd7070Spatrick 
61e5dd7070Spatrick     M[BCO->getCommon()] = S;
62e5dd7070Spatrick     BuildParentMap(M, BCO->getCommon(), OV_Transparent);
63e5dd7070Spatrick 
64e5dd7070Spatrick     M[BCO->getCond()] = S;
65e5dd7070Spatrick     BuildParentMap(M, BCO->getCond(), OV_Opaque);
66e5dd7070Spatrick 
67e5dd7070Spatrick     M[BCO->getTrueExpr()] = S;
68e5dd7070Spatrick     BuildParentMap(M, BCO->getTrueExpr(), OV_Opaque);
69e5dd7070Spatrick 
70e5dd7070Spatrick     M[BCO->getFalseExpr()] = S;
71e5dd7070Spatrick     BuildParentMap(M, BCO->getFalseExpr(), OV_Transparent);
72e5dd7070Spatrick 
73e5dd7070Spatrick     break;
74e5dd7070Spatrick   }
75e5dd7070Spatrick   case Stmt::OpaqueValueExprClass: {
76e5dd7070Spatrick     // FIXME: This isn't correct; it assumes that multiple OpaqueValueExprs
77e5dd7070Spatrick     // share a single source expression, but in the AST a single
78e5dd7070Spatrick     // OpaqueValueExpr is shared among multiple parent expressions.
79e5dd7070Spatrick     // The right thing to do is to give the OpaqueValueExpr its syntactic
80e5dd7070Spatrick     // parent, then not reassign that when traversing the semantic expressions.
81e5dd7070Spatrick     OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S);
82e5dd7070Spatrick     if (OVMode == OV_Transparent || !M[OVE->getSourceExpr()]) {
83e5dd7070Spatrick       M[OVE->getSourceExpr()] = S;
84e5dd7070Spatrick       BuildParentMap(M, OVE->getSourceExpr(), OV_Transparent);
85e5dd7070Spatrick     }
86e5dd7070Spatrick     break;
87e5dd7070Spatrick   }
88e5dd7070Spatrick   case Stmt::CapturedStmtClass:
89e5dd7070Spatrick     for (Stmt *SubStmt : S->children()) {
90e5dd7070Spatrick       if (SubStmt) {
91e5dd7070Spatrick         M[SubStmt] = S;
92e5dd7070Spatrick         BuildParentMap(M, SubStmt, OVMode);
93e5dd7070Spatrick       }
94e5dd7070Spatrick     }
95e5dd7070Spatrick     if (Stmt *SubStmt = cast<CapturedStmt>(S)->getCapturedStmt()) {
96e5dd7070Spatrick       M[SubStmt] = S;
97e5dd7070Spatrick       BuildParentMap(M, SubStmt, OVMode);
98e5dd7070Spatrick     }
99e5dd7070Spatrick     break;
100e5dd7070Spatrick   default:
101e5dd7070Spatrick     for (Stmt *SubStmt : S->children()) {
102e5dd7070Spatrick       if (SubStmt) {
103e5dd7070Spatrick         M[SubStmt] = S;
104e5dd7070Spatrick         BuildParentMap(M, SubStmt, OVMode);
105e5dd7070Spatrick       }
106e5dd7070Spatrick     }
107e5dd7070Spatrick     break;
108e5dd7070Spatrick   }
109e5dd7070Spatrick }
110e5dd7070Spatrick 
ParentMap(Stmt * S)111e5dd7070Spatrick ParentMap::ParentMap(Stmt *S) : Impl(nullptr) {
112e5dd7070Spatrick   if (S) {
113e5dd7070Spatrick     MapTy *M = new MapTy();
114e5dd7070Spatrick     BuildParentMap(*M, S);
115e5dd7070Spatrick     Impl = M;
116e5dd7070Spatrick   }
117e5dd7070Spatrick }
118e5dd7070Spatrick 
~ParentMap()119e5dd7070Spatrick ParentMap::~ParentMap() {
120e5dd7070Spatrick   delete (MapTy*) Impl;
121e5dd7070Spatrick }
122e5dd7070Spatrick 
addStmt(Stmt * S)123e5dd7070Spatrick void ParentMap::addStmt(Stmt* S) {
124e5dd7070Spatrick   if (S) {
125e5dd7070Spatrick     BuildParentMap(*(MapTy*) Impl, S);
126e5dd7070Spatrick   }
127e5dd7070Spatrick }
128e5dd7070Spatrick 
setParent(const Stmt * S,const Stmt * Parent)129e5dd7070Spatrick void ParentMap::setParent(const Stmt *S, const Stmt *Parent) {
130e5dd7070Spatrick   assert(S);
131e5dd7070Spatrick   assert(Parent);
132e5dd7070Spatrick   MapTy *M = reinterpret_cast<MapTy *>(Impl);
133e5dd7070Spatrick   M->insert(std::make_pair(const_cast<Stmt *>(S), const_cast<Stmt *>(Parent)));
134e5dd7070Spatrick }
135e5dd7070Spatrick 
getParent(Stmt * S) const136e5dd7070Spatrick Stmt* ParentMap::getParent(Stmt* S) const {
137e5dd7070Spatrick   MapTy* M = (MapTy*) Impl;
138*12c85518Srobert   return M->lookup(S);
139e5dd7070Spatrick }
140e5dd7070Spatrick 
getParentIgnoreParens(Stmt * S) const141e5dd7070Spatrick Stmt *ParentMap::getParentIgnoreParens(Stmt *S) const {
142e5dd7070Spatrick   do { S = getParent(S); } while (S && isa<ParenExpr>(S));
143e5dd7070Spatrick   return S;
144e5dd7070Spatrick }
145e5dd7070Spatrick 
getParentIgnoreParenCasts(Stmt * S) const146e5dd7070Spatrick Stmt *ParentMap::getParentIgnoreParenCasts(Stmt *S) const {
147e5dd7070Spatrick   do {
148e5dd7070Spatrick     S = getParent(S);
149e5dd7070Spatrick   }
150e5dd7070Spatrick   while (S && (isa<ParenExpr>(S) || isa<CastExpr>(S)));
151e5dd7070Spatrick 
152e5dd7070Spatrick   return S;
153e5dd7070Spatrick }
154e5dd7070Spatrick 
getParentIgnoreParenImpCasts(Stmt * S) const155e5dd7070Spatrick Stmt *ParentMap::getParentIgnoreParenImpCasts(Stmt *S) const {
156e5dd7070Spatrick   do {
157e5dd7070Spatrick     S = getParent(S);
158e5dd7070Spatrick   } while (S && isa<Expr>(S) && cast<Expr>(S)->IgnoreParenImpCasts() != S);
159e5dd7070Spatrick 
160e5dd7070Spatrick   return S;
161e5dd7070Spatrick }
162e5dd7070Spatrick 
getOuterParenParent(Stmt * S) const163e5dd7070Spatrick Stmt *ParentMap::getOuterParenParent(Stmt *S) const {
164e5dd7070Spatrick   Stmt *Paren = nullptr;
165e5dd7070Spatrick   while (isa<ParenExpr>(S)) {
166e5dd7070Spatrick     Paren = S;
167e5dd7070Spatrick     S = getParent(S);
168e5dd7070Spatrick   };
169e5dd7070Spatrick   return Paren;
170e5dd7070Spatrick }
171e5dd7070Spatrick 
isConsumedExpr(Expr * E) const172e5dd7070Spatrick bool ParentMap::isConsumedExpr(Expr* E) const {
173e5dd7070Spatrick   Stmt *P = getParent(E);
174e5dd7070Spatrick   Stmt *DirectChild = E;
175e5dd7070Spatrick 
176e5dd7070Spatrick   // Ignore parents that don't guarantee consumption.
177e5dd7070Spatrick   while (P && (isa<ParenExpr>(P) || isa<CastExpr>(P) ||
178e5dd7070Spatrick                isa<FullExpr>(P))) {
179e5dd7070Spatrick     DirectChild = P;
180e5dd7070Spatrick     P = getParent(P);
181e5dd7070Spatrick   }
182e5dd7070Spatrick 
183e5dd7070Spatrick   if (!P)
184e5dd7070Spatrick     return false;
185e5dd7070Spatrick 
186e5dd7070Spatrick   switch (P->getStmtClass()) {
187e5dd7070Spatrick     default:
188e5dd7070Spatrick       return isa<Expr>(P);
189e5dd7070Spatrick     case Stmt::DeclStmtClass:
190e5dd7070Spatrick       return true;
191e5dd7070Spatrick     case Stmt::BinaryOperatorClass: {
192e5dd7070Spatrick       BinaryOperator *BE = cast<BinaryOperator>(P);
193e5dd7070Spatrick       // If it is a comma, only the right side is consumed.
194e5dd7070Spatrick       // If it isn't a comma, both sides are consumed.
195e5dd7070Spatrick       return BE->getOpcode()!=BO_Comma ||DirectChild==BE->getRHS();
196e5dd7070Spatrick     }
197e5dd7070Spatrick     case Stmt::ForStmtClass:
198e5dd7070Spatrick       return DirectChild == cast<ForStmt>(P)->getCond();
199e5dd7070Spatrick     case Stmt::WhileStmtClass:
200e5dd7070Spatrick       return DirectChild == cast<WhileStmt>(P)->getCond();
201e5dd7070Spatrick     case Stmt::DoStmtClass:
202e5dd7070Spatrick       return DirectChild == cast<DoStmt>(P)->getCond();
203e5dd7070Spatrick     case Stmt::IfStmtClass:
204e5dd7070Spatrick       return DirectChild == cast<IfStmt>(P)->getCond();
205e5dd7070Spatrick     case Stmt::IndirectGotoStmtClass:
206e5dd7070Spatrick       return DirectChild == cast<IndirectGotoStmt>(P)->getTarget();
207e5dd7070Spatrick     case Stmt::SwitchStmtClass:
208e5dd7070Spatrick       return DirectChild == cast<SwitchStmt>(P)->getCond();
209e5dd7070Spatrick     case Stmt::ObjCForCollectionStmtClass:
210e5dd7070Spatrick       return DirectChild == cast<ObjCForCollectionStmt>(P)->getCollection();
211e5dd7070Spatrick     case Stmt::ReturnStmtClass:
212e5dd7070Spatrick       return true;
213e5dd7070Spatrick   }
214e5dd7070Spatrick }
215e5dd7070Spatrick 
216