blob: 926b5e3f1ee5d7c722e14f73ed5baa551f4108ca [file] [log] [blame]
//===- DeclObjC.h - Classes for representing declarations -------*- 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 DeclObjC interface and subclasses.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_DECLOBJC_H
#define LLVM_CLANG_AST_DECLOBJC_H
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/Redeclarable.h"
#include "clang/AST/SelectorLocationsKind.h"
#include "clang/AST/Type.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/TrailingObjects.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <string>
#include <utility>
namespace clang {
class ASTContext;
class CompoundStmt;
class CXXCtorInitializer;
class Expr;
class ObjCCategoryDecl;
class ObjCCategoryImplDecl;
class ObjCImplementationDecl;
class ObjCInterfaceDecl;
class ObjCIvarDecl;
class ObjCPropertyDecl;
class ObjCPropertyImplDecl;
class ObjCProtocolDecl;
class Stmt;
class ObjCListBase {
protected:
/// List is an array of pointers to objects that are not owned by this object.
void **List = nullptr;
unsigned NumElts = 0;
public:
ObjCListBase() = default;
ObjCListBase(const ObjCListBase &) = delete;
ObjCListBase &operator=(const ObjCListBase &) = delete;
unsigned size() const { return NumElts; }
bool empty() const { return NumElts == 0; }
protected:
void set(void *const* InList, unsigned Elts, ASTContext &Ctx);
};
/// ObjCList - This is a simple template class used to hold various lists of
/// decls etc, which is heavily used by the ObjC front-end. This only use case
/// this supports is setting the list all at once and then reading elements out
/// of it.
template <typename T>
class ObjCList : public ObjCListBase {
public:
void set(T* const* InList, unsigned Elts, ASTContext &Ctx) {
ObjCListBase::set(reinterpret_cast<void*const*>(InList), Elts, Ctx);
}
using iterator = T* const *;
iterator begin() const { return (iterator)List; }
iterator end() const { return (iterator)List+NumElts; }
T* operator[](unsigned Idx) const {
assert(Idx < NumElts && "Invalid access");
return (T*)List[Idx];
}
};
/// A list of Objective-C protocols, along with the source
/// locations at which they were referenced.
class ObjCProtocolList : public ObjCList<ObjCProtocolDecl> {
SourceLocation *Locations = nullptr;
using ObjCList<ObjCProtocolDecl>::set;
public:
ObjCProtocolList() = default;
using loc_iterator = const SourceLocation *;
loc_iterator loc_begin() const { return Locations; }
loc_iterator loc_end() const { return Locations + size(); }
void set(ObjCProtocolDecl* const* InList, unsigned Elts,
const SourceLocation *Locs, ASTContext &Ctx);
};
/// ObjCMethodDecl - Represents an instance or class method declaration.
/// ObjC methods can be declared within 4 contexts: class interfaces,
/// categories, protocols, and class implementations. While C++ member
/// functions leverage C syntax, Objective-C method syntax is modeled after
/// Smalltalk (using colons to specify argument types/expressions).
/// Here are some brief examples:
///
/// Setter/getter instance methods:
/// - (void)setMenu:(NSMenu *)menu;
/// - (NSMenu *)menu;
///
/// Instance method that takes 2 NSView arguments:
/// - (void)replaceSubview:(NSView *)oldView with:(NSView *)newView;
///
/// Getter class method:
/// + (NSMenu *)defaultMenu;
///
/// A selector represents a unique name for a method. The selector names for
/// the above methods are setMenu:, menu, replaceSubview:with:, and defaultMenu.
///
class ObjCMethodDecl : public NamedDecl, public DeclContext {
public:
enum ImplementationControl { None, Required, Optional };
private:
// The conventional meaning of this method; an ObjCMethodFamily.
// This is not serialized; instead, it is computed on demand and
// cached.
mutable unsigned Family : ObjCMethodFamilyBitWidth;
/// instance (true) or class (false) method.
unsigned IsInstance : 1;
unsigned IsVariadic : 1;
/// True if this method is the getter or setter for an explicit property.
unsigned IsPropertyAccessor : 1;
// Method has a definition.
unsigned IsDefined : 1;
/// Method redeclaration in the same interface.
unsigned IsRedeclaration : 1;
/// Is redeclared in the same interface.
mutable unsigned HasRedeclaration : 1;
// NOTE: VC++ treats enums as signed, avoid using ImplementationControl enum
/// \@required/\@optional
unsigned DeclImplementation : 2;
// NOTE: VC++ treats enums as signed, avoid using the ObjCDeclQualifier enum
/// in, inout, etc.
unsigned objcDeclQualifier : 7;
/// Indicates whether this method has a related result type.
unsigned RelatedResultType : 1;
/// Whether the locations of the selector identifiers are in a
/// "standard" position, a enum SelectorLocationsKind.
unsigned SelLocsKind : 2;
/// Whether this method overrides any other in the class hierarchy.
///
/// A method is said to override any method in the class's
/// base classes, its protocols, or its categories' protocols, that has
/// the same selector and is of the same kind (class or instance).
/// A method in an implementation is not considered as overriding the same
/// method in the interface or its categories.
unsigned IsOverriding : 1;
/// Indicates if the method was a definition but its body was skipped.
unsigned HasSkippedBody : 1;
// Return type of this method.
QualType MethodDeclType;
// Type source information for the return type.
TypeSourceInfo *ReturnTInfo;
/// Array of ParmVarDecls for the formal parameters of this method
/// and optionally followed by selector locations.
void *ParamsAndSelLocs = nullptr;
unsigned NumParams = 0;
/// List of attributes for this method declaration.
SourceLocation DeclEndLoc; // the location of the ';' or '{'.
// The following are only used for method definitions, null otherwise.
LazyDeclStmtPtr Body;
/// SelfDecl - Decl for the implicit self parameter. This is lazily
/// constructed by createImplicitParams.
ImplicitParamDecl *SelfDecl = nullptr;
/// CmdDecl - Decl for the implicit _cmd parameter. This is lazily
/// constructed by createImplicitParams.
ImplicitParamDecl *CmdDecl = nullptr;
ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc,
Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
DeclContext *contextDecl, bool isInstance = true,
bool isVariadic = false, bool isPropertyAccessor = false,
bool isImplicitlyDeclared = false, bool isDefined = false,
ImplementationControl impControl = None,
bool HasRelatedResultType = false)
: NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
DeclContext(ObjCMethod), Family(InvalidObjCMethodFamily),
IsInstance(isInstance), IsVariadic(isVariadic),
IsPropertyAccessor(isPropertyAccessor), IsDefined(isDefined),
IsRedeclaration(0), HasRedeclaration(0), DeclImplementation(impControl),
objcDeclQualifier(OBJC_TQ_None),
RelatedResultType(HasRelatedResultType),
SelLocsKind(SelLoc_StandardNoSpace), IsOverriding(0), HasSkippedBody(0),
MethodDeclType(T), ReturnTInfo(ReturnTInfo), DeclEndLoc(endLoc) {
setImplicit(isImplicitlyDeclared);
}
SelectorLocationsKind getSelLocsKind() const {
return (SelectorLocationsKind)SelLocsKind;
}
bool hasStandardSelLocs() const {
return getSelLocsKind() != SelLoc_NonStandard;
}
/// Get a pointer to the stored selector identifiers locations array.
/// No locations will be stored if HasStandardSelLocs is true.
SourceLocation *getStoredSelLocs() {
return reinterpret_cast<SourceLocation*>(getParams() + NumParams);
}
const SourceLocation *getStoredSelLocs() const {
return reinterpret_cast<const SourceLocation*>(getParams() + NumParams);
}
/// Get a pointer to the stored selector identifiers locations array.
/// No locations will be stored if HasStandardSelLocs is true.
ParmVarDecl **getParams() {
return reinterpret_cast<ParmVarDecl **>(ParamsAndSelLocs);
}
const ParmVarDecl *const *getParams() const {
return reinterpret_cast<const ParmVarDecl *const *>(ParamsAndSelLocs);
}
/// 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();
}
void setParamsAndSelLocs(ASTContext &C,
ArrayRef<ParmVarDecl*> Params,
ArrayRef<SourceLocation> SelLocs);
/// A definition will return its interface declaration.
/// An interface declaration will return its definition.
/// Otherwise it will return itself.
ObjCMethodDecl *getNextRedeclarationImpl() override;
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
static ObjCMethodDecl *
Create(ASTContext &C, SourceLocation beginLoc, SourceLocation endLoc,
Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
DeclContext *contextDecl, bool isInstance = true,
bool isVariadic = false, bool isPropertyAccessor = false,
bool isImplicitlyDeclared = false, bool isDefined = false,
ImplementationControl impControl = None,
bool HasRelatedResultType = false);
static ObjCMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID);
ObjCMethodDecl *getCanonicalDecl() override;
const ObjCMethodDecl *getCanonicalDecl() const {
return const_cast<ObjCMethodDecl*>(this)->getCanonicalDecl();
}
ObjCDeclQualifier getObjCDeclQualifier() const {
return ObjCDeclQualifier(objcDeclQualifier);
}
void setObjCDeclQualifier(ObjCDeclQualifier QV) { objcDeclQualifier = QV; }
/// Determine whether this method has a result type that is related
/// to the message receiver's type.
bool hasRelatedResultType() const { return RelatedResultType; }
/// Note whether this method has a related result type.
void SetRelatedResultType(bool RRT = true) { RelatedResultType = RRT; }
/// True if this is a method redeclaration in the same interface.
bool isRedeclaration() const { return IsRedeclaration; }
void setAsRedeclaration(const ObjCMethodDecl *PrevMethod);
/// Returns the location where the declarator ends. It will be
/// the location of ';' for a method declaration and the location of '{'
/// for a method definition.
SourceLocation getDeclaratorEndLoc() const { return DeclEndLoc; }
// Location information, modeled after the Stmt API.
SourceLocation getLocStart() const LLVM_READONLY { return getBeginLoc(); }
SourceLocation getBeginLoc() const LLVM_READONLY { return getLocation(); }
SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); }
SourceLocation getEndLoc() const LLVM_READONLY;
SourceRange getSourceRange() const override LLVM_READONLY {
return SourceRange(getLocation(), getLocEnd());
}
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,
parameters(),
DeclEndLoc);
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();
}
ObjCInterfaceDecl *getClassInterface();
const ObjCInterfaceDecl *getClassInterface() const {
return const_cast<ObjCMethodDecl*>(this)->getClassInterface();
}
Selector getSelector() const { return getDeclName().getObjCSelector(); }
QualType getReturnType() const { return MethodDeclType; }
void setReturnType(QualType T) { MethodDeclType = T; }
SourceRange getReturnTypeSourceRange() const;
/// Determine the type of an expression that sends a message to this
/// function. This replaces the type parameters with the types they would
/// get if the receiver was parameterless (e.g. it may replace the type
/// parameter with 'id').
QualType getSendResultType() const;
/// Determine the type of an expression that sends a message to this
/// function with the given receiver type.
QualType getSendResultType(QualType receiverType) const;
TypeSourceInfo *getReturnTypeSourceInfo() const { return ReturnTInfo; }
void setReturnTypeSourceInfo(TypeSourceInfo *TInfo) { ReturnTInfo = TInfo; }
// Iterator access to formal parameters.
unsigned param_size() const { return NumParams; }
using param_const_iterator = const ParmVarDecl *const *;
using param_iterator = ParmVarDecl *const *;
using param_range = llvm::iterator_range<param_iterator>;
using param_const_range = llvm::iterator_range<param_const_iterator>;
param_const_iterator param_begin() const {
return param_const_iterator(getParams());
}
param_const_iterator param_end() const {
return param_const_iterator(getParams() + NumParams);
}
param_iterator param_begin() { return param_iterator(getParams()); }
param_iterator param_end() { return param_iterator(getParams() + NumParams); }
// This method returns and of the parameters which are part of the selector
// name mangling requirements.
param_const_iterator sel_param_end() const {
return param_begin() + getSelector().getNumArgs();
}
// ArrayRef access to formal parameters. This should eventually
// replace the iterator interface above.
ArrayRef<ParmVarDecl*> parameters() const {
return llvm::makeArrayRef(const_cast<ParmVarDecl**>(getParams()),
NumParams);
}
/// Sets the method's parameters and selector source locations.
/// If the method is implicit (not coming from source) \p SelLocs is
/// ignored.
void setMethodParams(ASTContext &C,
ArrayRef<ParmVarDecl*> Params,
ArrayRef<SourceLocation> SelLocs = llvm::None);
// Iterator access to parameter types.
struct GetTypeFn {
QualType operator()(const ParmVarDecl *PD) const { return PD->getType(); }
};
using param_type_iterator =
llvm::mapped_iterator<param_const_iterator, GetTypeFn>;
param_type_iterator param_type_begin() const {
return llvm::map_iterator(param_begin(), GetTypeFn());
}
param_type_iterator param_type_end() const {
return llvm::map_iterator(param_end(), GetTypeFn());
}
/// createImplicitParams - Used to lazily create the self and cmd
/// implict parameters. This must be called prior to using getSelfDecl()
/// or getCmdDecl(). The call is ignored if the implicit parameters
/// have already been created.
void createImplicitParams(ASTContext &Context, const ObjCInterfaceDecl *ID);
/// \return the type for \c self and set \arg selfIsPseudoStrong and
/// \arg selfIsConsumed accordingly.
QualType getSelfType(ASTContext &Context, const ObjCInterfaceDecl *OID,
bool &selfIsPseudoStrong, bool &selfIsConsumed);
ImplicitParamDecl * getSelfDecl() const { return SelfDecl; }
void setSelfDecl(ImplicitParamDecl *SD) { SelfDecl = SD; }
ImplicitParamDecl * getCmdDecl() const { return CmdDecl; }
void setCmdDecl(ImplicitParamDecl *CD) { CmdDecl = CD; }
/// Determines the family of this method.
ObjCMethodFamily getMethodFamily() const;
bool isInstanceMethod() const { return IsInstance; }
void setInstanceMethod(bool isInst) { IsInstance = isInst; }
bool isVariadic() const { return IsVariadic; }
void setVariadic(bool isVar) { IsVariadic = isVar; }
bool isClassMethod() const { return !IsInstance; }
bool isPropertyAccessor() const { return IsPropertyAccessor; }
void setPropertyAccessor(bool isAccessor) { IsPropertyAccessor = isAccessor; }
bool isDefined() const { return IsDefined; }
void setDefined(bool isDefined) { IsDefined = isDefined; }
/// Whether this method overrides any other in the class hierarchy.
///
/// A method is said to override any method in the class's
/// base classes, its protocols, or its categories' protocols, that has
/// the same selector and is of the same kind (class or instance).
/// A method in an implementation is not considered as overriding the same
/// method in the interface or its categories.
bool isOverriding() const { return IsOverriding; }
void setOverriding(bool isOverriding) { IsOverriding = isOverriding; }
/// Return overridden methods for the given \p Method.
///
/// An ObjC method is considered to override any method in the class's
/// base classes (and base's categories), its protocols, or its categories'
/// protocols, that has
/// the same selector and is of the same kind (class or instance).
/// A method in an implementation is not considered as overriding the same
/// method in the interface or its categories.
void getOverriddenMethods(
SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const;
/// True if the method was a definition but its body was skipped.
bool hasSkippedBody() const { return HasSkippedBody; }
void setHasSkippedBody(bool Skipped = true) { HasSkippedBody = Skipped; }
/// Returns the property associated with this method's selector.
///
/// Note that even if this particular method is not marked as a property
/// accessor, it is still possible for it to match a property declared in a
/// superclass. Pass \c false if you only want to check the current class.
const ObjCPropertyDecl *findPropertyDecl(bool CheckOverrides = true) const;
// Related to protocols declared in \@protocol
void setDeclImplementation(ImplementationControl ic) {
DeclImplementation = ic;
}
ImplementationControl getImplementationControl() const {
return ImplementationControl(DeclImplementation);
}
bool isOptional() const {
return getImplementationControl() == Optional;
}
/// Returns true if this specific method declaration is marked with the
/// designated initializer attribute.
bool isThisDeclarationADesignatedInitializer() const;
/// Returns true if the method selector resolves to a designated initializer
/// in the class's interface.
///
/// \param InitMethod if non-null and the function returns true, it receives
/// the method declaration that was marked with the designated initializer
/// attribute.
bool isDesignatedInitializerForTheInterface(
const ObjCMethodDecl **InitMethod = nullptr) const;
/// Determine whether this method has a body.
bool hasBody() const override { return Body.isValid(); }
/// Retrieve the body of this method, if it has one.
Stmt *getBody() const override;
void setLazyBody(uint64_t Offset) { Body = Offset; }
CompoundStmt *getCompoundBody() { return (CompoundStmt*)getBody(); }
void setBody(Stmt *B) { Body = B; }
/// Returns whether this specific method is a definition.
bool isThisDeclarationADefinition() const { return hasBody(); }
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCMethod; }
static DeclContext *castToDeclContext(const ObjCMethodDecl *D) {
return static_cast<DeclContext *>(const_cast<ObjCMethodDecl*>(D));
}
static ObjCMethodDecl *castFromDeclContext(const DeclContext *DC) {
return static_cast<ObjCMethodDecl *>(const_cast<DeclContext*>(DC));
}
};
/// Describes the variance of a given generic parameter.
enum class ObjCTypeParamVariance : uint8_t {
/// The parameter is invariant: must match exactly.
Invariant,
/// The parameter is covariant, e.g., X<T> is a subtype of X<U> when
/// the type parameter is covariant and T is a subtype of U.
Covariant,
/// The parameter is contravariant, e.g., X<T> is a subtype of X<U>
/// when the type parameter is covariant and U is a subtype of T.
Contravariant,
};
/// Represents the declaration of an Objective-C type parameter.
///
/// \code
/// @interface NSDictionary<Key : id<NSCopying>, Value>
/// @end
/// \endcode
///
/// In the example above, both \c Key and \c Value are represented by
/// \c ObjCTypeParamDecl. \c Key has an explicit bound of \c id<NSCopying>,
/// while \c Value gets an implicit bound of \c id.
///
/// Objective-C type parameters are typedef-names in the grammar,
class ObjCTypeParamDecl : public TypedefNameDecl {
/// Index of this type parameter in the type parameter list.
unsigned Index : 14;
/// The variance of the type parameter.
unsigned Variance : 2;
/// The location of the variance, if any.
SourceLocation VarianceLoc;
/// The location of the ':', which will be valid when the bound was
/// explicitly specified.
SourceLocation ColonLoc;
ObjCTypeParamDecl(ASTContext &ctx, DeclContext *dc,
ObjCTypeParamVariance variance, SourceLocation varianceLoc,
unsigned index,
SourceLocation nameLoc, IdentifierInfo *name,
SourceLocation colonLoc, TypeSourceInfo *boundInfo)
: TypedefNameDecl(ObjCTypeParam, ctx, dc, nameLoc, nameLoc, name,
boundInfo),
Index(index), Variance(static_cast<unsigned>(variance)),
VarianceLoc(varianceLoc), ColonLoc(colonLoc) {}
void anchor() override;
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
static ObjCTypeParamDecl *Create(ASTContext &ctx, DeclContext *dc,
ObjCTypeParamVariance variance,
SourceLocation varianceLoc,
unsigned index,
SourceLocation nameLoc,
IdentifierInfo *name,
SourceLocation colonLoc,
TypeSourceInfo *boundInfo);
static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx, unsigned ID);
SourceRange getSourceRange() const override LLVM_READONLY;
/// Determine the variance of this type parameter.
ObjCTypeParamVariance getVariance() const {
return static_cast<ObjCTypeParamVariance>(Variance);
}
/// Set the variance of this type parameter.
void setVariance(ObjCTypeParamVariance variance) {
Variance = static_cast<unsigned>(variance);
}
/// Retrieve the location of the variance keyword.
SourceLocation getVarianceLoc() const { return VarianceLoc; }
/// Retrieve the index into its type parameter list.
unsigned getIndex() const { return Index; }
/// Whether this type parameter has an explicitly-written type bound, e.g.,
/// "T : NSView".
bool hasExplicitBound() const { return ColonLoc.isValid(); }
/// Retrieve the location of the ':' separating the type parameter name
/// from the explicitly-specified bound.
SourceLocation getColonLoc() const { return ColonLoc; }
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCTypeParam; }
};
/// Stores a list of Objective-C type parameters for a parameterized class
/// or a category/extension thereof.
///
/// \code
/// @interface NSArray<T> // stores the <T>
/// @end
/// \endcode
class ObjCTypeParamList final
: private llvm::TrailingObjects<ObjCTypeParamList, ObjCTypeParamDecl *> {
/// Stores the components of a SourceRange as a POD.
struct PODSourceRange {
unsigned Begin;
unsigned End;
};
union {
/// Location of the left and right angle brackets.
PODSourceRange Brackets;
// Used only for alignment.
ObjCTypeParamDecl *AlignmentHack;
};
/// The number of parameters in the list, which are tail-allocated.
unsigned NumParams;
ObjCTypeParamList(SourceLocation lAngleLoc,
ArrayRef<ObjCTypeParamDecl *> typeParams,
SourceLocation rAngleLoc);
public:
friend TrailingObjects;
/// Create a new Objective-C type parameter list.
static ObjCTypeParamList *create(ASTContext &ctx,
SourceLocation lAngleLoc,
ArrayRef<ObjCTypeParamDecl *> typeParams,
SourceLocation rAngleLoc);
/// Iterate through the type parameters in the list.
using iterator = ObjCTypeParamDecl **;
iterator begin() { return getTrailingObjects<ObjCTypeParamDecl *>(); }
iterator end() { return begin() + size(); }
/// Determine the number of type parameters in this list.
unsigned size() const { return NumParams; }
// Iterate through the type parameters in the list.
using const_iterator = ObjCTypeParamDecl * const *;
const_iterator begin() const {
return getTrailingObjects<ObjCTypeParamDecl *>();
}
const_iterator end() const {
return begin() + size();
}
ObjCTypeParamDecl *front() const {
assert(size() > 0 && "empty Objective-C type parameter list");
return *begin();
}
ObjCTypeParamDecl *back() const {
assert(size() > 0 && "empty Objective-C type parameter list");
return *(end() - 1);
}
SourceLocation getLAngleLoc() const {
return SourceLocation::getFromRawEncoding(Brackets.Begin);
}
SourceLocation getRAngleLoc() const {
return SourceLocation::getFromRawEncoding(Brackets.End);
}
SourceRange getSourceRange() const {
return SourceRange(getLAngleLoc(), getRAngleLoc());
}
/// Gather the default set of type arguments to be substituted for
/// these type parameters when dealing with an unspecialized type.
void gatherDefaultTypeArgs(SmallVectorImpl<QualType> &typeArgs) const;
};
enum class ObjCPropertyQueryKind : uint8_t {
OBJC_PR_query_unknown = 0x00,
OBJC_PR_query_instance,
OBJC_PR_query_class
};
/// Represents one property declaration in an Objective-C interface.
///
/// For example:
/// \code{.mm}
/// \@property (assign, readwrite) int MyProperty;
/// \endcode
class ObjCPropertyDecl : public NamedDecl {
void anchor() override;
public:
enum PropertyAttributeKind {
OBJC_PR_noattr = 0x00,
OBJC_PR_readonly = 0x01,
OBJC_PR_getter = 0x02,
OBJC_PR_assign = 0x04,
OBJC_PR_readwrite = 0x08,
OBJC_PR_retain = 0x10,
OBJC_PR_copy = 0x20,
OBJC_PR_nonatomic = 0x40,
OBJC_PR_setter = 0x80,
OBJC_PR_atomic = 0x100,
OBJC_PR_weak = 0x200,
OBJC_PR_strong = 0x400,
OBJC_PR_unsafe_unretained = 0x800,
/// Indicates that the nullability of the type was spelled with a
/// property attribute rather than a type qualifier.
OBJC_PR_nullability = 0x1000,
OBJC_PR_null_resettable = 0x2000,
OBJC_PR_class = 0x4000
// Adding a property should change NumPropertyAttrsBits
};
enum {
/// Number of bits fitting all the property attributes.
NumPropertyAttrsBits = 15
};
enum SetterKind { Assign, Retain, Copy, Weak };
enum PropertyControl { None, Required, Optional };
private:
// location of \@property
SourceLocation AtLoc;
// location of '(' starting attribute list or null.
SourceLocation LParenLoc;
QualType DeclType;
TypeSourceInfo *DeclTypeSourceInfo;
unsigned PropertyAttributes : NumPropertyAttrsBits;
unsigned PropertyAttributesAsWritten : NumPropertyAttrsBits;
// \@required/\@optional
unsigned PropertyImplementation : 2;
// getter name of NULL if no getter
Selector GetterName;
// setter name of NULL if no setter
Selector SetterName;
// location of the getter attribute's value
SourceLocation GetterNameLoc;
// location of the setter attribute's value
SourceLocation SetterNameLoc;
// Declaration of getter instance method
ObjCMethodDecl *GetterMethodDecl = nullptr;
// Declaration of setter instance method
ObjCMethodDecl *SetterMethodDecl = nullptr;
// Synthesize ivar for this property
ObjCIvarDecl *PropertyIvarDecl = nullptr;
ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
SourceLocation AtLocation, SourceLocation LParenLocation,
QualType T, TypeSourceInfo *TSI,
PropertyControl propControl)
: NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation),
LParenLoc(LParenLocation), DeclType(T), DeclTypeSourceInfo(TSI),
PropertyAttributes(OBJC_PR_noattr),
PropertyAttributesAsWritten(OBJC_PR_noattr),
PropertyImplementation(propControl), GetterName(Selector()),
SetterName(Selector()) {}
public:
static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
IdentifierInfo *Id, SourceLocation AtLocation,
SourceLocation LParenLocation,
QualType T,
TypeSourceInfo *TSI,
PropertyControl propControl = None);
static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID);
SourceLocation getAtLoc() const { return AtLoc; }
void setAtLoc(SourceLocation L) { AtLoc = L; }
SourceLocation getLParenLoc() const { return LParenLoc; }
void setLParenLoc(SourceLocation L) { LParenLoc = L; }
TypeSourceInfo *getTypeSourceInfo() const { return DeclTypeSourceInfo; }
QualType getType() const { return DeclType; }
void setType(QualType T, TypeSourceInfo *TSI) {
DeclType = T;
DeclTypeSourceInfo = TSI;
}
/// Retrieve the type when this property is used with a specific base object
/// type.
QualType getUsageType(QualType objectType) const;
PropertyAttributeKind getPropertyAttributes() const {
return PropertyAttributeKind(PropertyAttributes);
}
void setPropertyAttributes(PropertyAttributeKind PRVal) {
PropertyAttributes |= PRVal;
}
void overwritePropertyAttributes(unsigned PRVal) {
PropertyAttributes = PRVal;
}
PropertyAttributeKind getPropertyAttributesAsWritten() const {
return PropertyAttributeKind(PropertyAttributesAsWritten);
}
void setPropertyAttributesAsWritten(PropertyAttributeKind PRVal) {
PropertyAttributesAsWritten = PRVal;
}
// Helper methods for accessing attributes.
/// isReadOnly - Return true iff the property has a setter.
bool isReadOnly() const {
return (PropertyAttributes & OBJC_PR_readonly);
}
/// isAtomic - Return true if the property is atomic.
bool isAtomic() const {
return (PropertyAttributes & OBJC_PR_atomic);
}
/// isRetaining - Return true if the property retains its value.
bool isRetaining() const {
return (PropertyAttributes &
(OBJC_PR_retain | OBJC_PR_strong | OBJC_PR_copy));
}
bool isInstanceProperty() const { return !isClassProperty(); }
bool isClassProperty() const { return PropertyAttributes & OBJC_PR_class; }
ObjCPropertyQueryKind getQueryKind() const {
return isClassProperty() ? ObjCPropertyQueryKind::OBJC_PR_query_class :
ObjCPropertyQueryKind::OBJC_PR_query_instance;
}
static ObjCPropertyQueryKind getQueryKind(bool isClassProperty) {
return isClassProperty ? ObjCPropertyQueryKind::OBJC_PR_query_class :
ObjCPropertyQueryKind::OBJC_PR_query_instance;
}
/// getSetterKind - Return the method used for doing assignment in
/// the property setter. This is only valid if the property has been
/// defined to have a setter.
SetterKind getSetterKind() const {
if (PropertyAttributes & OBJC_PR_strong)
return getType()->isBlockPointerType() ? Copy : Retain;
if (PropertyAttributes & OBJC_PR_retain)
return Retain;
if (PropertyAttributes & OBJC_PR_copy)
return Copy;
if (PropertyAttributes & OBJC_PR_weak)
return Weak;
return Assign;
}
Selector getGetterName() const { return GetterName; }
SourceLocation getGetterNameLoc() const { return GetterNameLoc; }
void setGetterName(Selector Sel, SourceLocation Loc = SourceLocation()) {
GetterName = Sel;
GetterNameLoc = Loc;
}
Selector getSetterName() const { return SetterName; }
SourceLocation getSetterNameLoc() const { return SetterNameLoc; }
void setSetterName(Selector Sel, SourceLocation Loc = SourceLocation()) {
SetterName = Sel;
SetterNameLoc = Loc;
}
ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; }
void setGetterMethodDecl(ObjCMethodDecl *gDecl) { GetterMethodDecl = gDecl; }
ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; }
void setSetterMethodDecl(ObjCMethodDecl *gDecl) { SetterMethodDecl = gDecl; }
// Related to \@optional/\@required declared in \@protocol
void setPropertyImplementation(PropertyControl pc) {
PropertyImplementation = pc;
}
PropertyControl getPropertyImplementation() const {
return PropertyControl(PropertyImplementation);
}
bool isOptional() const {
return getPropertyImplementation() == PropertyControl::Optional;
}
void setPropertyIvarDecl(ObjCIvarDecl *Ivar) {
PropertyIvarDecl = Ivar;
}
ObjCIvarDecl *getPropertyIvarDecl() const {
return PropertyIvarDecl;
}
SourceRange getSourceRange() const override LLVM_READONLY {
return SourceRange(AtLoc, getLocation());
}
/// Get the default name of the synthesized ivar.
IdentifierInfo *getDefaultSynthIvarName(ASTContext &Ctx) const;
/// Lookup a property by name in the specified DeclContext.
static ObjCPropertyDecl *findPropertyDecl(const DeclContext *DC,
const IdentifierInfo *propertyID,
ObjCPropertyQueryKind queryKind);
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCProperty; }
};
/// ObjCContainerDecl - Represents a container for method declarations.
/// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl,
/// ObjCProtocolDecl, and ObjCImplDecl.
///
class ObjCContainerDecl : public NamedDecl, public DeclContext {
SourceLocation AtStart;
// These two locations in the range mark the end of the method container.
// The first points to the '@' token, and the second to the 'end' token.
SourceRange AtEnd;
void anchor() override;
public:
ObjCContainerDecl(Kind DK, DeclContext *DC,
IdentifierInfo *Id, SourceLocation nameLoc,
SourceLocation atStartLoc)
: NamedDecl(DK, DC, nameLoc, Id), DeclContext(DK), AtStart(atStartLoc) {}
// Iterator access to instance/class properties.
using prop_iterator = specific_decl_iterator<ObjCPropertyDecl>;
using prop_range =
llvm::iterator_range<specific_decl_iterator<ObjCPropertyDecl>>;
prop_range properties() const { return prop_range(prop_begin(), prop_end()); }
prop_iterator prop_begin() const {
return prop_iterator(decls_begin());
}
prop_iterator prop_end() const {
return prop_iterator(decls_end());
}
using instprop_iterator =
filtered_decl_iterator<ObjCPropertyDecl,
&ObjCPropertyDecl::isInstanceProperty>;
using instprop_range = llvm::iterator_range<instprop_iterator>;
instprop_range instance_properties() const {
return instprop_range(instprop_begin(), instprop_end());
}
instprop_iterator instprop_begin() const {
return instprop_iterator(decls_begin());
}
instprop_iterator instprop_end() const {
return instprop_iterator(decls_end());
}
using classprop_iterator =
filtered_decl_iterator<ObjCPropertyDecl,
&ObjCPropertyDecl::isClassProperty>;
using classprop_range = llvm::iterator_range<classprop_iterator>;
classprop_range class_properties() const {
return classprop_range(classprop_begin(), classprop_end());
}
classprop_iterator classprop_begin() const {
return classprop_iterator(decls_begin());
}
classprop_iterator classprop_end() const {
return classprop_iterator(decls_end());
}
// Iterator access to instance/class methods.
using method_iterator = specific_decl_iterator<ObjCMethodDecl>;
using method_range =
llvm::iterator_range<specific_decl_iterator<ObjCMethodDecl>>;
method_range methods() const {
return method_range(meth_begin(), meth_end());
}
method_iterator meth_begin() const {
return method_iterator(decls_begin());
}
method_iterator meth_end() const {
return method_iterator(decls_end());
}
using instmeth_iterator =
filtered_decl_iterator<ObjCMethodDecl,
&ObjCMethodDecl::isInstanceMethod>;
using instmeth_range = llvm::iterator_range<instmeth_iterator>;
instmeth_range instance_methods() const {
return instmeth_range(instmeth_begin(), instmeth_end());
}
instmeth_iterator instmeth_begin() const {
return instmeth_iterator(decls_begin());
}
instmeth_iterator instmeth_end() const {
return instmeth_iterator(decls_end());
}
using classmeth_iterator =
filtered_decl_iterator<ObjCMethodDecl,
&ObjCMethodDecl::isClassMethod>;
using classmeth_range = llvm::iterator_range<classmeth_iterator>;
classmeth_range class_methods() const {
return classmeth_range(classmeth_begin(), classmeth_end());
}
classmeth_iterator classmeth_begin() const {
return classmeth_iterator(decls_begin());
}
classmeth_iterator classmeth_end() const {
return classmeth_iterator(decls_end());
}
// Get the local instance/class method declared in this interface.
ObjCMethodDecl *getMethod(Selector Sel, bool isInstance,
bool AllowHidden = false) const;
ObjCMethodDecl *getInstanceMethod(Selector Sel,
bool AllowHidden = false) const {
return getMethod(Sel, true/*isInstance*/, AllowHidden);
}
ObjCMethodDecl *getClassMethod(Selector Sel, bool AllowHidden = false) const {
return getMethod(Sel, false/*isInstance*/, AllowHidden);
}
bool HasUserDeclaredSetterMethod(const ObjCPropertyDecl *P) const;
ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const;
ObjCPropertyDecl *
FindPropertyDeclaration(const IdentifierInfo *PropertyId,
ObjCPropertyQueryKind QueryKind) const;
using PropertyMap =
llvm::DenseMap<std::pair<IdentifierInfo *, unsigned/*isClassProperty*/>,
ObjCPropertyDecl *>;
using ProtocolPropertySet = llvm::SmallDenseSet<const ObjCProtocolDecl *, 8>;
using PropertyDeclOrder = llvm::SmallVector<ObjCPropertyDecl *, 8>;
/// This routine collects list of properties to be implemented in the class.
/// This includes, class's and its conforming protocols' properties.
/// Note, the superclass's properties are not included in the list.
virtual void collectPropertiesToImplement(PropertyMap &PM,
PropertyDeclOrder &PO) const {}
SourceLocation getAtStartLoc() const { return AtStart; }
void setAtStartLoc(SourceLocation Loc) { AtStart = Loc; }
// Marks the end of the container.
SourceRange getAtEndRange() const {
return AtEnd;
}
void setAtEndRange(SourceRange atEnd) {
AtEnd = atEnd;
}
SourceRange getSourceRange() const override LLVM_READONLY {
return SourceRange(AtStart, getAtEndRange().getEnd());
}
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
return K >= firstObjCContainer &&
K <= lastObjCContainer;
}
static DeclContext *castToDeclContext(const ObjCContainerDecl *D) {
return static_cast<DeclContext *>(const_cast<ObjCContainerDecl*>(D));
}
static ObjCContainerDecl *castFromDeclContext(const DeclContext *DC) {
return static_cast<ObjCContainerDecl *>(const_cast<DeclContext*>(DC));
}
};
/// Represents an ObjC class declaration.
///
/// For example:
///
/// \code
/// // MostPrimitive declares no super class (not particularly useful).
/// \@interface MostPrimitive
/// // no instance variables or methods.
/// \@end
///
/// // NSResponder inherits from NSObject & implements NSCoding (a protocol).
/// \@interface NSResponder : NSObject \<NSCoding>
/// { // instance variables are represented by ObjCIvarDecl.
/// id nextResponder; // nextResponder instance variable.
/// }
/// - (NSResponder *)nextResponder; // return a pointer to NSResponder.
/// - (void)mouseMoved:(NSEvent *)theEvent; // return void, takes a pointer
/// \@end // to an NSEvent.
/// \endcode
///
/// Unlike C/C++, forward class declarations are accomplished with \@class.
/// Unlike C/C++, \@class allows for a list of classes to be forward declared.
/// Unlike C++, ObjC is a single-rooted class model. In Cocoa, classes
/// typically inherit from NSObject (an exception is NSProxy).
///
class ObjCInterfaceDecl : public ObjCContainerDecl
, public Redeclarable<ObjCInterfaceDecl> {
friend class ASTContext;
/// TypeForDecl - This indicates the Type object that represents this
/// TypeDecl. It is a cache maintained by ASTContext::getObjCInterfaceType
mutable const Type *TypeForDecl = nullptr;
struct DefinitionData {
/// The definition of this class, for quick access from any
/// declaration.
ObjCInterfaceDecl *Definition = nullptr;
/// When non-null, this is always an ObjCObjectType.
TypeSourceInfo *SuperClassTInfo = nullptr;
/// Protocols referenced in the \@interface declaration
ObjCProtocolList ReferencedProtocols;
/// Protocols reference in both the \@interface and class extensions.
ObjCList<ObjCProtocolDecl> AllReferencedProtocols;
/// List of categories and class extensions defined for this class.
///
/// Categories are stored as a linked list in the AST, since the categories
/// and class extensions come long after the initial interface declaration,
/// and we avoid dynamically-resized arrays in the AST wherever possible.
ObjCCategoryDecl *CategoryList = nullptr;
/// IvarList - List of all ivars defined by this class; including class
/// extensions and implementation. This list is built lazily.
ObjCIvarDecl *IvarList = nullptr;
/// Indicates that the contents of this Objective-C class will be
/// completed by the external AST source when required.
mutable unsigned ExternallyCompleted : 1;
/// Indicates that the ivar cache does not yet include ivars
/// declared in the implementation.
mutable unsigned IvarListMissingImplementation : 1;
/// Indicates that this interface decl contains at least one initializer
/// marked with the 'objc_designated_initializer' attribute.
unsigned HasDesignatedInitializers : 1;
enum InheritedDesignatedInitializersState {
/// We didn't calculate whether the designated initializers should be
/// inherited or not.
IDI_Unknown = 0,
/// Designated initializers are inherited for the super class.
IDI_Inherited = 1,
/// The class does not inherit designated initializers.
IDI_NotInherited = 2
};
/// One of the \c InheritedDesignatedInitializersState enumeratos.
mutable unsigned InheritedDesignatedInitializers : 2;
/// The location of the last location in this declaration, before
/// the properties/methods. For example, this will be the '>', '}', or
/// identifier,
SourceLocation EndLoc;
DefinitionData()
: ExternallyCompleted(false), IvarListMissingImplementation(true),
HasDesignatedInitializers(false),
InheritedDesignatedInitializers(IDI_Unknown) {}
};
/// The type parameters associated with this class, if any.
ObjCTypeParamList *TypeParamList = nullptr;
/// Contains a pointer to the data associated with this class,
/// which will be NULL if this class has not yet been defined.
///
/// The bit indicates when we don't need to check for out-of-date
/// declarations. It will be set unless modules are enabled.
llvm::PointerIntPair<DefinitionData *, 1, bool> Data;
ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl,
bool IsInternal);
void anchor() override;
void LoadExternalDefinition() const;
DefinitionData &data() const {
assert(Data.getPointer() && "Declaration has no definition!");
return *Data.getPointer();
}
/// Allocate the definition data for this class.
void allocateDefinitionData();
using redeclarable_base = Redeclarable<ObjCInterfaceDecl>;
ObjCInterfaceDecl *getNextRedeclarationImpl() override {
return getNextRedeclaration();
}
ObjCInterfaceDecl *getPreviousDeclImpl() override {
return getPreviousDecl();
}
ObjCInterfaceDecl *getMostRecentDeclImpl() override {
return getMostRecentDecl();
}
public:
static ObjCInterfaceDecl *Create(const ASTContext &C, DeclContext *DC,
SourceLocation atLoc,
IdentifierInfo *Id,
ObjCTypeParamList *typeParamList,
ObjCInterfaceDecl *PrevDecl,
SourceLocation ClassLoc = SourceLocation(),
bool isInternal = false);
static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
/// Retrieve the type parameters of this class.
///
/// This function looks for a type parameter list for the given
/// class; if the class has been declared (with \c \@class) but not
/// defined (with \c \@interface), it will search for a declaration that
/// has type parameters, skipping any declarations that do not.
ObjCTypeParamList *getTypeParamList() const;
/// Set the type parameters of this class.
///
/// This function is used by the AST importer, which must import the type
/// parameters after creating their DeclContext to avoid loops.
void setTypeParamList(ObjCTypeParamList *TPL);
/// Retrieve the type parameters written on this particular declaration of
/// the class.
ObjCTypeParamList *getTypeParamListAsWritten() const {
return TypeParamList;
}
SourceRange getSourceRange() const override LLVM_READONLY {
if (isThisDeclarationADefinition())
return ObjCContainerDecl::getSourceRange();
return SourceRange(getAtStartLoc(), getLocation());
}
/// Indicate that this Objective-C class is complete, but that
/// the external AST source will be responsible for filling in its contents
/// when a complete class is required.
void setExternallyCompleted();
/// Indicate that this interface decl contains at least one initializer
/// marked with the 'objc_designated_initializer' attribute.
void setHasDesignatedInitializers();
/// Returns true if this interface decl contains at least one initializer
/// marked with the 'objc_designated_initializer' attribute.
bool hasDesignatedInitializers() const;
/// Returns true if this interface decl declares a designated initializer
/// or it inherites one from its super class.
bool declaresOrInheritsDesignatedInitializers() const {
return hasDesignatedInitializers() || inheritsDesignatedInitializers();
}
const ObjCProtocolList &getReferencedProtocols() const {
assert(hasDefinition() && "Caller did not check for forward reference!");
if (data().ExternallyCompleted)
LoadExternalDefinition();
return data().ReferencedProtocols;
}
ObjCImplementationDecl *getImplementation() const;
void setImplementation(ObjCImplementationDecl *ImplD);
ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const;
// Get the local instance/class method declared in a category.
ObjCMethodDecl *getCategoryInstanceMethod(Selector Sel) const;
ObjCMethodDecl *getCategoryClassMethod(Selector Sel) const;
ObjCMethodDecl *getCategoryMethod(Selector Sel, bool isInstance) const {
return isInstance ? getCategoryInstanceMethod(Sel)
: getCategoryClassMethod(Sel);
}
using protocol_iterator = ObjCProtocolList::iterator;
using protocol_range = llvm::iterator_range<protocol_iterator>;
protocol_range protocols() const {
return protocol_range(protocol_begin(), protocol_end());
}
protocol_iterator protocol_begin() const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return protocol_iterator();
if (data().ExternallyCompleted)
LoadExternalDefinition();
return data().ReferencedProtocols.begin();
}
protocol_iterator protocol_end() const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return protocol_iterator();
if (data().ExternallyCompleted)
LoadExternalDefinition();
return data().ReferencedProtocols.end();
}
using protocol_loc_iterator = ObjCProtocolList::loc_iterator;
using protocol_loc_range = llvm::iterator_range<protocol_loc_iterator>;
protocol_loc_range protocol_locs() const {
return protocol_loc_range(protocol_loc_begin(), protocol_loc_end());
}
protocol_loc_iterator protocol_loc_begin() const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return protocol_loc_iterator();
if (data().ExternallyCompleted)
LoadExternalDefinition();
return data().ReferencedProtocols.loc_begin();
}
protocol_loc_iterator protocol_loc_end() const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return protocol_loc_iterator();
if (data().ExternallyCompleted)
LoadExternalDefinition();
return data().ReferencedProtocols.loc_end();
}
using all_protocol_iterator = ObjCList<ObjCProtocolDecl>::iterator;
using all_protocol_range = llvm::iterator_range<all_protocol_iterator>;
all_protocol_range all_referenced_protocols() const {
return all_protocol_range(all_referenced_protocol_begin(),
all_referenced_protocol_end());
}
all_protocol_iterator all_referenced_protocol_begin() const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return all_protocol_iterator();
if (data().ExternallyCompleted)
LoadExternalDefinition();
return data().AllReferencedProtocols.empty()
? protocol_begin()
: data().AllReferencedProtocols.begin();
}
all_protocol_iterator all_referenced_protocol_end() const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return all_protocol_iterator();
if (data().ExternallyCompleted)
LoadExternalDefinition();
return data().AllReferencedProtocols.empty()
? protocol_end()
: data().AllReferencedProtocols.end();
}
using ivar_iterator = specific_decl_iterator<ObjCIvarDecl>;
using ivar_range = llvm::iterator_range<specific_decl_iterator<ObjCIvarDecl>>;
ivar_range ivars() const { return ivar_range(ivar_begin(), ivar_end()); }
ivar_iterator ivar_begin() const {
if (const ObjCInterfaceDecl *Def = getDefinition())
return ivar_iterator(Def->decls_begin());
// FIXME: Should make sure no callers ever do this.
return ivar_iterator();
}
ivar_iterator ivar_end() const {
if (const ObjCInterfaceDecl *Def = getDefinition())
return ivar_iterator(Def->decls_end());
// FIXME: Should make sure no callers ever do this.
return ivar_iterator();
}
unsigned ivar_size() const {
return std::distance(ivar_begin(), ivar_end());
}
bool ivar_empty() const { return ivar_begin() == ivar_end(); }
ObjCIvarDecl *all_declared_ivar_begin();
const ObjCIvarDecl *all_declared_ivar_begin() const {
// Even though this modifies IvarList, it's conceptually const:
// the ivar chain is essentially a cached property of ObjCInterfaceDecl.
return const_cast<ObjCInterfaceDecl *>(this)->all_declared_ivar_begin();
}
void setIvarList(ObjCIvarDecl *ivar) { data().IvarList = ivar; }
/// setProtocolList - Set the list of protocols that this interface
/// implements.
void setProtocolList(ObjCProtocolDecl *const* List, unsigned Num,
const SourceLocation *Locs, ASTContext &C) {
data().ReferencedProtocols.set(List, Num, Locs, C);
}
/// mergeClassExtensionProtocolList - Merge class extension's protocol list
/// into the protocol list for this class.
void mergeClassExtensionProtocolList(ObjCProtocolDecl *const* List,
unsigned Num,
ASTContext &C);
/// Produce a name to be used for class's metadata. It comes either via
/// objc_runtime_name attribute or class name.
StringRef getObjCRuntimeNameAsString() const;
/// Returns the designated initializers for the interface.
///
/// If this declaration does not have methods marked as designated
/// initializers then the interface inherits the designated initializers of
/// its super class.
void getDesignatedInitializers(
llvm::SmallVectorImpl<const ObjCMethodDecl *> &Methods) const;
/// Returns true if the given selector is a designated initializer for the
/// interface.
///
/// If this declaration does not have methods marked as designated
/// initializers then the interface inherits the designated initializers of
/// its super class.
///
/// \param InitMethod if non-null and the function returns true, it receives
/// the method that was marked as a designated initializer.
bool
isDesignatedInitializer(Selector Sel,
const ObjCMethodDecl **InitMethod = nullptr) const;
/// Determine whether this particular declaration of this class is
/// actually also a definition.
bool isThisDeclarationADefinition() const {
return getDefinition() == this;
}
/// Determine whether this class has been defined.
bool hasDefinition() const {
// If the name of this class is out-of-date, bring it up-to-date, which
// might bring in a definition.
// Note: a null value indicates that we don't have a definition and that
// modules are enabled.
if (!Data.getOpaqueValue())
getMostRecentDecl();
return Data.getPointer();
}
/// Retrieve the definition of this class, or NULL if this class
/// has been forward-declared (with \@class) but not yet defined (with
/// \@interface).
ObjCInterfaceDecl *getDefinition() {
return hasDefinition()? Data.getPointer()->Definition : nullptr;
}
/// Retrieve the definition of this class, or NULL if this class
/// has been forward-declared (with \@class) but not yet defined (with
/// \@interface).
const ObjCInterfaceDecl *getDefinition() const {
return hasDefinition()? Data.getPointer()->Definition : nullptr;
}
/// Starts the definition of this Objective-C class, taking it from
/// a forward declaration (\@class) to a definition (\@interface).
void startDefinition();
/// Retrieve the superclass type.
const ObjCObjectType *getSuperClassType() const {
if (TypeSourceInfo *TInfo = getSuperClassTInfo())
return TInfo->getType()->castAs<ObjCObjectType>();
return nullptr;
}
// Retrieve the type source information for the superclass.
TypeSourceInfo *getSuperClassTInfo() const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return nullptr;
if (data().ExternallyCompleted)
LoadExternalDefinition();
return data().SuperClassTInfo;
}
// Retrieve the declaration for the superclass of this class, which
// does not include any type arguments that apply to the superclass.
ObjCInterfaceDecl *getSuperClass() const;
void setSuperClass(TypeSourceInfo *superClass) {
data().SuperClassTInfo = superClass;
}
/// Iterator that walks over the list of categories, filtering out
/// those that do not meet specific criteria.
///
/// This class template is used for the various permutations of category
/// and extension iterators.
template<bool (*Filter)(ObjCCategoryDecl *)>
class filtered_category_iterator {
ObjCCategoryDecl *Current = nullptr;
void findAcceptableCategory();
public:
using value_type = ObjCCategoryDecl *;
using reference = value_type;
using pointer = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
filtered_category_iterator() = default;
explicit filtered_category_iterator(ObjCCategoryDecl *Current)
: Current(Current) {
findAcceptableCategory();
}
reference operator*() const { return Current; }
pointer operator->() const { return Current; }
filtered_category_iterator &operator++();
filtered_category_iterator operator++(int) {
filtered_category_iterator Tmp = *this;
++(*this);
return Tmp;
}
friend bool operator==(filtered_category_iterator X,
filtered_category_iterator Y) {
return X.Current == Y.Current;
}
friend bool operator!=(filtered_category_iterator X,
filtered_category_iterator Y) {
return X.Current != Y.Current;
}
};
private:
/// Test whether the given category is visible.
///
/// Used in the \c visible_categories_iterator.
static bool isVisibleCategory(ObjCCategoryDecl *Cat);
public:
/// Iterator that walks over the list of categories and extensions
/// that are visible, i.e., not hidden in a non-imported submodule.
using visible_categories_iterator =
filtered_category_iterator<isVisibleCategory>;
using visible_categories_range =
llvm::iterator_range<visible_categories_iterator>;
visible_categories_range visible_categories() const {
return visible_categories_range(visible_categories_begin(),
visible_categories_end());
}
/// Retrieve an iterator to the beginning of the visible-categories
/// list.
visible_categories_iterator visible_categories_begin() const {
return visible_categories_iterator(getCategoryListRaw());
}
/// Retrieve an iterator to the end of the visible-categories list.
visible_categories_iterator visible_categories_end() const {
return visible_categories_iterator();
}
/// Determine whether the visible-categories list is empty.
bool visible_categories_empty() const {
return visible_categories_begin() == visible_categories_end();
}
private:
/// Test whether the given category... is a category.
///
/// Used in the \c known_categories_iterator.
static bool isKnownCategory(ObjCCategoryDecl *) { return true; }
public:
/// Iterator that walks over all of the known categories and
/// extensions, including those that are hidden.
using known_categories_iterator = filtered_category_iterator<isKnownCategory>;
using known_categories_range =
llvm::iterator_range<known_categories_iterator>;
known_categories_range known_categories() const {
return known_categories_range(known_categories_begin(),
known_categories_end());
}
/// Retrieve an iterator to the beginning of the known-categories
/// list.
known_categories_iterator known_categories_begin() const {
return known_categories_iterator(getCategoryListRaw());
}
/// Retrieve an iterator to the end of the known-categories list.
known_categories_iterator known_categories_end() const {
return known_categories_iterator();
}
/// Determine whether the known-categories list is empty.
bool known_categories_empty() const {
return known_categories_begin() == known_categories_end();
}
private:
/// Test whether the given category is a visible extension.
///
/// Used in the \c visible_extensions_iterator.
static bool isVisibleExtension(ObjCCategoryDecl *Cat);
public:
/// Iterator that walks over all of the visible extensions, skipping
/// any that are known but hidden.
using visible_extensions_iterator =
filtered_category_iterator<isVisibleExtension>;
using visible_extensions_range =
llvm::iterator_range<visible_extensions_iterator>;
visible_extensions_range visible_extensions() const {
return visible_extensions_range(visible_extensions_begin(),
visible_extensions_end());
}
/// Retrieve an iterator to the beginning of the visible-extensions
/// list.
visible_extensions_iterator visible_extensions_begin() const {
return visible_extensions_iterator(getCategoryListRaw());
}
/// Retrieve an iterator to the end of the visible-extensions list.
visible_extensions_iterator visible_extensions_end() const {
return visible_extensions_iterator();
}
/// Determine whether the visible-extensions list is empty.
bool visible_extensions_empty() const {
return visible_extensions_begin() == visible_extensions_end();
}
private:
/// Test whether the given category is an extension.
///
/// Used in the \c known_extensions_iterator.
static bool isKnownExtension(ObjCCategoryDecl *Cat);
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
friend class ASTReader;
/// Iterator that walks over all of the known extensions.
using known_extensions_iterator =
filtered_category_iterator<isKnownExtension>;
using known_extensions_range =
llvm::iterator_range<known_extensions_iterator>;
known_extensions_range known_extensions() const {
return known_extensions_range(known_extensions_begin(),
known_extensions_end());
}
/// Retrieve an iterator to the beginning of the known-extensions
/// list.
known_extensions_iterator known_extensions_begin() const {
return known_extensions_iterator(getCategoryListRaw());
}
/// Retrieve an iterator to the end of the known-extensions list.
known_extensions_iterator known_extensions_end() const {
return known_extensions_iterator();
}
/// Determine whether the known-extensions list is empty.
bool known_extensions_empty() const {
return known_extensions_begin() == known_extensions_end();
}
/// Retrieve the raw pointer to the start of the category/extension
/// list.
ObjCCategoryDecl* getCategoryListRaw() const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return nullptr;
if (data().ExternallyCompleted)
LoadExternalDefinition();
return data().CategoryList;
}
/// Set the raw pointer to the start of the category/extension
/// list.
void setCategoryListRaw(ObjCCategoryDecl *category) {
data().CategoryList = category;
}
ObjCPropertyDecl
*FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId,
ObjCPropertyQueryKind QueryKind) const;
void collectPropertiesToImplement(PropertyMap &PM,
PropertyDeclOrder &PO) const override;
/// isSuperClassOf - Return true if this class is the specified class or is a
/// super class of the specified interface class.
bool isSuperClassOf(const ObjCInterfaceDecl *I) const {
// If RHS is derived from LHS it is OK; else it is not OK.
while (I != nullptr) {
if (declaresSameEntity(this, I))
return true;
I = I->getSuperClass();
}
return false;
}
/// isArcWeakrefUnavailable - Checks for a class or one of its super classes
/// to be incompatible with __weak references. Returns true if it is.
bool isArcWeakrefUnavailable() const;
/// isObjCRequiresPropertyDefs - Checks that a class or one of its super
/// classes must not be auto-synthesized. Returns class decl. if it must not
/// be; 0, otherwise.
const ObjCInterfaceDecl *isObjCRequiresPropertyDefs() const;
ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName,
ObjCInterfaceDecl *&ClassDeclared);
ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName) {
ObjCInterfaceDecl *ClassDeclared;
return lookupInstanceVariable(IVarName, ClassDeclared);
}
ObjCProtocolDecl *lookupNestedProtocol(IdentifierInfo *Name);
// Lookup a method. First, we search locally. If a method isn't
// found, we search referenced protocols and class categories.
ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance,
bool shallowCategoryLookup = false,
bool followSuper = true,
const ObjCCategoryDecl *C = nullptr) const;
/// Lookup an instance method for a given selector.
ObjCMethodDecl *lookupInstanceMethod(Selector Sel) const {
return lookupMethod(Sel, true/*isInstance*/);
}
/// Lookup a class method for a given selector.
ObjCMethodDecl *lookupClassMethod(Selector Sel) const {
return lookupMethod(Sel, false/*isInstance*/);
}
ObjCInterfaceDecl *lookupInheritedClass(const IdentifierInfo *ICName);
/// Lookup a method in the classes implementation hierarchy.
ObjCMethodDecl *lookupPrivateMethod(const Selector &Sel,
bool Instance=true) const;
ObjCMethodDecl *lookupPrivateClassMethod(const Selector &Sel) {
return lookupPrivateMethod(Sel, false);
}
/// Lookup a setter or getter in the class hierarchy,
/// including in all categories except for category passed
/// as argument.
ObjCMethodDecl *lookupPropertyAccessor(const Selector Sel,
const ObjCCategoryDecl *Cat,
bool IsClassProperty) const {
return lookupMethod(Sel, !IsClassProperty/*isInstance*/,
false/*shallowCategoryLookup*/,
true /* followsSuper */,
Cat);
}
SourceLocation getEndOfDefinitionLoc() const {
if (!hasDefinition())
return getLocation();
return data().EndLoc;
}
void setEndOfDefinitionLoc(SourceLocation LE) { data().EndLoc = LE; }
/// Retrieve the starting location of the superclass.
SourceLocation getSuperClassLoc() const;
/// isImplicitInterfaceDecl - check that this is an implicitly declared
/// ObjCInterfaceDecl node. This is for legacy objective-c \@implementation
/// declaration without an \@interface declaration.
bool isImplicitInterfaceDecl() const {
return hasDefinition() ? data().Definition->isImplicit() : isImplicit();
}
/// ClassImplementsProtocol - Checks that 'lProto' protocol
/// has been implemented in IDecl class, its super class or categories (if
/// lookupCategory is true).
bool ClassImplementsProtocol(ObjCProtocolDecl *lProto,
bool lookupCategory,
bool RHSIsQualifiedID = false);
using redecl_range = redeclarable_base::redecl_range;
using redecl_iterator = redeclarable_base::redecl_iterator;
using redeclarable_base::redecls_begin;
using redeclarable_base::redecls_end;
using redeclarable_base::redecls;
using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl;
using redeclarable_base::isFirstDecl;
/// Retrieves the canonical declaration of this Objective-C class.
ObjCInterfaceDecl *getCanonicalDecl() override { return getFirstDecl(); }
const ObjCInterfaceDecl *getCanonicalDecl() const { return getFirstDecl(); }
// Low-level accessor
const Type *getTypeForDecl() const { return TypeForDecl; }
void setTypeForDecl(const Type *TD) const { TypeForDecl = TD; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCInterface; }
private:
const ObjCInterfaceDecl *findInterfaceWithDesignatedInitializers() const;
bool inheritsDesignatedInitializers() const;
};
/// ObjCIvarDecl - Represents an ObjC instance variable. In general, ObjC
/// instance variables are identical to C. The only exception is Objective-C
/// supports C++ style access control. For example:
///
/// \@interface IvarExample : NSObject
/// {
/// id defaultToProtected;
/// \@public:
/// id canBePublic; // same as C++.
/// \@protected:
/// id canBeProtected; // same as C++.
/// \@package:
/// id canBePackage; // framework visibility (not available in C++).
/// }
///
class ObjCIvarDecl : public FieldDecl {
void anchor() override;
public:
enum AccessControl {
None, Private, Protected, Public, Package
};
private:
ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
bool synthesized)
: FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
/*Mutable=*/false, /*HasInit=*/ICIS_NoInit),
DeclAccess(ac), Synthesized(synthesized) {}
public:
static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo,
AccessControl ac, Expr *BW = nullptr,
bool synthesized=false);
static ObjCIvarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
/// Return the class interface that this ivar is logically contained
/// in; this is either the interface where the ivar was declared, or the
/// interface the ivar is conceptually a part of in the case of synthesized
/// ivars.
const ObjCInterfaceDecl *getContainingInterface() const;
ObjCIvarDecl *getNextIvar() { return NextIvar; }
const ObjCIvarDecl *getNextIvar() const { return NextIvar; }
void setNextIvar(ObjCIvarDecl *ivar) { NextIvar = ivar; }
void setAccessControl(AccessControl ac) { DeclAccess = ac; }
AccessControl getAccessControl() const { return AccessControl(DeclAccess); }
AccessControl getCanonicalAccessControl() const {
return DeclAccess == None ? Protected : AccessControl(DeclAccess);
}
void setSynthesize(bool synth) { Synthesized = synth; }
bool getSynthesize() const { return Synthesized; }
/// Retrieve the type of this instance variable when viewed as a member of a
/// specific object type.
QualType getUsageType(QualType objectType) const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCIvar; }
private:
/// NextIvar - Next Ivar in the list of ivars declared in class; class's
/// extensions and class's implementation
ObjCIvarDecl *NextIvar = nullptr;
// NOTE: VC++ treats enums as signed, avoid using the AccessControl enum
unsigned DeclAccess : 3;
unsigned Synthesized : 1;
};
/// Represents a field declaration created by an \@defs(...).
class ObjCAtDefsFieldDecl : public FieldDecl {
ObjCAtDefsFieldDecl(DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, Expr *BW)
: FieldDecl(ObjCAtDefsField, DC, StartLoc, IdLoc, Id, T,
/*TInfo=*/nullptr, // FIXME: Do ObjCAtDefs have declarators ?
BW, /*Mutable=*/false, /*HasInit=*/ICIS_NoInit) {}
void anchor() override;
public:
static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, Expr *BW);
static ObjCAtDefsFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCAtDefsField; }
};
/// Represents an Objective-C protocol declaration.
///
/// Objective-C protocols declare a pure abstract type (i.e., no instance
/// variables are permitted). Protocols originally drew inspiration from
/// C++ pure virtual functions (a C++ feature with nice semantics and lousy
/// syntax:-). Here is an example:
///
/// \code
/// \@protocol NSDraggingInfo <refproto1, refproto2>
/// - (NSWindow *)draggingDestinationWindow;
/// - (NSImage *)draggedImage;
/// \@end
/// \endcode
///
/// This says that NSDraggingInfo requires two methods and requires everything
/// that the two "referenced protocols" 'refproto1' and 'refproto2' require as
/// well.
///
/// \code
/// \@interface ImplementsNSDraggingInfo : NSObject \<NSDraggingInfo>
/// \@end
/// \endcode
///
/// ObjC protocols inspired Java interfaces. Unlike Java, ObjC classes and
/// protocols are in distinct namespaces. For example, Cocoa defines both
/// an NSObject protocol and class (which isn't allowed in Java). As a result,
/// protocols are referenced using angle brackets as follows:
///
/// id \<NSDraggingInfo> anyObjectThatImplementsNSDraggingInfo;
class ObjCProtocolDecl : public ObjCContainerDecl,
public Redeclarable<ObjCProtocolDecl> {
struct DefinitionData {
// The declaration that defines this protocol.
ObjCProtocolDecl *Definition;
/// Referenced protocols
ObjCProtocolList ReferencedProtocols;
};
/// Contains a pointer to the data associated with this class,
/// which will be NULL if this class has not yet been defined.
///
/// The bit indicates when we don't need to check for out-of-date
/// declarations. It will be set unless modules are enabled.
llvm::PointerIntPair<DefinitionData *, 1, bool> Data;
ObjCProtocolDecl(ASTContext &C, DeclContext *DC, IdentifierInfo *Id,
SourceLocation nameLoc, SourceLocation atStartLoc,
ObjCProtocolDecl *PrevDecl);
void anchor() override;
DefinitionData &data() const {
assert(Data.getPointer() && "Objective-C protocol has no definition!");
return *Data.getPointer();
}
void allocateDefinitionData();
using redeclarable_base = Redeclarable<ObjCProtocolDecl>;
ObjCProtocolDecl *getNextRedeclarationImpl() override {
return getNextRedeclaration();
}
ObjCProtocolDecl *getPreviousDeclImpl() override {
return getPreviousDecl();
}
ObjCProtocolDecl *getMostRecentDeclImpl() override {
return getMostRecentDecl();
}
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
friend class ASTReader;
static ObjCProtocolDecl *Create(ASTContext &C, DeclContext *DC,
IdentifierInfo *Id,
SourceLocation nameLoc,
SourceLocation atStartLoc,
ObjCProtocolDecl *PrevDecl);
static ObjCProtocolDecl *CreateDeserialized(ASTContext &C, unsigned ID);
const ObjCProtocolList &getReferencedProtocols() const {
assert(hasDefinition() && "No definition available!");
return data().ReferencedProtocols;
}
using protocol_iterator = ObjCProtocolList::iterator;
using protocol_range = llvm::iterator_range<protocol_iterator>;
protocol_range protocols() const {
return protocol_range(protocol_begin(), protocol_end());
}
protocol_iterator protocol_begin() const {
if (!hasDefinition())
return protocol_iterator();
return data().ReferencedProtocols.begin();
}
protocol_iterator protocol_end() const {
if (!hasDefinition())
return protocol_iterator();
return data().ReferencedProtocols.end();
}
using protocol_loc_iterator = ObjCProtocolList::loc_iterator;
using protocol_loc_range = llvm::iterator_range<protocol_loc_iterator>;
protocol_loc_range protocol_locs() const {
return protocol_loc_range(protocol_loc_begin(), protocol_loc_end());
}
protocol_loc_iterator protocol_loc_begin() const {
if (!hasDefinition())
return protocol_loc_iterator();
return data().ReferencedProtocols.loc_begin();
}
protocol_loc_iterator protocol_loc_end() const {
if (!hasDefinition())
return protocol_loc_iterator();
return data().ReferencedProtocols.loc_end();
}
unsigned protocol_size() const {
if (!hasDefinition())
return 0;
return data().ReferencedProtocols.size();
}
/// setProtocolList - Set the list of protocols that this interface
/// implements.
void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num,
const SourceLocation *Locs, ASTContext &C) {
assert(hasDefinition() && "Protocol is not defined");
data().ReferencedProtocols.set(List, Num, Locs, C);
}
ObjCProtocolDecl *lookupProtocolNamed(IdentifierInfo *PName);
// Lookup a method. First, we search locally. If a method isn't
// found, we search referenced protocols and class categories.
ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance) const;
ObjCMethodDecl *lookupInstanceMethod(Selector Sel) const {
return lookupMethod(Sel, true/*isInstance*/);
}
ObjCMethodDecl *lookupClassMethod(Selector Sel) const {
return lookupMethod(Sel, false/*isInstance*/);
}
/// Determine whether this protocol has a definition.
bool hasDefinition() const {
// If the name of this protocol is out-of-date, bring it up-to-date, which
// might bring in a definition.
// Note: a null value indicates that we don't have a definition and that
// modules are enabled.
if (!Data.getOpaqueValue())
getMostRecentDecl();
return Data.getPointer();
}
/// Retrieve the definition of this protocol, if any.
ObjCProtocolDecl *getDefinition() {
return hasDefinition()? Data.getPointer()->Definition : nullptr;
}
/// Retrieve the definition of this protocol, if any.
const ObjCProtocolDecl *getDefinition() const {
return hasDefinition()? Data.getPointer()->Definition : nullptr;
}
/// Determine whether this particular declaration is also the
/// definition.
bool isThisDeclarationADefinition() const {
return getDefinition() == this;
}
/// Starts the definition of this Objective-C protocol.
void startDefinition();
/// Produce a name to be used for protocol's metadata. It comes either via
/// objc_runtime_name attribute or protocol name.
StringRef getObjCRuntimeNameAsString() const;
SourceRange getSourceRange() const override LLVM_READONLY {
if (isThisDeclarationADefinition())
return ObjCContainerDecl::getSourceRange();
return SourceRange(getAtStartLoc(), getLocation());
}
using redecl_range = redeclarable_base::redecl_range;
using redecl_iterator = redeclarable_base::redecl_iterator;
using redeclarable_base::redecls_begin;
using redeclarable_base::redecls_end;
using redeclarable_base::redecls;
using redeclarable_base::getPreviousDecl;
using redeclarable_base::getMostRecentDecl;
using redeclarable_base::isFirstDecl;
/// Retrieves the canonical declaration of this Objective-C protocol.
ObjCProtocolDecl *getCanonicalDecl() override { return getFirstDecl(); }
const ObjCProtocolDecl *getCanonicalDecl() const { return getFirstDecl(); }
void collectPropertiesToImplement(PropertyMap &PM,
PropertyDeclOrder &PO) const override;
void collectInheritedProtocolProperties(const ObjCPropertyDecl *Property,
ProtocolPropertySet &PS,
PropertyDeclOrder &PO) const;
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCProtocol; }
};
/// ObjCCategoryDecl - Represents a category declaration. A category allows
/// you to add methods to an existing class (without subclassing or modifying
/// the original class interface or implementation:-). Categories don't allow
/// you to add instance data. The following example adds "myMethod" to all
/// NSView's within a process:
///
/// \@interface NSView (MyViewMethods)
/// - myMethod;
/// \@end
///
/// Categories also allow you to split the implementation of a class across
/// several files (a feature more naturally supported in C++).
///
/// Categories were originally inspired by dynamic languages such as Common
/// Lisp and Smalltalk. More traditional class-based languages (C++, Java)
/// don't support this level of dynamism, which is both powerful and dangerous.
class ObjCCategoryDecl : public ObjCContainerDecl {
/// Interface belonging to this category
ObjCInterfaceDecl *ClassInterface;
/// The type parameters associated with this category, if any.
ObjCTypeParamList *TypeParamList = nullptr;
/// referenced protocols in this category.
ObjCProtocolList ReferencedProtocols;
/// Next category belonging to this class.
/// FIXME: this should not be a singly-linked list. Move storage elsewhere.
ObjCCategoryDecl *NextClassCategory = nullptr;
/// The location of the category name in this declaration.
SourceLocation CategoryNameLoc;
/// class extension may have private ivars.
SourceLocation IvarLBraceLoc;
SourceLocation IvarRBraceLoc;
ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
ObjCTypeParamList *typeParamList,
SourceLocation IvarLBraceLoc = SourceLocation(),
SourceLocation IvarRBraceLoc = SourceLocation());
void anchor() override;
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation AtLoc,
SourceLocation ClassNameLoc,
SourceLocation CategoryNameLoc,
IdentifierInfo *Id,
ObjCInterfaceDecl *IDecl,
ObjCTypeParamList *typeParamList,
SourceLocation IvarLBraceLoc=SourceLocation(),
SourceLocation IvarRBraceLoc=SourceLocation());
static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID);
ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
/// Retrieve the type parameter list associated with this category or
/// extension.
ObjCTypeParamList *getTypeParamList() const { return TypeParamList; }
/// Set the type parameters of this category.
///
/// This function is used by the AST importer, which must import the type
/// parameters after creating their DeclContext to avoid loops.
void setTypeParamList(ObjCTypeParamList *TPL);
ObjCCategoryImplDecl *getImplementation() const;
void setImplementation(ObjCCategoryImplDecl *ImplD);
/// setProtocolList - Set the list of protocols that this interface
/// implements.
void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num,
const SourceLocation *Locs, ASTContext &C) {
ReferencedProtocols.set(List, Num, Locs, C);
}
const ObjCProtocolList &getReferencedProtocols() const {
return ReferencedProtocols;
}
using protocol_iterator = ObjCProtocolList::iterator;
using protocol_range = llvm::iterator_range<protocol_iterator>;
protocol_range protocols() const {
return protocol_range(protocol_begin(), protocol_end());
}
protocol_iterator protocol_begin() const {
return ReferencedProtocols.begin();
}
protocol_iterator protocol_end() const { return ReferencedProtocols.end(); }
unsigned protocol_size() const { return ReferencedProtocols.size(); }
using protocol_loc_iterator = ObjCProtocolList::loc_iterator;
using protocol_loc_range = llvm::iterator_range<protocol_loc_iterator>;
protocol_loc_range protocol_locs() const {
return protocol_loc_range(protocol_loc_begin(), protocol_loc_end());
}
protocol_loc_iterator protocol_loc_begin() const {
return ReferencedProtocols.loc_begin();
}
protocol_loc_iterator protocol_loc_end() const {
return ReferencedProtocols.loc_end();
}
ObjCCategoryDecl *getNextClassCategory() const { return NextClassCategory; }
/// Retrieve the pointer to the next stored category (or extension),
/// which may be hidden.
ObjCCategoryDecl *getNextClassCategoryRaw() const {
return NextClassCategory;
}
bool IsClassExtension() const { return getIdentifier() == nullptr; }
using ivar_iterator = specific_decl_iterator<ObjCIvarDecl>;
using ivar_range = llvm::iterator_range<specific_decl_iterator<ObjCIvarDecl>>;
ivar_range ivars() const { return ivar_range(ivar_begin(), ivar_end()); }
ivar_iterator ivar_begin() const {
return ivar_iterator(decls_begin());
}
ivar_iterator ivar_end() const {
return ivar_iterator(decls_end());
}
unsigned ivar_size() const {
return std::distance(ivar_begin(), ivar_end());
}
bool ivar_empty() const {
return ivar_begin() == ivar_end();
}
SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; }
void setCategoryNameLoc(SourceLocation Loc) { CategoryNameLoc = Loc; }
void setIvarLBraceLoc(SourceLocation Loc) { IvarLBraceLoc = Loc; }
SourceLocation getIvarLBraceLoc() const { return IvarLBraceLoc; }
void setIvarRBraceLoc(SourceLocation Loc) { IvarRBraceLoc = Loc; }
SourceLocation getIvarRBraceLoc() const { return IvarRBraceLoc; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCCategory; }
};
class ObjCImplDecl : public ObjCContainerDecl {
/// Class interface for this class/category implementation
ObjCInterfaceDecl *ClassInterface;
void anchor() override;
protected:
ObjCImplDecl(Kind DK, DeclContext *DC,
ObjCInterfaceDecl *classInterface,
IdentifierInfo *Id,
SourceLocation nameLoc, SourceLocation atStartLoc)
: ObjCContainerDecl(DK, DC, Id, nameLoc, atStartLoc),
ClassInterface(classInterface) {}
public:
const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
void setClassInterface(ObjCInterfaceDecl *IFace);
void addInstanceMethod(ObjCMethodDecl *method) {
// FIXME: Context should be set correctly before we get here.
method->setLexicalDeclContext(this);
addDecl(method);
}
void addClassMethod(ObjCMethodDecl *method) {
// FIXME: Context should be set correctly before we get here.
method->setLexicalDeclContext(this);
addDecl(method);
}
void addPropertyImplementation(ObjCPropertyImplDecl *property);
ObjCPropertyImplDecl *FindPropertyImplDecl(IdentifierInfo *propertyId,
ObjCPropertyQueryKind queryKind) const;
ObjCPropertyImplDecl *FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const;
// Iterator access to properties.
using propimpl_iterator = specific_decl_iterator<ObjCPropertyImplDecl>;
using propimpl_range =
llvm::iterator_range<specific_decl_iterator<ObjCPropertyImplDecl>>;
propimpl_range property_impls() const {
return propimpl_range(propimpl_begin(), propimpl_end());
}
propimpl_iterator propimpl_begin() const {
return propimpl_iterator(decls_begin());
}
propimpl_iterator propimpl_end() const {
return propimpl_iterator(decls_end());
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
return K >= firstObjCImpl && K <= lastObjCImpl;
}
};
/// ObjCCategoryImplDecl - An object of this class encapsulates a category
/// \@implementation declaration. If a category class has declaration of a
/// property, its implementation must be specified in the category's
/// \@implementation declaration. Example:
/// \@interface I \@end
/// \@interface I(CATEGORY)
/// \@property int p1, d1;
/// \@end
/// \@implementation I(CATEGORY)
/// \@dynamic p1,d1;
/// \@end
///
/// ObjCCategoryImplDecl
class ObjCCategoryImplDecl : public ObjCImplDecl {
// Category name location
SourceLocation CategoryNameLoc;
ObjCCategoryImplDecl(DeclContext *DC, IdentifierInfo *Id,
ObjCInterfaceDecl *classInterface,
SourceLocation nameLoc, SourceLocation atStartLoc,
SourceLocation CategoryNameLoc)
: ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id,
nameLoc, atStartLoc),
CategoryNameLoc(CategoryNameLoc) {}
void anchor() override;
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC,
IdentifierInfo *Id,
ObjCInterfaceDecl *classInterface,
SourceLocation nameLoc,
SourceLocation atStartLoc,
SourceLocation CategoryNameLoc);
static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, unsigned ID);
ObjCCategoryDecl *getCategoryDecl() const;
SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCCategoryImpl;}
};
raw_ostream &operator<<(raw_ostream &OS, const ObjCCategoryImplDecl &CID);
/// ObjCImplementationDecl - Represents a class definition - this is where
/// method definitions are specified. For example:
///
/// @code
/// \@implementation MyClass
/// - (void)myMethod { /* do something */ }
/// \@end
/// @endcode
///
/// In a non-fragile runtime, instance variables can appear in the class
/// interface, class extensions (nameless categories), and in the implementation
/// itself, as well as being synthesized as backing storage for properties.
///
/// In a fragile runtime, instance variables are specified in the class
/// interface, \em not in the implementation. Nevertheless (for legacy reasons),
/// we allow instance variables to be specified in the implementation. When
/// specified, they need to be \em identical to the interface.
class ObjCImplementationDecl : public ObjCImplDecl {
/// Implementation Class's super class.
ObjCInterfaceDecl *SuperClass;
SourceLocation SuperLoc;
/// \@implementation may have private ivars.
SourceLocation IvarLBraceLoc;
SourceLocation IvarRBraceLoc;
/// Support for ivar initialization.
/// The arguments used to initialize the ivars
LazyCXXCtorInitializersPtr IvarInitializers;
unsigned NumIvarInitializers = 0;
/// Do the ivars of this class require initialization other than
/// zero-initialization?
bool HasNonZeroConstructors : 1;
/// Do the ivars of this class require non-trivial destruction?
bool HasDestructors : 1;
ObjCImplementationDecl(DeclContext *DC,
ObjCInterfaceDecl *classInterface,
ObjCInterfaceDecl *superDecl,
SourceLocation nameLoc, SourceLocation atStartLoc,
SourceLocation superLoc = SourceLocation(),
SourceLocation IvarLBraceLoc=SourceLocation(),
SourceLocation IvarRBraceLoc=SourceLocation())
: ObjCImplDecl(ObjCImplementation, DC, classInterface,
classInterface ? classInterface->getIdentifier()
: nullptr,
nameLoc, atStartLoc),
SuperClass(superDecl), SuperLoc(superLoc),
IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc),
HasNonZeroConstructors(false), HasDestructors(false) {}
void anchor() override;
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC,
ObjCInterfaceDecl *classInterface,
ObjCInterfaceDecl *superDecl,
SourceLocation nameLoc,
SourceLocation atStartLoc,
SourceLocation superLoc = SourceLocation(),
SourceLocation IvarLBraceLoc=SourceLocation(),
SourceLocation IvarRBraceLoc=SourceLocation());
static ObjCImplementationDecl *CreateDeserialized(ASTContext &C, unsigned ID);
/// init_iterator - Iterates through the ivar initializer list.
using init_iterator = CXXCtorInitializer **;
/// init_const_iterator - Iterates through the ivar initializer list.
using init_const_iterator = CXXCtorInitializer * const *;
using init_range = llvm::iterator_range<init_iterator>;
using init_const_range = llvm::iterator_range<init_const_iterator>;
init_range inits() { return init_range(init_begin(), init_end()); }
init_const_range inits() const {
return init_const_range(init_begin(), init_end());
}
/// init_begin() - Retrieve an iterator to the first initializer.
init_iterator init_begin() {
const auto *ConstThis = this;
return const_cast<init_iterator>(ConstThis->init_begin());
}
/// begin() - Retrieve an iterator to the first initializer.
init_const_iterator init_begin() const;
/// init_end() - Retrieve an iterator past the last initializer.
init_iterator init_end() {
return init_begin() + NumIvarInitializers;
}
/// end() - Retrieve an iterator past the last initializer.
init_const_iterator init_end() const {
return init_begin() + NumIvarInitializers;
}
/// getNumArgs - Number of ivars which must be initialized.
unsigned getNumIvarInitializers() const {
return NumIvarInitializers;
}
void setNumIvarInitializers(unsigned numNumIvarInitializers) {
NumIvarInitializers = numNumIvarInitializers;
}
void setIvarInitializers(ASTContext &C,
CXXCtorInitializer ** initializers,
unsigned numInitializers);
/// Do any of the ivars of this class (not counting its base classes)
/// require construction other than zero-initialization?
bool hasNonZeroConstructors() const { return HasNonZeroConstructors; }
void setHasNonZeroConstructors(bool val) { HasNonZeroConstructors = val; }
/// Do any of the ivars of this class (not counting its base classes)
/// require non-trivial destruction?
bool hasDestructors() const { return HasDestructors; }
void setHasDestructors(bool val) { HasDestructors = val; }
/// getIdentifier - Get the identifier that names the class
/// interface associated with this implementation.
IdentifierInfo *getIdentifier() const {
return getClassInterface()->getIdentifier();
}
/// getName - Get the name of identifier for the class interface associated
/// with this implementation as a StringRef.
//
// FIXME: This is a bad API, we are hiding NamedDecl::getName with a different
// meaning.
StringRef getName() const {
assert(getIdentifier() && "Name is not a simple identifier");
return getIdentifier()->getName();
}
/// Get the name of the class associated with this interface.
//
// FIXME: Move to StringRef API.
std::string getNameAsString() const {
return getName();
}
/// Produce a name to be used for class's metadata. It comes either via
/// class's objc_runtime_name attribute or class name.
StringRef getObjCRuntimeNameAsString() const;
const ObjCInterfaceDecl *getSuperClass() const { return SuperClass; }
ObjCInterfaceDecl *getSuperClass() { return SuperClass; }
SourceLocation getSuperClassLoc() const { return SuperLoc; }
void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; }
void setIvarLBraceLoc(SourceLocation Loc) { IvarLBraceLoc = Loc; }
SourceLocation getIvarLBraceLoc() const { return IvarLBraceLoc; }
void setIvarRBraceLoc(SourceLocation Loc) { IvarRBraceLoc = Loc; }
SourceLocation getIvarRBraceLoc() const { return IvarRBraceLoc; }
using ivar_iterator = specific_decl_iterator<ObjCIvarDecl>;
using ivar_range = llvm::iterator_range<specific_decl_iterator<ObjCIvarDecl>>;
ivar_range ivars() const { return ivar_range(ivar_begin(), ivar_end()); }
ivar_iterator ivar_begin() const {
return ivar_iterator(decls_begin());
}
ivar_iterator ivar_end() const {
return ivar_iterator(decls_end());
}
unsigned ivar_size() const {
return std::distance(ivar_begin(), ivar_end());
}
bool ivar_empty() const {
return ivar_begin() == ivar_end();
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCImplementation; }
};
raw_ostream &operator<<(raw_ostream &OS, const ObjCImplementationDecl &ID);
/// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is
/// declared as \@compatibility_alias alias class.
class ObjCCompatibleAliasDecl : public NamedDecl {
/// Class that this is an alias of.
ObjCInterfaceDecl *AliasedClass;
ObjCCompatibleAliasDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
ObjCInterfaceDecl* aliasedClass)
: NamedDecl(ObjCCompatibleAlias, DC, L, Id), AliasedClass(aliasedClass) {}
void anchor() override;
public:
static ObjCCompatibleAliasDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
ObjCInterfaceDecl* aliasedClass);
static ObjCCompatibleAliasDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
const ObjCInterfaceDecl *getClassInterface() const { return AliasedClass; }
ObjCInterfaceDecl *getClassInterface() { return AliasedClass; }
void setClassInterface(ObjCInterfaceDecl *D) { AliasedClass = D; }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCCompatibleAlias; }
};
/// ObjCPropertyImplDecl - Represents implementation declaration of a property
/// in a class or category implementation block. For example:
/// \@synthesize prop1 = ivar1;
///
class ObjCPropertyImplDecl : public Decl {
public:
enum Kind {
Synthesize,
Dynamic
};
private:
SourceLocation AtLoc; // location of \@synthesize or \@dynamic
/// For \@synthesize, the location of the ivar, if it was written in
/// the source code.
///
/// \code
/// \@synthesize int a = b
/// \endcode
SourceLocation IvarLoc;
/// Property declaration being implemented
ObjCPropertyDecl *PropertyDecl;
/// Null for \@dynamic. Required for \@synthesize.
ObjCIvarDecl *PropertyIvarDecl;
/// Null for \@dynamic. Non-null if property must be copy-constructed in
/// getter.
Expr *GetterCXXConstructor = nullptr;
/// Null for \@dynamic. Non-null if property has assignment operator to call
/// in Setter synthesis.
Expr *SetterCXXAssignment = nullptr;
ObjCPropertyImplDecl(DeclContext *DC, SourceLocation atLoc, SourceLocation L,
ObjCPropertyDecl *property,
Kind PK,
ObjCIvarDecl *ivarDecl,
SourceLocation ivarLoc)
: Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc),
IvarLoc(ivarLoc), PropertyDecl(property), PropertyIvarDecl(ivarDecl) {
assert(PK == Dynamic || PropertyIvarDecl);
}
public:
friend class ASTDeclReader;
static ObjCPropertyImplDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation atLoc, SourceLocation L,
ObjCPropertyDecl *property,
Kind PK,
ObjCIvarDecl *ivarDecl,
SourceLocation ivarLoc);
static ObjCPropertyImplDecl *CreateDeserialized(ASTContext &C, unsigned ID);
SourceRange getSourceRange() const override LLVM_READONLY;
SourceLocation getLocStart() const LLVM_READONLY { return getBeginLoc(); }
SourceLocation getBeginLoc() const LLVM_READONLY { return AtLoc; }
void setAtLoc(SourceLocation Loc) { AtLoc = Loc; }
ObjCPropertyDecl *getPropertyDecl() const {
return PropertyDecl;
}
void setPropertyDecl(ObjCPropertyDecl *Prop) { PropertyDecl = Prop; }
Kind getPropertyImplementation() const {
return PropertyIvarDecl ? Synthesize : Dynamic;
}
ObjCIvarDecl *getPropertyIvarDecl() const {
return PropertyIvarDecl;
}
SourceLocation getPropertyIvarDeclLoc() const { return IvarLoc; }
void setPropertyIvarDecl(ObjCIvarDecl *Ivar,
SourceLocation IvarLoc) {
PropertyIvarDecl = Ivar;
this->IvarLoc = IvarLoc;
}
/// For \@synthesize, returns true if an ivar name was explicitly
/// specified.
///
/// \code
/// \@synthesize int a = b; // true
/// \@synthesize int a; // false
/// \endcode
bool isIvarNameSpecified() const {
return IvarLoc.isValid() && IvarLoc != getLocation();
}
Expr *getGetterCXXConstructor() const {
return GetterCXXConstructor;
}
void setGetterCXXConstructor(Expr *getterCXXConstructor) {
GetterCXXConstructor = getterCXXConstructor;
}
Expr *getSetterCXXAssignment() const {
return SetterCXXAssignment;
}
void setSetterCXXAssignment(Expr *setterCXXAssignment) {
SetterCXXAssignment = setterCXXAssignment;
}
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; }
};
template<bool (*Filter)(ObjCCategoryDecl *)>
void
ObjCInterfaceDecl::filtered_category_iterator<Filter>::
findAcceptableCategory() {
while (Current && !Filter(Current))
Current = Current->getNextClassCategoryRaw();
}
template<bool (*Filter)(ObjCCategoryDecl *)>
inline ObjCInterfaceDecl::filtered_category_iterator<Filter> &
ObjCInterfaceDecl::filtered_category_iterator<Filter>::operator++() {
Current = Current->getNextClassCategoryRaw();
findAcceptableCategory();
return *this;
}
inline bool ObjCInterfaceDecl::isVisibleCategory(ObjCCategoryDecl *Cat) {
return !Cat->isHidden();
}
inline bool ObjCInterfaceDecl::isVisibleExtension(ObjCCategoryDecl *Cat) {
return Cat->IsClassExtension() && !Cat->isHidden();
}
inline bool ObjCInterfaceDecl::isKnownExtension(ObjCCategoryDecl *Cat) {
return Cat->IsClassExtension();
}
} // namespace clang
#endif // LLVM_CLANG_AST_DECLOBJC_H