diff options
author | vitalyisaev <vitalyisaev@yandex-team.com> | 2023-06-29 10:00:50 +0300 |
---|---|---|
committer | vitalyisaev <vitalyisaev@yandex-team.com> | 2023-06-29 10:00:50 +0300 |
commit | 6ffe9e53658409f212834330e13564e4952558f6 (patch) | |
tree | 85b1e00183517648b228aafa7c8fb07f5276f419 /contrib/libs/clang16/include/clang/AST/DeclObjC.h | |
parent | 726057070f9c5a91fc10fde0d5024913d10f1ab9 (diff) | |
download | ydb-6ffe9e53658409f212834330e13564e4952558f6.tar.gz |
YQ Connector: support managed ClickHouse
Со стороны dqrun можно обратиться к инстансу коннектора, который работает на streaming стенде, и извлечь данные из облачного CH.
Diffstat (limited to 'contrib/libs/clang16/include/clang/AST/DeclObjC.h')
-rw-r--r-- | contrib/libs/clang16/include/clang/AST/DeclObjC.h | 2952 |
1 files changed, 2952 insertions, 0 deletions
diff --git a/contrib/libs/clang16/include/clang/AST/DeclObjC.h b/contrib/libs/clang16/include/clang/AST/DeclObjC.h new file mode 100644 index 0000000000..e079d5359d --- /dev/null +++ b/contrib/libs/clang16/include/clang/AST/DeclObjC.h @@ -0,0 +1,2952 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- DeclObjC.h - Classes for representing declarations -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// 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/DeclObjCCommon.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/DenseSet.h" +#include "llvm/ADT/MapVector.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 { + // This class stores some data in DeclContext::ObjCMethodDeclBits + // to save some space. Use the provided accessors to access it. + +public: + enum ImplementationControl { None, Required, Optional }; + +private: + /// 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 isSynthesizedAccessorStub = false, + bool isImplicitlyDeclared = false, bool isDefined = false, + ImplementationControl impControl = None, + bool HasRelatedResultType = false); + + SelectorLocationsKind getSelLocsKind() const { + return static_cast<SelectorLocationsKind>(ObjCMethodDeclBits.SelLocsKind); + } + + void setSelLocsKind(SelectorLocationsKind Kind) { + ObjCMethodDeclBits.SelLocsKind = Kind; + } + + 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 isSynthesizedAccessorStub = 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 static_cast<ObjCDeclQualifier>(ObjCMethodDeclBits.objcDeclQualifier); + } + + void setObjCDeclQualifier(ObjCDeclQualifier QV) { + ObjCMethodDeclBits.objcDeclQualifier = QV; + } + + /// Determine whether this method has a result type that is related + /// to the message receiver's type. + bool hasRelatedResultType() const { + return ObjCMethodDeclBits.RelatedResultType; + } + + /// Note whether this method has a related result type. + void setRelatedResultType(bool RRT = true) { + ObjCMethodDeclBits.RelatedResultType = RRT; + } + + /// True if this is a method redeclaration in the same interface. + bool isRedeclaration() const { return ObjCMethodDeclBits.IsRedeclaration; } + void setIsRedeclaration(bool RD) { ObjCMethodDeclBits.IsRedeclaration = RD; } + void setAsRedeclaration(const ObjCMethodDecl *PrevMethod); + + /// True if redeclared in the same interface. + bool hasRedeclaration() const { return ObjCMethodDeclBits.HasRedeclaration; } + void setHasRedeclaration(bool HRD) const { + ObjCMethodDeclBits.HasRedeclaration = HRD; + } + + /// 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 getBeginLoc() const LLVM_READONLY { return getLocation(); } + SourceLocation getEndLoc() const LLVM_READONLY; + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(getLocation(), getEndLoc()); + } + + SourceLocation getSelectorStartLoc() const { + if (isImplicit()) + return getBeginLoc(); + 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(); + } + + /// If this method is declared or implemented in a category, return + /// that category. + ObjCCategoryDecl *getCategory(); + const ObjCCategoryDecl *getCategory() const { + return const_cast<ObjCMethodDecl*>(this)->getCategory(); + } + + 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::ArrayRef(const_cast<ParmVarDecl **>(getParams()), NumParams); + } + + ParmVarDecl *getParamDecl(unsigned Idx) { + assert(Idx < NumParams && "Index out of bounds!"); + return getParams()[Idx]; + } + const ParmVarDecl *getParamDecl(unsigned Idx) const { + return const_cast<ObjCMethodDecl *>(this)->getParamDecl(Idx); + } + + /// 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 = std::nullopt); + + // 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 + /// implicit 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) const; + + 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 ObjCMethodDeclBits.IsInstance; } + void setInstanceMethod(bool isInst) { + ObjCMethodDeclBits.IsInstance = isInst; + } + + bool isVariadic() const { return ObjCMethodDeclBits.IsVariadic; } + void setVariadic(bool isVar) { ObjCMethodDeclBits.IsVariadic = isVar; } + + bool isClassMethod() const { return !isInstanceMethod(); } + + bool isPropertyAccessor() const { + return ObjCMethodDeclBits.IsPropertyAccessor; + } + + void setPropertyAccessor(bool isAccessor) { + ObjCMethodDeclBits.IsPropertyAccessor = isAccessor; + } + + bool isSynthesizedAccessorStub() const { + return ObjCMethodDeclBits.IsSynthesizedAccessorStub; + } + + void setSynthesizedAccessorStub(bool isSynthesizedAccessorStub) { + ObjCMethodDeclBits.IsSynthesizedAccessorStub = isSynthesizedAccessorStub; + } + + bool isDefined() const { return ObjCMethodDeclBits.IsDefined; } + void setDefined(bool isDefined) { ObjCMethodDeclBits.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 ObjCMethodDeclBits.IsOverriding; } + void setOverriding(bool IsOver) { ObjCMethodDeclBits.IsOverriding = IsOver; } + + /// 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 ObjCMethodDeclBits.HasSkippedBody; } + void setHasSkippedBody(bool Skipped = true) { + ObjCMethodDeclBits.HasSkippedBody = Skipped; + } + + /// True if the method is tagged as objc_direct + bool isDirectMethod() const; + + /// True if the method has a parameter that's destroyed in the callee. + bool hasParamDestroyedInCallee() const; + + /// 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) { + ObjCMethodDeclBits.DeclImplementation = ic; + } + + ImplementationControl getImplementationControl() const { + return ImplementationControl(ObjCMethodDeclBits.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(); } + + /// Is this method defined in the NSObject base class? + bool definedInNSObject(const ASTContext &) const; + + // 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 *> { + /// Location of the left and right angle brackets. + SourceRange Brackets; + /// 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 Brackets.getBegin(); } + SourceLocation getRAngleLoc() const { return Brackets.getEnd(); } + SourceRange getSourceRange() const { return Brackets; } + + /// 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 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 : NumObjCPropertyAttrsBits; + unsigned PropertyAttributesAsWritten : NumObjCPropertyAttrsBits; + + // \@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(ObjCPropertyAttribute::kind_noattr), + PropertyAttributesAsWritten(ObjCPropertyAttribute::kind_noattr), + PropertyImplementation(propControl) {} + +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; + + ObjCPropertyAttribute::Kind getPropertyAttributes() const { + return ObjCPropertyAttribute::Kind(PropertyAttributes); + } + + void setPropertyAttributes(ObjCPropertyAttribute::Kind PRVal) { + PropertyAttributes |= PRVal; + } + + void overwritePropertyAttributes(unsigned PRVal) { + PropertyAttributes = PRVal; + } + + ObjCPropertyAttribute::Kind getPropertyAttributesAsWritten() const { + return ObjCPropertyAttribute::Kind(PropertyAttributesAsWritten); + } + + void setPropertyAttributesAsWritten(ObjCPropertyAttribute::Kind PRVal) { + PropertyAttributesAsWritten = PRVal; + } + + // Helper methods for accessing attributes. + + /// isReadOnly - Return true iff the property has a setter. + bool isReadOnly() const { + return (PropertyAttributes & ObjCPropertyAttribute::kind_readonly); + } + + /// isAtomic - Return true if the property is atomic. + bool isAtomic() const { + return (PropertyAttributes & ObjCPropertyAttribute::kind_atomic); + } + + /// isRetaining - Return true if the property retains its value. + bool isRetaining() const { + return (PropertyAttributes & (ObjCPropertyAttribute::kind_retain | + ObjCPropertyAttribute::kind_strong | + ObjCPropertyAttribute::kind_copy)); + } + + bool isInstanceProperty() const { return !isClassProperty(); } + bool isClassProperty() const { + return PropertyAttributes & ObjCPropertyAttribute::kind_class; + } + bool isDirectProperty() const; + + 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 & ObjCPropertyAttribute::kind_strong) + return getType()->isBlockPointerType() ? Copy : Retain; + if (PropertyAttributes & ObjCPropertyAttribute::kind_retain) + return Retain; + if (PropertyAttributes & ObjCPropertyAttribute::kind_copy) + return Copy; + if (PropertyAttributes & ObjCPropertyAttribute::kind_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 { + // This class stores some data in DeclContext::ObjCContainerDeclBits + // to save some space. Use the provided accessors to access it. + + // 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); + + // 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 *getProperty(const IdentifierInfo *Id, + bool IsInstance) const; + + ObjCPropertyDecl * + FindPropertyDeclaration(const IdentifierInfo *PropertyId, + ObjCPropertyQueryKind QueryKind) const; + + using PropertyMap = + llvm::MapVector<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) const {} + + SourceLocation getAtStartLoc() const { return ObjCContainerDeclBits.AtStart; } + + void setAtStartLoc(SourceLocation Loc) { + ObjCContainerDeclBits.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(getAtStartLoc(), 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; + friend class ODRDiagsEmitter; + + /// 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; + + /// Tracks whether a ODR hash has been computed for this interface. + unsigned HasODRHash : 1; + + /// A hash of parts of the class to help in ODR checking. + unsigned ODRHash = 0; + + /// 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), HasODRHash(false) {} + }; + + /// 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(); + + /// Starts the definition without sharing it with other redeclarations. + /// Such definition shouldn't be used for anything but only to compare if + /// a duplicate is compatible with previous definition or if it is + /// a distinct duplicate. + void startDuplicateDefinitionForComparison(); + void mergeDuplicateDefinitionWithCommon(const ObjCInterfaceDecl *Definition); + + /// 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) 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; } + + /// Get precomputed ODRHash or add a new one. + unsigned getODRHash(); + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ObjCInterface; } + +private: + /// True if a valid hash is stored in ODRHash. + bool hasODRHash() const; + void setHasODRHash(bool HasHash); + + 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. + ObjCInterfaceDecl *getContainingInterface(); + const ObjCInterfaceDecl *getContainingInterface() const { + return const_cast<ObjCIvarDecl *>(this)->getContainingInterface(); + } + + ObjCIvarDecl *getNextIvar() { return NextIvar; } + const ObjCIvarDecl *getNextIvar() const { return NextIvar; } + void setNextIvar(ObjCIvarDecl *ivar) { NextIvar = ivar; } + + ObjCIvarDecl *getCanonicalDecl() override { + return cast<ObjCIvarDecl>(FieldDecl::getCanonicalDecl()); + } + const ObjCIvarDecl *getCanonicalDecl() const { + return const_cast<ObjCIvarDecl *>(this)->getCanonicalDecl(); + } + + 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; + + /// Tracks whether a ODR hash has been computed for this protocol. + unsigned HasODRHash : 1; + + /// A hash of parts of the class to help in ODR checking. + unsigned ODRHash = 0; + }; + + /// 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(); + } + + /// True if a valid hash is stored in ODRHash. + bool hasODRHash() const; + void setHasODRHash(bool HasHash); + +public: + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend class ASTReader; + friend class ODRDiagsEmitter; + + 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); + } + + /// This is true iff the protocol is tagged with the + /// `objc_non_runtime_protocol` attribute. + bool isNonRuntimeProtocol() const; + + /// Get the set of all protocols implied by this protocols inheritance + /// hierarchy. + void getImpliedProtocols(llvm::DenseSet<const ObjCProtocolDecl *> &IPs) const; + + 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(); + + /// Starts the definition without sharing it with other redeclarations. + /// Such definition shouldn't be used for anything but only to compare if + /// a duplicate is compatible with previous definition or if it is + /// a distinct duplicate. + void startDuplicateDefinitionForComparison(); + void mergeDuplicateDefinitionWithCommon(const ObjCProtocolDecl *Definition); + + /// 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) const override; + + void collectInheritedProtocolProperties(const ObjCPropertyDecl *Property, + ProtocolPropertySet &PS, + PropertyDeclOrder &PO) const; + + /// Get precomputed ODRHash or add a new one. + unsigned getODRHash(); + + 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 std::string(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; + + /// The getter's definition, which has an empty body if synthesized. + ObjCMethodDecl *GetterMethodDecl = nullptr; + /// The getter's definition, which has an empty body if synthesized. + ObjCMethodDecl *SetterMethodDecl = nullptr; + + /// 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 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(); + } + + ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; } + void setGetterMethodDecl(ObjCMethodDecl *MD) { GetterMethodDecl = MD; } + + ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; } + void setSetterMethodDecl(ObjCMethodDecl *MD) { SetterMethodDecl = MD; } + + 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->isInvalidDecl() && Cat->isUnconditionallyVisible(); +} + +inline bool ObjCInterfaceDecl::isVisibleExtension(ObjCCategoryDecl *Cat) { + return !Cat->isInvalidDecl() && Cat->IsClassExtension() && + Cat->isUnconditionallyVisible(); +} + +inline bool ObjCInterfaceDecl::isKnownExtension(ObjCCategoryDecl *Cat) { + return !Cat->isInvalidDecl() && Cat->IsClassExtension(); +} + +} // namespace clang + +#endif // LLVM_CLANG_AST_DECLOBJC_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif |