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 : public Stmt {
166 private:
167   // The location of the @ in the \@try.
168   SourceLocation AtTryLoc;
169 
170   // The number of catch blocks in this statement.
171   unsigned NumCatchStmts : 16;
172 
173   // Whether this statement has a \@finally statement.
174   bool HasFinally : 1;
175 
176   /// Retrieve the statements that are stored after this \@try statement.
177   ///
178   /// The order of the statements in memory follows the order in the source,
179   /// with the \@try body first, followed by the \@catch statements (if any)
180   /// and, finally, the \@finally (if it exists).
181   Stmt **getStmts() { return reinterpret_cast<Stmt **> (this + 1); }
182   const Stmt* const *getStmts() const {
183     return reinterpret_cast<const Stmt * const*> (this + 1);
184   }
185 
186   ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
187                 Stmt **CatchStmts, unsigned NumCatchStmts,
188                 Stmt *atFinallyStmt);
189 
190   explicit ObjCAtTryStmt(EmptyShell Empty, unsigned NumCatchStmts,
191                          bool HasFinally)
192     : Stmt(ObjCAtTryStmtClass, Empty), NumCatchStmts(NumCatchStmts),
193       HasFinally(HasFinally) { }
194 
195 public:
196   static ObjCAtTryStmt *Create(const ASTContext &Context,
197                                SourceLocation atTryLoc, Stmt *atTryStmt,
198                                Stmt **CatchStmts, unsigned NumCatchStmts,
199                                Stmt *atFinallyStmt);
200   static ObjCAtTryStmt *CreateEmpty(const ASTContext &Context,
201                                     unsigned NumCatchStmts, bool HasFinally);
202 
203   /// Retrieve the location of the @ in the \@try.
204   SourceLocation getAtTryLoc() const { return AtTryLoc; }
205   void setAtTryLoc(SourceLocation Loc) { AtTryLoc = Loc; }
206 
207   /// Retrieve the \@try body.
208   const Stmt *getTryBody() const { return getStmts()[0]; }
209   Stmt *getTryBody() { return getStmts()[0]; }
210   void setTryBody(Stmt *S) { getStmts()[0] = S; }
211 
212   /// Retrieve the number of \@catch statements in this try-catch-finally
213   /// block.
214   unsigned getNumCatchStmts() const { return NumCatchStmts; }
215 
216   /// Retrieve a \@catch statement.
217   const ObjCAtCatchStmt *getCatchStmt(unsigned I) const {
218     assert(I < NumCatchStmts && "Out-of-bounds @catch index");
219     return cast_or_null<ObjCAtCatchStmt>(getStmts()[I + 1]);
220   }
221 
222   /// Retrieve a \@catch statement.
223   ObjCAtCatchStmt *getCatchStmt(unsigned I) {
224     assert(I < NumCatchStmts && "Out-of-bounds @catch index");
225     return cast_or_null<ObjCAtCatchStmt>(getStmts()[I + 1]);
226   }
227 
228   /// Set a particular catch statement.
229   void setCatchStmt(unsigned I, ObjCAtCatchStmt *S) {
230     assert(I < NumCatchStmts && "Out-of-bounds @catch index");
231     getStmts()[I + 1] = S;
232   }
233 
234   /// Retrieve the \@finally statement, if any.
235   const ObjCAtFinallyStmt *getFinallyStmt() const {
236     if (!HasFinally)
237       return nullptr;
238 
239     return cast_or_null<ObjCAtFinallyStmt>(getStmts()[1 + NumCatchStmts]);
240   }
241   ObjCAtFinallyStmt *getFinallyStmt() {
242     if (!HasFinally)
243       return nullptr;
244 
245     return cast_or_null<ObjCAtFinallyStmt>(getStmts()[1 + NumCatchStmts]);
246   }
247   void setFinallyStmt(Stmt *S) {
248     assert(HasFinally && "@try does not have a @finally slot!");
249     getStmts()[1 + NumCatchStmts] = S;
250   }
251 
252   SourceLocation getBeginLoc() const LLVM_READONLY { return AtTryLoc; }
253   SourceLocation getEndLoc() const LLVM_READONLY;
254 
255   static bool classof(const Stmt *T) {
256     return T->getStmtClass() == ObjCAtTryStmtClass;
257   }
258 
259   child_range children() {
260     return child_range(getStmts(),
261                        getStmts() + 1 + NumCatchStmts + HasFinally);
262   }
263 
264   const_child_range children() const {
265     return const_child_range(const_cast<ObjCAtTryStmt *>(this)->children());
266   }
267 };
268 
269 /// Represents Objective-C's \@synchronized statement.
270 ///
271 /// Example:
272 /// \code
273 ///   @synchronized (sem) {
274 ///     do-something;
275 ///   }
276 /// \endcode
277 class ObjCAtSynchronizedStmt : public Stmt {
278 private:
279   SourceLocation AtSynchronizedLoc;
280   enum { SYNC_EXPR, SYNC_BODY, END_EXPR };
281   Stmt* SubStmts[END_EXPR];
282 
283 public:
284   ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Stmt *synchExpr,
285                          Stmt *synchBody)
286   : Stmt(ObjCAtSynchronizedStmtClass) {
287     SubStmts[SYNC_EXPR] = synchExpr;
288     SubStmts[SYNC_BODY] = synchBody;
289     AtSynchronizedLoc = atSynchronizedLoc;
290   }
291   explicit ObjCAtSynchronizedStmt(EmptyShell Empty) :
292     Stmt(ObjCAtSynchronizedStmtClass, Empty) { }
293 
294   SourceLocation getAtSynchronizedLoc() const { return AtSynchronizedLoc; }
295   void setAtSynchronizedLoc(SourceLocation Loc) { AtSynchronizedLoc = Loc; }
296 
297   const CompoundStmt *getSynchBody() const {
298     return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]);
299   }
300   CompoundStmt *getSynchBody() {
301     return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]);
302   }
303   void setSynchBody(Stmt *S) { SubStmts[SYNC_BODY] = S; }
304 
305   const Expr *getSynchExpr() const {
306     return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]);
307   }
308   Expr *getSynchExpr() {
309     return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]);
310   }
311   void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; }
312 
313   SourceLocation getBeginLoc() const LLVM_READONLY { return AtSynchronizedLoc; }
314   SourceLocation getEndLoc() const LLVM_READONLY {
315     return getSynchBody()->getEndLoc();
316   }
317 
318   static bool classof(const Stmt *T) {
319     return T->getStmtClass() == ObjCAtSynchronizedStmtClass;
320   }
321 
322   child_range children() {
323     return child_range(&SubStmts[0], &SubStmts[0]+END_EXPR);
324   }
325 
326   const_child_range children() const {
327     return const_child_range(&SubStmts[0], &SubStmts[0] + END_EXPR);
328   }
329 };
330 
331 /// Represents Objective-C's \@throw statement.
332 class ObjCAtThrowStmt : public Stmt {
333   SourceLocation AtThrowLoc;
334   Stmt *Throw;
335 
336 public:
337   ObjCAtThrowStmt(SourceLocation atThrowLoc, Stmt *throwExpr)
338   : Stmt(ObjCAtThrowStmtClass), Throw(throwExpr) {
339     AtThrowLoc = atThrowLoc;
340   }
341   explicit ObjCAtThrowStmt(EmptyShell Empty) :
342     Stmt(ObjCAtThrowStmtClass, Empty) { }
343 
344   const Expr *getThrowExpr() const { return reinterpret_cast<Expr*>(Throw); }
345   Expr *getThrowExpr() { return reinterpret_cast<Expr*>(Throw); }
346   void setThrowExpr(Stmt *S) { Throw = S; }
347 
348   SourceLocation getThrowLoc() const LLVM_READONLY { return AtThrowLoc; }
349   void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; }
350 
351   SourceLocation getBeginLoc() const LLVM_READONLY { return AtThrowLoc; }
352   SourceLocation getEndLoc() const LLVM_READONLY {
353     return Throw ? Throw->getEndLoc() : AtThrowLoc;
354   }
355 
356   static bool classof(const Stmt *T) {
357     return T->getStmtClass() == ObjCAtThrowStmtClass;
358   }
359 
360   child_range children() { return child_range(&Throw, &Throw+1); }
361 
362   const_child_range children() const {
363     return const_child_range(&Throw, &Throw + 1);
364   }
365 };
366 
367 /// Represents Objective-C's \@autoreleasepool Statement
368 class ObjCAutoreleasePoolStmt : public Stmt {
369   SourceLocation AtLoc;
370   Stmt *SubStmt;
371 
372 public:
373   ObjCAutoreleasePoolStmt(SourceLocation atLoc, Stmt *subStmt)
374       : Stmt(ObjCAutoreleasePoolStmtClass), AtLoc(atLoc), SubStmt(subStmt) {}
375 
376   explicit ObjCAutoreleasePoolStmt(EmptyShell Empty) :
377     Stmt(ObjCAutoreleasePoolStmtClass, Empty) { }
378 
379   const Stmt *getSubStmt() const { return SubStmt; }
380   Stmt *getSubStmt() { return SubStmt; }
381   void setSubStmt(Stmt *S) { SubStmt = S; }
382 
383   SourceLocation getBeginLoc() const LLVM_READONLY { return AtLoc; }
384   SourceLocation getEndLoc() const LLVM_READONLY {
385     return SubStmt->getEndLoc();
386   }
387 
388   SourceLocation getAtLoc() const { return AtLoc; }
389   void setAtLoc(SourceLocation Loc) { AtLoc = Loc; }
390 
391   static bool classof(const Stmt *T) {
392     return T->getStmtClass() == ObjCAutoreleasePoolStmtClass;
393   }
394 
395   child_range children() { return child_range(&SubStmt, &SubStmt + 1); }
396 
397   const_child_range children() const {
398     return const_child_range(&SubStmt, &SubStmt + 1);
399   }
400 };
401 
402 }  // end namespace clang
403 
404 #endif
405