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