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