mirror of https://github.com/microsoft/clang.git
Parsing, semantic analysis, and AST for Objective-C type parameters.
Produce type parameter declarations for Objective-C type parameters, and attach lists of type parameters to Objective-C classes, categories, forward declarations, and extensions as appropriate. Perform semantic analysis of type bounds for type parameters, both in isolation and across classes/categories/extensions to ensure consistency. Also handle (de-)serialization of Objective-C type parameter lists, along with sundry other things one must do to add a new declaration to Clang. Note that Objective-C type parameters are typedef name declarations, like typedefs and C++11 type aliases, in support of type erasure. Part of rdar://problem/6294649. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@241541 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
27cac9536c
commit
5df68d34cd
|
@ -1307,7 +1307,12 @@ DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {// FIXME: implement
|
|||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement
|
||||
})
|
||||
if (ObjCTypeParamList *typeParamList = D->getTypeParamList()) {
|
||||
for (auto typeParam : *typeParamList)
|
||||
TRY_TO(TraverseObjCTypeParamDecl(typeParam));
|
||||
}
|
||||
return true;
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement
|
||||
})
|
||||
|
@ -1316,7 +1321,12 @@ DEF_TRAVERSE_DECL(ObjCImplementationDecl, {// FIXME: implement
|
|||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement
|
||||
})
|
||||
if (ObjCTypeParamList *typeParamList = D->getTypeParamListAsWritten()) {
|
||||
for (auto typeParam : *typeParamList)
|
||||
TRY_TO(TraverseObjCTypeParamDecl(typeParam));
|
||||
}
|
||||
return true;
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement
|
||||
})
|
||||
|
@ -1335,6 +1345,15 @@ DEF_TRAVERSE_DECL(ObjCMethodDecl, {
|
|||
return true;
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCTypeParamDecl, {
|
||||
if (D->hasExplicitBound()) {
|
||||
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||
// We shouldn't traverse D->getTypeForDecl(); it's a result of
|
||||
// declaring the type alias, not something that was written in the
|
||||
// source.
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
|
||||
if (D->getTypeSourceInfo())
|
||||
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||
|
|
|
@ -501,6 +501,124 @@ public:
|
|||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// 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 {
|
||||
void anchor() override;
|
||||
|
||||
// The location of the ':', which will be valid when the bound was
|
||||
// explicitly specified.
|
||||
SourceLocation ColonLoc;
|
||||
|
||||
ObjCTypeParamDecl(ASTContext &ctx, DeclContext *dc,
|
||||
SourceLocation nameLoc, IdentifierInfo *name,
|
||||
SourceLocation colonLoc, TypeSourceInfo *boundInfo)
|
||||
: TypedefNameDecl(ObjCTypeParam, ctx, dc, nameLoc, nameLoc, name,
|
||||
boundInfo),
|
||||
ColonLoc(colonLoc) { }
|
||||
|
||||
public:
|
||||
static ObjCTypeParamDecl *Create(ASTContext &ctx, DeclContext *dc,
|
||||
SourceLocation nameLoc,
|
||||
IdentifierInfo *name,
|
||||
SourceLocation colonLoc,
|
||||
TypeSourceInfo *boundInfo);
|
||||
static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx, unsigned ID);
|
||||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY;
|
||||
|
||||
/// 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; }
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
/// 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 {
|
||||
union {
|
||||
/// Location of the left and right angle brackets.
|
||||
SourceRange Brackets;
|
||||
|
||||
// Used only for alignment.
|
||||
ObjCTypeParamDecl *AlignmentHack;
|
||||
};
|
||||
|
||||
/// The number of parameters in the list, which are tail-allocated.
|
||||
unsigned NumParams;
|
||||
|
||||
ObjCTypeParamList(SourceLocation lAngleLoc,
|
||||
ArrayRef<ObjCTypeParamDecl *> typeParams,
|
||||
SourceLocation rAngleLoc);
|
||||
|
||||
public:
|
||||
/// 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.
|
||||
typedef ObjCTypeParamDecl **iterator;
|
||||
|
||||
iterator begin() { return reinterpret_cast<ObjCTypeParamDecl **>(this + 1); }
|
||||
|
||||
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.
|
||||
typedef ObjCTypeParamDecl * const *const_iterator;
|
||||
|
||||
const_iterator begin() const {
|
||||
return reinterpret_cast<ObjCTypeParamDecl * const *>(this + 1);
|
||||
}
|
||||
|
||||
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; }
|
||||
};
|
||||
|
||||
/// ObjCContainerDecl - Represents a container for method declarations.
|
||||
/// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl,
|
||||
/// ObjCProtocolDecl, and ObjCImplDecl.
|
||||
|
@ -736,11 +854,15 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
|
|||
};
|
||||
|
||||
ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
|
||||
IdentifierInfo *Id, SourceLocation CLoc,
|
||||
ObjCInterfaceDecl *PrevDecl, bool IsInternal);
|
||||
IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
|
||||
SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl,
|
||||
bool IsInternal);
|
||||
|
||||
void LoadExternalDefinition() const;
|
||||
|
||||
/// The type parameters associated with this class, if any.
|
||||
ObjCTypeParamList *TypeParamList;
|
||||
|
||||
/// \brief Contains a pointer to the data associated with this class,
|
||||
/// which will be NULL if this class has not yet been defined.
|
||||
///
|
||||
|
@ -771,12 +893,27 @@ 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 @class) but not
|
||||
/// defined (with @interface), it will search for a declaration that
|
||||
/// has type parameters, skipping any declarations that do not.
|
||||
ObjCTypeParamList *getTypeParamList() const;
|
||||
|
||||
/// 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();
|
||||
|
@ -1719,6 +1856,9 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
|||
/// Interface belonging to this category
|
||||
ObjCInterfaceDecl *ClassInterface;
|
||||
|
||||
/// The type parameters associated with this category, if any.
|
||||
ObjCTypeParamList *TypeParamList;
|
||||
|
||||
/// referenced protocols in this category.
|
||||
ObjCProtocolList ReferencedProtocols;
|
||||
|
||||
|
@ -1736,13 +1876,9 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
|
|||
ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
|
||||
SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
|
||||
IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
SourceLocation IvarLBraceLoc=SourceLocation(),
|
||||
SourceLocation IvarRBraceLoc=SourceLocation())
|
||||
: ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
|
||||
ClassInterface(IDecl), NextClassCategory(nullptr),
|
||||
CategoryNameLoc(CategoryNameLoc),
|
||||
IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) {
|
||||
}
|
||||
SourceLocation IvarRBraceLoc=SourceLocation());
|
||||
|
||||
public:
|
||||
|
||||
|
@ -1752,6 +1888,7 @@ public:
|
|||
SourceLocation CategoryNameLoc,
|
||||
IdentifierInfo *Id,
|
||||
ObjCInterfaceDecl *IDecl,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
SourceLocation IvarLBraceLoc=SourceLocation(),
|
||||
SourceLocation IvarRBraceLoc=SourceLocation());
|
||||
static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
@ -1759,6 +1896,10 @@ public:
|
|||
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; }
|
||||
|
||||
ObjCCategoryImplDecl *getImplementation() const;
|
||||
void setImplementation(ObjCCategoryImplDecl *ImplD);
|
||||
|
||||
|
|
|
@ -1382,7 +1382,11 @@ DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {// FIXME: implement
|
|||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement
|
||||
})
|
||||
if (ObjCTypeParamList *typeParamList = D->getTypeParamList()) {
|
||||
for (auto typeParam : *typeParamList)
|
||||
TRY_TO(TraverseObjCTypeParamDecl(typeParam));
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement
|
||||
})
|
||||
|
@ -1391,7 +1395,11 @@ DEF_TRAVERSE_DECL(ObjCImplementationDecl, {// FIXME: implement
|
|||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement
|
||||
})
|
||||
if (ObjCTypeParamList *typeParamList = D->getTypeParamListAsWritten()) {
|
||||
for (auto typeParam : *typeParamList)
|
||||
TRY_TO(TraverseObjCTypeParamDecl(typeParam));
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement
|
||||
})
|
||||
|
@ -1410,6 +1418,15 @@ DEF_TRAVERSE_DECL(ObjCMethodDecl, {
|
|||
return true;
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCTypeParamDecl, {
|
||||
if (D->hasExplicitBound()) {
|
||||
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||
// We shouldn't traverse D->getTypeForDecl(); it's a result of
|
||||
// declaring the type alias, not something that was written in the
|
||||
// source.
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCPropertyDecl, {
|
||||
if (D->getTypeSourceInfo())
|
||||
TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc()));
|
||||
|
|
|
@ -21,6 +21,7 @@ def Named : Decl<1>;
|
|||
def TypedefName : DDecl<Type, 1>;
|
||||
def Typedef : DDecl<TypedefName>;
|
||||
def TypeAlias : DDecl<TypedefName>;
|
||||
def ObjCTypeParam : DDecl<TypedefName>;
|
||||
def UnresolvedUsingTypename : DDecl<Type>;
|
||||
def Tag : DDecl<Type, 1>, DeclContext;
|
||||
def Enum : DDecl<Tag>;
|
||||
|
|
|
@ -1017,4 +1017,17 @@ def err_module_expected_semi : Error<
|
|||
"expected ';' after module name">;
|
||||
}
|
||||
|
||||
let CategoryName = "Generics Issue" in {
|
||||
|
||||
def err_objc_expected_type_parameter : Error<
|
||||
"expected type parameter name">;
|
||||
|
||||
def err_objc_parameterized_class_without_base : Error<
|
||||
"parameterized Objective-C class %0 must have a superclass">;
|
||||
|
||||
def err_objc_parameterized_implementation : Error<
|
||||
"@implementation cannot have type parameters">;
|
||||
|
||||
}
|
||||
|
||||
} // end of Parser diagnostics
|
||||
|
|
|
@ -7743,6 +7743,42 @@ def warn_nullability_missing : Warning<
|
|||
"%select{pointer|block pointer|member pointer}0 is missing a nullability "
|
||||
"type specifier (_Nonnull, _Nullable, or _Null_unspecified)">,
|
||||
InGroup<NullabilityCompleteness>;
|
||||
}
|
||||
|
||||
let CategoryName = "Generics Issue" in {
|
||||
|
||||
def err_objc_type_param_bound_nonobject : Error<
|
||||
"type bound %0 for type parameter %1 is not an Objective-C pointer type">;
|
||||
|
||||
def err_objc_type_param_bound_missing_pointer : Error<
|
||||
"missing '*' in type bound %0 for type parameter %1">;
|
||||
|
||||
def err_objc_type_param_redecl : Error<
|
||||
"redeclaration of type parameter %0">;
|
||||
|
||||
def err_objc_type_param_arity_mismatch : Error<
|
||||
"%select{forward class declaration|class definition|category|extension}0 has "
|
||||
"too %select{few|many}1 type parameters (expected %2, have %3)">;
|
||||
|
||||
def err_objc_type_param_bound_conflict : Error<
|
||||
"type bound %0 for type parameter %1 conflicts with "
|
||||
"%select{implicit|previous}2 bound %3%select{for type parameter %5|}4">;
|
||||
|
||||
def note_objc_type_param_here : Note<"type parameter %0 declared here">;
|
||||
|
||||
def err_objc_type_param_bound_missing : Error<
|
||||
"missing type bound %0 for type parameter %1 in %select{@interface|@class}2">;
|
||||
|
||||
def err_objc_parameterized_category_nonclass : Error<
|
||||
"%select{extension|category}0 of non-parameterized class %1 cannot have type "
|
||||
"parameters">;
|
||||
|
||||
def err_objc_parameterized_forward_class : Error<
|
||||
"forward declaration of non-parameterized class %0 cannot have type "
|
||||
"parameters">;
|
||||
|
||||
def err_objc_parameterized_forward_class_first : Error<
|
||||
"class %0 previously declared with type parameters">;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace clang {
|
|||
class PoisonSEHIdentifiersRAIIObject;
|
||||
class VersionTuple;
|
||||
class OMPClause;
|
||||
class ObjCTypeParamList;
|
||||
class ObjCTypeParameter;
|
||||
|
||||
/// Parser - This implements a parser for the C family of languages. After
|
||||
/// parsing units of the grammar, productions are invoked to handle whatever has
|
||||
|
@ -1246,6 +1248,13 @@ private:
|
|||
DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
|
||||
Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
||||
ParsedAttributes &prefixAttrs);
|
||||
ObjCTypeParamList *parseObjCTypeParamList();
|
||||
ObjCTypeParamList *parseObjCTypeParamListOrProtocolRefs(
|
||||
SourceLocation &lAngleLoc,
|
||||
SmallVectorImpl<IdentifierLocPair> &protocolIdents,
|
||||
SourceLocation &rAngleLoc,
|
||||
bool mayBeProtocolList = true);
|
||||
|
||||
void HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
|
||||
BalancedDelimiterTracker &T,
|
||||
SmallVectorImpl<Decl *> &AllIvarDecls,
|
||||
|
@ -2469,7 +2478,8 @@ private:
|
|||
typedef SmallVector<ParsedTemplateArgument, 16> TemplateArgList;
|
||||
|
||||
bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
|
||||
bool ConsumeLastToken);
|
||||
bool ConsumeLastToken,
|
||||
bool ObjCGenericList);
|
||||
bool ParseTemplateIdAfterTemplateName(TemplateTy Template,
|
||||
SourceLocation TemplateNameLoc,
|
||||
const CXXScopeSpec &SS,
|
||||
|
|
|
@ -7088,9 +7088,20 @@ public:
|
|||
};
|
||||
ObjCContainerKind getObjCContainerKind() const;
|
||||
|
||||
DeclResult actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName,
|
||||
SourceLocation paramLoc,
|
||||
SourceLocation colonLoc,
|
||||
ParsedType typeBound);
|
||||
|
||||
ObjCTypeParamList *actOnObjCTypeParamList(Scope *S, SourceLocation lAngleLoc,
|
||||
ArrayRef<Decl *> typeParams,
|
||||
SourceLocation rAngleLoc);
|
||||
void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList);
|
||||
|
||||
Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
|
||||
IdentifierInfo *ClassName,
|
||||
SourceLocation ClassLoc,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
IdentifierInfo *SuperName,
|
||||
SourceLocation SuperLoc,
|
||||
Decl * const *ProtoRefs,
|
||||
|
@ -7124,6 +7135,7 @@ public:
|
|||
Decl *ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
|
||||
IdentifierInfo *ClassName,
|
||||
SourceLocation ClassLoc,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
IdentifierInfo *CategoryName,
|
||||
SourceLocation CategoryLoc,
|
||||
Decl * const *ProtoRefs,
|
||||
|
@ -7147,9 +7159,10 @@ public:
|
|||
ArrayRef<Decl *> Decls);
|
||||
|
||||
DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc,
|
||||
IdentifierInfo **IdentList,
|
||||
SourceLocation *IdentLocs,
|
||||
unsigned NumElts);
|
||||
IdentifierInfo **IdentList,
|
||||
SourceLocation *IdentLocs,
|
||||
ArrayRef<ObjCTypeParamList *> TypeParamLists,
|
||||
unsigned NumElts);
|
||||
|
||||
DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc,
|
||||
const IdentifierLocPair *IdentList,
|
||||
|
|
|
@ -413,6 +413,7 @@ namespace clang {
|
|||
#define LINKAGESPEC(DERIVED, BASE)
|
||||
#define OBJCCOMPATIBLEALIAS(DERIVED, BASE)
|
||||
#define OBJCMETHOD(DERIVED, BASE)
|
||||
#define OBJCTYPEPARAM(DERIVED, BASE)
|
||||
#define OBJCIVAR(DERIVED, BASE)
|
||||
#define OBJCPROPERTY(DERIVED, BASE)
|
||||
#define OBJCPROPERTYIMPL(DERIVED, BASE)
|
||||
|
|
|
@ -1105,7 +1105,9 @@ namespace clang {
|
|||
/// \brief An OMPThreadPrivateDecl record.
|
||||
DECL_OMP_THREADPRIVATE,
|
||||
/// \brief An EmptyDecl record.
|
||||
DECL_EMPTY
|
||||
DECL_EMPTY,
|
||||
/// \brief An ObjCTypeParamDecl record.
|
||||
DECL_OBJC_TYPE_PARAM,
|
||||
};
|
||||
|
||||
/// \brief Record codes for each kind of statement or expression.
|
||||
|
|
|
@ -5951,6 +5951,7 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const {
|
|||
= ObjCInterfaceDecl::Create(*this, getTranslationUnitDecl(),
|
||||
SourceLocation(),
|
||||
&Idents.get("Protocol"),
|
||||
/*typeParamList=*/nullptr,
|
||||
/*PrevDecl=*/nullptr,
|
||||
SourceLocation(), true);
|
||||
}
|
||||
|
|
|
@ -240,6 +240,9 @@ namespace {
|
|||
void dumpTemplateArgument(const TemplateArgument &A,
|
||||
SourceRange R = SourceRange());
|
||||
|
||||
// Objective-C utilities.
|
||||
void dumpObjCTypeParamList(const ObjCTypeParamList *typeParams);
|
||||
|
||||
// Types
|
||||
void VisitComplexType(const ComplexType *T) {
|
||||
dumpTypeAsChild(T->getElementType());
|
||||
|
@ -463,6 +466,7 @@ namespace {
|
|||
// ObjC Decls
|
||||
void VisitObjCIvarDecl(const ObjCIvarDecl *D);
|
||||
void VisitObjCMethodDecl(const ObjCMethodDecl *D);
|
||||
void VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D);
|
||||
void VisitObjCCategoryDecl(const ObjCCategoryDecl *D);
|
||||
void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D);
|
||||
void VisitObjCProtocolDecl(const ObjCProtocolDecl *D);
|
||||
|
@ -954,6 +958,18 @@ void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) {
|
|||
});
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Objective-C Utilities
|
||||
//===----------------------------------------------------------------------===//
|
||||
void ASTDumper::dumpObjCTypeParamList(const ObjCTypeParamList *typeParams) {
|
||||
if (!typeParams)
|
||||
return;
|
||||
|
||||
for (auto typeParam : *typeParams) {
|
||||
dumpDecl(typeParam);
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Decl dumping methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -1457,9 +1473,17 @@ void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
|
|||
dumpStmt(D->getBody());
|
||||
}
|
||||
|
||||
void ASTDumper::VisitObjCTypeParamDecl(const ObjCTypeParamDecl *D) {
|
||||
dumpName(D);
|
||||
if (D->hasExplicitBound())
|
||||
OS << " bounded";
|
||||
dumpType(D->getUnderlyingType());
|
||||
}
|
||||
|
||||
void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
|
||||
dumpName(D);
|
||||
dumpDeclRef(D->getClassInterface());
|
||||
dumpObjCTypeParamList(D->getTypeParamList());
|
||||
dumpDeclRef(D->getImplementation());
|
||||
for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
|
||||
E = D->protocol_end();
|
||||
|
@ -1482,6 +1506,7 @@ void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
|
|||
|
||||
void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
|
||||
dumpName(D);
|
||||
dumpObjCTypeParamList(D->getTypeParamListAsWritten());
|
||||
dumpDeclRef(D->getSuperClass(), "super");
|
||||
|
||||
dumpDeclRef(D->getImplementation());
|
||||
|
|
|
@ -150,9 +150,12 @@ namespace clang {
|
|||
Decl *VisitImplicitParamDecl(ImplicitParamDecl *D);
|
||||
Decl *VisitParmVarDecl(ParmVarDecl *D);
|
||||
Decl *VisitObjCMethodDecl(ObjCMethodDecl *D);
|
||||
Decl *VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
|
||||
Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D);
|
||||
Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D);
|
||||
Decl *VisitLinkageSpecDecl(LinkageSpecDecl *D);
|
||||
|
||||
ObjCTypeParamList *ImportObjCTypeParamList(ObjCTypeParamList *list);
|
||||
Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
|
||||
Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
|
||||
Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D);
|
||||
|
@ -3423,6 +3426,32 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
|
|||
return ToMethod;
|
||||
}
|
||||
|
||||
Decl *ASTNodeImporter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
|
||||
// Import the major distinguishing characteristics of a category.
|
||||
DeclContext *DC, *LexicalDC;
|
||||
DeclarationName Name;
|
||||
SourceLocation Loc;
|
||||
NamedDecl *ToD;
|
||||
if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc))
|
||||
return nullptr;
|
||||
if (ToD)
|
||||
return ToD;
|
||||
|
||||
TypeSourceInfo *BoundInfo = Importer.Import(D->getTypeSourceInfo());
|
||||
if (!BoundInfo)
|
||||
return nullptr;
|
||||
|
||||
ObjCTypeParamDecl *Result = ObjCTypeParamDecl::Create(
|
||||
Importer.getToContext(), DC,
|
||||
Importer.Import(D->getLocation()),
|
||||
Name.getAsIdentifierInfo(),
|
||||
Importer.Import(D->getColonLoc()),
|
||||
BoundInfo);
|
||||
Importer.Imported(D, Result);
|
||||
Result->setLexicalDeclContext(LexicalDC);
|
||||
return Result;
|
||||
}
|
||||
|
||||
Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
|
||||
// Import the major distinguishing characteristics of a category.
|
||||
DeclContext *DC, *LexicalDC;
|
||||
|
@ -3450,6 +3479,8 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
|
|||
Importer.Import(D->getCategoryNameLoc()),
|
||||
Name.getAsIdentifierInfo(),
|
||||
ToInterface,
|
||||
ImportObjCTypeParamList(
|
||||
D->getTypeParamList()),
|
||||
Importer.Import(D->getIvarLBraceLoc()),
|
||||
Importer.Import(D->getIvarRBraceLoc()));
|
||||
ToCategory->setLexicalDeclContext(LexicalDC);
|
||||
|
@ -3716,6 +3747,27 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From,
|
|||
return false;
|
||||
}
|
||||
|
||||
ObjCTypeParamList *
|
||||
ASTNodeImporter::ImportObjCTypeParamList(ObjCTypeParamList *list) {
|
||||
if (!list)
|
||||
return nullptr;
|
||||
|
||||
SmallVector<ObjCTypeParamDecl *, 4> toTypeParams;
|
||||
for (auto fromTypeParam : *list) {
|
||||
auto toTypeParam = cast_or_null<ObjCTypeParamDecl>(
|
||||
Importer.Import(fromTypeParam));
|
||||
if (!toTypeParam)
|
||||
return nullptr;
|
||||
|
||||
toTypeParams.push_back(toTypeParam);
|
||||
}
|
||||
|
||||
return ObjCTypeParamList::create(Importer.getToContext(),
|
||||
Importer.Import(list->getLAngleLoc()),
|
||||
toTypeParams,
|
||||
Importer.Import(list->getRAngleLoc()));
|
||||
}
|
||||
|
||||
Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
|
||||
// If this class has a definition in the translation unit we're coming from,
|
||||
// but this particular declaration is not that definition, import the
|
||||
|
@ -3756,7 +3808,9 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
|
|||
if (!ToIface) {
|
||||
ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
|
||||
Importer.Import(D->getAtStartLoc()),
|
||||
Name.getAsIdentifierInfo(),
|
||||
Name.getAsIdentifierInfo(),
|
||||
ImportObjCTypeParamList(
|
||||
D->getTypeParamListAsWritten()),
|
||||
/*PrevDecl=*/nullptr, Loc,
|
||||
D->isImplicitInterfaceDecl());
|
||||
ToIface->setLexicalDeclContext(LexicalDC);
|
||||
|
|
|
@ -561,6 +561,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
|
|||
case TypeAliasTemplate:
|
||||
case UnresolvedUsingTypename:
|
||||
case TemplateTypeParm:
|
||||
case ObjCTypeParam:
|
||||
return IDNS_Ordinary | IDNS_Type;
|
||||
|
||||
case UsingShadow:
|
||||
|
|
|
@ -239,6 +239,26 @@ ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration(
|
|||
|
||||
void ObjCInterfaceDecl::anchor() { }
|
||||
|
||||
ObjCTypeParamList *ObjCInterfaceDecl::getTypeParamList() const {
|
||||
// If this particular declaration has a type parameter list, return it.
|
||||
if (ObjCTypeParamList *written = getTypeParamListAsWritten())
|
||||
return written;
|
||||
|
||||
// If there is a definition, return its type parameter list.
|
||||
if (const ObjCInterfaceDecl *def = getDefinition())
|
||||
return def->getTypeParamListAsWritten();
|
||||
|
||||
// Otherwise, look at previous declarations to determine whether any
|
||||
// of them has a type parameter list, skipping over those
|
||||
// declarations that do not.
|
||||
for (auto decl = getPreviousDecl(); decl; decl = decl->getPreviousDecl()) {
|
||||
if (ObjCTypeParamList *written = decl->getTypeParamListAsWritten())
|
||||
return written;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property
|
||||
/// with name 'PropertyId' in the primary class; including those in protocols
|
||||
/// (direct or indirect) used by the primary class.
|
||||
|
@ -1136,6 +1156,62 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ObjCTypeParamDecl
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void ObjCTypeParamDecl::anchor() { }
|
||||
|
||||
ObjCTypeParamDecl *ObjCTypeParamDecl::Create(ASTContext &ctx, DeclContext *dc,
|
||||
SourceLocation nameLoc,
|
||||
IdentifierInfo *name,
|
||||
SourceLocation colonLoc,
|
||||
TypeSourceInfo *boundInfo) {
|
||||
return new (ctx, dc) ObjCTypeParamDecl(ctx, dc, nameLoc, name, colonLoc,
|
||||
boundInfo);
|
||||
}
|
||||
|
||||
ObjCTypeParamDecl *ObjCTypeParamDecl::CreateDeserialized(ASTContext &ctx,
|
||||
unsigned ID) {
|
||||
return new (ctx, ID) ObjCTypeParamDecl(ctx, nullptr, SourceLocation(),
|
||||
nullptr, SourceLocation(), nullptr);
|
||||
}
|
||||
|
||||
SourceRange ObjCTypeParamDecl::getSourceRange() const {
|
||||
if (hasExplicitBound()) {
|
||||
return SourceRange(getLocation(),
|
||||
getTypeSourceInfo()->getTypeLoc().getEndLoc());
|
||||
}
|
||||
|
||||
return SourceRange(getLocation());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ObjCTypeParamList
|
||||
//===----------------------------------------------------------------------===//
|
||||
ObjCTypeParamList::ObjCTypeParamList(SourceLocation lAngleLoc,
|
||||
ArrayRef<ObjCTypeParamDecl *> typeParams,
|
||||
SourceLocation rAngleLoc)
|
||||
: Brackets(lAngleLoc, rAngleLoc), NumParams(typeParams.size())
|
||||
{
|
||||
std::copy(typeParams.begin(), typeParams.end(), begin());
|
||||
}
|
||||
|
||||
|
||||
ObjCTypeParamList *ObjCTypeParamList::create(
|
||||
ASTContext &ctx,
|
||||
SourceLocation lAngleLoc,
|
||||
ArrayRef<ObjCTypeParamDecl *> typeParams,
|
||||
SourceLocation rAngleLoc) {
|
||||
unsigned size = sizeof(ObjCTypeParamList)
|
||||
+ sizeof(ObjCTypeParamDecl *) * typeParams.size();
|
||||
static_assert(alignof(ObjCTypeParamList) >= alignof(ObjCTypeParamDecl*),
|
||||
"type parameter list needs greater alignment");
|
||||
unsigned align = llvm::alignOf<ObjCTypeParamList>();
|
||||
void *mem = ctx.Allocate(size, align);
|
||||
return new (mem) ObjCTypeParamList(lAngleLoc, typeParams, rAngleLoc);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ObjCInterfaceDecl
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -1144,11 +1220,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
|
|||
DeclContext *DC,
|
||||
SourceLocation atLoc,
|
||||
IdentifierInfo *Id,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
ObjCInterfaceDecl *PrevDecl,
|
||||
SourceLocation ClassLoc,
|
||||
bool isInternal){
|
||||
ObjCInterfaceDecl *Result = new (C, DC)
|
||||
ObjCInterfaceDecl(C, DC, atLoc, Id, ClassLoc, PrevDecl, isInternal);
|
||||
ObjCInterfaceDecl(C, DC, atLoc, Id, typeParamList, ClassLoc, PrevDecl,
|
||||
isInternal);
|
||||
Result->Data.setInt(!C.getLangOpts().Modules);
|
||||
C.getObjCInterfaceType(Result, PrevDecl);
|
||||
return Result;
|
||||
|
@ -1159,6 +1237,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C,
|
|||
ObjCInterfaceDecl *Result = new (C, ID) ObjCInterfaceDecl(C, nullptr,
|
||||
SourceLocation(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
SourceLocation(),
|
||||
nullptr, false);
|
||||
Result->Data.setInt(!C.getLangOpts().Modules);
|
||||
|
@ -1167,11 +1246,13 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C,
|
|||
|
||||
ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
|
||||
SourceLocation AtLoc, IdentifierInfo *Id,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
SourceLocation CLoc,
|
||||
ObjCInterfaceDecl *PrevDecl,
|
||||
bool IsInternal)
|
||||
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc),
|
||||
redeclarable_base(C), TypeForDecl(nullptr), Data() {
|
||||
redeclarable_base(C), TypeForDecl(nullptr), TypeParamList(typeParamList),
|
||||
Data() {
|
||||
setPreviousDecl(PrevDecl);
|
||||
|
||||
// Copy the 'data' pointer over.
|
||||
|
@ -1179,6 +1260,12 @@ ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC,
|
|||
Data = PrevDecl->Data;
|
||||
|
||||
setImplicit(IsInternal);
|
||||
|
||||
// Update the declaration context of the type parameters.
|
||||
if (typeParamList) {
|
||||
for (auto typeParam : *typeParamList)
|
||||
typeParam->setDeclContext(this);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjCInterfaceDecl::LoadExternalDefinition() const {
|
||||
|
@ -1648,17 +1735,39 @@ ObjCProtocolDecl::getObjCRuntimeNameAsString() const {
|
|||
|
||||
void ObjCCategoryDecl::anchor() { }
|
||||
|
||||
ObjCCategoryDecl::ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
|
||||
SourceLocation ClassNameLoc,
|
||||
SourceLocation CategoryNameLoc,
|
||||
IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
SourceLocation IvarLBraceLoc,
|
||||
SourceLocation IvarRBraceLoc)
|
||||
: ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc),
|
||||
ClassInterface(IDecl), TypeParamList(typeParamList),
|
||||
NextClassCategory(nullptr), CategoryNameLoc(CategoryNameLoc),
|
||||
IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc)
|
||||
{
|
||||
// Set the declaration context of each of the type parameters.
|
||||
if (typeParamList) {
|
||||
for (auto typeParam : *typeParamList) {
|
||||
typeParam->setDeclContext(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation AtLoc,
|
||||
SourceLocation ClassNameLoc,
|
||||
SourceLocation CategoryNameLoc,
|
||||
IdentifierInfo *Id,
|
||||
ObjCInterfaceDecl *IDecl,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
SourceLocation IvarLBraceLoc,
|
||||
SourceLocation IvarRBraceLoc) {
|
||||
ObjCCategoryDecl *CatDecl =
|
||||
new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id,
|
||||
IDecl, IvarLBraceLoc, IvarRBraceLoc);
|
||||
IDecl, typeParamList, IvarLBraceLoc,
|
||||
IvarRBraceLoc);
|
||||
if (IDecl) {
|
||||
// Link this category into its class's category list.
|
||||
CatDecl->NextClassCategory = IDecl->getCategoryListRaw();
|
||||
|
@ -1676,7 +1785,7 @@ ObjCCategoryDecl *ObjCCategoryDecl::CreateDeserialized(ASTContext &C,
|
|||
unsigned ID) {
|
||||
return new (C, ID) ObjCCategoryDecl(nullptr, SourceLocation(),
|
||||
SourceLocation(), SourceLocation(),
|
||||
nullptr, nullptr);
|
||||
nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const {
|
||||
|
|
|
@ -44,6 +44,8 @@ namespace {
|
|||
void PrintObjCMethodType(ASTContext &Ctx, Decl::ObjCDeclQualifier Quals,
|
||||
QualType T);
|
||||
|
||||
void PrintObjCTypeParams(ObjCTypeParamList *Params);
|
||||
|
||||
public:
|
||||
DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
|
||||
unsigned Indentation = 0, bool PrintInstantiation = false)
|
||||
|
@ -962,6 +964,25 @@ void DeclPrinter::PrintObjCMethodType(ASTContext &Ctx,
|
|||
Out << ')';
|
||||
}
|
||||
|
||||
void DeclPrinter::PrintObjCTypeParams(ObjCTypeParamList *Params) {
|
||||
Out << "<";
|
||||
unsigned First = true;
|
||||
for (auto *Param : *Params) {
|
||||
if (First) {
|
||||
First = false;
|
||||
} else {
|
||||
Out << ", ";
|
||||
}
|
||||
|
||||
Out << Param->getDeclName().getAsString();
|
||||
|
||||
if (Param->hasExplicitBound()) {
|
||||
Out << " : " << Param->getUnderlyingType().getAsString(Policy);
|
||||
}
|
||||
}
|
||||
Out << ">";
|
||||
}
|
||||
|
||||
void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
|
||||
if (OMD->isInstanceMethod())
|
||||
Out << "- ";
|
||||
|
@ -1037,14 +1058,24 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
|
|||
ObjCInterfaceDecl *SID = OID->getSuperClass();
|
||||
|
||||
if (!OID->isThisDeclarationADefinition()) {
|
||||
Out << "@class " << I << ";";
|
||||
Out << "@class " << I;
|
||||
|
||||
if (auto TypeParams = OID->getTypeParamListAsWritten()) {
|
||||
PrintObjCTypeParams(TypeParams);
|
||||
}
|
||||
|
||||
Out << ";";
|
||||
return;
|
||||
}
|
||||
bool eolnOut = false;
|
||||
Out << "@interface " << I;
|
||||
|
||||
if (auto TypeParams = OID->getTypeParamListAsWritten()) {
|
||||
PrintObjCTypeParams(TypeParams);
|
||||
}
|
||||
|
||||
if (SID)
|
||||
Out << "@interface " << I << " : " << *SID;
|
||||
else
|
||||
Out << "@interface " << I;
|
||||
Out << " : " << OID->getSuperClass()->getName();
|
||||
|
||||
// Protocols?
|
||||
const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
|
||||
|
@ -1107,7 +1138,11 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
|
|||
}
|
||||
|
||||
void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
|
||||
Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n";
|
||||
Out << "@interface " << *PID->getClassInterface();
|
||||
if (auto TypeParams = PID->getTypeParamList()) {
|
||||
PrintObjCTypeParams(TypeParams);
|
||||
}
|
||||
Out << "(" << *PID << ")\n";
|
||||
if (PID->ivar_size() > 0) {
|
||||
Out << "{\n";
|
||||
Indentation += Policy.Indentation;
|
||||
|
|
|
@ -79,6 +79,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
|
|||
case Decl::Captured:
|
||||
case Decl::ClassScopeFunctionSpecialization:
|
||||
case Decl::UsingShadow:
|
||||
case Decl::ObjCTypeParam:
|
||||
llvm_unreachable("Declaration should not be in declstmts!");
|
||||
case Decl::Function: // void X();
|
||||
case Decl::Record: // struct/union/class X;
|
||||
|
|
|
@ -96,14 +96,17 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
|
|||
|
||||
///
|
||||
/// objc-class-declaration:
|
||||
/// '@' 'class' identifier-list ';'
|
||||
/// '@' 'class' objc-class-forward-decl (',' objc-class-forward-decl)* ';'
|
||||
///
|
||||
/// objc-class-forward-decl:
|
||||
/// identifier objc-type-parameter-list[opt]
|
||||
///
|
||||
Parser::DeclGroupPtrTy
|
||||
Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
|
||||
ConsumeToken(); // the identifier "class"
|
||||
SmallVector<IdentifierInfo *, 8> ClassNames;
|
||||
SmallVector<SourceLocation, 8> ClassLocs;
|
||||
|
||||
SmallVector<ObjCTypeParamList *, 8> ClassTypeParams;
|
||||
|
||||
while (1) {
|
||||
MaybeSkipAttributes(tok::objc_class);
|
||||
|
@ -116,6 +119,14 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
|
|||
ClassLocs.push_back(Tok.getLocation());
|
||||
ConsumeToken();
|
||||
|
||||
// Parse the optional objc-type-parameter-list.
|
||||
ObjCTypeParamList *TypeParams = nullptr;
|
||||
if (Tok.is(tok::less)) {
|
||||
TypeParams = parseObjCTypeParamList();
|
||||
if (TypeParams)
|
||||
Actions.popObjCTypeParamList(getCurScope(), TypeParams);
|
||||
}
|
||||
ClassTypeParams.push_back(TypeParams);
|
||||
if (!TryConsumeToken(tok::comma))
|
||||
break;
|
||||
}
|
||||
|
@ -126,6 +137,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
|
|||
|
||||
return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(),
|
||||
ClassLocs.data(),
|
||||
ClassTypeParams,
|
||||
ClassNames.size());
|
||||
}
|
||||
|
||||
|
@ -154,15 +166,15 @@ void Parser::CheckNestedObjCContexts(SourceLocation AtLoc)
|
|||
/// objc-category-interface
|
||||
///
|
||||
/// objc-class-interface:
|
||||
/// '@' 'interface' identifier objc-superclass[opt]
|
||||
/// objc-protocol-refs[opt]
|
||||
/// '@' 'interface' identifier objc-type-parameter-list[opt]
|
||||
/// objc-superclass[opt] objc-protocol-refs[opt]
|
||||
/// objc-class-instance-variables[opt]
|
||||
/// objc-interface-decl-list
|
||||
/// @end
|
||||
///
|
||||
/// objc-category-interface:
|
||||
/// '@' 'interface' identifier '(' identifier[opt] ')'
|
||||
/// objc-protocol-refs[opt]
|
||||
/// '@' 'interface' identifier objc-type-parameter-list[opt]
|
||||
/// '(' identifier[opt] ')' objc-protocol-refs[opt]
|
||||
/// objc-interface-decl-list
|
||||
/// @end
|
||||
///
|
||||
|
@ -202,7 +214,20 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
|||
// We have a class or category name - consume it.
|
||||
IdentifierInfo *nameId = Tok.getIdentifierInfo();
|
||||
SourceLocation nameLoc = ConsumeToken();
|
||||
if (Tok.is(tok::l_paren) &&
|
||||
|
||||
// Parse the objc-type-parameter-list or objc-protocol-refs. For the latter
|
||||
// case, LAngleLoc will be valid and ProtocolIdents will capture the
|
||||
// protocol references (that have not yet been resolved).
|
||||
SourceLocation LAngleLoc, EndProtoLoc;
|
||||
SmallVector<IdentifierLocPair, 8> ProtocolIdents;
|
||||
ObjCTypeParamList *typeParameterList = nullptr;
|
||||
if (Tok.is(tok::less)) {
|
||||
typeParameterList = parseObjCTypeParamListOrProtocolRefs(LAngleLoc,
|
||||
ProtocolIdents,
|
||||
EndProtoLoc);
|
||||
}
|
||||
|
||||
if (Tok.is(tok::l_paren) &&
|
||||
!isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category.
|
||||
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||
|
@ -237,7 +262,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
|||
}
|
||||
|
||||
// Next, we need to check for any protocol references.
|
||||
SourceLocation LAngleLoc, EndProtoLoc;
|
||||
assert(LAngleLoc.isInvalid() && "Cannot have already parsed protocols");
|
||||
SmallVector<Decl *, 8> ProtocolRefs;
|
||||
SmallVector<SourceLocation, 8> ProtocolLocs;
|
||||
if (Tok.is(tok::less) &&
|
||||
|
@ -248,6 +273,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
|||
Decl *CategoryType =
|
||||
Actions.ActOnStartCategoryInterface(AtLoc,
|
||||
nameId, nameLoc,
|
||||
typeParameterList,
|
||||
categoryId, categoryLoc,
|
||||
ProtocolRefs.data(),
|
||||
ProtocolRefs.size(),
|
||||
|
@ -258,6 +284,10 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
|||
ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, AtLoc);
|
||||
|
||||
ParseObjCInterfaceDeclList(tok::objc_not_keyword, CategoryType);
|
||||
|
||||
if (typeParameterList)
|
||||
Actions.popObjCTypeParamList(getCurScope(), typeParameterList);
|
||||
|
||||
return CategoryType;
|
||||
}
|
||||
// Parse a class interface.
|
||||
|
@ -281,21 +311,44 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
|||
}
|
||||
superClassId = Tok.getIdentifierInfo();
|
||||
superClassLoc = ConsumeToken();
|
||||
} else if (typeParameterList) {
|
||||
// An objc-type-parameter-list is ambiguous with an objc-protocol-refs
|
||||
// in an @interface without a specified superclass, so such classes
|
||||
// are ill-formed. We have determined that we have an
|
||||
// objc-type-parameter-list but no superclass, so complain and record
|
||||
// as if we inherited from NSObject.
|
||||
SourceLocation insertLoc = PP.getLocForEndOfToken(PrevTokLocation);
|
||||
Diag(insertLoc, diag::err_objc_parameterized_class_without_base)
|
||||
<< nameId
|
||||
<< FixItHint::CreateInsertion(insertLoc, " : NSObject");
|
||||
superClassId = PP.getIdentifierInfo("NSObject");
|
||||
superClassLoc = Tok.getLocation();
|
||||
}
|
||||
|
||||
// Next, we need to check for any protocol references.
|
||||
SmallVector<Decl *, 8> ProtocolRefs;
|
||||
SmallVector<SourceLocation, 8> ProtocolLocs;
|
||||
SourceLocation LAngleLoc, EndProtoLoc;
|
||||
if (Tok.is(tok::less) &&
|
||||
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
|
||||
LAngleLoc, EndProtoLoc))
|
||||
if (LAngleLoc.isValid()) {
|
||||
// We already parsed the protocols named when we thought we had a
|
||||
// type parameter list. Translate them into actual protocol references.
|
||||
for (const auto &pair : ProtocolIdents) {
|
||||
ProtocolLocs.push_back(pair.second);
|
||||
}
|
||||
Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true,
|
||||
/*ForObjCContainer=*/true,
|
||||
&ProtocolIdents[0], ProtocolIdents.size(),
|
||||
ProtocolRefs);
|
||||
} else if (Tok.is(tok::less) &&
|
||||
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
|
||||
LAngleLoc, EndProtoLoc)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (Tok.isNot(tok::less))
|
||||
Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
|
||||
|
||||
Decl *ClsType =
|
||||
Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc,
|
||||
Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, typeParameterList,
|
||||
superClassId, superClassLoc,
|
||||
ProtocolRefs.data(), ProtocolRefs.size(),
|
||||
ProtocolLocs.data(),
|
||||
|
@ -305,6 +358,10 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
|
|||
ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, AtLoc);
|
||||
|
||||
ParseObjCInterfaceDeclList(tok::objc_interface, ClsType);
|
||||
|
||||
if (typeParameterList)
|
||||
Actions.popObjCTypeParamList(getCurScope(), typeParameterList);
|
||||
|
||||
return ClsType;
|
||||
}
|
||||
|
||||
|
@ -339,6 +396,172 @@ static void addContextSensitiveTypeNullability(Parser &P,
|
|||
}
|
||||
}
|
||||
|
||||
/// Parse an Objective-C type parameter list, if present, or capture
|
||||
/// the locations of the protocol identifiers for a list of protocol
|
||||
/// references.
|
||||
///
|
||||
/// objc-type-parameter-list:
|
||||
/// '<' objc-type-parameter (',' objc-type-parameter)* '>'
|
||||
///
|
||||
/// objc-type-parameter:
|
||||
/// identifier objc-type-parameter-bound[opt]
|
||||
///
|
||||
/// objc-type-parameter-bound:
|
||||
/// ':' type-name
|
||||
///
|
||||
/// \param lAngleLoc The location of the starting '<'.
|
||||
///
|
||||
/// \param protocolIdents Will capture the list of identifiers, if the
|
||||
/// angle brackets contain a list of protocol references rather than a
|
||||
/// type parameter list.
|
||||
///
|
||||
/// \param rAngleLoc The location of the ending '>'.
|
||||
ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs(
|
||||
SourceLocation &lAngleLoc,
|
||||
SmallVectorImpl<IdentifierLocPair> &protocolIdents,
|
||||
SourceLocation &rAngleLoc,
|
||||
bool mayBeProtocolList) {
|
||||
assert(Tok.is(tok::less) && "Not at the beginning of a type parameter list");
|
||||
|
||||
// Within the type parameter list, don't treat '>' as an operator.
|
||||
GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
|
||||
|
||||
// Local function to "flush" the protocol identifiers, turning them into
|
||||
// type parameters.
|
||||
SmallVector<Decl *, 4> typeParams;
|
||||
auto makeProtocolIdentsIntoTypeParameters = [&]() {
|
||||
for (const auto &pair : protocolIdents) {
|
||||
DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(),
|
||||
pair.first,
|
||||
pair.second,
|
||||
SourceLocation(),
|
||||
ParsedType());
|
||||
if (typeParam.isUsable())
|
||||
typeParams.push_back(typeParam.get());
|
||||
}
|
||||
|
||||
protocolIdents.clear();
|
||||
mayBeProtocolList = false;
|
||||
};
|
||||
|
||||
bool invalid = false;
|
||||
lAngleLoc = ConsumeToken();
|
||||
do {
|
||||
// Parse the identifier.
|
||||
if (!Tok.is(tok::identifier)) {
|
||||
// Code completion.
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
// FIXME: If these aren't protocol references, we'll need different
|
||||
// completions.
|
||||
Actions.CodeCompleteObjCProtocolReferences(protocolIdents.data(),
|
||||
protocolIdents.size());
|
||||
cutOffParsing();
|
||||
|
||||
// FIXME: Better recovery here?.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Diag(Tok, diag::err_objc_expected_type_parameter);
|
||||
invalid = true;
|
||||
break;
|
||||
}
|
||||
|
||||
IdentifierInfo *paramName = Tok.getIdentifierInfo();
|
||||
SourceLocation paramLoc = ConsumeToken();
|
||||
|
||||
// If there is a bound, parse it.
|
||||
SourceLocation colonLoc;
|
||||
TypeResult boundType;
|
||||
if (TryConsumeToken(tok::colon, colonLoc)) {
|
||||
// Once we've seen a bound, we know this is not a list of protocol
|
||||
// references.
|
||||
if (mayBeProtocolList) {
|
||||
// Up until now, we have been queuing up parameters because they
|
||||
// might be protocol references. Turn them into parameters now.
|
||||
makeProtocolIdentsIntoTypeParameters();
|
||||
}
|
||||
|
||||
// type-name
|
||||
boundType = ParseTypeName();
|
||||
if (boundType.isInvalid())
|
||||
invalid = true;
|
||||
} else if (mayBeProtocolList) {
|
||||
// If this could still be a protocol list, just capture the identifier.
|
||||
// We don't want to turn it into a parameter.
|
||||
protocolIdents.push_back(std::make_pair(paramName, paramLoc));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the type parameter.
|
||||
DeclResult typeParam = Actions.actOnObjCTypeParam(getCurScope(),
|
||||
paramName,
|
||||
paramLoc,
|
||||
colonLoc,
|
||||
boundType.isUsable()
|
||||
? boundType.get()
|
||||
: ParsedType());
|
||||
if (typeParam.isUsable())
|
||||
typeParams.push_back(typeParam.get());
|
||||
} while (TryConsumeToken(tok::comma));
|
||||
|
||||
// Parse the '>'.
|
||||
if (invalid) {
|
||||
SkipUntil(tok::greater, tok::at, StopBeforeMatch);
|
||||
if (Tok.is(tok::greater))
|
||||
ConsumeToken();
|
||||
} else if (ParseGreaterThanInTemplateList(rAngleLoc,
|
||||
/*ConsumeLastToken=*/true,
|
||||
/*ObjCGenericList=*/true)) {
|
||||
Diag(lAngleLoc, diag::note_matching) << "'<'";
|
||||
SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus,
|
||||
tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace,
|
||||
tok::comma, tok::semi },
|
||||
StopBeforeMatch);
|
||||
if (Tok.is(tok::greater))
|
||||
ConsumeToken();
|
||||
}
|
||||
|
||||
if (mayBeProtocolList) {
|
||||
// A type parameter list must be followed by either a ':' (indicating the
|
||||
// presence of a superclass) or a '(' (indicating that this is a category
|
||||
// or extension). This disambiguates between an objc-type-parameter-list
|
||||
// and a objc-protocol-refs.
|
||||
if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_paren)) {
|
||||
// Returning null indicates that we don't have a type parameter list.
|
||||
// The results the caller needs to handle the protocol references are
|
||||
// captured in the reference parameters already.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We have a type parameter list that looks like a list of protocol
|
||||
// references. Turn that parameter list into type parameters.
|
||||
makeProtocolIdentsIntoTypeParameters();
|
||||
}
|
||||
|
||||
// Form the type parameter list.
|
||||
ObjCTypeParamList *list = Actions.actOnObjCTypeParamList(
|
||||
getCurScope(),
|
||||
lAngleLoc,
|
||||
typeParams,
|
||||
rAngleLoc);
|
||||
|
||||
// Clear out the angle locations; they're used by the caller to indicate
|
||||
// whether there are any protocol references.
|
||||
lAngleLoc = SourceLocation();
|
||||
rAngleLoc = SourceLocation();
|
||||
return list;
|
||||
}
|
||||
|
||||
/// Parse an objc-type-parameter-list.
|
||||
ObjCTypeParamList *Parser::parseObjCTypeParamList() {
|
||||
SourceLocation lAngleLoc;
|
||||
SmallVector<IdentifierLocPair, 1> protocolIdents;
|
||||
SourceLocation rAngleLoc;
|
||||
return parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents,
|
||||
rAngleLoc,
|
||||
/*mayBeProtocolList=*/false);
|
||||
}
|
||||
|
||||
/// objc-interface-decl-list:
|
||||
/// empty
|
||||
/// objc-interface-decl-list objc-property-decl [OBJC2]
|
||||
|
@ -1311,7 +1534,8 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
|
|||
}
|
||||
|
||||
// Consume the '>'.
|
||||
if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true))
|
||||
if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true,
|
||||
/*ObjCGenericList=*/false))
|
||||
return true;
|
||||
|
||||
// Convert the list of protocols identifiers into a list of protocol decls.
|
||||
|
@ -1598,6 +1822,22 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
|
|||
SourceLocation nameLoc = ConsumeToken(); // consume class or category name
|
||||
Decl *ObjCImpDecl = nullptr;
|
||||
|
||||
// Neither a type parameter list nor a list of protocol references is
|
||||
// permitted here. Parse and diagnose them.
|
||||
if (Tok.is(tok::less)) {
|
||||
SourceLocation lAngleLoc, rAngleLoc;
|
||||
SmallVector<IdentifierLocPair, 8> protocolIdents;
|
||||
SourceLocation diagLoc = Tok.getLocation();
|
||||
if (parseObjCTypeParamListOrProtocolRefs(lAngleLoc, protocolIdents,
|
||||
rAngleLoc)) {
|
||||
Diag(diagLoc, diag::err_objc_parameterized_implementation)
|
||||
<< SourceRange(diagLoc, PrevTokLocation);
|
||||
} else if (lAngleLoc.isValid()) {
|
||||
Diag(lAngleLoc, diag::err_unexpected_protocol_qualifier)
|
||||
<< FixItHint::CreateRemoval(SourceRange(lAngleLoc, rAngleLoc));
|
||||
}
|
||||
}
|
||||
|
||||
if (Tok.is(tok::l_paren)) {
|
||||
// we have a category implementation.
|
||||
ConsumeParen();
|
||||
|
|
|
@ -738,11 +738,16 @@ void Parser::DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc,
|
|||
///
|
||||
/// \param RAngleLoc the location of the consumed '>'.
|
||||
///
|
||||
/// \param ConsumeLastToken if true, the '>' is not consumed.
|
||||
/// \param ConsumeLastToken if true, the '>' is consumed.
|
||||
///
|
||||
/// \param ObjCGenericList if true, this is the '>' closing an Objective-C
|
||||
/// type parameter or type argument list, rather than a C++ template parameter
|
||||
/// or argument list.
|
||||
///
|
||||
/// \returns true, if current token does not start with '>', false otherwise.
|
||||
bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
|
||||
bool ConsumeLastToken) {
|
||||
bool ConsumeLastToken,
|
||||
bool ObjCGenericList) {
|
||||
// What will be left once we've consumed the '>'.
|
||||
tok::TokenKind RemainingToken;
|
||||
const char *ReplacementStr = "> >";
|
||||
|
@ -783,40 +788,44 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
|
|||
// the token isn't '>>' or '>>>'.
|
||||
// '>>>' is for CUDA, where this sequence of characters is parsed into
|
||||
// tok::greatergreatergreater, rather than two separate tokens.
|
||||
|
||||
//
|
||||
// We always allow this for Objective-C type parameter and type argument
|
||||
// lists.
|
||||
RAngleLoc = Tok.getLocation();
|
||||
|
||||
// The source range of the '>>' or '>=' at the start of the token.
|
||||
CharSourceRange ReplacementRange =
|
||||
CharSourceRange::getCharRange(RAngleLoc,
|
||||
Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(),
|
||||
getLangOpts()));
|
||||
|
||||
// A hint to put a space between the '>>'s. In order to make the hint as
|
||||
// clear as possible, we include the characters either side of the space in
|
||||
// the replacement, rather than just inserting a space at SecondCharLoc.
|
||||
FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange,
|
||||
ReplacementStr);
|
||||
|
||||
// A hint to put another space after the token, if it would otherwise be
|
||||
// lexed differently.
|
||||
FixItHint Hint2;
|
||||
Token Next = NextToken();
|
||||
if ((RemainingToken == tok::greater ||
|
||||
RemainingToken == tok::greatergreater) &&
|
||||
Next.isOneOf(tok::greater, tok::greatergreater,
|
||||
tok::greatergreatergreater, tok::equal, tok::greaterequal,
|
||||
tok::greatergreaterequal, tok::equalequal) &&
|
||||
areTokensAdjacent(Tok, Next))
|
||||
Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " ");
|
||||
if (!ObjCGenericList) {
|
||||
// The source range of the '>>' or '>=' at the start of the token.
|
||||
CharSourceRange ReplacementRange =
|
||||
CharSourceRange::getCharRange(RAngleLoc,
|
||||
Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(),
|
||||
getLangOpts()));
|
||||
|
||||
unsigned DiagId = diag::err_two_right_angle_brackets_need_space;
|
||||
if (getLangOpts().CPlusPlus11 &&
|
||||
Tok.isOneOf(tok::greatergreater, tok::greatergreatergreater))
|
||||
DiagId = diag::warn_cxx98_compat_two_right_angle_brackets;
|
||||
else if (Tok.is(tok::greaterequal))
|
||||
DiagId = diag::err_right_angle_bracket_equal_needs_space;
|
||||
Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2;
|
||||
// A hint to put a space between the '>>'s. In order to make the hint as
|
||||
// clear as possible, we include the characters either side of the space in
|
||||
// the replacement, rather than just inserting a space at SecondCharLoc.
|
||||
FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange,
|
||||
ReplacementStr);
|
||||
|
||||
// A hint to put another space after the token, if it would otherwise be
|
||||
// lexed differently.
|
||||
FixItHint Hint2;
|
||||
if ((RemainingToken == tok::greater ||
|
||||
RemainingToken == tok::greatergreater) &&
|
||||
(Next.isOneOf(tok::greater, tok::greatergreater,
|
||||
tok::greatergreatergreater, tok::equal,
|
||||
tok::greaterequal, tok::greatergreaterequal,
|
||||
tok::equalequal)) &&
|
||||
areTokensAdjacent(Tok, Next))
|
||||
Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " ");
|
||||
|
||||
unsigned DiagId = diag::err_two_right_angle_brackets_need_space;
|
||||
if (getLangOpts().CPlusPlus11 &&
|
||||
(Tok.is(tok::greatergreater) || Tok.is(tok::greatergreatergreater)))
|
||||
DiagId = diag::warn_cxx98_compat_two_right_angle_brackets;
|
||||
else if (Tok.is(tok::greaterequal))
|
||||
DiagId = diag::err_right_angle_bracket_equal_needs_space;
|
||||
Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2;
|
||||
}
|
||||
|
||||
// Strip the initial '>' from the token.
|
||||
if (RemainingToken == tok::equal && Next.is(tok::equal) &&
|
||||
|
@ -895,7 +904,8 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
|
|||
}
|
||||
}
|
||||
|
||||
return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken);
|
||||
return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken,
|
||||
/*ObjCGenericList=*/false);
|
||||
}
|
||||
|
||||
/// \brief Replace the tokens that form a simple-template-id with an
|
||||
|
|
|
@ -3029,7 +3029,9 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) {
|
|||
|
||||
case Decl::Import:
|
||||
return CXCursor_ModuleImportDecl;
|
||||
|
||||
|
||||
case Decl::ObjCTypeParam: return CXCursor_TemplateTypeParameter;
|
||||
|
||||
default:
|
||||
if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
|
||||
switch (TD->getTagKind()) {
|
||||
|
|
|
@ -20,12 +20,15 @@
|
|||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Sema/DeclSpec.h"
|
||||
#include "clang/Sema/ExternalSemaSource.h"
|
||||
#include "clang/Sema/Lookup.h"
|
||||
#include "clang/Sema/Scope.h"
|
||||
#include "clang/Sema/ScopeInfo.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "TypeLocBuilder.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
|
@ -461,9 +464,214 @@ static void diagnoseUseOfProtocols(Sema &TheSema,
|
|||
}
|
||||
}
|
||||
|
||||
DeclResult Sema::actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName,
|
||||
SourceLocation paramLoc,
|
||||
SourceLocation colonLoc,
|
||||
ParsedType parsedTypeBound) {
|
||||
// If there was an explicitly-provided type bound, check it.
|
||||
TypeSourceInfo *typeBoundInfo = nullptr;
|
||||
if (parsedTypeBound) {
|
||||
// The type bound can be any Objective-C pointer type.
|
||||
QualType typeBound = GetTypeFromParser(parsedTypeBound, &typeBoundInfo);
|
||||
if (typeBound->isObjCObjectPointerType()) {
|
||||
// okay
|
||||
} else if (typeBound->isObjCObjectType()) {
|
||||
// The user forgot the * on an Objective-C pointer type, e.g.,
|
||||
// "T : NSView".
|
||||
SourceLocation starLoc = PP.getLocForEndOfToken(
|
||||
typeBoundInfo->getTypeLoc().getEndLoc());
|
||||
Diag(typeBoundInfo->getTypeLoc().getBeginLoc(),
|
||||
diag::err_objc_type_param_bound_missing_pointer)
|
||||
<< typeBound << paramName
|
||||
<< FixItHint::CreateInsertion(starLoc, " *");
|
||||
|
||||
// Create a new type location builder so we can update the type
|
||||
// location information we have.
|
||||
TypeLocBuilder builder;
|
||||
builder.pushFullCopy(typeBoundInfo->getTypeLoc());
|
||||
|
||||
// Create the Objective-C pointer type.
|
||||
typeBound = Context.getObjCObjectPointerType(typeBound);
|
||||
ObjCObjectPointerTypeLoc newT
|
||||
= builder.push<ObjCObjectPointerTypeLoc>(typeBound);
|
||||
newT.setStarLoc(starLoc);
|
||||
|
||||
// Form the new type source information.
|
||||
typeBoundInfo = builder.getTypeSourceInfo(Context, typeBound);
|
||||
} else {
|
||||
// Not a
|
||||
Diag(typeBoundInfo->getTypeLoc().getBeginLoc(),
|
||||
diag::err_objc_type_param_bound_nonobject)
|
||||
<< typeBound << paramName;
|
||||
|
||||
// Forget the bound; we'll default to id later.
|
||||
typeBoundInfo = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// If there was no explicit type bound (or we removed it due to an error),
|
||||
// use 'id' instead.
|
||||
if (!typeBoundInfo) {
|
||||
colonLoc = SourceLocation();
|
||||
typeBoundInfo = Context.getTrivialTypeSourceInfo(Context.getObjCIdType());
|
||||
}
|
||||
|
||||
// Create the type parameter.
|
||||
return ObjCTypeParamDecl::Create(Context, CurContext, paramLoc, paramName,
|
||||
colonLoc, typeBoundInfo);
|
||||
}
|
||||
|
||||
ObjCTypeParamList *Sema::actOnObjCTypeParamList(Scope *S,
|
||||
SourceLocation lAngleLoc,
|
||||
ArrayRef<Decl *> typeParamsIn,
|
||||
SourceLocation rAngleLoc) {
|
||||
// We know that the array only contains Objective-C type parameters.
|
||||
ArrayRef<ObjCTypeParamDecl *>
|
||||
typeParams(
|
||||
reinterpret_cast<ObjCTypeParamDecl * const *>(typeParamsIn.data()),
|
||||
typeParamsIn.size());
|
||||
|
||||
// Diagnose redeclarations of type parameters.
|
||||
// We do this now because Objective-C type parameters aren't pushed into
|
||||
// scope until later (after the instance variable block), but we want the
|
||||
// diagnostics to occur right after we parse the type parameter list.
|
||||
llvm::SmallDenseMap<IdentifierInfo *, ObjCTypeParamDecl *> knownParams;
|
||||
for (auto typeParam : typeParams) {
|
||||
auto known = knownParams.find(typeParam->getIdentifier());
|
||||
if (known != knownParams.end()) {
|
||||
Diag(typeParam->getLocation(), diag::err_objc_type_param_redecl)
|
||||
<< typeParam->getIdentifier()
|
||||
<< SourceRange(known->second->getLocation());
|
||||
|
||||
typeParam->setInvalidDecl();
|
||||
} else {
|
||||
knownParams.insert(std::make_pair(typeParam->getIdentifier(), typeParam));
|
||||
|
||||
// Push the type parameter into scope.
|
||||
PushOnScopeChains(typeParam, S, /*AddToContext=*/false);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the parameter list.
|
||||
return ObjCTypeParamList::create(Context, lAngleLoc, typeParams, rAngleLoc);
|
||||
}
|
||||
|
||||
void Sema::popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList) {
|
||||
for (auto typeParam : *typeParamList) {
|
||||
if (!typeParam->isInvalidDecl()) {
|
||||
S->RemoveDecl(typeParam);
|
||||
IdResolver.RemoveDecl(typeParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// The context in which an Objective-C type parameter list occurs, for use
|
||||
/// in diagnostics.
|
||||
enum class TypeParamListContext {
|
||||
ForwardDeclaration,
|
||||
Definition,
|
||||
Category,
|
||||
Extension
|
||||
};
|
||||
}
|
||||
|
||||
/// Check consistency between two Objective-C type parameter lists, e.g.,
|
||||
/// between a category/extension and an @interface or between an @class and an
|
||||
/// @interface.
|
||||
static bool checkTypeParamListConsistency(Sema &S,
|
||||
ObjCTypeParamList *prevTypeParams,
|
||||
ObjCTypeParamList *newTypeParams,
|
||||
TypeParamListContext newContext) {
|
||||
// If the sizes don't match, complain about that.
|
||||
if (prevTypeParams->size() != newTypeParams->size()) {
|
||||
SourceLocation diagLoc;
|
||||
if (newTypeParams->size() > prevTypeParams->size()) {
|
||||
diagLoc = newTypeParams->begin()[prevTypeParams->size()]->getLocation();
|
||||
} else {
|
||||
diagLoc = S.PP.getLocForEndOfToken(newTypeParams->back()->getLocEnd());
|
||||
}
|
||||
|
||||
S.Diag(diagLoc, diag::err_objc_type_param_arity_mismatch)
|
||||
<< static_cast<unsigned>(newContext)
|
||||
<< (newTypeParams->size() > prevTypeParams->size())
|
||||
<< prevTypeParams->size()
|
||||
<< newTypeParams->size();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Match up the type parameters.
|
||||
for (unsigned i = 0, n = prevTypeParams->size(); i != n; ++i) {
|
||||
ObjCTypeParamDecl *prevTypeParam = prevTypeParams->begin()[i];
|
||||
ObjCTypeParamDecl *newTypeParam = newTypeParams->begin()[i];
|
||||
|
||||
// If the bound types match, there's nothing to do.
|
||||
if (S.Context.hasSameType(prevTypeParam->getUnderlyingType(),
|
||||
newTypeParam->getUnderlyingType()))
|
||||
continue;
|
||||
|
||||
// If the new type parameter's bound was explicit, complain about it being
|
||||
// different from the original.
|
||||
if (newTypeParam->hasExplicitBound()) {
|
||||
SourceRange newBoundRange = newTypeParam->getTypeSourceInfo()
|
||||
->getTypeLoc().getSourceRange();
|
||||
S.Diag(newBoundRange.getBegin(), diag::err_objc_type_param_bound_conflict)
|
||||
<< newTypeParam->getUnderlyingType()
|
||||
<< newTypeParam->getDeclName()
|
||||
<< prevTypeParam->hasExplicitBound()
|
||||
<< prevTypeParam->getUnderlyingType()
|
||||
<< (newTypeParam->getDeclName() == prevTypeParam->getDeclName())
|
||||
<< prevTypeParam->getDeclName()
|
||||
<< FixItHint::CreateReplacement(
|
||||
newBoundRange,
|
||||
prevTypeParam->getUnderlyingType().getAsString(
|
||||
S.Context.getPrintingPolicy()));
|
||||
|
||||
S.Diag(prevTypeParam->getLocation(), diag::note_objc_type_param_here)
|
||||
<< prevTypeParam->getDeclName();
|
||||
|
||||
// Override the new type parameter's bound type with the previous type,
|
||||
// so that it's consistent.
|
||||
newTypeParam->setTypeSourceInfo(
|
||||
S.Context.getTrivialTypeSourceInfo(prevTypeParam->getUnderlyingType()));
|
||||
continue;
|
||||
}
|
||||
|
||||
// The new type parameter got the implicit bound of 'id'. That's okay for
|
||||
// categories and extensions (overwrite it later), but not for forward
|
||||
// declarations and @interfaces, because those must be standalone.
|
||||
if (newContext == TypeParamListContext::ForwardDeclaration ||
|
||||
newContext == TypeParamListContext::Definition) {
|
||||
// Diagnose this problem for forward declarations and definitions.
|
||||
SourceLocation insertionLoc
|
||||
= S.PP.getLocForEndOfToken(newTypeParam->getLocation());
|
||||
std::string newCode
|
||||
= " : " + prevTypeParam->getUnderlyingType().getAsString(
|
||||
S.Context.getPrintingPolicy());
|
||||
S.Diag(newTypeParam->getLocation(),
|
||||
diag::err_objc_type_param_bound_missing)
|
||||
<< prevTypeParam->getUnderlyingType()
|
||||
<< newTypeParam->getDeclName()
|
||||
<< (newContext == TypeParamListContext::ForwardDeclaration)
|
||||
<< FixItHint::CreateInsertion(insertionLoc, newCode);
|
||||
|
||||
S.Diag(prevTypeParam->getLocation(), diag::note_objc_type_param_here)
|
||||
<< prevTypeParam->getDeclName();
|
||||
}
|
||||
|
||||
// Update the new type parameter's bound to match the previous one.
|
||||
newTypeParam->setTypeSourceInfo(
|
||||
S.Context.getTrivialTypeSourceInfo(prevTypeParam->getUnderlyingType()));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Decl *Sema::
|
||||
ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
|
||||
IdentifierInfo *ClassName, SourceLocation ClassLoc,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
IdentifierInfo *SuperName, SourceLocation SuperLoc,
|
||||
Decl * const *ProtoRefs, unsigned NumProtoRefs,
|
||||
const SourceLocation *ProtoLocs,
|
||||
|
@ -498,10 +706,47 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
|
|||
ClassName = PrevIDecl->getIdentifier();
|
||||
}
|
||||
|
||||
// If there was a forward declaration with type parameters, check
|
||||
// for consistency.
|
||||
if (PrevIDecl) {
|
||||
if (ObjCTypeParamList *prevTypeParamList = PrevIDecl->getTypeParamList()) {
|
||||
if (typeParamList) {
|
||||
// Both have type parameter lists; check for consistency.
|
||||
if (checkTypeParamListConsistency(*this, prevTypeParamList,
|
||||
typeParamList,
|
||||
TypeParamListContext::Definition)) {
|
||||
typeParamList = nullptr;
|
||||
}
|
||||
} else {
|
||||
Diag(ClassLoc, diag::err_objc_parameterized_forward_class_first)
|
||||
<< ClassName;
|
||||
Diag(prevTypeParamList->getLAngleLoc(), diag::note_previous_decl)
|
||||
<< ClassName;
|
||||
|
||||
// Clone the type parameter list.
|
||||
SmallVector<ObjCTypeParamDecl *, 4> clonedTypeParams;
|
||||
for (auto typeParam : *prevTypeParamList) {
|
||||
clonedTypeParams.push_back(
|
||||
ObjCTypeParamDecl::Create(
|
||||
Context,
|
||||
CurContext,
|
||||
SourceLocation(),
|
||||
typeParam->getIdentifier(),
|
||||
SourceLocation(),
|
||||
Context.getTrivialTypeSourceInfo(typeParam->getUnderlyingType())));
|
||||
}
|
||||
|
||||
typeParamList = ObjCTypeParamList::create(Context,
|
||||
SourceLocation(),
|
||||
clonedTypeParams,
|
||||
SourceLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ObjCInterfaceDecl *IDecl
|
||||
= ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, ClassName,
|
||||
PrevIDecl, ClassLoc);
|
||||
|
||||
typeParamList, PrevIDecl, ClassLoc);
|
||||
if (PrevIDecl) {
|
||||
// Class already seen. Was it a definition?
|
||||
if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
|
||||
|
@ -906,6 +1151,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
|
|||
Decl *Sema::
|
||||
ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
|
||||
IdentifierInfo *ClassName, SourceLocation ClassLoc,
|
||||
ObjCTypeParamList *typeParamList,
|
||||
IdentifierInfo *CategoryName,
|
||||
SourceLocation CategoryLoc,
|
||||
Decl * const *ProtoRefs,
|
||||
|
@ -925,7 +1171,8 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
|
|||
// the enclosing method declarations. We mark the decl invalid
|
||||
// to make it clear that this isn't a valid AST.
|
||||
CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
|
||||
ClassLoc, CategoryLoc, CategoryName,IDecl);
|
||||
ClassLoc, CategoryLoc, CategoryName,
|
||||
IDecl, typeParamList);
|
||||
CDecl->setInvalidDecl();
|
||||
CurContext->addDecl(CDecl);
|
||||
|
||||
|
@ -951,8 +1198,28 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
|
|||
}
|
||||
}
|
||||
|
||||
// If we have a type parameter list, check it.
|
||||
if (typeParamList) {
|
||||
if (auto prevTypeParamList = IDecl->getTypeParamList()) {
|
||||
if (checkTypeParamListConsistency(*this, prevTypeParamList, typeParamList,
|
||||
CategoryName
|
||||
? TypeParamListContext::Category
|
||||
: TypeParamListContext::Extension))
|
||||
typeParamList = nullptr;
|
||||
} else {
|
||||
Diag(typeParamList->getLAngleLoc(),
|
||||
diag::err_objc_parameterized_category_nonclass)
|
||||
<< (CategoryName != nullptr)
|
||||
<< ClassName
|
||||
<< typeParamList->getSourceRange();
|
||||
|
||||
typeParamList = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CDecl = ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc,
|
||||
ClassLoc, CategoryLoc, CategoryName, IDecl);
|
||||
ClassLoc, CategoryLoc, CategoryName, IDecl,
|
||||
typeParamList);
|
||||
// FIXME: PushOnScopeChains?
|
||||
CurContext->addDecl(CDecl);
|
||||
|
||||
|
@ -987,7 +1254,8 @@ Decl *Sema::ActOnStartCategoryImplementation(
|
|||
// Create and install one.
|
||||
CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, AtCatImplLoc,
|
||||
ClassLoc, CatLoc,
|
||||
CatName, IDecl);
|
||||
CatName, IDecl,
|
||||
/*typeParamList=*/nullptr);
|
||||
CatIDecl->setImplicit();
|
||||
}
|
||||
}
|
||||
|
@ -1101,7 +1369,8 @@ Decl *Sema::ActOnStartClassImplementation(
|
|||
// FIXME: Do we support attributes on the @implementation? If so we should
|
||||
// copy them over.
|
||||
IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
|
||||
ClassName, /*PrevDecl=*/nullptr, ClassLoc,
|
||||
ClassName, /*typeParamList=*/nullptr,
|
||||
/*PrevDecl=*/nullptr, ClassLoc,
|
||||
true);
|
||||
IDecl->startDefinition();
|
||||
if (SDecl) {
|
||||
|
@ -2083,6 +2352,7 @@ Sema::DeclGroupPtrTy
|
|||
Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
|
||||
IdentifierInfo **IdentList,
|
||||
SourceLocation *IdentLocs,
|
||||
ArrayRef<ObjCTypeParamList *> TypeParamLists,
|
||||
unsigned NumElts) {
|
||||
SmallVector<Decl *, 8> DeclsInGroup;
|
||||
for (unsigned i = 0; i != NumElts; ++i) {
|
||||
|
@ -2137,9 +2407,33 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
|
|||
ClassName = PrevIDecl->getIdentifier();
|
||||
}
|
||||
|
||||
// If this forward declaration has type parameters, compare them with the
|
||||
// type parameters of the previous declaration.
|
||||
ObjCTypeParamList *TypeParams = TypeParamLists[i];
|
||||
if (PrevIDecl && TypeParams) {
|
||||
if (ObjCTypeParamList *PrevTypeParams = PrevIDecl->getTypeParamList()) {
|
||||
// Check for consistency with the previous declaration.
|
||||
if (checkTypeParamListConsistency(
|
||||
*this, PrevTypeParams, TypeParams,
|
||||
TypeParamListContext::ForwardDeclaration)) {
|
||||
TypeParams = nullptr;
|
||||
}
|
||||
} else if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
|
||||
// The @interface does not have type parameters. Complain.
|
||||
Diag(IdentLocs[i], diag::err_objc_parameterized_forward_class)
|
||||
<< ClassName
|
||||
<< TypeParams->getSourceRange();
|
||||
Diag(Def->getLocation(), diag::note_defined_here)
|
||||
<< ClassName;
|
||||
|
||||
TypeParams = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ObjCInterfaceDecl *IDecl
|
||||
= ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
|
||||
ClassName, PrevIDecl, IdentLocs[i]);
|
||||
ClassName, TypeParams, PrevIDecl,
|
||||
IdentLocs[i]);
|
||||
IDecl->setAtEndRange(IdentLocs[i]);
|
||||
|
||||
PushOnScopeChains(IDecl, TUScope);
|
||||
|
|
|
@ -133,7 +133,7 @@ ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){
|
|||
ObjCInterfaceDecl::Create (Context,
|
||||
Context.getTranslationUnitDecl(),
|
||||
SourceLocation(), NSIdent,
|
||||
nullptr, SourceLocation());
|
||||
nullptr, nullptr, SourceLocation());
|
||||
Ty = Context.getObjCInterfaceType(NSStringIDecl);
|
||||
Context.setObjCNSStringType(Ty);
|
||||
}
|
||||
|
@ -208,7 +208,8 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
|
|||
S.NSNumberDecl = ObjCInterfaceDecl::Create(CX,
|
||||
CX.getTranslationUnitDecl(),
|
||||
SourceLocation(), NSNumberId,
|
||||
nullptr, SourceLocation());
|
||||
nullptr, nullptr,
|
||||
SourceLocation());
|
||||
} else {
|
||||
// Otherwise, require a declaration of NSNumber.
|
||||
S.Diag(Loc, diag::err_undeclared_nsnumber);
|
||||
|
@ -475,7 +476,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
|
|||
NSStringDecl = ObjCInterfaceDecl::Create(Context, TU,
|
||||
SourceLocation(),
|
||||
NSStringId,
|
||||
nullptr, SourceLocation());
|
||||
nullptr, nullptr,
|
||||
SourceLocation());
|
||||
} else {
|
||||
Diag(SR.getBegin(), diag::err_undeclared_nsstring);
|
||||
return ExprError();
|
||||
|
@ -591,7 +593,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
|
|||
DeclContext *TU = Context.getTranslationUnitDecl();
|
||||
NSValueDecl = ObjCInterfaceDecl::Create(Context, TU,
|
||||
SourceLocation(), NSValueId,
|
||||
nullptr, SourceLocation());
|
||||
nullptr, nullptr,
|
||||
SourceLocation());
|
||||
} else {
|
||||
// Otherwise, require a declaration of NSValue.
|
||||
Diag(SR.getBegin(), diag::err_undeclared_nsvalue);
|
||||
|
@ -755,7 +758,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
|
|||
Context.getTranslationUnitDecl(),
|
||||
SourceLocation(),
|
||||
NSAPIObj->getNSClassId(NSAPI::ClassId_NSArray),
|
||||
nullptr, SourceLocation());
|
||||
nullptr, nullptr, SourceLocation());
|
||||
|
||||
if (!NSArrayDecl) {
|
||||
Diag(SR.getBegin(), diag::err_undeclared_nsarray);
|
||||
|
@ -870,7 +873,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
|
|||
Context.getTranslationUnitDecl(),
|
||||
SourceLocation(),
|
||||
NSAPIObj->getNSClassId(NSAPI::ClassId_NSDictionary),
|
||||
nullptr, SourceLocation());
|
||||
nullptr, nullptr, SourceLocation());
|
||||
|
||||
if (!NSDictionaryDecl) {
|
||||
Diag(SR.getBegin(), diag::err_undeclared_nsdictionary);
|
||||
|
|
|
@ -221,6 +221,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
|
|||
// redeclarable.
|
||||
case Decl::ImplicitParam:
|
||||
case Decl::ParmVar:
|
||||
case Decl::ObjCTypeParam:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -350,8 +350,11 @@ namespace clang {
|
|||
RedeclarableTemplateDecl *Existing,
|
||||
DeclID DsID);
|
||||
|
||||
ObjCTypeParamList *ReadObjCTypeParamList();
|
||||
|
||||
// FIXME: Reorder according to DeclNodes.td?
|
||||
void VisitObjCMethodDecl(ObjCMethodDecl *D);
|
||||
void VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
|
||||
void VisitObjCContainerDecl(ObjCContainerDecl *D);
|
||||
void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
|
||||
void VisitObjCIvarDecl(ObjCIvarDecl *D);
|
||||
|
@ -899,18 +902,46 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
|
|||
MD->setParamsAndSelLocs(Reader.getContext(), Params, SelLocs);
|
||||
}
|
||||
|
||||
void ASTDeclReader::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
|
||||
VisitTypedefNameDecl(D);
|
||||
D->ColonLoc = ReadSourceLocation(Record, Idx);
|
||||
}
|
||||
|
||||
void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
|
||||
VisitNamedDecl(CD);
|
||||
CD->setAtStartLoc(ReadSourceLocation(Record, Idx));
|
||||
CD->setAtEndRange(ReadSourceRange(Record, Idx));
|
||||
}
|
||||
|
||||
ObjCTypeParamList *ASTDeclReader::ReadObjCTypeParamList() {
|
||||
unsigned numParams = Record[Idx++];
|
||||
if (numParams == 0)
|
||||
return nullptr;
|
||||
|
||||
SmallVector<ObjCTypeParamDecl *, 4> typeParams;
|
||||
typeParams.reserve(numParams);
|
||||
for (unsigned i = 0; i != numParams; ++i) {
|
||||
auto typeParam = ReadDeclAs<ObjCTypeParamDecl>(Record, Idx);
|
||||
if (!typeParam)
|
||||
return nullptr;
|
||||
|
||||
typeParams.push_back(typeParam);
|
||||
}
|
||||
|
||||
SourceLocation lAngleLoc = ReadSourceLocation(Record, Idx);
|
||||
SourceLocation rAngleLoc = ReadSourceLocation(Record, Idx);
|
||||
|
||||
return ObjCTypeParamList::create(Reader.getContext(), lAngleLoc,
|
||||
typeParams, rAngleLoc);
|
||||
}
|
||||
|
||||
void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
|
||||
RedeclarableResult Redecl = VisitRedeclarable(ID);
|
||||
VisitObjCContainerDecl(ID);
|
||||
TypeIDForTypeDecl = Reader.getGlobalTypeID(F, Record[Idx++]);
|
||||
mergeRedeclarable(ID, Redecl);
|
||||
|
||||
|
||||
ID->TypeParamList = ReadObjCTypeParamList();
|
||||
if (Record[Idx++]) {
|
||||
// Read the definition.
|
||||
ID->allocateDefinitionData();
|
||||
|
@ -1020,6 +1051,7 @@ void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) {
|
|||
Reader.CategoriesDeserialized.insert(CD);
|
||||
|
||||
CD->ClassInterface = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
|
||||
CD->TypeParamList = ReadObjCTypeParamList();
|
||||
unsigned NumProtoRefs = Record[Idx++];
|
||||
SmallVector<ObjCProtocolDecl *, 16> ProtoRefs;
|
||||
ProtoRefs.reserve(NumProtoRefs);
|
||||
|
@ -3259,6 +3291,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
|
|||
case DECL_EMPTY:
|
||||
D = EmptyDecl::CreateDeserialized(Context, ID);
|
||||
break;
|
||||
case DECL_OBJC_TYPE_PARAM:
|
||||
D = ObjCTypeParamDecl::CreateDeserialized(Context, ID);
|
||||
break;
|
||||
}
|
||||
|
||||
assert(D && "Unknown declaration reading AST file");
|
||||
|
|
|
@ -117,6 +117,7 @@ namespace clang {
|
|||
|
||||
// FIXME: Put in the same order is DeclNodes.td?
|
||||
void VisitObjCMethodDecl(ObjCMethodDecl *D);
|
||||
void VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
|
||||
void VisitObjCContainerDecl(ObjCContainerDecl *D);
|
||||
void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
|
||||
void VisitObjCIvarDecl(ObjCIvarDecl *D);
|
||||
|
@ -131,6 +132,22 @@ namespace clang {
|
|||
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
|
||||
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
|
||||
|
||||
/// Add an Objective-C type parameter list to the given record.
|
||||
void AddObjCTypeParamList(ObjCTypeParamList *typeParams) {
|
||||
// Empty type parameter list.
|
||||
if (!typeParams) {
|
||||
Record.push_back(0);
|
||||
return;
|
||||
}
|
||||
|
||||
Record.push_back(typeParams->size());
|
||||
for (auto typeParam : *typeParams) {
|
||||
Writer.AddDeclRef(typeParam, Record);
|
||||
}
|
||||
Writer.AddSourceLocation(typeParams->getLAngleLoc(), Record);
|
||||
Writer.AddSourceLocation(typeParams->getRAngleLoc(), Record);
|
||||
}
|
||||
|
||||
void AddFunctionDefinition(const FunctionDecl *FD) {
|
||||
assert(FD->doesThisDeclarationHaveABody());
|
||||
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) {
|
||||
|
@ -562,6 +579,13 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
|
|||
Code = serialization::DECL_OBJC_METHOD;
|
||||
}
|
||||
|
||||
void ASTDeclWriter::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
|
||||
VisitTypedefNameDecl(D);
|
||||
Writer.AddSourceLocation(D->ColonLoc, Record);
|
||||
|
||||
Code = serialization::DECL_OBJC_TYPE_PARAM;
|
||||
}
|
||||
|
||||
void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
|
||||
VisitNamedDecl(D);
|
||||
Writer.AddSourceLocation(D->getAtStartLoc(), Record);
|
||||
|
@ -573,6 +597,7 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
|
|||
VisitRedeclarable(D);
|
||||
VisitObjCContainerDecl(D);
|
||||
Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
|
||||
AddObjCTypeParamList(D->TypeParamList);
|
||||
|
||||
Record.push_back(D->isThisDeclarationADefinition());
|
||||
if (D->isThisDeclarationADefinition()) {
|
||||
|
@ -660,6 +685,7 @@ void ASTDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
|
|||
Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record);
|
||||
Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record);
|
||||
Writer.AddDeclRef(D->getClassInterface(), Record);
|
||||
AddObjCTypeParamList(D->TypeParamList);
|
||||
Record.push_back(D->protocol_size());
|
||||
for (const auto *I : D->protocols())
|
||||
Writer.AddDeclRef(I, Record);
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: mkdir %t
|
||||
// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 %s > %t/out
|
||||
// RUN: FileCheck %s < %t/out
|
||||
|
||||
// Ensure that XML we generate is not invalid.
|
||||
// RUN: FileCheck %s -check-prefix=WRONG < %t/out
|
||||
// WRONG-NOT: CommentXMLInvalid
|
||||
|
||||
@protocol NSObject
|
||||
@end
|
||||
|
||||
@interface NSObject
|
||||
@end
|
||||
|
||||
// CHECK: <Declaration>@interface A <T : id, U : NSObject *> : NSObject
|
||||
/// A
|
||||
@interface A<T : id, U : NSObject *> : NSObject
|
||||
@end
|
|
@ -0,0 +1,30 @@
|
|||
// RUN: %clang_cc1 -emit-pch %s -o %t
|
||||
// RUN: %clang_cc1 -include-pch %t -verify %s
|
||||
|
||||
#ifndef HEADER_INCLUDED
|
||||
|
||||
#define HEADER_INCLUDED
|
||||
|
||||
@protocol NSObject
|
||||
@end
|
||||
|
||||
__attribute__((objc_root_class))
|
||||
@interface NSObject
|
||||
@end
|
||||
|
||||
@interface PC1<T, U : NSObject *> : NSObject
|
||||
// expected-note@-2{{type parameter 'U' declared here}}
|
||||
@end
|
||||
|
||||
@interface PC1<T, U : NSObject *> (Cat1)
|
||||
@end
|
||||
|
||||
#else
|
||||
|
||||
@interface PC1<T : NSObject *, // expected-error{{type bound 'NSObject *' for type parameter 'T' conflicts with implicit bound 'id}}
|
||||
// expected-note@15{{type parameter 'T' declared here}}
|
||||
U : id> (Cat2) // expected-error{{type bound 'id' for type parameter 'U' conflicts with previous bound 'NSObject *'}}
|
||||
// expected-note@15{{type parameter 'U' declared here}}
|
||||
@end
|
||||
|
||||
#endif
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
@interface K @end
|
||||
|
||||
@implementation K <P // expected-error {{@implementation declaration cannot be protocol qualified}}
|
||||
@implementation K <P // expected-error {{@implementation declaration cannot be protocol qualified}} expected-note{{to match this '<'}}
|
||||
@end // expected-error {{expected '>'}}
|
||||
|
||||
// rdar://13920026
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
// RUN: %clang_cc1 %s -verify
|
||||
|
||||
@protocol NSObject
|
||||
@end
|
||||
|
||||
__attribute__((objc_root_class))
|
||||
@interface NSObject <NSObject> // expected-note{{'NSObject' defined here}}
|
||||
@end
|
||||
|
||||
@interface NSString : NSObject
|
||||
@end
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Parsing parameterized classes.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Parse type parameters with a bound
|
||||
@interface PC1<T, U : NSObject*> : NSObject
|
||||
// expected-note@-1{{type parameter 'T' declared here}}
|
||||
// expected-note@-2{{type parameter 'U' declared here}}
|
||||
@end
|
||||
|
||||
// Parse a type parameter with a bound that terminates in '>>'.
|
||||
@interface PC2<T : id<NSObject>> : NSObject // expected-error{{a space is required between consecutive right angle brackets (use '> >')}}
|
||||
@end
|
||||
|
||||
// Parse multiple type parameters.
|
||||
@interface PC3<T, U : id> : NSObject
|
||||
@end
|
||||
|
||||
// Parse multiple type parameters--grammatically ambiguous with protocol refs.
|
||||
@interface PC4<T, U, V> : NSObject
|
||||
@end
|
||||
|
||||
// Parse a type parameter list without a superclass.
|
||||
@interface PC5<T : id> // expected-error{{parameterized Objective-C class 'PC5' must have a superclass}}
|
||||
@end
|
||||
|
||||
// Parse a type parameter with name conflicts.
|
||||
@interface PC6<T, U,
|
||||
T> : NSObject // expected-error{{redeclaration of type parameter 'T'}}
|
||||
@end
|
||||
|
||||
// Parse Objective-C protocol references.
|
||||
@interface PC7<T> // expected-error{{cannot find protocol declaration for 'T'}}
|
||||
@end
|
||||
|
||||
// Parse both type parameters and protocol references.
|
||||
@interface PC8<T> : NSObject <NSObject>
|
||||
@end
|
||||
|
||||
// Type parameters with improper bounds.
|
||||
@interface PC9<T : int, // expected-error{{type bound 'int' for type parameter 'T' is not an Objective-C pointer type}}
|
||||
U : NSString> : NSObject // expected-error{{missing '*' in type bound 'NSString' for type parameter 'U'}}
|
||||
@end
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Parsing parameterized forward declarations classes.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Okay: forward declaration without type parameters.
|
||||
@class PC10;
|
||||
|
||||
// Okay: forward declarations with type parameters.
|
||||
@class PC10<T, U : NSObject *>, PC11<T : NSObject *, U : id>; // expected-note{{type parameter 'T' declared here}}
|
||||
|
||||
// Okay: forward declaration without type parameters following ones
|
||||
// with type parameters.
|
||||
@class PC10, PC11;
|
||||
|
||||
// Okay: definition of class with type parameters that was formerly
|
||||
// declared with the same type parameters.
|
||||
@interface PC10<T, U : NSObject *> : NSObject
|
||||
@end
|
||||
|
||||
// Mismatched parameters in declaration of @interface following @class.
|
||||
@interface PC11<T, U> : NSObject // expected-error{{missing type bound 'NSObject *' for type parameter 'T' in @interface}}
|
||||
@end
|
||||
|
||||
@interface PC12<T : NSObject *> : NSObject // expected-note{{type parameter 'T' declared here}}
|
||||
@end
|
||||
|
||||
@class PC12;
|
||||
|
||||
// Mismatched parameters in subsequent forward declarations.
|
||||
@class PC13<T : NSObject *>; // expected-note{{type parameter 'T' declared here}}
|
||||
@class PC13;
|
||||
@class PC13<U>; // expected-error{{missing type bound 'NSObject *' for type parameter 'U' in @class}}
|
||||
|
||||
// Mismatch parameters in declaration of @class following @interface.
|
||||
@class PC12<T>; // expected-error{{missing type bound 'NSObject *' for type parameter 'T' in @class}}
|
||||
|
||||
// Parameterized forward declaration a class that is not parameterized.
|
||||
@class NSObject<T>; // expected-error{{forward declaration of non-parameterized class 'NSObject' cannot have type parameters}}
|
||||
|
||||
// Parameterized forward declaration preceding the definition (that is
|
||||
// not parameterized).
|
||||
@class NSNumber<T : NSObject *>; // expected-note{{'NSNumber' declared here}}
|
||||
@interface NSNumber : NSObject // expected-error{{class 'NSNumber' previously declared with type parameters}}
|
||||
@end
|
||||
|
||||
@class PC14;
|
||||
|
||||
// Okay: definition of class with type parameters that was formerly
|
||||
// declared without type parameters.
|
||||
@interface PC14<T, U : NSObject *> : NSObject
|
||||
@end
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Parsing parameterized categories and extensions.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// Inferring type bounds
|
||||
@interface PC1<T, U> (Cat1) <NSObject>
|
||||
@end
|
||||
|
||||
// Matching type bounds
|
||||
@interface PC1<T : id, U : NSObject *> (Cat2) <NSObject>
|
||||
@end
|
||||
|
||||
// Inferring type bounds
|
||||
@interface PC1<T, U> () <NSObject>
|
||||
@end
|
||||
|
||||
// Matching type bounds
|
||||
@interface PC1<T : id, U : NSObject *> () <NSObject>
|
||||
@end
|
||||
|
||||
// Missing type parameters.
|
||||
@interface PC1<T> () // expected-error{{extension has too few type parameters (expected 2, have 1)}}
|
||||
@end
|
||||
|
||||
// Extra type parameters.
|
||||
@interface PC1<T, U, V> (Cat3) // expected-error{{category has too many type parameters (expected 2, have 3)}}
|
||||
@end
|
||||
|
||||
// Mismatched bounds.
|
||||
@interface PC1<T : NSObject *, // expected-error{{type bound 'NSObject *' for type parameter 'T' conflicts with implicit bound 'id'}}
|
||||
X : id> () // expected-error{{type bound 'id' for type parameter 'X' conflicts with previous bound 'NSObject *'for type parameter 'U'}}
|
||||
@end
|
||||
|
||||
// Parameterized category/extension of non-parameterized class.
|
||||
@interface NSObject<T> (Cat1) // expected-error{{category of non-parameterized class 'NSObject' cannot have type parameters}}
|
||||
@end
|
||||
|
||||
@interface NSObject<T> () // expected-error{{extension of non-parameterized class 'NSObject' cannot have type parameters}}
|
||||
@end
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// @implementations cannot have type parameters
|
||||
// --------------------------------------------------------------------------
|
||||
@implementation PC1<T : id> // expected-error{{@implementation cannot have type parameters}}
|
||||
@end
|
||||
|
||||
@implementation PC2<T> // expected-error{{@implementation declaration cannot be protocol qualified}}
|
||||
@end
|
||||
|
||||
@implementation PC1<T> (Cat1) // expected-error{{@implementation cannot have type parameters}}
|
||||
@end
|
||||
|
||||
@implementation PC1<T : id> (Cat2) // expected-error{{@implementation cannot have type parameters}}
|
||||
@end
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Interfaces involving type parameters
|
||||
// --------------------------------------------------------------------------
|
||||
@interface PC20<T : id, U : NSObject *, V : NSString *> : NSObject {
|
||||
T object;
|
||||
}
|
||||
|
||||
- (U)method:(V)param; // expected-note{{passing argument to parameter 'param' here}}
|
||||
@end
|
||||
|
||||
@interface PC20<T, U, V> (Cat1)
|
||||
- (U)catMethod:(V)param; // expected-note{{passing argument to parameter 'param' here}}
|
||||
@end
|
||||
|
||||
@interface PC20<X, Y, Z>()
|
||||
- (X)extMethod:(Y)param; // expected-note{{passing argument to parameter 'param' here}}
|
||||
@end
|
||||
|
||||
void test_PC20_unspecialized(PC20 *pc20) {
|
||||
// FIXME: replace type parameters with underlying types?
|
||||
int *ip = [pc20 method: 0]; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'U' (aka 'NSObject *')}}
|
||||
[pc20 method: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'V' (aka 'NSString *')}}
|
||||
|
||||
ip = [pc20 catMethod: 0]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'U' (aka 'NSObject *')}}
|
||||
[pc20 catMethod: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'V' (aka 'NSString *')}}
|
||||
|
||||
ip = [pc20 extMethod: 0]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'X' (aka 'id')}}
|
||||
[pc20 extMethod: ip]; // expected-warning{{incompatible pointer types sending 'int *' to parameter of type 'Y' (aka 'NSObject *')}}
|
||||
}
|
|
@ -5038,6 +5038,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
|
|||
case Decl::ClassScopeFunctionSpecialization:
|
||||
case Decl::Import:
|
||||
case Decl::OMPThreadPrivate:
|
||||
case Decl::ObjCTypeParam:
|
||||
return C;
|
||||
|
||||
// Declaration kinds that don't make any sense here, but are
|
||||
|
@ -6321,6 +6322,7 @@ static CXLanguageKind getDeclLanguage(const Decl *D) {
|
|||
case Decl::ObjCProperty:
|
||||
case Decl::ObjCPropertyImpl:
|
||||
case Decl::ObjCProtocol:
|
||||
case Decl::ObjCTypeParam:
|
||||
return CXLanguage_ObjC;
|
||||
case Decl::CXXConstructor:
|
||||
case Decl::CXXConversion:
|
||||
|
|
Loading…
Reference in New Issue