| //===--- ExprObjC.h - Classes for representing ObjC expressions -*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the ExprObjC interface and subclasses. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_AST_EXPROBJC_H |
| #define LLVM_CLANG_AST_EXPROBJC_H |
| |
| #include "clang/AST/DeclObjC.h" |
| #include "clang/AST/Expr.h" |
| #include "clang/AST/SelectorLocationsKind.h" |
| #include "clang/Basic/IdentifierTable.h" |
| #include "llvm/Support/Compiler.h" |
| |
| namespace clang { |
| class IdentifierInfo; |
| class ASTContext; |
| |
| /// ObjCStringLiteral, used for Objective-C string literals |
| /// i.e. @"foo". |
| class ObjCStringLiteral : public Expr { |
| Stmt *String; |
| SourceLocation AtLoc; |
| public: |
| ObjCStringLiteral(StringLiteral *SL, QualType T, SourceLocation L) |
| : Expr(ObjCStringLiteralClass, T, VK_RValue, OK_Ordinary, false, false, |
| false, false), |
| String(SL), AtLoc(L) {} |
| explicit ObjCStringLiteral(EmptyShell Empty) |
| : Expr(ObjCStringLiteralClass, Empty) {} |
| |
| StringLiteral *getString() { return cast<StringLiteral>(String); } |
| const StringLiteral *getString() const { return cast<StringLiteral>(String); } |
| void setString(StringLiteral *S) { String = S; } |
| |
| SourceLocation getAtLoc() const { return AtLoc; } |
| void setAtLoc(SourceLocation L) { AtLoc = L; } |
| |
| SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } |
| SourceLocation getLocEnd() const LLVM_READONLY { return String->getLocEnd(); } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCStringLiteralClass; |
| } |
| |
| // Iterators |
| child_range children() { return child_range(&String, &String+1); } |
| }; |
| |
| /// ObjCBoolLiteralExpr - Objective-C Boolean Literal. |
| /// |
| class ObjCBoolLiteralExpr : public Expr { |
| bool Value; |
| SourceLocation Loc; |
| public: |
| ObjCBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) : |
| Expr(ObjCBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, |
| false, false), Value(val), Loc(l) {} |
| |
| explicit ObjCBoolLiteralExpr(EmptyShell Empty) |
| : Expr(ObjCBoolLiteralExprClass, Empty) { } |
| |
| bool getValue() const { return Value; } |
| void setValue(bool V) { Value = V; } |
| |
| SourceLocation getLocStart() const LLVM_READONLY { return Loc; } |
| SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } |
| |
| SourceLocation getLocation() const { return Loc; } |
| void setLocation(SourceLocation L) { Loc = L; } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCBoolLiteralExprClass; |
| } |
| |
| // Iterators |
| child_range children() { |
| return child_range(child_iterator(), child_iterator()); |
| } |
| }; |
| |
| /// ObjCBoxedExpr - used for generalized expression boxing. |
| /// as in: @(strdup("hello world")), @(random()) or @(view.frame) |
| /// Also used for boxing non-parenthesized numeric literals; |
| /// as in: @42 or \@true (c++/objc++) or \@__yes (c/objc). |
| class ObjCBoxedExpr : public Expr { |
| Stmt *SubExpr; |
| ObjCMethodDecl *BoxingMethod; |
| SourceRange Range; |
| public: |
| ObjCBoxedExpr(Expr *E, QualType T, ObjCMethodDecl *method, |
| SourceRange R) |
| : Expr(ObjCBoxedExprClass, T, VK_RValue, OK_Ordinary, |
| E->isTypeDependent(), E->isValueDependent(), |
| E->isInstantiationDependent(), E->containsUnexpandedParameterPack()), |
| SubExpr(E), BoxingMethod(method), Range(R) {} |
| explicit ObjCBoxedExpr(EmptyShell Empty) |
| : Expr(ObjCBoxedExprClass, Empty) {} |
| |
| Expr *getSubExpr() { return cast<Expr>(SubExpr); } |
| const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } |
| |
| ObjCMethodDecl *getBoxingMethod() const { |
| return BoxingMethod; |
| } |
| |
| SourceLocation getAtLoc() const { return Range.getBegin(); } |
| |
| SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } |
| SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } |
| SourceRange getSourceRange() const LLVM_READONLY { |
| return Range; |
| } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCBoxedExprClass; |
| } |
| |
| // Iterators |
| child_range children() { return child_range(&SubExpr, &SubExpr+1); } |
| |
| typedef ConstExprIterator const_arg_iterator; |
| |
| const_arg_iterator arg_begin() const { |
| return reinterpret_cast<Stmt const * const*>(&SubExpr); |
| } |
| const_arg_iterator arg_end() const { |
| return reinterpret_cast<Stmt const * const*>(&SubExpr + 1); |
| } |
| |
| friend class ASTStmtReader; |
| }; |
| |
| /// ObjCArrayLiteral - used for objective-c array containers; as in: |
| /// @[@"Hello", NSApp, [NSNumber numberWithInt:42]]; |
| class ObjCArrayLiteral final |
| : public Expr, |
| private llvm::TrailingObjects<ObjCArrayLiteral, Expr *> { |
| unsigned NumElements; |
| SourceRange Range; |
| ObjCMethodDecl *ArrayWithObjectsMethod; |
| |
| ObjCArrayLiteral(ArrayRef<Expr *> Elements, |
| QualType T, ObjCMethodDecl * Method, |
| SourceRange SR); |
| |
| explicit ObjCArrayLiteral(EmptyShell Empty, unsigned NumElements) |
| : Expr(ObjCArrayLiteralClass, Empty), NumElements(NumElements) {} |
| |
| public: |
| static ObjCArrayLiteral *Create(const ASTContext &C, |
| ArrayRef<Expr *> Elements, |
| QualType T, ObjCMethodDecl * Method, |
| SourceRange SR); |
| |
| static ObjCArrayLiteral *CreateEmpty(const ASTContext &C, |
| unsigned NumElements); |
| |
| SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } |
| SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } |
| SourceRange getSourceRange() const LLVM_READONLY { return Range; } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCArrayLiteralClass; |
| } |
| |
| /// \brief Retrieve elements of array of literals. |
| Expr **getElements() { return getTrailingObjects<Expr *>(); } |
| |
| /// \brief Retrieve elements of array of literals. |
| const Expr * const *getElements() const { |
| return getTrailingObjects<Expr *>(); |
| } |
| |
| /// getNumElements - Return number of elements of objective-c array literal. |
| unsigned getNumElements() const { return NumElements; } |
| |
| /// getExpr - Return the Expr at the specified index. |
| Expr *getElement(unsigned Index) { |
| assert((Index < NumElements) && "Arg access out of range!"); |
| return cast<Expr>(getElements()[Index]); |
| } |
| const Expr *getElement(unsigned Index) const { |
| assert((Index < NumElements) && "Arg access out of range!"); |
| return cast<Expr>(getElements()[Index]); |
| } |
| |
| ObjCMethodDecl *getArrayWithObjectsMethod() const { |
| return ArrayWithObjectsMethod; |
| } |
| |
| // Iterators |
| child_range children() { |
| return child_range(reinterpret_cast<Stmt **>(getElements()), |
| reinterpret_cast<Stmt **>(getElements()) + NumElements); |
| } |
| |
| friend TrailingObjects; |
| friend class ASTStmtReader; |
| }; |
| |
| /// \brief An element in an Objective-C dictionary literal. |
| /// |
| struct ObjCDictionaryElement { |
| /// \brief The key for the dictionary element. |
| Expr *Key; |
| |
| /// \brief The value of the dictionary element. |
| Expr *Value; |
| |
| /// \brief The location of the ellipsis, if this is a pack expansion. |
| SourceLocation EllipsisLoc; |
| |
| /// \brief The number of elements this pack expansion will expand to, if |
| /// this is a pack expansion and is known. |
| Optional<unsigned> NumExpansions; |
| |
| /// \brief Determines whether this dictionary element is a pack expansion. |
| bool isPackExpansion() const { return EllipsisLoc.isValid(); } |
| }; |
| } // end namespace clang |
| |
| namespace llvm { |
| template <> struct isPodLike<clang::ObjCDictionaryElement> : std::true_type {}; |
| } |
| |
| namespace clang { |
| /// \brief Internal struct for storing Key/value pair. |
| struct ObjCDictionaryLiteral_KeyValuePair { |
| Expr *Key; |
| Expr *Value; |
| }; |
| |
| /// \brief Internal struct to describes an element that is a pack |
| /// expansion, used if any of the elements in the dictionary literal |
| /// are pack expansions. |
| struct ObjCDictionaryLiteral_ExpansionData { |
| /// \brief The location of the ellipsis, if this element is a pack |
| /// expansion. |
| SourceLocation EllipsisLoc; |
| |
| /// \brief If non-zero, the number of elements that this pack |
| /// expansion will expand to (+1). |
| unsigned NumExpansionsPlusOne; |
| }; |
| |
| /// ObjCDictionaryLiteral - AST node to represent objective-c dictionary |
| /// literals; as in: @{@"name" : NSUserName(), @"date" : [NSDate date] }; |
| class ObjCDictionaryLiteral final |
| : public Expr, |
| private llvm::TrailingObjects<ObjCDictionaryLiteral, |
| ObjCDictionaryLiteral_KeyValuePair, |
| ObjCDictionaryLiteral_ExpansionData> { |
| /// \brief The number of elements in this dictionary literal. |
| unsigned NumElements : 31; |
| |
| /// \brief Determine whether this dictionary literal has any pack expansions. |
| /// |
| /// If the dictionary literal has pack expansions, then there will |
| /// be an array of pack expansion data following the array of |
| /// key/value pairs, which provide the locations of the ellipses (if |
| /// any) and number of elements in the expansion (if known). If |
| /// there are no pack expansions, we optimize away this storage. |
| unsigned HasPackExpansions : 1; |
| |
| SourceRange Range; |
| ObjCMethodDecl *DictWithObjectsMethod; |
| |
| typedef ObjCDictionaryLiteral_KeyValuePair KeyValuePair; |
| typedef ObjCDictionaryLiteral_ExpansionData ExpansionData; |
| |
| size_t numTrailingObjects(OverloadToken<KeyValuePair>) const { |
| return NumElements; |
| } |
| |
| ObjCDictionaryLiteral(ArrayRef<ObjCDictionaryElement> VK, |
| bool HasPackExpansions, |
| QualType T, ObjCMethodDecl *method, |
| SourceRange SR); |
| |
| explicit ObjCDictionaryLiteral(EmptyShell Empty, unsigned NumElements, |
| bool HasPackExpansions) |
| : Expr(ObjCDictionaryLiteralClass, Empty), NumElements(NumElements), |
| HasPackExpansions(HasPackExpansions) {} |
| |
| public: |
| static ObjCDictionaryLiteral *Create(const ASTContext &C, |
| ArrayRef<ObjCDictionaryElement> VK, |
| bool HasPackExpansions, |
| QualType T, ObjCMethodDecl *method, |
| SourceRange SR); |
| |
| static ObjCDictionaryLiteral *CreateEmpty(const ASTContext &C, |
| unsigned NumElements, |
| bool HasPackExpansions); |
| |
| /// getNumElements - Return number of elements of objective-c dictionary |
| /// literal. |
| unsigned getNumElements() const { return NumElements; } |
| |
| ObjCDictionaryElement getKeyValueElement(unsigned Index) const { |
| assert((Index < NumElements) && "Arg access out of range!"); |
| const KeyValuePair &KV = getTrailingObjects<KeyValuePair>()[Index]; |
| ObjCDictionaryElement Result = { KV.Key, KV.Value, SourceLocation(), None }; |
| if (HasPackExpansions) { |
| const ExpansionData &Expansion = |
| getTrailingObjects<ExpansionData>()[Index]; |
| Result.EllipsisLoc = Expansion.EllipsisLoc; |
| if (Expansion.NumExpansionsPlusOne > 0) |
| Result.NumExpansions = Expansion.NumExpansionsPlusOne - 1; |
| } |
| return Result; |
| } |
| |
| ObjCMethodDecl *getDictWithObjectsMethod() const |
| { return DictWithObjectsMethod; } |
| |
| SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } |
| SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } |
| SourceRange getSourceRange() const LLVM_READONLY { return Range; } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCDictionaryLiteralClass; |
| } |
| |
| // Iterators |
| child_range children() { |
| // Note: we're taking advantage of the layout of the KeyValuePair struct |
| // here. If that struct changes, this code will need to change as well. |
| static_assert(sizeof(KeyValuePair) == sizeof(Stmt *) * 2, |
| "KeyValuePair is expected size"); |
| return child_range( |
| reinterpret_cast<Stmt **>(getTrailingObjects<KeyValuePair>()), |
| reinterpret_cast<Stmt **>(getTrailingObjects<KeyValuePair>()) + |
| NumElements * 2); |
| } |
| |
| friend class ASTStmtReader; |
| friend class ASTStmtWriter; |
| friend TrailingObjects; |
| }; |
| |
| |
| /// ObjCEncodeExpr, used for \@encode in Objective-C. \@encode has the same |
| /// type and behavior as StringLiteral except that the string initializer is |
| /// obtained from ASTContext with the encoding type as an argument. |
| class ObjCEncodeExpr : public Expr { |
| TypeSourceInfo *EncodedType; |
| SourceLocation AtLoc, RParenLoc; |
| public: |
| ObjCEncodeExpr(QualType T, TypeSourceInfo *EncodedType, |
| SourceLocation at, SourceLocation rp) |
| : Expr(ObjCEncodeExprClass, T, VK_LValue, OK_Ordinary, |
| EncodedType->getType()->isDependentType(), |
| EncodedType->getType()->isDependentType(), |
| EncodedType->getType()->isInstantiationDependentType(), |
| EncodedType->getType()->containsUnexpandedParameterPack()), |
| EncodedType(EncodedType), AtLoc(at), RParenLoc(rp) {} |
| |
| explicit ObjCEncodeExpr(EmptyShell Empty) : Expr(ObjCEncodeExprClass, Empty){} |
| |
| |
| SourceLocation getAtLoc() const { return AtLoc; } |
| void setAtLoc(SourceLocation L) { AtLoc = L; } |
| SourceLocation getRParenLoc() const { return RParenLoc; } |
| void setRParenLoc(SourceLocation L) { RParenLoc = L; } |
| |
| QualType getEncodedType() const { return EncodedType->getType(); } |
| |
| TypeSourceInfo *getEncodedTypeSourceInfo() const { return EncodedType; } |
| void setEncodedTypeSourceInfo(TypeSourceInfo *EncType) { |
| EncodedType = EncType; |
| } |
| |
| SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } |
| SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCEncodeExprClass; |
| } |
| |
| // Iterators |
| child_range children() { |
| return child_range(child_iterator(), child_iterator()); |
| } |
| }; |
| |
| /// ObjCSelectorExpr used for \@selector in Objective-C. |
| class ObjCSelectorExpr : public Expr { |
| Selector SelName; |
| SourceLocation AtLoc, RParenLoc; |
| public: |
| ObjCSelectorExpr(QualType T, Selector selInfo, |
| SourceLocation at, SourceLocation rp) |
| : Expr(ObjCSelectorExprClass, T, VK_RValue, OK_Ordinary, false, false, |
| false, false), |
| SelName(selInfo), AtLoc(at), RParenLoc(rp){} |
| explicit ObjCSelectorExpr(EmptyShell Empty) |
| : Expr(ObjCSelectorExprClass, Empty) {} |
| |
| Selector getSelector() const { return SelName; } |
| void setSelector(Selector S) { SelName = S; } |
| |
| SourceLocation getAtLoc() const { return AtLoc; } |
| SourceLocation getRParenLoc() const { return RParenLoc; } |
| void setAtLoc(SourceLocation L) { AtLoc = L; } |
| void setRParenLoc(SourceLocation L) { RParenLoc = L; } |
| |
| SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } |
| SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } |
| |
| /// getNumArgs - Return the number of actual arguments to this call. |
| unsigned getNumArgs() const { return SelName.getNumArgs(); } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCSelectorExprClass; |
| } |
| |
| // Iterators |
| child_range children() { |
| return child_range(child_iterator(), child_iterator()); |
| } |
| }; |
| |
| /// ObjCProtocolExpr used for protocol expression in Objective-C. |
| /// |
| /// This is used as: \@protocol(foo), as in: |
| /// \code |
| /// [obj conformsToProtocol:@protocol(foo)] |
| /// \endcode |
| /// |
| /// The return type is "Protocol*". |
| class ObjCProtocolExpr : public Expr { |
| ObjCProtocolDecl *TheProtocol; |
| SourceLocation AtLoc, ProtoLoc, RParenLoc; |
| public: |
| ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol, |
| SourceLocation at, SourceLocation protoLoc, SourceLocation rp) |
| : Expr(ObjCProtocolExprClass, T, VK_RValue, OK_Ordinary, false, false, |
| false, false), |
| TheProtocol(protocol), AtLoc(at), ProtoLoc(protoLoc), RParenLoc(rp) {} |
| explicit ObjCProtocolExpr(EmptyShell Empty) |
| : Expr(ObjCProtocolExprClass, Empty) {} |
| |
| ObjCProtocolDecl *getProtocol() const { return TheProtocol; } |
| void setProtocol(ObjCProtocolDecl *P) { TheProtocol = P; } |
| |
| SourceLocation getProtocolIdLoc() const { return ProtoLoc; } |
| SourceLocation getAtLoc() const { return AtLoc; } |
| SourceLocation getRParenLoc() const { return RParenLoc; } |
| void setAtLoc(SourceLocation L) { AtLoc = L; } |
| void setRParenLoc(SourceLocation L) { RParenLoc = L; } |
| |
| SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } |
| SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCProtocolExprClass; |
| } |
| |
| // Iterators |
| child_range children() { |
| return child_range(child_iterator(), child_iterator()); |
| } |
| |
| friend class ASTStmtReader; |
| friend class ASTStmtWriter; |
| }; |
| |
| /// ObjCIvarRefExpr - A reference to an ObjC instance variable. |
| class ObjCIvarRefExpr : public Expr { |
| ObjCIvarDecl *D; |
| Stmt *Base; |
| SourceLocation Loc; |
| /// OpLoc - This is the location of '.' or '->' |
| SourceLocation OpLoc; |
| |
| bool IsArrow:1; // True if this is "X->F", false if this is "X.F". |
| bool IsFreeIvar:1; // True if ivar reference has no base (self assumed). |
| |
| public: |
| ObjCIvarRefExpr(ObjCIvarDecl *d, QualType t, |
| SourceLocation l, SourceLocation oploc, |
| Expr *base, |
| bool arrow = false, bool freeIvar = false) : |
| Expr(ObjCIvarRefExprClass, t, VK_LValue, |
| d->isBitField() ? OK_BitField : OK_Ordinary, |
| /*TypeDependent=*/false, base->isValueDependent(), |
| base->isInstantiationDependent(), |
| base->containsUnexpandedParameterPack()), |
| D(d), Base(base), Loc(l), OpLoc(oploc), |
| IsArrow(arrow), IsFreeIvar(freeIvar) {} |
| |
| explicit ObjCIvarRefExpr(EmptyShell Empty) |
| : Expr(ObjCIvarRefExprClass, Empty) {} |
| |
| ObjCIvarDecl *getDecl() { return D; } |
| const ObjCIvarDecl *getDecl() const { return D; } |
| void setDecl(ObjCIvarDecl *d) { D = d; } |
| |
| const Expr *getBase() const { return cast<Expr>(Base); } |
| Expr *getBase() { return cast<Expr>(Base); } |
| void setBase(Expr * base) { Base = base; } |
| |
| bool isArrow() const { return IsArrow; } |
| bool isFreeIvar() const { return IsFreeIvar; } |
| void setIsArrow(bool A) { IsArrow = A; } |
| void setIsFreeIvar(bool A) { IsFreeIvar = A; } |
| |
| SourceLocation getLocation() const { return Loc; } |
| void setLocation(SourceLocation L) { Loc = L; } |
| |
| SourceLocation getLocStart() const LLVM_READONLY { |
| return isFreeIvar() ? Loc : getBase()->getLocStart(); |
| } |
| SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } |
| |
| SourceLocation getOpLoc() const { return OpLoc; } |
| void setOpLoc(SourceLocation L) { OpLoc = L; } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCIvarRefExprClass; |
| } |
| |
| // Iterators |
| child_range children() { return child_range(&Base, &Base+1); } |
| }; |
| |
| /// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC |
| /// property. |
| class ObjCPropertyRefExpr : public Expr { |
| private: |
| /// If the bool is true, this is an implicit property reference; the |
| /// pointer is an (optional) ObjCMethodDecl and Setter may be set. |
| /// if the bool is false, this is an explicit property reference; |
| /// the pointer is an ObjCPropertyDecl and Setter is always null. |
| llvm::PointerIntPair<NamedDecl*, 1, bool> PropertyOrGetter; |
| |
| /// \brief Indicates whether the property reference will result in a message |
| /// to the getter, the setter, or both. |
| /// This applies to both implicit and explicit property references. |
| enum MethodRefFlags { |
| MethodRef_None = 0, |
| MethodRef_Getter = 0x1, |
| MethodRef_Setter = 0x2 |
| }; |
| |
| /// \brief Contains the Setter method pointer and MethodRefFlags bit flags. |
| llvm::PointerIntPair<ObjCMethodDecl *, 2, unsigned> SetterAndMethodRefFlags; |
| |
| // FIXME: Maybe we should store the property identifier here, |
| // because it's not rederivable from the other data when there's an |
| // implicit property with no getter (because the 'foo' -> 'setFoo:' |
| // transformation is lossy on the first character). |
| |
| SourceLocation IdLoc; |
| |
| /// \brief When the receiver in property access is 'super', this is |
| /// the location of the 'super' keyword. When it's an interface, |
| /// this is that interface. |
| SourceLocation ReceiverLoc; |
| llvm::PointerUnion3<Stmt*, const Type*, ObjCInterfaceDecl*> Receiver; |
| |
| public: |
| ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, |
| ExprValueKind VK, ExprObjectKind OK, |
| SourceLocation l, Expr *base) |
| : Expr(ObjCPropertyRefExprClass, t, VK, OK, |
| /*TypeDependent=*/false, base->isValueDependent(), |
| base->isInstantiationDependent(), |
| base->containsUnexpandedParameterPack()), |
| PropertyOrGetter(PD, false), SetterAndMethodRefFlags(), |
| IdLoc(l), ReceiverLoc(), Receiver(base) { |
| assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject)); |
| } |
| |
| ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, |
| ExprValueKind VK, ExprObjectKind OK, |
| SourceLocation l, SourceLocation sl, QualType st) |
| : Expr(ObjCPropertyRefExprClass, t, VK, OK, |
| /*TypeDependent=*/false, false, st->isInstantiationDependentType(), |
| st->containsUnexpandedParameterPack()), |
| PropertyOrGetter(PD, false), SetterAndMethodRefFlags(), |
| IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) { |
| assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject)); |
| } |
| |
| ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, |
| QualType T, ExprValueKind VK, ExprObjectKind OK, |
| SourceLocation IdLoc, Expr *Base) |
| : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, |
| Base->isValueDependent(), Base->isInstantiationDependent(), |
| Base->containsUnexpandedParameterPack()), |
| PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), |
| IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) { |
| assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); |
| } |
| |
| ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, |
| QualType T, ExprValueKind VK, ExprObjectKind OK, |
| SourceLocation IdLoc, |
| SourceLocation SuperLoc, QualType SuperTy) |
| : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), |
| PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), |
| IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) { |
| assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); |
| } |
| |
| ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, |
| QualType T, ExprValueKind VK, ExprObjectKind OK, |
| SourceLocation IdLoc, |
| SourceLocation ReceiverLoc, ObjCInterfaceDecl *Receiver) |
| : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), |
| PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), |
| IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) { |
| assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); |
| } |
| |
| explicit ObjCPropertyRefExpr(EmptyShell Empty) |
| : Expr(ObjCPropertyRefExprClass, Empty) {} |
| |
| bool isImplicitProperty() const { return PropertyOrGetter.getInt(); } |
| bool isExplicitProperty() const { return !PropertyOrGetter.getInt(); } |
| |
| ObjCPropertyDecl *getExplicitProperty() const { |
| assert(!isImplicitProperty()); |
| return cast<ObjCPropertyDecl>(PropertyOrGetter.getPointer()); |
| } |
| |
| ObjCMethodDecl *getImplicitPropertyGetter() const { |
| assert(isImplicitProperty()); |
| return cast_or_null<ObjCMethodDecl>(PropertyOrGetter.getPointer()); |
| } |
| |
| ObjCMethodDecl *getImplicitPropertySetter() const { |
| assert(isImplicitProperty()); |
| return SetterAndMethodRefFlags.getPointer(); |
| } |
| |
| Selector getGetterSelector() const { |
| if (isImplicitProperty()) |
| return getImplicitPropertyGetter()->getSelector(); |
| return getExplicitProperty()->getGetterName(); |
| } |
| |
| Selector getSetterSelector() const { |
| if (isImplicitProperty()) |
| return getImplicitPropertySetter()->getSelector(); |
| return getExplicitProperty()->getSetterName(); |
| } |
| |
| /// \brief True if the property reference will result in a message to the |
| /// getter. |
| /// This applies to both implicit and explicit property references. |
| bool isMessagingGetter() const { |
| return SetterAndMethodRefFlags.getInt() & MethodRef_Getter; |
| } |
| |
| /// \brief True if the property reference will result in a message to the |
| /// setter. |
| /// This applies to both implicit and explicit property references. |
| bool isMessagingSetter() const { |
| return SetterAndMethodRefFlags.getInt() & MethodRef_Setter; |
| } |
| |
| void setIsMessagingGetter(bool val = true) { |
| setMethodRefFlag(MethodRef_Getter, val); |
| } |
| |
| void setIsMessagingSetter(bool val = true) { |
| setMethodRefFlag(MethodRef_Setter, val); |
| } |
| |
| const Expr *getBase() const { |
| return cast<Expr>(Receiver.get<Stmt*>()); |
| } |
| Expr *getBase() { |
| return cast<Expr>(Receiver.get<Stmt*>()); |
| } |
| |
| SourceLocation getLocation() const { return IdLoc; } |
| |
| SourceLocation getReceiverLocation() const { return ReceiverLoc; } |
| QualType getSuperReceiverType() const { |
| return QualType(Receiver.get<const Type*>(), 0); |
| } |
| |
| ObjCInterfaceDecl *getClassReceiver() const { |
| return Receiver.get<ObjCInterfaceDecl*>(); |
| } |
| bool isObjectReceiver() const { return Receiver.is<Stmt*>(); } |
| bool isSuperReceiver() const { return Receiver.is<const Type*>(); } |
| bool isClassReceiver() const { return Receiver.is<ObjCInterfaceDecl*>(); } |
| |
| /// Determine the type of the base, regardless of the kind of receiver. |
| QualType getReceiverType(const ASTContext &ctx) const; |
| |
| SourceLocation getLocStart() const LLVM_READONLY { |
| return isObjectReceiver() ? getBase()->getLocStart() :getReceiverLocation(); |
| } |
| SourceLocation getLocEnd() const LLVM_READONLY { return IdLoc; } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCPropertyRefExprClass; |
| } |
| |
| // Iterators |
| child_range children() { |
| if (Receiver.is<Stmt*>()) { |
| Stmt **begin = reinterpret_cast<Stmt**>(&Receiver); // hack! |
| return child_range(begin, begin+1); |
| } |
| return child_range(child_iterator(), child_iterator()); |
| } |
| |
| private: |
| friend class ASTStmtReader; |
| friend class ASTStmtWriter; |
| void setExplicitProperty(ObjCPropertyDecl *D, unsigned methRefFlags) { |
| PropertyOrGetter.setPointer(D); |
| PropertyOrGetter.setInt(false); |
| SetterAndMethodRefFlags.setPointer(nullptr); |
| SetterAndMethodRefFlags.setInt(methRefFlags); |
| } |
| void setImplicitProperty(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, |
| unsigned methRefFlags) { |
| PropertyOrGetter.setPointer(Getter); |
| PropertyOrGetter.setInt(true); |
| SetterAndMethodRefFlags.setPointer(Setter); |
| SetterAndMethodRefFlags.setInt(methRefFlags); |
| } |
| void setBase(Expr *Base) { Receiver = Base; } |
| void setSuperReceiver(QualType T) { Receiver = T.getTypePtr(); } |
| void setClassReceiver(ObjCInterfaceDecl *D) { Receiver = D; } |
| |
| void setLocation(SourceLocation L) { IdLoc = L; } |
| void setReceiverLocation(SourceLocation Loc) { ReceiverLoc = Loc; } |
| |
| void setMethodRefFlag(MethodRefFlags flag, bool val) { |
| unsigned f = SetterAndMethodRefFlags.getInt(); |
| if (val) |
| f |= flag; |
| else |
| f &= ~flag; |
| SetterAndMethodRefFlags.setInt(f); |
| } |
| }; |
| |
| /// ObjCSubscriptRefExpr - used for array and dictionary subscripting. |
| /// array[4] = array[3]; dictionary[key] = dictionary[alt_key]; |
| /// |
| class ObjCSubscriptRefExpr : public Expr { |
| // Location of ']' in an indexing expression. |
| SourceLocation RBracket; |
| // array/dictionary base expression. |
| // for arrays, this is a numeric expression. For dictionaries, this is |
| // an objective-c object pointer expression. |
| enum { BASE, KEY, END_EXPR }; |
| Stmt* SubExprs[END_EXPR]; |
| |
| ObjCMethodDecl *GetAtIndexMethodDecl; |
| |
| // For immutable objects this is null. When ObjCSubscriptRefExpr is to read |
| // an indexed object this is null too. |
| ObjCMethodDecl *SetAtIndexMethodDecl; |
| |
| public: |
| |
| ObjCSubscriptRefExpr(Expr *base, Expr *key, QualType T, |
| ExprValueKind VK, ExprObjectKind OK, |
| ObjCMethodDecl *getMethod, |
| ObjCMethodDecl *setMethod, SourceLocation RB) |
| : Expr(ObjCSubscriptRefExprClass, T, VK, OK, |
| base->isTypeDependent() || key->isTypeDependent(), |
| base->isValueDependent() || key->isValueDependent(), |
| base->isInstantiationDependent() || key->isInstantiationDependent(), |
| (base->containsUnexpandedParameterPack() || |
| key->containsUnexpandedParameterPack())), |
| RBracket(RB), |
| GetAtIndexMethodDecl(getMethod), |
| SetAtIndexMethodDecl(setMethod) |
| {SubExprs[BASE] = base; SubExprs[KEY] = key;} |
| |
| explicit ObjCSubscriptRefExpr(EmptyShell Empty) |
| : Expr(ObjCSubscriptRefExprClass, Empty) {} |
| |
| SourceLocation getRBracket() const { return RBracket; } |
| void setRBracket(SourceLocation RB) { RBracket = RB; } |
| |
| SourceLocation getLocStart() const LLVM_READONLY { |
| return SubExprs[BASE]->getLocStart(); |
| } |
| SourceLocation getLocEnd() const LLVM_READONLY { return RBracket; } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCSubscriptRefExprClass; |
| } |
| |
| Expr *getBaseExpr() const { return cast<Expr>(SubExprs[BASE]); } |
| void setBaseExpr(Stmt *S) { SubExprs[BASE] = S; } |
| |
| Expr *getKeyExpr() const { return cast<Expr>(SubExprs[KEY]); } |
| void setKeyExpr(Stmt *S) { SubExprs[KEY] = S; } |
| |
| ObjCMethodDecl *getAtIndexMethodDecl() const { |
| return GetAtIndexMethodDecl; |
| } |
| |
| ObjCMethodDecl *setAtIndexMethodDecl() const { |
| return SetAtIndexMethodDecl; |
| } |
| |
| bool isArraySubscriptRefExpr() const { |
| return getKeyExpr()->getType()->isIntegralOrEnumerationType(); |
| } |
| |
| child_range children() { |
| return child_range(SubExprs, SubExprs+END_EXPR); |
| } |
| private: |
| friend class ASTStmtReader; |
| }; |
| |
| |
| /// \brief An expression that sends a message to the given Objective-C |
| /// object or class. |
| /// |
| /// The following contains two message send expressions: |
| /// |
| /// \code |
| /// [[NSString alloc] initWithString:@"Hello"] |
| /// \endcode |
| /// |
| /// The innermost message send invokes the "alloc" class method on the |
| /// NSString class, while the outermost message send invokes the |
| /// "initWithString" instance method on the object returned from |
| /// NSString's "alloc". In all, an Objective-C message send can take |
| /// on four different (although related) forms: |
| /// |
| /// 1. Send to an object instance. |
| /// 2. Send to a class. |
| /// 3. Send to the superclass instance of the current class. |
| /// 4. Send to the superclass of the current class. |
| /// |
| /// All four kinds of message sends are modeled by the ObjCMessageExpr |
| /// class, and can be distinguished via \c getReceiverKind(). Example: |
| /// |
| /// The "void *" trailing objects are actually ONE void * (the |
| /// receiver pointer), and NumArgs Expr *. But due to the |
| /// implementation of children(), these must be together contiguously. |
| |
| class ObjCMessageExpr final |
| : public Expr, |
| private llvm::TrailingObjects<ObjCMessageExpr, void *, SourceLocation> { |
| /// \brief Stores either the selector that this message is sending |
| /// to (when \c HasMethod is zero) or an \c ObjCMethodDecl pointer |
| /// referring to the method that we type-checked against. |
| uintptr_t SelectorOrMethod; |
| |
| enum { NumArgsBitWidth = 16 }; |
| |
| /// \brief The number of arguments in the message send, not |
| /// including the receiver. |
| unsigned NumArgs : NumArgsBitWidth; |
| |
| /// \brief The kind of message send this is, which is one of the |
| /// ReceiverKind values. |
| /// |
| /// We pad this out to a byte to avoid excessive masking and shifting. |
| unsigned Kind : 8; |
| |
| /// \brief Whether we have an actual method prototype in \c |
| /// SelectorOrMethod. |
| /// |
| /// When non-zero, we have a method declaration; otherwise, we just |
| /// have a selector. |
| unsigned HasMethod : 1; |
| |
| /// \brief Whether this message send is a "delegate init call", |
| /// i.e. a call of an init method on self from within an init method. |
| unsigned IsDelegateInitCall : 1; |
| |
| /// \brief Whether this message send was implicitly generated by |
| /// the implementation rather than explicitly written by the user. |
| unsigned IsImplicit : 1; |
| |
| /// \brief Whether the locations of the selector identifiers are in a |
| /// "standard" position, a enum SelectorLocationsKind. |
| unsigned SelLocsKind : 2; |
| |
| /// \brief When the message expression is a send to 'super', this is |
| /// the location of the 'super' keyword. |
| SourceLocation SuperLoc; |
| |
| /// \brief The source locations of the open and close square |
| /// brackets ('[' and ']', respectively). |
| SourceLocation LBracLoc, RBracLoc; |
| |
| size_t numTrailingObjects(OverloadToken<void *>) const { return NumArgs + 1; } |
| |
| void setNumArgs(unsigned Num) { |
| assert((Num >> NumArgsBitWidth) == 0 && "Num of args is out of range!"); |
| NumArgs = Num; |
| } |
| |
| ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs) |
| : Expr(ObjCMessageExprClass, Empty), SelectorOrMethod(0), Kind(0), |
| HasMethod(0), IsDelegateInitCall(0), IsImplicit(0), SelLocsKind(0) { |
| setNumArgs(NumArgs); |
| } |
| |
| ObjCMessageExpr(QualType T, ExprValueKind VK, |
| SourceLocation LBracLoc, |
| SourceLocation SuperLoc, |
| bool IsInstanceSuper, |
| QualType SuperType, |
| Selector Sel, |
| ArrayRef<SourceLocation> SelLocs, |
| SelectorLocationsKind SelLocsK, |
| ObjCMethodDecl *Method, |
| ArrayRef<Expr *> Args, |
| SourceLocation RBracLoc, |
| bool isImplicit); |
| ObjCMessageExpr(QualType T, ExprValueKind VK, |
| SourceLocation LBracLoc, |
| TypeSourceInfo *Receiver, |
| Selector Sel, |
| ArrayRef<SourceLocation> SelLocs, |
| SelectorLocationsKind SelLocsK, |
| ObjCMethodDecl *Method, |
| ArrayRef<Expr *> Args, |
| SourceLocation RBracLoc, |
| bool isImplicit); |
| ObjCMessageExpr(QualType T, ExprValueKind VK, |
| SourceLocation LBracLoc, |
| Expr *Receiver, |
| Selector Sel, |
| ArrayRef<SourceLocation> SelLocs, |
| SelectorLocationsKind SelLocsK, |
| ObjCMethodDecl *Method, |
| ArrayRef<Expr *> Args, |
| SourceLocation RBracLoc, |
| bool isImplicit); |
| |
| void initArgsAndSelLocs(ArrayRef<Expr *> Args, |
| ArrayRef<SourceLocation> SelLocs, |
| SelectorLocationsKind SelLocsK); |
| |
| /// \brief Retrieve the pointer value of the message receiver. |
| void *getReceiverPointer() const { return *getTrailingObjects<void *>(); } |
| |
| /// \brief Set the pointer value of the message receiver. |
| void setReceiverPointer(void *Value) { |
| *getTrailingObjects<void *>() = Value; |
| } |
| |
| SelectorLocationsKind getSelLocsKind() const { |
| return (SelectorLocationsKind)SelLocsKind; |
| } |
| bool hasStandardSelLocs() const { |
| return getSelLocsKind() != SelLoc_NonStandard; |
| } |
| |
| /// \brief Get a pointer to the stored selector identifiers locations array. |
| /// No locations will be stored if HasStandardSelLocs is true. |
| SourceLocation *getStoredSelLocs() { |
| return getTrailingObjects<SourceLocation>(); |
| } |
| const SourceLocation *getStoredSelLocs() const { |
| return getTrailingObjects<SourceLocation>(); |
| } |
| |
| /// \brief Get the number of stored selector identifiers locations. |
| /// No locations will be stored if HasStandardSelLocs is true. |
| unsigned getNumStoredSelLocs() const { |
| if (hasStandardSelLocs()) |
| return 0; |
| return getNumSelectorLocs(); |
| } |
| |
| static ObjCMessageExpr *alloc(const ASTContext &C, |
| ArrayRef<Expr *> Args, |
| SourceLocation RBraceLoc, |
| ArrayRef<SourceLocation> SelLocs, |
| Selector Sel, |
| SelectorLocationsKind &SelLocsK); |
| static ObjCMessageExpr *alloc(const ASTContext &C, |
| unsigned NumArgs, |
| unsigned NumStoredSelLocs); |
| |
| public: |
| /// \brief The kind of receiver this message is sending to. |
| enum ReceiverKind { |
| /// \brief The receiver is a class. |
| Class = 0, |
| /// \brief The receiver is an object instance. |
| Instance, |
| /// \brief The receiver is a superclass. |
| SuperClass, |
| /// \brief The receiver is the instance of the superclass object. |
| SuperInstance |
| }; |
| |
| /// \brief Create a message send to super. |
| /// |
| /// \param Context The ASTContext in which this expression will be created. |
| /// |
| /// \param T The result type of this message. |
| /// |
| /// \param VK The value kind of this message. A message returning |
| /// a l-value or r-value reference will be an l-value or x-value, |
| /// respectively. |
| /// |
| /// \param LBracLoc The location of the open square bracket '['. |
| /// |
| /// \param SuperLoc The location of the "super" keyword. |
| /// |
| /// \param IsInstanceSuper Whether this is an instance "super" |
| /// message (otherwise, it's a class "super" message). |
| /// |
| /// \param Sel The selector used to determine which method gets called. |
| /// |
| /// \param Method The Objective-C method against which this message |
| /// send was type-checked. May be NULL. |
| /// |
| /// \param Args The message send arguments. |
| /// |
| /// \param RBracLoc The location of the closing square bracket ']'. |
| static ObjCMessageExpr *Create(const ASTContext &Context, QualType T, |
| ExprValueKind VK, |
| SourceLocation LBracLoc, |
| SourceLocation SuperLoc, |
| bool IsInstanceSuper, |
| QualType SuperType, |
| Selector Sel, |
| ArrayRef<SourceLocation> SelLocs, |
| ObjCMethodDecl *Method, |
| ArrayRef<Expr *> Args, |
| SourceLocation RBracLoc, |
| bool isImplicit); |
| |
| /// \brief Create a class message send. |
| /// |
| /// \param Context The ASTContext in which this expression will be created. |
| /// |
| /// \param T The result type of this message. |
| /// |
| /// \param VK The value kind of this message. A message returning |
| /// a l-value or r-value reference will be an l-value or x-value, |
| /// respectively. |
| /// |
| /// \param LBracLoc The location of the open square bracket '['. |
| /// |
| /// \param Receiver The type of the receiver, including |
| /// source-location information. |
| /// |
| /// \param Sel The selector used to determine which method gets called. |
| /// |
| /// \param Method The Objective-C method against which this message |
| /// send was type-checked. May be NULL. |
| /// |
| /// \param Args The message send arguments. |
| /// |
| /// \param RBracLoc The location of the closing square bracket ']'. |
| static ObjCMessageExpr *Create(const ASTContext &Context, QualType T, |
| ExprValueKind VK, |
| SourceLocation LBracLoc, |
| TypeSourceInfo *Receiver, |
| Selector Sel, |
| ArrayRef<SourceLocation> SelLocs, |
| ObjCMethodDecl *Method, |
| ArrayRef<Expr *> Args, |
| SourceLocation RBracLoc, |
| bool isImplicit); |
| |
| /// \brief Create an instance message send. |
| /// |
| /// \param Context The ASTContext in which this expression will be created. |
| /// |
| /// \param T The result type of this message. |
| /// |
| /// \param VK The value kind of this message. A message returning |
| /// a l-value or r-value reference will be an l-value or x-value, |
| /// respectively. |
| /// |
| /// \param LBracLoc The location of the open square bracket '['. |
| /// |
| /// \param Receiver The expression used to produce the object that |
| /// will receive this message. |
| /// |
| /// \param Sel The selector used to determine which method gets called. |
| /// |
| /// \param Method The Objective-C method against which this message |
| /// send was type-checked. May be NULL. |
| /// |
| /// \param Args The message send arguments. |
| /// |
| /// \param RBracLoc The location of the closing square bracket ']'. |
| static ObjCMessageExpr *Create(const ASTContext &Context, QualType T, |
| ExprValueKind VK, |
| SourceLocation LBracLoc, |
| Expr *Receiver, |
| Selector Sel, |
| ArrayRef<SourceLocation> SeLocs, |
| ObjCMethodDecl *Method, |
| ArrayRef<Expr *> Args, |
| SourceLocation RBracLoc, |
| bool isImplicit); |
| |
| /// \brief Create an empty Objective-C message expression, to be |
| /// filled in by subsequent calls. |
| /// |
| /// \param Context The context in which the message send will be created. |
| /// |
| /// \param NumArgs The number of message arguments, not including |
| /// the receiver. |
| static ObjCMessageExpr *CreateEmpty(const ASTContext &Context, |
| unsigned NumArgs, |
| unsigned NumStoredSelLocs); |
| |
| /// \brief Indicates whether the message send was implicitly |
| /// generated by the implementation. If false, it was written explicitly |
| /// in the source code. |
| bool isImplicit() const { return IsImplicit; } |
| |
| /// \brief Determine the kind of receiver that this message is being |
| /// sent to. |
| ReceiverKind getReceiverKind() const { return (ReceiverKind)Kind; } |
| |
| /// \brief Source range of the receiver. |
| SourceRange getReceiverRange() const; |
| |
| /// \brief Determine whether this is an instance message to either a |
| /// computed object or to super. |
| bool isInstanceMessage() const { |
| return getReceiverKind() == Instance || getReceiverKind() == SuperInstance; |
| } |
| |
| /// \brief Determine whether this is an class message to either a |
| /// specified class or to super. |
| bool isClassMessage() const { |
| return getReceiverKind() == Class || getReceiverKind() == SuperClass; |
| } |
| |
| /// \brief Returns the object expression (receiver) for an instance message, |
| /// or null for a message that is not an instance message. |
| Expr *getInstanceReceiver() { |
| if (getReceiverKind() == Instance) |
| return static_cast<Expr *>(getReceiverPointer()); |
| |
| return nullptr; |
| } |
| const Expr *getInstanceReceiver() const { |
| return const_cast<ObjCMessageExpr*>(this)->getInstanceReceiver(); |
| } |
| |
| /// \brief Turn this message send into an instance message that |
| /// computes the receiver object with the given expression. |
| void setInstanceReceiver(Expr *rec) { |
| Kind = Instance; |
| setReceiverPointer(rec); |
| } |
| |
| /// \brief Returns the type of a class message send, or NULL if the |
| /// message is not a class message. |
| QualType getClassReceiver() const { |
| if (TypeSourceInfo *TSInfo = getClassReceiverTypeInfo()) |
| return TSInfo->getType(); |
| |
| return QualType(); |
| } |
| |
| /// \brief Returns a type-source information of a class message |
| /// send, or NULL if the message is not a class message. |
| TypeSourceInfo *getClassReceiverTypeInfo() const { |
| if (getReceiverKind() == Class) |
| return reinterpret_cast<TypeSourceInfo *>(getReceiverPointer()); |
| return nullptr; |
| } |
| |
| void setClassReceiver(TypeSourceInfo *TSInfo) { |
| Kind = Class; |
| setReceiverPointer(TSInfo); |
| } |
| |
| /// \brief Retrieve the location of the 'super' keyword for a class |
| /// or instance message to 'super', otherwise an invalid source location. |
| SourceLocation getSuperLoc() const { |
| if (getReceiverKind() == SuperInstance || getReceiverKind() == SuperClass) |
| return SuperLoc; |
| |
| return SourceLocation(); |
| } |
| |
| /// \brief Retrieve the receiver type to which this message is being directed. |
| /// |
| /// This routine cross-cuts all of the different kinds of message |
| /// sends to determine what the underlying (statically known) type |
| /// of the receiver will be; use \c getReceiverKind() to determine |
| /// whether the message is a class or an instance method, whether it |
| /// is a send to super or not, etc. |
| /// |
| /// \returns The type of the receiver. |
| QualType getReceiverType() const; |
| |
| /// \brief Retrieve the Objective-C interface to which this message |
| /// is being directed, if known. |
| /// |
| /// This routine cross-cuts all of the different kinds of message |
| /// sends to determine what the underlying (statically known) type |
| /// of the receiver will be; use \c getReceiverKind() to determine |
| /// whether the message is a class or an instance method, whether it |
| /// is a send to super or not, etc. |
| /// |
| /// \returns The Objective-C interface if known, otherwise NULL. |
| ObjCInterfaceDecl *getReceiverInterface() const; |
| |
| /// \brief Retrieve the type referred to by 'super'. |
| /// |
| /// The returned type will either be an ObjCInterfaceType (for an |
| /// class message to super) or an ObjCObjectPointerType that refers |
| /// to a class (for an instance message to super); |
| QualType getSuperType() const { |
| if (getReceiverKind() == SuperInstance || getReceiverKind() == SuperClass) |
| return QualType::getFromOpaquePtr(getReceiverPointer()); |
| |
| return QualType(); |
| } |
| |
| void setSuper(SourceLocation Loc, QualType T, bool IsInstanceSuper) { |
| Kind = IsInstanceSuper? SuperInstance : SuperClass; |
| SuperLoc = Loc; |
| setReceiverPointer(T.getAsOpaquePtr()); |
| } |
| |
| Selector getSelector() const; |
| |
| void setSelector(Selector S) { |
| HasMethod = false; |
| SelectorOrMethod = reinterpret_cast<uintptr_t>(S.getAsOpaquePtr()); |
| } |
| |
| const ObjCMethodDecl *getMethodDecl() const { |
| if (HasMethod) |
| return reinterpret_cast<const ObjCMethodDecl *>(SelectorOrMethod); |
| |
| return nullptr; |
| } |
| |
| ObjCMethodDecl *getMethodDecl() { |
| if (HasMethod) |
| return reinterpret_cast<ObjCMethodDecl *>(SelectorOrMethod); |
| |
| return nullptr; |
| } |
| |
| void setMethodDecl(ObjCMethodDecl *MD) { |
| HasMethod = true; |
| SelectorOrMethod = reinterpret_cast<uintptr_t>(MD); |
| } |
| |
| ObjCMethodFamily getMethodFamily() const { |
| if (HasMethod) return getMethodDecl()->getMethodFamily(); |
| return getSelector().getMethodFamily(); |
| } |
| |
| /// \brief Return the number of actual arguments in this message, |
| /// not counting the receiver. |
| unsigned getNumArgs() const { return NumArgs; } |
| |
| /// \brief Retrieve the arguments to this message, not including the |
| /// receiver. |
| Expr **getArgs() { |
| return reinterpret_cast<Expr **>(getTrailingObjects<void *>() + 1); |
| } |
| const Expr * const *getArgs() const { |
| return reinterpret_cast<const Expr *const *>(getTrailingObjects<void *>() + |
| 1); |
| } |
| |
| /// getArg - Return the specified argument. |
| Expr *getArg(unsigned Arg) { |
| assert(Arg < NumArgs && "Arg access out of range!"); |
| return getArgs()[Arg]; |
| } |
| const Expr *getArg(unsigned Arg) const { |
| assert(Arg < NumArgs && "Arg access out of range!"); |
| return getArgs()[Arg]; |
| } |
| /// setArg - Set the specified argument. |
| void setArg(unsigned Arg, Expr *ArgExpr) { |
| assert(Arg < NumArgs && "Arg access out of range!"); |
| getArgs()[Arg] = ArgExpr; |
| } |
| |
| /// isDelegateInitCall - Answers whether this message send has been |
| /// tagged as a "delegate init call", i.e. a call to a method in the |
| /// -init family on self from within an -init method implementation. |
| bool isDelegateInitCall() const { return IsDelegateInitCall; } |
| void setDelegateInitCall(bool isDelegate) { IsDelegateInitCall = isDelegate; } |
| |
| SourceLocation getLeftLoc() const { return LBracLoc; } |
| SourceLocation getRightLoc() const { return RBracLoc; } |
| |
| SourceLocation getSelectorStartLoc() const { |
| if (isImplicit()) |
| return getLocStart(); |
| return getSelectorLoc(0); |
| } |
| SourceLocation getSelectorLoc(unsigned Index) const { |
| assert(Index < getNumSelectorLocs() && "Index out of range!"); |
| if (hasStandardSelLocs()) |
| return getStandardSelectorLoc(Index, getSelector(), |
| getSelLocsKind() == SelLoc_StandardWithSpace, |
| llvm::makeArrayRef(const_cast<Expr**>(getArgs()), |
| getNumArgs()), |
| RBracLoc); |
| return getStoredSelLocs()[Index]; |
| } |
| |
| void getSelectorLocs(SmallVectorImpl<SourceLocation> &SelLocs) const; |
| |
| unsigned getNumSelectorLocs() const { |
| if (isImplicit()) |
| return 0; |
| Selector Sel = getSelector(); |
| if (Sel.isUnarySelector()) |
| return 1; |
| return Sel.getNumArgs(); |
| } |
| |
| void setSourceRange(SourceRange R) { |
| LBracLoc = R.getBegin(); |
| RBracLoc = R.getEnd(); |
| } |
| SourceLocation getLocStart() const LLVM_READONLY { return LBracLoc; } |
| SourceLocation getLocEnd() const LLVM_READONLY { return RBracLoc; } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCMessageExprClass; |
| } |
| |
| // Iterators |
| child_range children(); |
| |
| typedef ExprIterator arg_iterator; |
| typedef ConstExprIterator const_arg_iterator; |
| |
| llvm::iterator_range<arg_iterator> arguments() { |
| return llvm::make_range(arg_begin(), arg_end()); |
| } |
| |
| llvm::iterator_range<const_arg_iterator> arguments() const { |
| return llvm::make_range(arg_begin(), arg_end()); |
| } |
| |
| arg_iterator arg_begin() { return reinterpret_cast<Stmt **>(getArgs()); } |
| arg_iterator arg_end() { |
| return reinterpret_cast<Stmt **>(getArgs() + NumArgs); |
| } |
| const_arg_iterator arg_begin() const { |
| return reinterpret_cast<Stmt const * const*>(getArgs()); |
| } |
| const_arg_iterator arg_end() const { |
| return reinterpret_cast<Stmt const * const*>(getArgs() + NumArgs); |
| } |
| |
| friend TrailingObjects; |
| friend class ASTStmtReader; |
| friend class ASTStmtWriter; |
| }; |
| |
| /// ObjCIsaExpr - Represent X->isa and X.isa when X is an ObjC 'id' type. |
| /// (similar in spirit to MemberExpr). |
| class ObjCIsaExpr : public Expr { |
| /// Base - the expression for the base object pointer. |
| Stmt *Base; |
| |
| /// IsaMemberLoc - This is the location of the 'isa'. |
| SourceLocation IsaMemberLoc; |
| |
| /// OpLoc - This is the location of '.' or '->' |
| SourceLocation OpLoc; |
| |
| /// IsArrow - True if this is "X->F", false if this is "X.F". |
| bool IsArrow; |
| public: |
| ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, SourceLocation oploc, |
| QualType ty) |
| : Expr(ObjCIsaExprClass, ty, VK_LValue, OK_Ordinary, |
| /*TypeDependent=*/false, base->isValueDependent(), |
| base->isInstantiationDependent(), |
| /*ContainsUnexpandedParameterPack=*/false), |
| Base(base), IsaMemberLoc(l), OpLoc(oploc), IsArrow(isarrow) {} |
| |
| /// \brief Build an empty expression. |
| explicit ObjCIsaExpr(EmptyShell Empty) : Expr(ObjCIsaExprClass, Empty) { } |
| |
| void setBase(Expr *E) { Base = E; } |
| Expr *getBase() const { return cast<Expr>(Base); } |
| |
| bool isArrow() const { return IsArrow; } |
| void setArrow(bool A) { IsArrow = A; } |
| |
| /// getMemberLoc - Return the location of the "member", in X->F, it is the |
| /// location of 'F'. |
| SourceLocation getIsaMemberLoc() const { return IsaMemberLoc; } |
| void setIsaMemberLoc(SourceLocation L) { IsaMemberLoc = L; } |
| |
| SourceLocation getOpLoc() const { return OpLoc; } |
| void setOpLoc(SourceLocation L) { OpLoc = L; } |
| |
| SourceLocation getLocStart() const LLVM_READONLY { |
| return getBase()->getLocStart(); |
| } |
| |
| SourceLocation getBaseLocEnd() const LLVM_READONLY { |
| return getBase()->getLocEnd(); |
| } |
| |
| SourceLocation getLocEnd() const LLVM_READONLY { return IsaMemberLoc; } |
| |
| SourceLocation getExprLoc() const LLVM_READONLY { return IsaMemberLoc; } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCIsaExprClass; |
| } |
| |
| // Iterators |
| child_range children() { return child_range(&Base, &Base+1); } |
| }; |
| |
| |
| /// ObjCIndirectCopyRestoreExpr - Represents the passing of a function |
| /// argument by indirect copy-restore in ARC. This is used to support |
| /// passing indirect arguments with the wrong lifetime, e.g. when |
| /// passing the address of a __strong local variable to an 'out' |
| /// parameter. This expression kind is only valid in an "argument" |
| /// position to some sort of call expression. |
| /// |
| /// The parameter must have type 'pointer to T', and the argument must |
| /// have type 'pointer to U', where T and U agree except possibly in |
| /// qualification. If the argument value is null, then a null pointer |
| /// is passed; otherwise it points to an object A, and: |
| /// 1. A temporary object B of type T is initialized, either by |
| /// zero-initialization (used when initializing an 'out' parameter) |
| /// or copy-initialization (used when initializing an 'inout' |
| /// parameter). |
| /// 2. The address of the temporary is passed to the function. |
| /// 3. If the call completes normally, A is move-assigned from B. |
| /// 4. Finally, A is destroyed immediately. |
| /// |
| /// Currently 'T' must be a retainable object lifetime and must be |
| /// __autoreleasing; this qualifier is ignored when initializing |
| /// the value. |
| class ObjCIndirectCopyRestoreExpr : public Expr { |
| Stmt *Operand; |
| |
| // unsigned ObjCIndirectCopyRestoreBits.ShouldCopy : 1; |
| |
| friend class ASTReader; |
| friend class ASTStmtReader; |
| |
| void setShouldCopy(bool shouldCopy) { |
| ObjCIndirectCopyRestoreExprBits.ShouldCopy = shouldCopy; |
| } |
| |
| explicit ObjCIndirectCopyRestoreExpr(EmptyShell Empty) |
| : Expr(ObjCIndirectCopyRestoreExprClass, Empty) { } |
| |
| public: |
| ObjCIndirectCopyRestoreExpr(Expr *operand, QualType type, bool shouldCopy) |
| : Expr(ObjCIndirectCopyRestoreExprClass, type, VK_LValue, OK_Ordinary, |
| operand->isTypeDependent(), operand->isValueDependent(), |
| operand->isInstantiationDependent(), |
| operand->containsUnexpandedParameterPack()), |
| Operand(operand) { |
| setShouldCopy(shouldCopy); |
| } |
| |
| Expr *getSubExpr() { return cast<Expr>(Operand); } |
| const Expr *getSubExpr() const { return cast<Expr>(Operand); } |
| |
| /// shouldCopy - True if we should do the 'copy' part of the |
| /// copy-restore. If false, the temporary will be zero-initialized. |
| bool shouldCopy() const { return ObjCIndirectCopyRestoreExprBits.ShouldCopy; } |
| |
| child_range children() { return child_range(&Operand, &Operand+1); } |
| |
| // Source locations are determined by the subexpression. |
| SourceLocation getLocStart() const LLVM_READONLY { |
| return Operand->getLocStart(); |
| } |
| SourceLocation getLocEnd() const LLVM_READONLY { return Operand->getLocEnd();} |
| |
| SourceLocation getExprLoc() const LLVM_READONLY { |
| return getSubExpr()->getExprLoc(); |
| } |
| |
| static bool classof(const Stmt *s) { |
| return s->getStmtClass() == ObjCIndirectCopyRestoreExprClass; |
| } |
| }; |
| |
| /// \brief An Objective-C "bridged" cast expression, which casts between |
| /// Objective-C pointers and C pointers, transferring ownership in the process. |
| /// |
| /// \code |
| /// NSString *str = (__bridge_transfer NSString *)CFCreateString(); |
| /// \endcode |
| class ObjCBridgedCastExpr final |
| : public ExplicitCastExpr, |
| private llvm::TrailingObjects<ObjCBridgedCastExpr, CXXBaseSpecifier *> { |
| SourceLocation LParenLoc; |
| SourceLocation BridgeKeywordLoc; |
| unsigned Kind : 2; |
| |
| friend TrailingObjects; |
| friend class CastExpr; |
| friend class ASTStmtReader; |
| friend class ASTStmtWriter; |
| |
| public: |
| ObjCBridgedCastExpr(SourceLocation LParenLoc, ObjCBridgeCastKind Kind, |
| CastKind CK, SourceLocation BridgeKeywordLoc, |
| TypeSourceInfo *TSInfo, Expr *Operand) |
| : ExplicitCastExpr(ObjCBridgedCastExprClass, TSInfo->getType(), VK_RValue, |
| CK, Operand, 0, TSInfo), |
| LParenLoc(LParenLoc), BridgeKeywordLoc(BridgeKeywordLoc), Kind(Kind) { } |
| |
| /// \brief Construct an empty Objective-C bridged cast. |
| explicit ObjCBridgedCastExpr(EmptyShell Shell) |
| : ExplicitCastExpr(ObjCBridgedCastExprClass, Shell, 0) { } |
| |
| SourceLocation getLParenLoc() const { return LParenLoc; } |
| |
| /// \brief Determine which kind of bridge is being performed via this cast. |
| ObjCBridgeCastKind getBridgeKind() const { |
| return static_cast<ObjCBridgeCastKind>(Kind); |
| } |
| |
| /// \brief Retrieve the kind of bridge being performed as a string. |
| StringRef getBridgeKindName() const; |
| |
| /// \brief The location of the bridge keyword. |
| SourceLocation getBridgeKeywordLoc() const { return BridgeKeywordLoc; } |
| |
| SourceLocation getLocStart() const LLVM_READONLY { return LParenLoc; } |
| SourceLocation getLocEnd() const LLVM_READONLY { |
| return getSubExpr()->getLocEnd(); |
| } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCBridgedCastExprClass; |
| } |
| }; |
| |
| /// \brief A runtime availability query. |
| /// |
| /// There are 2 ways to spell this node: |
| /// \code |
| /// @available(macos 10.10, ios 8, *); // Objective-C |
| /// __builtin_available(macos 10.10, ios 8, *); // C, C++, and Objective-C |
| /// \endcode |
| /// |
| /// Note that we only need to keep track of one \c VersionTuple here, which is |
| /// the one that corresponds to the current deployment target. This is meant to |
| /// be used in the condition of an \c if, but it is also usable as top level |
| /// expressions. |
| /// |
| class ObjCAvailabilityCheckExpr : public Expr { |
| VersionTuple VersionToCheck; |
| SourceLocation AtLoc, RParen; |
| |
| friend class ASTStmtReader; |
| public: |
| ObjCAvailabilityCheckExpr(VersionTuple VersionToCheck, SourceLocation AtLoc, |
| SourceLocation RParen, QualType Ty) |
| : Expr(ObjCAvailabilityCheckExprClass, Ty, VK_RValue, OK_Ordinary, false, |
| false, false, false), |
| VersionToCheck(VersionToCheck), AtLoc(AtLoc), RParen(RParen) {} |
| |
| explicit ObjCAvailabilityCheckExpr(EmptyShell Shell) |
| : Expr(ObjCAvailabilityCheckExprClass, Shell) {} |
| |
| SourceLocation getLocStart() const { return AtLoc; } |
| SourceLocation getLocEnd() const { return RParen; } |
| SourceRange getSourceRange() const { return {AtLoc, RParen}; } |
| |
| /// \brief This may be '*', in which case this should fold to true. |
| bool hasVersion() const { return !VersionToCheck.empty(); } |
| VersionTuple getVersion() { return VersionToCheck; } |
| |
| child_range children() { |
| return child_range(child_iterator(), child_iterator()); |
| } |
| |
| static bool classof(const Stmt *T) { |
| return T->getStmtClass() == ObjCAvailabilityCheckExprClass; |
| } |
| }; |
| |
| } // end namespace clang |
| |
| #endif |