1 | //===--- StmtObjC.h - Classes for representing ObjC statements --*- 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 | /// \file |
10 | /// Defines the Objective-C statement AST node classes. |
11 | |
12 | #ifndef LLVM_CLANG_AST_STMTOBJC_H |
13 | #define LLVM_CLANG_AST_STMTOBJC_H |
14 | |
15 | #include "clang/AST/Stmt.h" |
16 | #include "llvm/Support/Compiler.h" |
17 | |
18 | namespace clang { |
19 | |
20 | /// Represents Objective-C's collection statement. |
21 | /// |
22 | /// This is represented as 'for (element 'in' collection-expression)' stmt. |
23 | class ObjCForCollectionStmt : public Stmt { |
24 | enum { ELEM, COLLECTION, BODY, END_EXPR }; |
25 | Stmt* SubExprs[END_EXPR]; // SubExprs[ELEM] is an expression or declstmt. |
26 | SourceLocation ForLoc; |
27 | SourceLocation RParenLoc; |
28 | public: |
29 | ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, Stmt *Body, |
30 | SourceLocation FCL, SourceLocation RPL); |
31 | explicit ObjCForCollectionStmt(EmptyShell Empty) : |
32 | Stmt(ObjCForCollectionStmtClass, Empty) { } |
33 | |
34 | Stmt *getElement() { return SubExprs[ELEM]; } |
35 | Expr *getCollection() { |
36 | return reinterpret_cast<Expr*>(SubExprs[COLLECTION]); |
37 | } |
38 | Stmt *getBody() { return SubExprs[BODY]; } |
39 | |
40 | const Stmt *getElement() const { return SubExprs[ELEM]; } |
41 | const Expr *getCollection() const { |
42 | return reinterpret_cast<Expr*>(SubExprs[COLLECTION]); |
43 | } |
44 | const Stmt *getBody() const { return SubExprs[BODY]; } |
45 | |
46 | void setElement(Stmt *S) { SubExprs[ELEM] = S; } |
47 | void setCollection(Expr *E) { |
48 | SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(E); |
49 | } |
50 | void setBody(Stmt *S) { SubExprs[BODY] = S; } |
51 | |
52 | SourceLocation getForLoc() const { return ForLoc; } |
53 | void setForLoc(SourceLocation Loc) { ForLoc = Loc; } |
54 | SourceLocation getRParenLoc() const { return RParenLoc; } |
55 | void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } |
56 | |
57 | SourceLocation getBeginLoc() const LLVM_READONLY { return ForLoc; } |
58 | SourceLocation getEndLoc() const LLVM_READONLY { |
59 | return SubExprs[BODY]->getEndLoc(); |
60 | } |
61 | |
62 | static bool classof(const Stmt *T) { |
63 | return T->getStmtClass() == ObjCForCollectionStmtClass; |
64 | } |
65 | |
66 | // Iterators |
67 | child_range children() { |
68 | return child_range(&SubExprs[0], &SubExprs[END_EXPR]); |
69 | } |
70 | |
71 | const_child_range children() const { |
72 | return const_child_range(&SubExprs[0], &SubExprs[END_EXPR]); |
73 | } |
74 | }; |
75 | |
76 | /// Represents Objective-C's \@catch statement. |
77 | class ObjCAtCatchStmt : public Stmt { |
78 | private: |
79 | VarDecl *ExceptionDecl; |
80 | Stmt *Body; |
81 | SourceLocation AtCatchLoc, RParenLoc; |
82 | |
83 | public: |
84 | ObjCAtCatchStmt(SourceLocation atCatchLoc, SourceLocation rparenloc, |
85 | VarDecl *catchVarDecl, |
86 | Stmt *atCatchStmt) |
87 | : Stmt(ObjCAtCatchStmtClass), ExceptionDecl(catchVarDecl), |
88 | Body(atCatchStmt), AtCatchLoc(atCatchLoc), RParenLoc(rparenloc) { } |
89 | |
90 | explicit ObjCAtCatchStmt(EmptyShell Empty) : |
91 | Stmt(ObjCAtCatchStmtClass, Empty) { } |
92 | |
93 | const Stmt *getCatchBody() const { return Body; } |
94 | Stmt *getCatchBody() { return Body; } |
95 | void setCatchBody(Stmt *S) { Body = S; } |
96 | |
97 | const VarDecl *getCatchParamDecl() const { |
98 | return ExceptionDecl; |
99 | } |
100 | VarDecl *getCatchParamDecl() { |
101 | return ExceptionDecl; |
102 | } |
103 | void setCatchParamDecl(VarDecl *D) { ExceptionDecl = D; } |
104 | |
105 | SourceLocation getAtCatchLoc() const { return AtCatchLoc; } |
106 | void setAtCatchLoc(SourceLocation Loc) { AtCatchLoc = Loc; } |
107 | SourceLocation getRParenLoc() const { return RParenLoc; } |
108 | void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } |
109 | |
110 | SourceLocation getBeginLoc() const LLVM_READONLY { return AtCatchLoc; } |
111 | SourceLocation getEndLoc() const LLVM_READONLY { return Body->getEndLoc(); } |
112 | |
113 | bool hasEllipsis() const { return getCatchParamDecl() == nullptr; } |
114 | |
115 | static bool classof(const Stmt *T) { |
116 | return T->getStmtClass() == ObjCAtCatchStmtClass; |
117 | } |
118 | |
119 | child_range children() { return child_range(&Body, &Body + 1); } |
120 | |
121 | const_child_range children() const { |
122 | return const_child_range(&Body, &Body + 1); |
123 | } |
124 | }; |
125 | |
126 | /// Represents Objective-C's \@finally statement |
127 | class ObjCAtFinallyStmt : public Stmt { |
128 | SourceLocation AtFinallyLoc; |
129 | Stmt *AtFinallyStmt; |
130 | |
131 | public: |
132 | ObjCAtFinallyStmt(SourceLocation atFinallyLoc, Stmt *atFinallyStmt) |
133 | : Stmt(ObjCAtFinallyStmtClass), AtFinallyLoc(atFinallyLoc), |
134 | AtFinallyStmt(atFinallyStmt) {} |
135 | |
136 | explicit ObjCAtFinallyStmt(EmptyShell Empty) : |
137 | Stmt(ObjCAtFinallyStmtClass, Empty) { } |
138 | |
139 | const Stmt *getFinallyBody() const { return AtFinallyStmt; } |
140 | Stmt *getFinallyBody() { return AtFinallyStmt; } |
141 | void setFinallyBody(Stmt *S) { AtFinallyStmt = S; } |
142 | |
143 | SourceLocation getBeginLoc() const LLVM_READONLY { return AtFinallyLoc; } |
144 | SourceLocation getEndLoc() const LLVM_READONLY { |
145 | return AtFinallyStmt->getEndLoc(); |
146 | } |
147 | |
148 | SourceLocation getAtFinallyLoc() const { return AtFinallyLoc; } |
149 | void setAtFinallyLoc(SourceLocation Loc) { AtFinallyLoc = Loc; } |
150 | |
151 | static bool classof(const Stmt *T) { |
152 | return T->getStmtClass() == ObjCAtFinallyStmtClass; |
153 | } |
154 | |
155 | child_range children() { |
156 | return child_range(&AtFinallyStmt, &AtFinallyStmt+1); |
157 | } |
158 | |
159 | const_child_range children() const { |
160 | return const_child_range(&AtFinallyStmt, &AtFinallyStmt + 1); |
161 | } |
162 | }; |
163 | |
164 | /// Represents Objective-C's \@try ... \@catch ... \@finally statement. |
165 | class ObjCAtTryStmt final |
166 | : public Stmt, |
167 | private llvm::TrailingObjects<ObjCAtTryStmt, Stmt *> { |
168 | friend TrailingObjects; |
169 | size_t numTrailingObjects(OverloadToken<Stmt *>) const { |
170 | return 1 + NumCatchStmts + HasFinally; |
171 | } |
172 | |
173 | // The location of the @ in the \@try. |
174 | SourceLocation AtTryLoc; |
175 | |
176 | // The number of catch blocks in this statement. |
177 | unsigned NumCatchStmts : 16; |
178 | |
179 | // Whether this statement has a \@finally statement. |
180 | LLVM_PREFERRED_TYPE(bool) |
181 | unsigned HasFinally : 1; |
182 | |
183 | /// Retrieve the statements that are stored after this \@try statement. |
184 | /// |
185 | /// The order of the statements in memory follows the order in the source, |
186 | /// with the \@try body first, followed by the \@catch statements (if any) |
187 | /// and, finally, the \@finally (if it exists). |
188 | Stmt **getStmts() { return getTrailingObjects<Stmt *>(); } |
189 | Stmt *const *getStmts() const { return getTrailingObjects<Stmt *>(); } |
190 | |
191 | ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt, |
192 | Stmt **CatchStmts, unsigned NumCatchStmts, |
193 | Stmt *atFinallyStmt); |
194 | |
195 | explicit ObjCAtTryStmt(EmptyShell Empty, unsigned NumCatchStmts, |
196 | bool HasFinally) |
197 | : Stmt(ObjCAtTryStmtClass, Empty), NumCatchStmts(NumCatchStmts), |
198 | HasFinally(HasFinally) { } |
199 | |
200 | public: |
201 | static ObjCAtTryStmt *Create(const ASTContext &Context, |
202 | SourceLocation atTryLoc, Stmt *atTryStmt, |
203 | Stmt **CatchStmts, unsigned NumCatchStmts, |
204 | Stmt *atFinallyStmt); |
205 | static ObjCAtTryStmt *CreateEmpty(const ASTContext &Context, |
206 | unsigned NumCatchStmts, bool HasFinally); |
207 | |
208 | /// Retrieve the location of the @ in the \@try. |
209 | SourceLocation getAtTryLoc() const { return AtTryLoc; } |
210 | void setAtTryLoc(SourceLocation Loc) { AtTryLoc = Loc; } |
211 | |
212 | /// Retrieve the \@try body. |
213 | const Stmt *getTryBody() const { return getStmts()[0]; } |
214 | Stmt *getTryBody() { return getStmts()[0]; } |
215 | void setTryBody(Stmt *S) { getStmts()[0] = S; } |
216 | |
217 | /// Retrieve the number of \@catch statements in this try-catch-finally |
218 | /// block. |
219 | unsigned getNumCatchStmts() const { return NumCatchStmts; } |
220 | |
221 | /// Retrieve a \@catch statement. |
222 | const ObjCAtCatchStmt *getCatchStmt(unsigned I) const { |
223 | assert(I < NumCatchStmts && "Out-of-bounds @catch index" ); |
224 | return cast_or_null<ObjCAtCatchStmt>(Val: getStmts()[I + 1]); |
225 | } |
226 | |
227 | /// Retrieve a \@catch statement. |
228 | ObjCAtCatchStmt *getCatchStmt(unsigned I) { |
229 | assert(I < NumCatchStmts && "Out-of-bounds @catch index" ); |
230 | return cast_or_null<ObjCAtCatchStmt>(Val: getStmts()[I + 1]); |
231 | } |
232 | |
233 | /// Set a particular catch statement. |
234 | void setCatchStmt(unsigned I, ObjCAtCatchStmt *S) { |
235 | assert(I < NumCatchStmts && "Out-of-bounds @catch index" ); |
236 | getStmts()[I + 1] = S; |
237 | } |
238 | |
239 | /// Retrieve the \@finally statement, if any. |
240 | const ObjCAtFinallyStmt *getFinallyStmt() const { |
241 | if (!HasFinally) |
242 | return nullptr; |
243 | |
244 | return cast_or_null<ObjCAtFinallyStmt>(Val: getStmts()[1 + NumCatchStmts]); |
245 | } |
246 | ObjCAtFinallyStmt *getFinallyStmt() { |
247 | if (!HasFinally) |
248 | return nullptr; |
249 | |
250 | return cast_or_null<ObjCAtFinallyStmt>(Val: getStmts()[1 + NumCatchStmts]); |
251 | } |
252 | void setFinallyStmt(Stmt *S) { |
253 | assert(HasFinally && "@try does not have a @finally slot!" ); |
254 | getStmts()[1 + NumCatchStmts] = S; |
255 | } |
256 | |
257 | SourceLocation getBeginLoc() const LLVM_READONLY { return AtTryLoc; } |
258 | SourceLocation getEndLoc() const LLVM_READONLY; |
259 | |
260 | static bool classof(const Stmt *T) { |
261 | return T->getStmtClass() == ObjCAtTryStmtClass; |
262 | } |
263 | |
264 | child_range children() { |
265 | return child_range( |
266 | getStmts(), getStmts() + numTrailingObjects(OverloadToken<Stmt *>())); |
267 | } |
268 | |
269 | const_child_range children() const { |
270 | return const_child_range(const_cast<ObjCAtTryStmt *>(this)->children()); |
271 | } |
272 | |
273 | using catch_stmt_iterator = CastIterator<ObjCAtCatchStmt>; |
274 | using const_catch_stmt_iterator = ConstCastIterator<ObjCAtCatchStmt>; |
275 | using catch_range = llvm::iterator_range<catch_stmt_iterator>; |
276 | using catch_const_range = llvm::iterator_range<const_catch_stmt_iterator>; |
277 | |
278 | catch_stmt_iterator catch_stmts_begin() { return getStmts() + 1; } |
279 | catch_stmt_iterator catch_stmts_end() { |
280 | return catch_stmts_begin() + NumCatchStmts; |
281 | } |
282 | catch_range catch_stmts() { |
283 | return catch_range(catch_stmts_begin(), catch_stmts_end()); |
284 | } |
285 | |
286 | const_catch_stmt_iterator catch_stmts_begin() const { return getStmts() + 1; } |
287 | const_catch_stmt_iterator catch_stmts_end() const { |
288 | return catch_stmts_begin() + NumCatchStmts; |
289 | } |
290 | catch_const_range catch_stmts() const { |
291 | return catch_const_range(catch_stmts_begin(), catch_stmts_end()); |
292 | } |
293 | }; |
294 | |
295 | /// Represents Objective-C's \@synchronized statement. |
296 | /// |
297 | /// Example: |
298 | /// \code |
299 | /// @synchronized (sem) { |
300 | /// do-something; |
301 | /// } |
302 | /// \endcode |
303 | class ObjCAtSynchronizedStmt : public Stmt { |
304 | private: |
305 | SourceLocation AtSynchronizedLoc; |
306 | enum { SYNC_EXPR, SYNC_BODY, END_EXPR }; |
307 | Stmt* SubStmts[END_EXPR]; |
308 | |
309 | public: |
310 | ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Stmt *synchExpr, |
311 | Stmt *synchBody) |
312 | : Stmt(ObjCAtSynchronizedStmtClass) { |
313 | SubStmts[SYNC_EXPR] = synchExpr; |
314 | SubStmts[SYNC_BODY] = synchBody; |
315 | AtSynchronizedLoc = atSynchronizedLoc; |
316 | } |
317 | explicit ObjCAtSynchronizedStmt(EmptyShell Empty) : |
318 | Stmt(ObjCAtSynchronizedStmtClass, Empty) { } |
319 | |
320 | SourceLocation getAtSynchronizedLoc() const { return AtSynchronizedLoc; } |
321 | void setAtSynchronizedLoc(SourceLocation Loc) { AtSynchronizedLoc = Loc; } |
322 | |
323 | const CompoundStmt *getSynchBody() const { |
324 | return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]); |
325 | } |
326 | CompoundStmt *getSynchBody() { |
327 | return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]); |
328 | } |
329 | void setSynchBody(Stmt *S) { SubStmts[SYNC_BODY] = S; } |
330 | |
331 | const Expr *getSynchExpr() const { |
332 | return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]); |
333 | } |
334 | Expr *getSynchExpr() { |
335 | return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]); |
336 | } |
337 | void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; } |
338 | |
339 | SourceLocation getBeginLoc() const LLVM_READONLY { return AtSynchronizedLoc; } |
340 | SourceLocation getEndLoc() const LLVM_READONLY { |
341 | return getSynchBody()->getEndLoc(); |
342 | } |
343 | |
344 | static bool classof(const Stmt *T) { |
345 | return T->getStmtClass() == ObjCAtSynchronizedStmtClass; |
346 | } |
347 | |
348 | child_range children() { |
349 | return child_range(&SubStmts[0], &SubStmts[0]+END_EXPR); |
350 | } |
351 | |
352 | const_child_range children() const { |
353 | return const_child_range(&SubStmts[0], &SubStmts[0] + END_EXPR); |
354 | } |
355 | }; |
356 | |
357 | /// Represents Objective-C's \@throw statement. |
358 | class ObjCAtThrowStmt : public Stmt { |
359 | SourceLocation AtThrowLoc; |
360 | Stmt *Throw; |
361 | |
362 | public: |
363 | ObjCAtThrowStmt(SourceLocation atThrowLoc, Stmt *throwExpr) |
364 | : Stmt(ObjCAtThrowStmtClass), Throw(throwExpr) { |
365 | AtThrowLoc = atThrowLoc; |
366 | } |
367 | explicit ObjCAtThrowStmt(EmptyShell Empty) : |
368 | Stmt(ObjCAtThrowStmtClass, Empty) { } |
369 | |
370 | const Expr *getThrowExpr() const { return reinterpret_cast<Expr*>(Throw); } |
371 | Expr *getThrowExpr() { return reinterpret_cast<Expr*>(Throw); } |
372 | void setThrowExpr(Stmt *S) { Throw = S; } |
373 | |
374 | SourceLocation getThrowLoc() const LLVM_READONLY { return AtThrowLoc; } |
375 | void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; } |
376 | |
377 | SourceLocation getBeginLoc() const LLVM_READONLY { return AtThrowLoc; } |
378 | SourceLocation getEndLoc() const LLVM_READONLY { |
379 | return Throw ? Throw->getEndLoc() : AtThrowLoc; |
380 | } |
381 | |
382 | static bool classof(const Stmt *T) { |
383 | return T->getStmtClass() == ObjCAtThrowStmtClass; |
384 | } |
385 | |
386 | child_range children() { return child_range(&Throw, &Throw+1); } |
387 | |
388 | const_child_range children() const { |
389 | return const_child_range(&Throw, &Throw + 1); |
390 | } |
391 | }; |
392 | |
393 | /// Represents Objective-C's \@autoreleasepool Statement |
394 | class ObjCAutoreleasePoolStmt : public Stmt { |
395 | SourceLocation AtLoc; |
396 | Stmt *SubStmt; |
397 | |
398 | public: |
399 | ObjCAutoreleasePoolStmt(SourceLocation atLoc, Stmt *subStmt) |
400 | : Stmt(ObjCAutoreleasePoolStmtClass), AtLoc(atLoc), SubStmt(subStmt) {} |
401 | |
402 | explicit ObjCAutoreleasePoolStmt(EmptyShell Empty) : |
403 | Stmt(ObjCAutoreleasePoolStmtClass, Empty) { } |
404 | |
405 | const Stmt *getSubStmt() const { return SubStmt; } |
406 | Stmt *getSubStmt() { return SubStmt; } |
407 | void setSubStmt(Stmt *S) { SubStmt = S; } |
408 | |
409 | SourceLocation getBeginLoc() const LLVM_READONLY { return AtLoc; } |
410 | SourceLocation getEndLoc() const LLVM_READONLY { |
411 | return SubStmt->getEndLoc(); |
412 | } |
413 | |
414 | SourceLocation getAtLoc() const { return AtLoc; } |
415 | void setAtLoc(SourceLocation Loc) { AtLoc = Loc; } |
416 | |
417 | static bool classof(const Stmt *T) { |
418 | return T->getStmtClass() == ObjCAutoreleasePoolStmtClass; |
419 | } |
420 | |
421 | child_range children() { return child_range(&SubStmt, &SubStmt + 1); } |
422 | |
423 | const_child_range children() const { |
424 | return const_child_range(&SubStmt, &SubStmt + 1); |
425 | } |
426 | }; |
427 | |
428 | } // end namespace clang |
429 | |
430 | #endif |
431 | |