diff options
39 files changed, 1706 insertions, 354 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 682be3d4151..e7a90be8b2b 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -236,6 +236,12 @@ class ASTContext : public RefCountedBase<ASTContext> { QualType ObjCClassRedefinitionType; QualType ObjCSelRedefinitionType; + /// The identifier 'NSObject'. + IdentifierInfo *NSObjectName = nullptr; + + /// The identifier 'NSCopying'. + IdentifierInfo *NSCopyingName = nullptr; + QualType ObjCConstantStringType; mutable RecordDecl *CFConstantStringTypeDecl; @@ -1189,9 +1195,14 @@ public: QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl, ObjCInterfaceDecl *PrevDecl = nullptr) const; + /// Legacy interface: cannot provide type arguments. QualType getObjCObjectType(QualType Base, ObjCProtocolDecl * const *Protocols, unsigned NumProtocols) const; + + QualType getObjCObjectType(QualType Base, + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols) const; bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl); /// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in @@ -1351,6 +1362,24 @@ public: ObjCSelRedefinitionType = RedefType; } + /// Retrieve the identifier 'NSObject'. + IdentifierInfo *getNSObjectName() { + if (!NSObjectName) { + NSObjectName = &Idents.get("NSObject"); + } + + return NSObjectName; + } + + /// Retrieve the identifier 'NSCopying'. + IdentifierInfo *getNSCopyingName() { + if (!NSCopyingName) { + NSCopyingName = &Idents.get("NSCopying"); + } + + return NSCopyingName; + } + /// \brief Retrieve the Objective-C "instancetype" type, if already known; /// otherwise, returns a NULL type; QualType getObjCInstanceType() { diff --git a/clang/include/clang/AST/DataRecursiveASTVisitor.h b/clang/include/clang/AST/DataRecursiveASTVisitor.h index 789bb8fb410..0d47771eb38 100644 --- a/clang/include/clang/AST/DataRecursiveASTVisitor.h +++ b/clang/include/clang/AST/DataRecursiveASTVisitor.h @@ -940,6 +940,8 @@ DEF_TRAVERSE_TYPE(ObjCObjectType, { // type is itself. if (T->getBaseType().getTypePtr() != T) TRY_TO(TraverseType(T->getBaseType())); + for (auto typeArg : T->getTypeArgsAsWritten()) + TRY_TO(TraverseType(typeArg)); }) DEF_TRAVERSE_TYPE(ObjCObjectPointerType, @@ -1166,6 +1168,8 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectType, { // type is itself. if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr()) TRY_TO(TraverseTypeLoc(TL.getBaseLoc())); + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) + TRY_TO(TraverseTypeLoc(TL.getTypeArgTInfo(i)->getTypeLoc())); }) DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, @@ -1325,7 +1329,10 @@ DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement for (auto typeParam : *typeParamList) TRY_TO(TraverseObjCTypeParamDecl(typeParam)); } - return true; + + if (TypeSourceInfo *superTInfo = D->getSuperClassTInfo()) { + TRY_TO(TraverseTypeLoc(superTInfo->getTypeLoc())); + } }) DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index 78990c9f391..4a0606825bd 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -794,9 +794,9 @@ class ObjCInterfaceDecl : public ObjCContainerDecl /// declaration. ObjCInterfaceDecl *Definition; - /// Class's super class. - ObjCInterfaceDecl *SuperClass; - + /// When non-null, this is always an ObjCObjectType. + TypeSourceInfo *SuperClassTInfo; + /// Protocols referenced in the \@interface declaration ObjCProtocolList ReferencedProtocols; @@ -837,16 +837,13 @@ class ObjCInterfaceDecl : public ObjCContainerDecl }; /// One of the \c InheritedDesignatedInitializersState enumeratos. mutable unsigned InheritedDesignatedInitializers : 2; - - /// \brief The location of the superclass, if any. - SourceLocation SuperClassLoc; /// \brief The location of the last location in this declaration, before /// the properties/methods. For example, this will be the '>', '}', or /// identifier, SourceLocation EndLoc; - DefinitionData() : Definition(), SuperClass(), CategoryList(), IvarList(), + DefinitionData() : Definition(), SuperClassTInfo(), CategoryList(), IvarList(), ExternallyCompleted(), IvarListMissingImplementation(true), HasDesignatedInitializers(), @@ -903,8 +900,8 @@ public: /// 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 + /// class; if the class has been declared (with \c \@class) but not + /// defined (with \c \@interface), it will search for a declaration that /// has type parameters, skipping any declarations that do not. ObjCTypeParamList *getTypeParamList() const; @@ -1160,7 +1157,16 @@ public: /// a forward declaration (\@class) to a definition (\@interface). void startDefinition(); - ObjCInterfaceDecl *getSuperClass() const { + /// Retrieve the superclass type. + const ObjCObjectType *getSuperClassType() const { + if (TypeSourceInfo *TInfo = getSuperClassTInfo()) + return TInfo->getType()->castAs<ObjCObjectType>(); + + return nullptr; + } + + // Retrieve the type source information for the superclass. + TypeSourceInfo *getSuperClassTInfo() const { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) return nullptr; @@ -1168,13 +1174,15 @@ public: if (data().ExternallyCompleted) LoadExternalDefinition(); - return data().SuperClass; + return data().SuperClassTInfo; } - void setSuperClass(ObjCInterfaceDecl * superCls) { - data().SuperClass = - (superCls && superCls->hasDefinition()) ? superCls->getDefinition() - : superCls; + // Retrieve the declaration for the superclass of this class, which + // does not include any type arguments that apply to the superclass. + ObjCInterfaceDecl *getSuperClass() const; + + void setSuperClass(TypeSourceInfo *superClass) { + data().SuperClassTInfo = superClass; } /// \brief Iterator that walks over the list of categories, filtering out @@ -1466,8 +1474,8 @@ public: void setEndOfDefinitionLoc(SourceLocation LE) { data().EndLoc = LE; } - void setSuperClassLoc(SourceLocation Loc) { data().SuperClassLoc = Loc; } - SourceLocation getSuperClassLoc() const { return data().SuperClassLoc; } + /// Retrieve the starting location of the superclass. + SourceLocation getSuperClassLoc() const; /// isImplicitInterfaceDecl - check that this is an implicitly declared /// ObjCInterfaceDecl node. This is for legacy objective-c \@implementation diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 8633c0f4183..d402ce33fd5 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1008,6 +1008,8 @@ DEF_TRAVERSE_TYPE(ObjCObjectType, { // type is itself. if (T->getBaseType().getTypePtr() != T) TRY_TO(TraverseType(T->getBaseType())); + for (auto typeArg : T->getTypeArgsAsWritten()) + TRY_TO(TraverseType(typeArg)); }) DEF_TRAVERSE_TYPE(ObjCObjectPointerType, @@ -1234,6 +1236,8 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectType, { // type is itself. if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr()) TRY_TO(TraverseTypeLoc(TL.getBaseLoc())); + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) + TRY_TO(TraverseTypeLoc(TL.getTypeArgTInfo(i)->getTypeLoc())); }) DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, @@ -1399,6 +1403,10 @@ DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement for (auto typeParam : *typeParamList) TRY_TO(TraverseObjCTypeParamDecl(typeParam)); } + + if (TypeSourceInfo *superTInfo = D->getSuperClassTInfo()) { + TRY_TO(TraverseTypeLoc(superTInfo->getTypeLoc())); + } }) DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 97f13313b33..70db6ea0e19 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1288,10 +1288,14 @@ protected: unsigned : NumTypeBits; + /// The number of type arguments stored directly on this object type. + unsigned NumTypeArgs : 7; + /// NumProtocols - The number of protocols stored directly on this /// object type. - unsigned NumProtocols : 32 - NumTypeBits; + unsigned NumProtocols : 7; }; + static_assert(NumTypeBits + 7 + 7 <= 32, "Does not fit in an unsigned"); class ReferenceTypeBitfields { friend class ReferenceType; @@ -1586,6 +1590,7 @@ public: bool isObjCObjectOrInterfaceType() const; bool isObjCIdType() const; // id bool isObjCClassType() const; // Class + bool isBlockCompatibleObjCPointerType(ASTContext &ctx) const; bool isObjCSelType() const; // Class bool isObjCBuiltinType() const; // 'id' or 'Class' bool isObjCARCBridgableType() const; @@ -4369,19 +4374,25 @@ public: }; /// ObjCObjectType - Represents a class type in Objective C. -/// Every Objective C type is a combination of a base type and a -/// list of protocols. +/// +/// Every Objective C type is a combination of a base type, a set of +/// type arguments (optional, for parameterized classes) and a list of +/// protocols. /// /// Given the following declarations: /// \code -/// \@class C; +/// \@class C<T>; /// \@protocol P; /// \endcode /// /// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType /// with base C and no protocols. /// -/// 'C<P>' is an ObjCObjectType with base C and protocol list [P]. +/// 'C<P>' is an unspecialized ObjCObjectType with base C and protocol list [P]. +/// 'C<C*>' is a specialized ObjCObjectType with type arguments 'C*' and no +/// protocol list. +/// 'C<C*><P>' is a specialized ObjCObjectType with base C, type arguments 'C*', +/// and protocol list [P]. /// /// 'id' is a TypedefType which is sugar for an ObjCObjectPointerType whose /// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType @@ -4391,8 +4402,10 @@ public: /// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually /// this should get its own sugar class to better represent the source. class ObjCObjectType : public Type { - // ObjCObjectType.NumProtocols - the number of protocols stored + // ObjCObjectType.NumTypeArgs - the number of type arguments stored // after the ObjCObjectPointerType node. + // ObjCObjectType.NumProtocols - the number of protocols stored + // after the type arguments of ObjCObjectPointerType node. // // These protocols are those written directly on the type. If // protocol qualifiers ever become additive, the iterators will need @@ -4408,17 +4421,24 @@ class ObjCObjectType : public Type { return const_cast<ObjCObjectType*>(this)->getProtocolStorage(); } + QualType *getTypeArgStorage(); + const QualType *getTypeArgStorage() const { + return const_cast<ObjCObjectType *>(this)->getTypeArgStorage(); + } + ObjCProtocolDecl **getProtocolStorage(); protected: ObjCObjectType(QualType Canonical, QualType Base, - ObjCProtocolDecl * const *Protocols, unsigned NumProtocols); + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols); enum Nonce_ObjCInterface { Nonce_ObjCInterface }; ObjCObjectType(enum Nonce_ObjCInterface) : Type(ObjCInterface, QualType(), false, false, false, false), BaseType(QualType(this_(), 0)) { ObjCObjectTypeBits.NumProtocols = 0; + ObjCObjectTypeBits.NumTypeArgs = 0; } public: @@ -4452,6 +4472,33 @@ public: /// really is an interface. ObjCInterfaceDecl *getInterface() const; + /// Determine whether this object type is "specialized", meaning + /// that it has type arguments. + bool isSpecialized() const; + + /// Determine whether this object type was written with type arguments. + bool isSpecializedAsWritten() const { + return ObjCObjectTypeBits.NumTypeArgs > 0; + } + + /// Determine whether this object type is "unspecialized", meaning + /// that it has no type arguments. + bool isUnspecialized() const { return !isSpecialized(); } + + /// Determine whether this object type is "unspecialized" as + /// written, meaning that it has no type arguments. + bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } + + /// Retrieve the type arguments of this object type (semantically). + ArrayRef<QualType> getTypeArgs() const; + + /// Retrieve the type arguments of this object type as they were + /// written. + ArrayRef<QualType> getTypeArgsAsWritten() const { + return ArrayRef<QualType>(getTypeArgStorage(), + ObjCObjectTypeBits.NumTypeArgs); + } + typedef ObjCProtocolDecl * const *qual_iterator; typedef llvm::iterator_range<qual_iterator> qual_range; @@ -4491,21 +4538,25 @@ class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode { // will need to be modified. ObjCObjectTypeImpl(QualType Canonical, QualType Base, - ObjCProtocolDecl * const *Protocols, - unsigned NumProtocols) - : ObjCObjectType(Canonical, Base, Protocols, NumProtocols) {} + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols) + : ObjCObjectType(Canonical, Base, typeArgs, protocols) {} public: void Profile(llvm::FoldingSetNodeID &ID); static void Profile(llvm::FoldingSetNodeID &ID, QualType Base, - ObjCProtocolDecl *const *protocols, - unsigned NumProtocols); + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols); }; +inline QualType *ObjCObjectType::getTypeArgStorage() { + return reinterpret_cast<QualType *>(static_cast<ObjCObjectTypeImpl*>(this)+1); +} + inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorage() { - return reinterpret_cast<ObjCProtocolDecl**>( - static_cast<ObjCObjectTypeImpl*>(this) + 1); + return reinterpret_cast<ObjCProtocolDecl**>( + getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs); } /// ObjCInterfaceType - Interfaces are the core concept in Objective-C for @@ -4556,9 +4607,14 @@ public: }; inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const { - if (const ObjCInterfaceType *T = - getBaseType()->getAs<ObjCInterfaceType>()) - return T->getDecl(); + QualType baseType = getBaseType(); + while (const ObjCObjectType *ObjT = baseType->getAs<ObjCObjectType>()) { + if (const ObjCInterfaceType *T = dyn_cast<ObjCInterfaceType>(ObjT)) + return T->getDecl(); + + baseType = ObjT->getBaseType(); + } + return nullptr; } @@ -4653,6 +4709,31 @@ public: return getObjectType()->isObjCQualifiedClass(); } + /// Whether this type is specialized, meaning that it has type arguments. + bool isSpecialized() const { return getObjectType()->isSpecialized(); } + + /// Whether this type is specialized, meaning that it has type arguments. + bool isSpecializedAsWritten() const { + return getObjectType()->isSpecializedAsWritten(); + } + + /// Whether this type is unspecialized, meaning that is has no type arguments. + bool isUnspecialized() const { return getObjectType()->isUnspecialized(); } + + /// Determine whether this object type is "unspecialized" as + /// written, meaning that it has no type arguments. + bool isUnspecializedAsWritten() const { return !isSpecializedAsWritten(); } + + /// Retrieve the type arguments for this type. + ArrayRef<QualType> getTypeArgs() const { + return getObjectType()->getTypeArgs(); + } + + /// Retrieve the type arguments for this type. + ArrayRef<QualType> getTypeArgsAsWritten() const { + return getObjectType()->getTypeArgsAsWritten(); + } + /// An iterator over the qualifiers on the object type. Provided /// for convenience. This will always iterate over the full set of /// protocols on a type, not just those provided directly. diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index e29fa490328..ff2730ab15d 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -799,9 +799,11 @@ public: }; -struct ObjCProtocolListLocInfo { - SourceLocation LAngleLoc; - SourceLocation RAngleLoc; +struct ObjCObjectTypeLocInfo { + SourceLocation TypeArgsLAngleLoc; + SourceLocation TypeArgsRAngleLoc; + SourceLocation ProtocolLAngleLoc; + SourceLocation ProtocolRAngleLoc; bool HasBaseTypeAsWritten; }; @@ -813,25 +815,59 @@ struct ObjCProtocolListLocInfo { class ObjCObjectTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, ObjCObjectTypeLoc, ObjCObjectType, - ObjCProtocolListLocInfo> { - // SourceLocations are stored after Info, one for each Protocol. + ObjCObjectTypeLocInfo> { + // TypeSourceInfo*'s are stored after Info, one for each type argument. + TypeSourceInfo **getTypeArgLocArray() const { + return (TypeSourceInfo**)this->getExtraLocalData(); + } + + // SourceLocations are stored after the type argument information, one for + // each Protocol. SourceLocation *getProtocolLocArray() const { - return (SourceLocation*) this->getExtraLocalData(); + return (SourceLocation*)(getTypeArgLocArray() + getNumTypeArgs()); } public: - SourceLocation getLAngleLoc() const { - return this->getLocalData()->LAngleLoc; + SourceLocation getTypeArgsLAngleLoc() const { + return this->getLocalData()->TypeArgsLAngleLoc; } - void setLAngleLoc(SourceLocation Loc) { - this->getLocalData()->LAngleLoc = Loc; + void setTypeArgsLAngleLoc(SourceLocation Loc) { + this->getLocalData()->TypeArgsLAngleLoc = Loc; } - SourceLocation getRAngleLoc() const { - return this->getLocalData()->RAngleLoc; + SourceLocation getTypeArgsRAngleLoc() const { + return this->getLocalData()->TypeArgsRAngleLoc; } - void setRAngleLoc(SourceLocation Loc) { - this->getLocalData()->RAngleLoc = Loc; + void setTypeArgsRAngleLoc(SourceLocation Loc) { + this->getLocalData()->TypeArgsRAngleLoc = Loc; + } + + unsigned getNumTypeArgs() const { + return this->getTypePtr()->getTypeArgsAsWritten().size(); + } + + TypeSourceInfo *getTypeArgTInfo(unsigned i) const { + assert(i < getNumTypeArgs() && "Index is out of bounds!"); + return getTypeArgLocArray()[i]; + } + + void setTypeArgTInfo(unsigned i, TypeSourceInfo *TInfo) { + assert(i < getNumTypeArgs() && "Index is out of bounds!"); + getTypeArgLocArray()[i] = TInfo; + } + + SourceLocation getProtocolLAngleLoc() const { + return this->getLocalData()->ProtocolLAngleLoc; + } + void setProtocolLAngleLoc(SourceLocation Loc) { + this->getLocalData()->ProtocolLAngleLoc = Loc; + } + + SourceLocation getProtocolRAngleLoc() const { + return this->getLocalData()->ProtocolRAngleLoc; + } + void setProtocolRAngleLoc(SourceLocation Loc) { + this->getLocalData()->ProtocolRAngleLoc = Loc; } unsigned getNumProtocols() const { @@ -865,23 +901,26 @@ public: } SourceRange getLocalSourceRange() const { - return SourceRange(getLAngleLoc(), getRAngleLoc()); + SourceLocation start = getTypeArgsLAngleLoc(); + if (start.isInvalid()) + start = getProtocolLAngleLoc(); + SourceLocation end = getProtocolRAngleLoc(); + if (end.isInvalid()) + end = getTypeArgsRAngleLoc(); + return SourceRange(start, end); } - void initializeLocal(ASTContext &Context, SourceLocation Loc) { - setHasBaseTypeAsWritten(true); - setLAngleLoc(Loc); - setRAngleLoc(Loc); - for (unsigned i = 0, e = getNumProtocols(); i != e; ++i) - setProtocolLoc(i, Loc); - } + void initializeLocal(ASTContext &Context, SourceLocation Loc); unsigned getExtraLocalDataSize() const { - return this->getNumProtocols() * sizeof(SourceLocation); + return this->getNumTypeArgs() * sizeof(TypeSourceInfo *) + + this->getNumProtocols() * sizeof(SourceLocation); } unsigned getExtraLocalDataAlignment() const { - return llvm::alignOf<SourceLocation>(); + static_assert(alignof(ObjCObjectTypeLoc) >= alignof(TypeSourceInfo *), + "not enough alignment for tail-allocated data"); + return llvm::alignOf<TypeSourceInfo *>(); } QualType getInnerType() const { diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 05bce63835e..3a468d71f14 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1022,12 +1022,11 @@ 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">; +def err_objc_type_args_after_protocols : Error< + "protocol qualifiers must precede type arguments">; } } // end of Parser diagnostics diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 3722b512ccc..0f86ffc733a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7780,6 +7780,36 @@ def err_objc_parameterized_forward_class : Error< def err_objc_parameterized_forward_class_first : Error< "class %0 previously declared with type parameters">; +def err_objc_type_arg_missing_star : Error< + "type argument %0 must be a pointer (requires a '*')">; + +def err_objc_type_arg_missing : Error< + "no type or protocol named %0">; + +def err_objc_protocol_suggest : Error< + "no protocol named %0: did you mean %1?">; + +def err_objc_type_args_and_protocols : Error< + "angle brackets contain both a %select{type|protocol}0 (%1) and a " + "%select{protocol|type}0 (%2)">; + +def err_objc_type_args_non_class : Error< + "type arguments cannot be applied to non-class type %0">; + +def err_objc_type_args_non_parameterized_class : Error< + "type arguments cannot be applied to non-parameterized class %0">; + +def err_objc_type_args_specialized_class : Error< + "type arguments cannot be applied to already-specialized class type %0">; + +def err_objc_type_args_wrong_arity : Error< + "too %select{many|few}0 type arguments for class %1 (have %2, expected %3)">; } +def err_objc_type_arg_not_id_compatible : Error< + "type argument %0 is neither an Objective-C object nor a block type">; + +def err_objc_type_arg_does_not_match_bound : Error< + "type argument %0 does not satisy the bound (%1) of type parameter %2">; + } // end of sema component. diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 0da9d581570..ae241c23cb0 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1269,6 +1269,8 @@ private: SourceLocation &LAngleLoc, SourceLocation &EndProtoLoc); bool ParseObjCProtocolQualifiers(DeclSpec &DS); + void ParseObjCTypeArgsOrProtocolQualifiers(DeclSpec &DS, + bool warnOnIncompleteProtocols); void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, Decl *CDecl); DeclGroupPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc, diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index d375ec30378..f4eb69cc8e9 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -373,6 +373,14 @@ private: // Scope specifier for the type spec, if applicable. CXXScopeSpec TypeScope; + /// List of Objective-C type arguments, e.g., in \c NSArray<NSView *>. + ArrayRef<ParsedType> ObjCTypeArgs; + + /// Location of the '<' that starts a list of Objective-C type arguments. + SourceLocation ObjCTypeArgsLAngleLoc; + /// Location of the '>' that ends a list of Objective-C type arguments. + SourceLocation ObjCTypeArgsRAngleLoc; + // List of protocol qualifiers for objective-c classes. Used for // protocol-qualified interfaces "NString<foo>" and protocol-qualified id // "id<foo>". @@ -449,6 +457,7 @@ public: ObjCQualifiers(nullptr) { } ~DeclSpec() { + delete [] ObjCTypeArgs.data(); delete [] ProtocolQualifiers; delete [] ProtocolLocs; } @@ -751,6 +760,25 @@ public: Attrs.takeAllFrom(attrs); } + /// Determine whether the declaration specifiers contain Objective-C + /// type arguments. + bool hasObjCTypeArgs() const { return !ObjCTypeArgs.empty(); } + + ArrayRef<ParsedType> getObjCTypeArgs() const { return ObjCTypeArgs; } + SourceLocation getObjCTypeArgsLAngleLoc() const { + return ObjCTypeArgsLAngleLoc; + } + SourceLocation getObjCTypeArgsRAngleLoc() const { + return ObjCTypeArgsRAngleLoc; + } + SourceRange getObjCTypeArgsRange() const { + return SourceRange(ObjCTypeArgsLAngleLoc, ObjCTypeArgsRAngleLoc); + } + + void setObjCTypeArgs(SourceLocation lAngleLoc, + ArrayRef<ParsedType> args, + SourceLocation rAngleLoc); + typedef Decl * const *ProtocolQualifierListTy; ProtocolQualifierListTy getProtocolQualifiers() const { return ProtocolQualifiers; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index cd0eb26aba2..4cead93efe3 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7098,17 +7098,30 @@ public: SourceLocation rAngleLoc); void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList); - Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc, + Decl *ActOnStartClassInterface(Scope *S, + SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, IdentifierInfo *SuperName, SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange, Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); + + void ActOnSuperClassOfClassInterface(Scope *S, + SourceLocation AtInterfaceLoc, + ObjCInterfaceDecl *IDecl, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperName, + SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange); void ActOnTypedefedProtocols(SmallVectorImpl<Decl *> &ProtocolRefs, IdentifierInfo *SuperName, @@ -7174,6 +7187,19 @@ public: unsigned NumProtocols, SmallVectorImpl<Decl *> &Protocols); + /// Given a list of identifiers (and their locations), resolve the + /// names to either Objective-C protocol qualifiers or type + /// arguments, as appropriate. The result will be attached to the + /// given declaration specifiers. + void actOnObjCTypeArgsOrProtocolQualifiers( + Scope *S, + DeclSpec &DS, + SourceLocation lAngleLoc, + ArrayRef<IdentifierInfo *> identifiers, + ArrayRef<SourceLocation> identifierLocs, + SourceLocation rAngleLoc, + bool warnOnIncompleteProtocols); + /// Ensure attributes are consistent with type. /// \param [in, out] Attributes The attributes to check; they will /// be modified to be consistent with \p PropertyTy. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 61b7c5db8e1..c7a66d74897 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3618,45 +3618,85 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **Protocols, QualType ASTContext::getObjCObjectType(QualType BaseType, ObjCProtocolDecl * const *Protocols, unsigned NumProtocols) const { - // If the base type is an interface and there aren't any protocols - // to add, then the interface type will do just fine. - if (!NumProtocols && isa<ObjCInterfaceType>(BaseType)) - return BaseType; + return getObjCObjectType(BaseType, { }, + llvm::makeArrayRef(Protocols, NumProtocols)); +} + +QualType ASTContext::getObjCObjectType( + QualType baseType, + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols) const { + // If the base type is an interface and there aren't any protocols or + // type arguments to add, then the interface type will do just fine. + if (typeArgs.empty() && protocols.empty() && isa<ObjCInterfaceType>(baseType)) + return baseType; // Look in the folding set for an existing type. llvm::FoldingSetNodeID ID; - ObjCObjectTypeImpl::Profile(ID, BaseType, Protocols, NumProtocols); + ObjCObjectTypeImpl::Profile(ID, baseType, typeArgs, protocols); void *InsertPos = nullptr; if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(QT, 0); - // Build the canonical type, which has the canonical base type and - // a sorted-and-uniqued list of protocols. - QualType Canonical; - bool ProtocolsSorted = areSortedAndUniqued(Protocols, NumProtocols); - if (!ProtocolsSorted || !BaseType.isCanonical()) { - if (!ProtocolsSorted) { - SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols, - Protocols + NumProtocols); - unsigned UniqueCount = NumProtocols; - - SortAndUniqueProtocols(&Sorted[0], UniqueCount); - Canonical = getObjCObjectType(getCanonicalType(BaseType), - &Sorted[0], UniqueCount); + // Determine the type arguments to be used for canonicalization, + // which may be explicitly specified here or written on the base + // type. + ArrayRef<QualType> effectiveTypeArgs = typeArgs; + if (effectiveTypeArgs.empty()) { + if (auto baseObject = baseType->getAs<ObjCObjectType>()) + effectiveTypeArgs = baseObject->getTypeArgs(); + } + + // Build the canonical type, which has the canonical base type and a + // sorted-and-uniqued list of protocols and the type arguments + // canonicalized. + QualType canonical; + bool typeArgsAreCanonical = std::all_of(effectiveTypeArgs.begin(), + effectiveTypeArgs.end(), + [&](QualType type) { + return type.isCanonical(); + }); + bool protocolsSorted = areSortedAndUniqued(protocols.data(), + protocols.size()); + if (!typeArgsAreCanonical || !protocolsSorted || !baseType.isCanonical()) { + // Determine the canonical type arguments. + ArrayRef<QualType> canonTypeArgs; + SmallVector<QualType, 4> canonTypeArgsVec; + if (!typeArgsAreCanonical) { + canonTypeArgsVec.reserve(effectiveTypeArgs.size()); + for (auto typeArg : effectiveTypeArgs) + canonTypeArgsVec.push_back(getCanonicalType(typeArg)); + canonTypeArgs = canonTypeArgsVec; } else { - Canonical = getObjCObjectType(getCanonicalType(BaseType), - Protocols, NumProtocols); + canonTypeArgs = effectiveTypeArgs; } + ArrayRef<ObjCProtocolDecl *> canonProtocols; + SmallVector<ObjCProtocolDecl*, 8> canonProtocolsVec; + if (!protocolsSorted) { + canonProtocolsVec.insert(canonProtocolsVec.begin(), + protocols.begin(), + protocols.end()); + unsigned uniqueCount = protocols.size(); + SortAndUniqueProtocols(&canonProtocolsVec[0], uniqueCount); + canonProtocols = llvm::makeArrayRef(&canonProtocolsVec[0], uniqueCount); + } else { + canonProtocols = protocols; + } + + canonical = getObjCObjectType(getCanonicalType(baseType), canonTypeArgs, + canonProtocols); + // Regenerate InsertPos. ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos); } - unsigned Size = sizeof(ObjCObjectTypeImpl); - Size += NumProtocols * sizeof(ObjCProtocolDecl *); - void *Mem = Allocate(Size, TypeAlignment); + unsigned size = sizeof(ObjCObjectTypeImpl); + size += typeArgs.size() * sizeof(QualType); + size += protocols.size() * sizeof(ObjCProtocolDecl *); + void *mem = Allocate(size, TypeAlignment); ObjCObjectTypeImpl *T = - new (Mem) ObjCObjectTypeImpl(Canonical, BaseType, Protocols, NumProtocols); + new (mem) ObjCObjectTypeImpl(canonical, baseType, typeArgs, protocols); Types.push_back(T); ObjCObjectTypes.InsertNode(T, InsertPos); @@ -5921,7 +5961,7 @@ void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, TypedefDecl *ASTContext::getObjCIdDecl() const { if (!ObjCIdDecl) { - QualType T = getObjCObjectType(ObjCBuiltinIdTy, nullptr, 0); + QualType T = getObjCObjectType(ObjCBuiltinIdTy, { }, { }); T = getObjCObjectPointerType(T); ObjCIdDecl = buildImplicitTypedef(T, "id"); } @@ -5938,7 +5978,7 @@ TypedefDecl *ASTContext::getObjCSelDecl() const { TypedefDecl *ASTContext::getObjCClassDecl() const { if (!ObjCClassDecl) { - QualType T = getObjCObjectType(ObjCBuiltinClassTy, nullptr, 0); + QualType T = getObjCObjectType(ObjCBuiltinClassTy, { }, { }); T = getObjCObjectPointerType(T); ObjCClassDecl = buildImplicitTypedef(T, "Class"); } diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index 000588face9..d6de4548466 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -125,12 +125,22 @@ break; \ if (const PointerType *Ty = QT->getAs<PointerType>()) { QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(), ShouldAKA)); + } else if (const auto *Ty = QT->getAs<ObjCObjectPointerType>()) { + QT = Context.getObjCObjectPointerType(Desugar(Context, Ty->getPointeeType(), + ShouldAKA)); } else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) { QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(), ShouldAKA)); } else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) { QT = Context.getRValueReferenceType(Desugar(Context, Ty->getPointeeType(), ShouldAKA)); + } else if (const auto *Ty = QT->getAs<ObjCObjectType>()) { + if (Ty->getBaseType().getTypePtr() != Ty && !ShouldAKA) { + QualType BaseType = Desugar(Context, Ty->getBaseType(), ShouldAKA); + QT = Context.getObjCObjectType(BaseType, Ty->getTypeArgsAsWritten(), + llvm::makeArrayRef(Ty->qual_begin(), + Ty->getNumProtocols())); + } } return QC.apply(Context, QT); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 88cca6d5924..ff80ba1ce7e 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1844,6 +1844,16 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { if (ToBaseType.isNull()) return QualType(); + SmallVector<QualType, 4> TypeArgs; + for (auto TypeArg : T->getTypeArgs()) { + QualType ImportedTypeArg = Importer.Import(TypeArg); + if (ImportedTypeArg.isNull()) + return QualType(); + + TypeArgs.push_back(ImportedTypeArg); + } + + SmallVector<ObjCProtocolDecl *, 4> Protocols; for (auto *P : T->quals()) { ObjCProtocolDecl *Protocol @@ -1853,9 +1863,8 @@ QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { Protocols.push_back(Protocol); } - return Importer.getToContext().getObjCObjectType(ToBaseType, - Protocols.data(), - Protocols.size()); + return Importer.getToContext().getObjCObjectType(ToBaseType, TypeArgs, + Protocols); } QualType @@ -3694,13 +3703,11 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From, // If this class has a superclass, import it. if (From->getSuperClass()) { - ObjCInterfaceDecl *Super = cast_or_null<ObjCInterfaceDecl>( - Importer.Import(From->getSuperClass())); - if (!Super) + TypeSourceInfo *SuperTInfo = Importer.Import(From->getSuperClassTInfo()); + if (!SuperTInfo) return true; - - To->setSuperClass(Super); - To->setSuperClassLoc(Importer.Import(From->getSuperClassLoc())); + + To->setSuperClass(SuperTInfo); } // Import protocols @@ -5367,7 +5374,7 @@ TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) { return nullptr; return ToContext.getTrivialTypeSourceInfo(T, - FromTSI->getTypeLoc().getLocStart()); + Import(FromTSI->getTypeLoc().getLocStart())); } Decl *ASTImporter::GetAlreadyImportedOrNull(Decl *FromD) { diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 79054c7862f..a93c8f61336 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -259,6 +259,33 @@ ObjCTypeParamList *ObjCInterfaceDecl::getTypeParamList() const { return nullptr; } +ObjCInterfaceDecl *ObjCInterfaceDecl::getSuperClass() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return nullptr; + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + if (const ObjCObjectType *superType = getSuperClassType()) { + if (ObjCInterfaceDecl *superDecl = superType->getInterface()) { + if (ObjCInterfaceDecl *superDef = superDecl->getDefinition()) + return superDef; + + return superDecl; + } + } + + return nullptr; +} + +SourceLocation ObjCInterfaceDecl::getSuperClassLoc() const { + if (TypeSourceInfo *superTInfo = getSuperClassTInfo()) + return superTInfo->getTypeLoc().getLocStart(); + + return SourceLocation(); +} + /// 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. diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 541bd1ebdf8..48245f648bb 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -467,19 +467,56 @@ const RecordType *Type::getAsUnionType() const { } ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, - ObjCProtocolDecl * const *Protocols, - unsigned NumProtocols) + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols) : Type(ObjCObject, Canonical, false, false, false, false), BaseType(Base) { - ObjCObjectTypeBits.NumProtocols = NumProtocols; - assert(getNumProtocols() == NumProtocols && + ObjCObjectTypeBits.NumTypeArgs = typeArgs.size(); + assert(getTypeArgsAsWritten().size() == typeArgs.size() && + "bitfield overflow in type argument count"); + ObjCObjectTypeBits.NumProtocols = protocols.size(); + assert(getNumProtocols() == protocols.size() && "bitfield overflow in protocol count"); - if (NumProtocols) - memcpy(getProtocolStorage(), Protocols, - NumProtocols * sizeof(ObjCProtocolDecl*)); + if (!typeArgs.empty()) + memcpy(getTypeArgStorage(), typeArgs.data(), + typeArgs.size() * sizeof(QualType)); + if (!protocols.empty()) + memcpy(getProtocolStorage(), protocols.data(), + protocols.size() * sizeof(ObjCProtocolDecl*)); } +bool ObjCObjectType::isSpecialized() const { + // If we have type arguments written here, the type is specialized. + if (ObjCObjectTypeBits.NumTypeArgs > 0) + return true; + + if (!qual_empty()) { + // Otherwise, check whether the base type is specialized. + if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) + return objcObject->isSpecialized(); + } + + // Not specialized. + return false; +} + +ArrayRef<QualType> ObjCObjectType::getTypeArgs() const { + // We have type arguments written on this type. + if (isSpecializedAsWritten()) + return getTypeArgsAsWritten(); + + if (!qual_empty()) { + // Look at the base type, which might have type arguments. + if (auto objcObject = getBaseType()->getAs<ObjCObjectType>()) + return objcObject->getTypeArgs(); + } + + // No type arguments. + return { }; +} + + const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const { // There is no sugar for ObjCObjectType's, just return the canonical // type pointer if it is the right class. There is no typedef information to @@ -2076,15 +2113,20 @@ QualifierCollector::apply(const ASTContext &Context, const Type *T) const { void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID, QualType BaseType, - ObjCProtocolDecl * const *Protocols, - unsigned NumProtocols) { + ArrayRef<QualType> typeArgs, + ArrayRef<ObjCProtocolDecl *> protocols) { ID.AddPointer(BaseType.getAsOpaquePtr()); - for (unsigned i = 0; i != NumProtocols; i++) - ID.AddPointer(Protocols[i]); + ID.AddInteger(typeArgs.size()); + for (auto typeArg : typeArgs) + ID.AddPointer(typeArg.getAsOpaquePtr()); + ID.AddInteger(protocols.size()); + for (auto proto : protocols) + ID.AddPointer(proto); } void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getBaseType(), qual_begin(), getNumProtocols()); + Profile(ID, getBaseType(), getTypeArgs(), + llvm::makeArrayRef(qual_begin(), getNumProtocols())); } namespace { @@ -2495,6 +2537,39 @@ Optional<NullabilityKind> AttributedType::stripOuterNullability(QualType &T) { return None; } +bool Type::isBlockCompatibleObjCPointerType(ASTContext &ctx) const { + const ObjCObjectPointerType *objcPtr = getAs<ObjCObjectPointerType>(); + if (!objcPtr) + return false; + + if (objcPtr->isObjCIdType()) { + // id is always okay. + return true; + } + + // Blocks are NSObjects. + if (ObjCInterfaceDecl *iface = objcPtr->getInterfaceDecl()) { + if (iface->getIdentifier() != ctx.getNSObjectName()) + return false; + + // Continue to check qualifiers, below. + } else if (objcPtr->isObjCQualifiedIdType()) { + // Continue to check qualifiers, below. + } else { + return false; + } + + // Check protocol qualifiers. + for (ObjCProtocolDecl *proto : objcPtr->quals()) { + // Blocks conform to NSObject and NSCopying. + if (proto->getIdentifier() != ctx.getNSObjectName() && + proto->getIdentifier() != ctx.getNSCopyingName()) + return false; + } + + return true; +} + Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const { if (isObjCARCImplicitlyUnretainedType()) return Qualifiers::OCL_ExplicitNone; diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index c069eb06173..0d497aad8e4 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -312,6 +312,22 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) { return TL; } +void ObjCObjectTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + setHasBaseTypeAsWritten(true); + setTypeArgsLAngleLoc(Loc); + setTypeArgsRAngleLoc(Loc); + for (unsigned i = 0, e = getNumTypeArgs(); i != e; ++i) { + setTypeArgTInfo(i, + Context.getTrivialTypeSourceInfo( + getTypePtr()->getTypeArgsAsWritten()[i], Loc)); + } + setProtocolLAngleLoc(Loc); + setProtocolRAngleLoc(Loc); + for (unsigned i = 0, e = getNumProtocols(); i != e; ++i) + setProtocolLoc(i, Loc); +} + void TypeOfTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo> diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 9938170c321..ab63babf3f5 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1310,59 +1310,56 @@ void TypePrinter::printObjCInterfaceAfter(const ObjCInterfaceType *T, void TypePrinter::printObjCObjectBefore(const ObjCObjectType *T, raw_ostream &OS) { - if (T->qual_empty()) + if (T->qual_empty() && T->isUnspecializedAsWritten()) return printBefore(T->getBaseType(), OS); print(T->getBaseType(), OS, StringRef()); - OS << '<'; - bool isFirst = true; - for (const auto *I : T->quals()) { - if (isFirst) - isFirst = false; - else - OS << ','; - OS << I->getName(); + + if (T->isSpecializedAsWritten()) { + bool isFirst = true; + OS << '<'; + for (auto typeArg : T->getTypeArgsAsWritten()) { + if (isFirst) + isFirst = false; + else + OS << ","; + + print(typeArg, OS, StringRef()); + } + OS << '>'; } - OS << '>'; + + if (!T->qual_empty()) { + bool isFirst = true; + OS << '<'; + for (const auto *I : T->quals()) { + if (isFirst) + isFirst = false; + else + OS << ','; + OS << I->getName(); + } + OS << '>'; + } + spaceBeforePlaceHolder(OS); } void TypePrinter::printObjCObjectAfter(const ObjCObjectType *T, raw_ostream &OS) { - if (T->qual_empty()) + if (T->qual_empty() && T->isUnspecializedAsWritten()) return printAfter(T->getBaseType(), OS); } void TypePrinter::printObjCObjectPointerBefore(const ObjCObjectPointerType *T, raw_ostream &OS) { - T->getPointeeType().getLocalQualifiers().print(OS, Policy, - /*appendSpaceIfNonEmpty=*/true); - - assert(!T->isObjCSelType()); + printBefore(T->getPointeeType(), OS); - if (T->isObjCIdType() || T->isObjCQualifiedIdType()) - OS << "id"; - else if (T->isObjCClassType() || T->isObjCQualifiedClassType()) - OS << "Class"; - else - OS << T->getInterfaceDecl()->getName(); - - if (!T->qual_empty()) { - OS << '<'; - for (ObjCObjectPointerType::qual_iterator I = T->qual_begin(), - E = T->qual_end(); - I != E; ++I) { - OS << (*I)->getName(); - if (I+1 != E) - OS << ','; - } - OS << '>'; - } - + // If we need to print the pointer, print it now. if (!T->isObjCIdType() && !T->isObjCQualifiedIdType() && !T->isObjCClassType() && !T->isObjCQualifiedClassType()) { - OS << " *"; // Don't forget the implicit pointer. - } else { - spaceBeforePlaceHolder(OS); + if (HasEmptyPlaceHolder) + OS << ' '; + OS << '*'; } } void TypePrinter::printObjCObjectPointerAfter(const ObjCObjectPointerType *T, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index d843e801b63..fdd10522ee5 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2886,11 +2886,26 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); // The typename - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); + // Objective-C supports type arguments and protocol references + // following an Objective-C object pointer type. Handle either + // one of them. + if (Tok.is(tok::less) && getLangOpts().ObjC1) { + ParseObjCTypeArgsOrProtocolQualifiers( + DS, /*warnOnIncompleteProtocols=*/false); + + // An Objective-C object pointer followed by type arguments + // can then be followed again by a set of protocol references, e.g., + // \c NSArray<NSView><NSTextDelegate> + if (Tok.is(tok::less)) { + if (DS.getProtocolQualifiers()) { + Diag(Tok, diag::err_objc_type_args_after_protocols) + << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd()); + SkipUntil(tok::greater, tok::greatergreater); + } else { + ParseObjCProtocolQualifiers(DS); + } + } + } continue; } @@ -2997,11 +3012,26 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); // The identifier - // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' - // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an - // Objective-C interface. - if (Tok.is(tok::less) && getLangOpts().ObjC1) - ParseObjCProtocolQualifiers(DS); + // Objective-C supports type arguments and protocol references + // following an Objective-C object pointer type. Handle either + // one of them. + if (Tok.is(tok::less) && getLangOpts().ObjC1) { + ParseObjCTypeArgsOrProtocolQualifiers( + DS, /*warnOnIncompleteProtocols=*/false); + + // An Objective-C object pointer followed by type arguments + // can then be followed again by a set of protocol references, e.g., + // \c NSArray<NSView><NSTextDelegate> + if (Tok.is(tok::less)) { + if (DS.getProtocolQualifiers()) { + Diag(Tok, diag::err_objc_type_args_after_protocols) + << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd()); + SkipUntil(tok::greater, tok::greatergreater); + } else { + ParseObjCProtocolQualifiers(DS); + } + } + } // Need to support trailing type qualifiers (e.g. "id<p> const"). // If a type specifier follows, it will be diagnosed elsewhere. diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 3ef187af8d7..0e4574056b0 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -179,7 +179,7 @@ void Parser::CheckNestedObjCContexts(SourceLocation AtLoc) /// @end /// /// objc-superclass: -/// ':' identifier +/// ':' identifier objc-type-arguments[opt] /// /// objc-class-interface-attributes: /// __attribute__((visibility("default"))) @@ -293,6 +293,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, // Parse a class interface. IdentifierInfo *superClassId = nullptr; SourceLocation superClassLoc; + DeclSpec superClassDS(AttrFactory); if (Tok.is(tok::colon)) { // a super class is specified. ConsumeToken(); @@ -311,18 +312,12 @@ 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(); + + // Type arguments for the superclass or protocol conformances. + if (Tok.is(tok::less)) { + ParseObjCTypeArgsOrProtocolQualifiers(superClassDS, + /*warnOnIncompleteProtocols=*/true); + } } // Next, we need to check for any protocol references. @@ -338,6 +333,16 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, /*ForObjCContainer=*/true, &ProtocolIdents[0], ProtocolIdents.size(), ProtocolRefs); + } else if (auto protocols = superClassDS.getProtocolQualifiers()) { + // We already parsed the protocols named when we thought we had a + // type argument list (for a specialized superclass). Treat them + // as actual protocol references. + unsigned numProtocols = superClassDS.getNumProtocolQualifiers(); + ProtocolRefs.append(protocols, protocols + numProtocols); + ProtocolLocs.append(superClassDS.getProtocolLocs(), + superClassDS.getProtocolLocs() + numProtocols); + LAngleLoc = superClassDS.getProtocolLAngleLoc(); + EndProtoLoc = superClassDS.getLocEnd(); } else if (Tok.is(tok::less) && ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true, LAngleLoc, EndProtoLoc)) { @@ -348,8 +353,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc); Decl *ClsType = - Actions.ActOnStartClassInterface(AtLoc, nameId, nameLoc, typeParameterList, - superClassId, superClassLoc, + Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc, + typeParameterList, superClassId, + superClassLoc, + superClassDS.getObjCTypeArgs(), + superClassDS.getObjCTypeArgsRange(), ProtocolRefs.data(), ProtocolRefs.size(), ProtocolLocs.data(), EndProtoLoc, attrs.getList()); @@ -1554,8 +1562,7 @@ bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) { SmallVector<Decl *, 8> ProtocolDecl; SmallVector<SourceLocation, 8> ProtocolLocs; bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, - false, - LAngleLoc, EndProtoLoc); + false, LAngleLoc, EndProtoLoc); DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(), ProtocolLocs.data(), LAngleLoc); if (EndProtoLoc.isValid()) @@ -1563,6 +1570,111 @@ bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) { return Result; } +/// Parse Objective-C type arguments or protocol qualifiers. +/// +/// objc-type-arguments: +/// '<' type-name (',' type-name)* '>' +/// +void Parser::ParseObjCTypeArgsOrProtocolQualifiers( + DeclSpec &DS, + bool warnOnIncompleteProtocols) { + assert(Tok.is(tok::less) && "Not at the start of type args or protocols"); + SourceLocation lAngleLoc = ConsumeToken(); + + // Whether all of the elements we've parsed thus far are single + // identifiers, which might be types or might be protocols. + bool allSingleIdentifiers = true; + SmallVector<IdentifierInfo *, 4> identifiers; + SmallVector<SourceLocation, 4> identifierLocs; + + // Parse a list of comma-separated identifiers, bailing out if we + // see something different. + do { + // Parse a single identifier. + if (Tok.is(tok::identifier) && + (NextToken().is(tok::comma) || + NextToken().is(tok::greater) || + NextToken().is(tok::greatergreater))) { + identifiers.push_back(Tok.getIdentifierInfo()); + identifierLocs.push_back(ConsumeToken()); + continue; + } + + if (Tok.is(tok::code_completion)) { + // FIXME: Also include types here. + SmallVector<IdentifierLocPair, 4> identifierLocPairs; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + identifierLocPairs.push_back(IdentifierLocPair(identifiers[i], + identifierLocs[i])); + } + + Actions.CodeCompleteObjCProtocolReferences(identifierLocPairs.data(), + identifierLocPairs.size()); + cutOffParsing(); + return; + } + + allSingleIdentifiers = false; + break; + } while (TryConsumeToken(tok::comma)); + + // If we parsed an identifier list, semantic analysis sorts out + // whether it refers to protocols or to type arguments. + if (allSingleIdentifiers) { + // Parse the closing '>'. + SourceLocation rAngleLoc; + (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true, + /*ObjCGenericList=*/true); + + // Let Sema figure out what we parsed. + Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(), + DS, + lAngleLoc, + identifiers, + identifierLocs, + rAngleLoc, + warnOnIncompleteProtocols); + return; + } + + // We syntactically matched a type argument, so commit to parsing + // type arguments. + SmallVector<ParsedType, 4> typeArgs; + + // Convert the identifiers into type arguments. + bool invalid = false; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + ParsedType typeArg + = Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope()); + if (typeArg) { + typeArgs.push_back(typeArg); + } else { + invalid = true; + } + } + + // Continue parsing type-names. + do { + TypeResult typeArg = ParseTypeName(); + if (typeArg.isUsable()) { + typeArgs.push_back(typeArg.get()); + } else { + invalid = true; + } + } while (TryConsumeToken(tok::comma)); + + // Parse the closing '>'. + SourceLocation rAngleLoc; + (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true, + /*ObjCGenericList=*/true); + + if (invalid) + return; + + // Update the DeclSpec appropriately. + DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc); +} + void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc, BalancedDelimiterTracker &T, SmallVectorImpl<Decl *> &AllIvarDecls, diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 368cb934bba..3fdd902f07c 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1384,7 +1384,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case_typename: // In Objective-C, we might have a protocol-qualified type. if (getLangOpts().ObjC1 && NextToken().is(tok::less)) { - // Tentatively parse the + // Tentatively parse the protocol qualifiers. TentativeParsingAction PA(*this); ConsumeToken(); // The type token diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index d5c8871cac8..5c75536e94a 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -893,6 +893,7 @@ bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec, return false; } + bool DeclSpec::SetConceptSpec(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { if (Concept_specified) { @@ -905,6 +906,16 @@ bool DeclSpec::SetConceptSpec(SourceLocation Loc, const char *&PrevSpec, return false; } +void DeclSpec::setObjCTypeArgs(SourceLocation lAngleLoc, + ArrayRef<ParsedType> args, + SourceLocation rAngleLoc) { + ParsedType *argsCopy = new ParsedType[args.size()]; + memcpy(argsCopy, args.data(), args.size() * sizeof(ParsedType)); + ObjCTypeArgs = llvm::makeArrayRef(argsCopy, args.size()); + ObjCTypeArgsLAngleLoc = lAngleLoc; + ObjCTypeArgsRAngleLoc = rAngleLoc; +} + void DeclSpec::setProtocolQualifiers(Decl * const *Protos, unsigned NP, SourceLocation *ProtoLocs, diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 574a7c8857c..ac1e3923afa 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -464,6 +464,142 @@ static void diagnoseUseOfProtocols(Sema &TheSema, } } +void Sema:: +ActOnSuperClassOfClassInterface(Scope *S, + SourceLocation AtInterfaceLoc, + ObjCInterfaceDecl *IDecl, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperName, + SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange) { + // Check if a different kind of symbol declared in this scope. + NamedDecl *PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc, + LookupOrdinaryName); + + if (!PrevDecl) { + // Try to correct for a typo in the superclass name without correcting + // to the class we're defining. + if (TypoCorrection Corrected = CorrectTypo( + DeclarationNameInfo(SuperName, SuperLoc), + LookupOrdinaryName, TUScope, + NULL, llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl), + CTK_ErrorRecovery)) { + diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest) + << SuperName << ClassName); + PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>(); + } + } + + if (declaresSameEntity(PrevDecl, IDecl)) { + Diag(SuperLoc, diag::err_recursive_superclass) + << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); + IDecl->setEndOfDefinitionLoc(ClassLoc); + } else { + ObjCInterfaceDecl *SuperClassDecl = + dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); + QualType SuperClassType; + + // Diagnose classes that inherit from deprecated classes. + if (SuperClassDecl) { + (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); + SuperClassType = Context.getObjCInterfaceType(SuperClassDecl); + } + + if (PrevDecl && SuperClassDecl == 0) { + // The previous declaration was not a class decl. Check if we have a + // typedef. If we do, get the underlying class type. + if (const TypedefNameDecl *TDecl = + dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { + QualType T = TDecl->getUnderlyingType(); + if (T->isObjCObjectType()) { + if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { + SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); + SuperClassType = Context.getTypeDeclType(TDecl); + + // This handles the following case: + // @interface NewI @end + // typedef NewI DeprI __attribute__((deprecated("blah"))) + // @interface SI : DeprI /* warn here */ @end + (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), SuperLoc); + } + } + } + + // This handles the following case: + // + // typedef int SuperClass; + // @interface MyClass : SuperClass {} @end + // + if (!SuperClassDecl) { + Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + } + } + + if (!dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { + if (!SuperClassDecl) + Diag(SuperLoc, diag::err_undef_superclass) + << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); + else if (RequireCompleteType(SuperLoc, + SuperClassType, + diag::err_forward_superclass, + SuperClassDecl->getDeclName(), + ClassName, + SourceRange(AtInterfaceLoc, ClassLoc))) { + SuperClassDecl = 0; + SuperClassType = QualType(); + } + } + + if (SuperClassType.isNull()) { + assert(!SuperClassDecl && "Failed to set SuperClassType?"); + return; + } + + // Handle type arguments on the superclass. + TypeSourceInfo *SuperClassTInfo = nullptr; + if (!SuperTypeArgs.empty()) { + // Form declaration specifiers naming this superclass type with + // type arguments. + AttributeFactory attrFactory; + DeclSpec DS(attrFactory); + const char* prevSpec; // unused + unsigned diagID; // unused + TypeSourceInfo *parsedTSInfo + = Context.getTrivialTypeSourceInfo(SuperClassType, SuperLoc); + ParsedType parsedType = CreateParsedType(SuperClassType, parsedTSInfo); + + DS.SetTypeSpecType(DeclSpec::TST_typename, SuperLoc, prevSpec, diagID, + parsedType, Context.getPrintingPolicy()); + DS.SetRangeStart(SuperLoc); + DS.SetRangeEnd(SuperLoc); + DS.setObjCTypeArgs(SuperTypeArgsRange.getBegin(), + SuperTypeArgs, + SuperTypeArgsRange.getEnd()); + + // Form the declarator. + Declarator D(DS, Declarator::TypeNameContext); + + TypeResult fullSuperClassType = ActOnTypeName(S, D); + if (!fullSuperClassType.isUsable()) + return; + + SuperClassType = GetTypeFromParser(fullSuperClassType.get(), + &SuperClassTInfo); + } + + if (!SuperClassTInfo) { + SuperClassTInfo = Context.getTrivialTypeSourceInfo(SuperClassType, + SuperLoc); + } + + IDecl->setSuperClass(SuperClassTInfo); + IDecl->setEndOfDefinitionLoc(SuperClassTInfo->getTypeLoc().getLocEnd()); + } +} + DeclResult Sema::actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName, SourceLocation paramLoc, SourceLocation colonLoc, @@ -499,7 +635,7 @@ DeclResult Sema::actOnObjCTypeParam(Scope *S, IdentifierInfo *paramName, // Form the new type source information. typeBoundInfo = builder.getTypeSourceInfo(Context, typeBound); } else { - // Not a + // Not a valid type bound. Diag(typeBoundInfo->getTypeLoc().getBeginLoc(), diag::err_objc_type_param_bound_nonobject) << typeBound << paramName; @@ -669,10 +805,12 @@ static bool checkTypeParamListConsistency(Sema &S, } Decl *Sema:: -ActOnStartClassInterface(SourceLocation AtInterfaceLoc, +ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, IdentifierInfo *SuperName, SourceLocation SuperLoc, + ArrayRef<ParsedType> SuperTypeArgs, + SourceRange SuperTypeArgsRange, Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { @@ -767,84 +905,13 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IDecl->startDefinition(); if (SuperName) { - // Check if a different kind of symbol declared in this scope. - PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc, - LookupOrdinaryName); - - if (!PrevDecl) { - // Try to correct for a typo in the superclass name without correcting - // to the class we're defining. - if (TypoCorrection Corrected = - CorrectTypo(DeclarationNameInfo(SuperName, SuperLoc), - LookupOrdinaryName, TUScope, nullptr, - llvm::make_unique<ObjCInterfaceValidatorCCC>(IDecl), - CTK_ErrorRecovery)) { - diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest) - << SuperName << ClassName); - PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>(); - } - } - - if (declaresSameEntity(PrevDecl, IDecl)) { - Diag(SuperLoc, diag::err_recursive_superclass) - << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); - IDecl->setEndOfDefinitionLoc(ClassLoc); - } else { - ObjCInterfaceDecl *SuperClassDecl = - dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); - - // Diagnose availability in the context of the @interface. - ContextRAII SavedContext(*this, IDecl); - // Diagnose classes that inherit from deprecated classes. - if (SuperClassDecl) - (void)DiagnoseUseOfDecl(SuperClassDecl, SuperLoc); - - if (PrevDecl && !SuperClassDecl) { - // The previous declaration was not a class decl. Check if we have a - // typedef. If we do, get the underlying class type. - if (const TypedefNameDecl *TDecl = - dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { - QualType T = TDecl->getUnderlyingType(); - if (T->isObjCObjectType()) { - if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { - SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl); - // This handles the following case: - // @interface NewI @end - // typedef NewI DeprI __attribute__((deprecated("blah"))) - // @interface SI : DeprI /* warn here */ @end - (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), SuperLoc); - } - } - } - - // This handles the following case: - // - // typedef int SuperClass; - // @interface MyClass : SuperClass {} @end - // - if (!SuperClassDecl) { - Diag(SuperLoc, diag::err_redefinition_different_kind) << SuperName; - Diag(PrevDecl->getLocation(), diag::note_previous_definition); - } - } + // Diagnose availability in the context of the @interface. + ContextRAII SavedContext(*this, IDecl); - if (!dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { - if (!SuperClassDecl) - Diag(SuperLoc, diag::err_undef_superclass) - << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); - else if (RequireCompleteType(SuperLoc, - Context.getObjCInterfaceType(SuperClassDecl), - diag::err_forward_superclass, - SuperClassDecl->getDeclName(), - ClassName, - SourceRange(AtInterfaceLoc, ClassLoc))) { - SuperClassDecl = nullptr; - } - } - IDecl->setSuperClass(SuperClassDecl); - IDecl->setSuperClassLoc(SuperLoc); - IDecl->setEndOfDefinitionLoc(SuperLoc); - } + ActOnSuperClassOfClassInterface(S, AtInterfaceLoc, IDecl, + ClassName, ClassLoc, + SuperName, SuperLoc, SuperTypeArgs, + SuperTypeArgsRange); } else { // we have a root class. IDecl->setEndOfDefinitionLoc(ClassLoc); } @@ -1091,6 +1158,325 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer, } } +// Callback to only accept typo corrections that are either +// Objective-C protocols or valid Objective-C type arguments. +class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback { + ASTContext &Context; + Sema::LookupNameKind LookupKind; + public: + ObjCTypeArgOrProtocolValidatorCCC(ASTContext &context, + Sema::LookupNameKind lookupKind) + : Context(context), LookupKind(lookupKind) { } + + bool ValidateCandidate(const TypoCorrection &candidate) override { + // If we're allowed to find protocols and we have a protocol, accept it. + if (LookupKind != Sema::LookupOrdinaryName) { + if (candidate.getCorrectionDeclAs<ObjCProtocolDecl>()) + return true; + } + + // If we're allowed to find type names and we have one, accept it. + if (LookupKind != Sema::LookupObjCProtocolName) { + // If we have a type declaration, we might accept this result. + if (auto typeDecl = candidate.getCorrectionDeclAs<TypeDecl>()) { + // If we found a tag declaration outside of C++, skip it. This + // can happy because we look for any name when there is no + // bias to protocol or type names. + if (isa<RecordDecl>(typeDecl) && !Context.getLangOpts().CPlusPlus) + return false; + + // Make sure the type is something we would accept as a type + // argument. + auto type = Context.getTypeDeclType(typeDecl); + if (type->isObjCObjectPointerType() || + type->isBlockPointerType() || + type->isDependentType() || + type->isObjCObjectType()) + return true; + + return false; + } + + // If we have an Objective-C class type, accept it; there will + // be another fix to add the '*'. + if (candidate.getCorrectionDeclAs<ObjCInterfaceDecl>()) + return true; + + return false; + } + + return false; + } +}; + +void Sema::actOnObjCTypeArgsOrProtocolQualifiers( + Scope *S, + DeclSpec &DS, + SourceLocation lAngleLoc, + ArrayRef<IdentifierInfo *> identifiers, + ArrayRef<SourceLocation> identifierLocs, + SourceLocation rAngleLoc, + bool warnOnIncompleteProtocols) { + // Local function that updates the declaration specifiers with + // protocol information. + SmallVector<ObjCProtocolDecl *, 4> protocols; + unsigned numProtocolsResolved = 0; + auto resolvedAsProtocols = [&] { + assert(numProtocolsResolved == identifiers.size() && "Unresolved protocols"); + + for (unsigned i = 0, n = protocols.size(); i != n; ++i) { + ObjCProtocolDecl *&proto = protocols[i]; + // For an objc container, delay protocol reference checking until after we + // can set the objc decl as the availability context, otherwise check now. + if (!warnOnIncompleteProtocols) { + (void)DiagnoseUseOfDecl(proto, identifierLocs[i]); + } + + // If this is a forward protocol declaration, get its definition. + if (!proto->isThisDeclarationADefinition() && proto->getDefinition()) + proto = proto->getDefinition(); + + // If this is a forward declaration and we are supposed to warn in this + // case, do it. + // FIXME: Recover nicely in the hidden case. + ObjCProtocolDecl *forwardDecl = nullptr; + if (warnOnIncompleteProtocols && + NestedProtocolHasNoDefinition(proto, forwardDecl)) { + Diag(identifierLocs[i], diag::warn_undef_protocolref) + << proto->getDeclName(); + Diag(forwardDecl->getLocation(), diag::note_protocol_decl_undefined) + << forwardDecl; + } + } + + DS.setProtocolQualifiers((Decl * const *)(protocols.data()), + protocols.size(), + const_cast<SourceLocation *>(identifierLocs.data()), + lAngleLoc); + if (rAngleLoc.isValid()) + DS.SetRangeEnd(rAngleLoc); + }; + + // Attempt to resolve all of the identifiers as protocols. + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + ObjCProtocolDecl *proto = LookupProtocol(identifiers[i], identifierLocs[i]); + protocols.push_back(proto); + if (proto) + ++numProtocolsResolved; + } + + // If all of the names were protocols, these were protocol qualifiers. + if (numProtocolsResolved == identifiers.size()) + return resolvedAsProtocols(); + + // Attempt to resolve all of the identifiers as type names or + // Objective-C class names. The latter is technically ill-formed, + // but is probably something like \c NSArray<NSView *> missing the + // \c*. + typedef llvm::PointerUnion<TypeDecl *, ObjCInterfaceDecl *> TypeOrClassDecl; + SmallVector<TypeOrClassDecl, 4> typeDecls; + unsigned numTypeDeclsResolved = 0; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + NamedDecl *decl = LookupSingleName(S, identifiers[i], identifierLocs[i], + LookupOrdinaryName); + if (!decl) { + typeDecls.push_back(TypeOrClassDecl()); + continue; + } + + if (auto typeDecl = dyn_cast<TypeDecl>(decl)) { + typeDecls.push_back(typeDecl); + ++numTypeDeclsResolved; + continue; + } + + if (auto objcClass = dyn_cast<ObjCInterfaceDecl>(decl)) { + typeDecls.push_back(objcClass); + ++numTypeDeclsResolved; + continue; + } + + typeDecls.push_back(TypeOrClassDecl()); + } + + AttributeFactory attrFactory; + + // Local function that forms a reference to the given type or + // Objective-C class declaration. + auto resolveTypeReference = [&](TypeOrClassDecl typeDecl, SourceLocation loc) + -> TypeResult { + // Form declaration specifiers. They simply refer to the type. + DeclSpec DS(attrFactory); + const char* prevSpec; // unused + unsigned diagID; // unused + QualType type; + if (auto *actualTypeDecl = typeDecl.dyn_cast<TypeDecl *>()) + type = Context.getTypeDeclType(actualTypeDecl); + else + type = Context.getObjCInterfaceType(typeDecl.get<ObjCInterfaceDecl *>()); + TypeSourceInfo *parsedTSInfo = Context.getTrivialTypeSourceInfo(type, loc); + ParsedType parsedType = CreateParsedType(type, parsedTSInfo); + DS.SetTypeSpecType(DeclSpec::TST_typename, loc, prevSpec, diagID, + parsedType, Context.getPrintingPolicy()); + // Use the identifier location for the type source range. + DS.SetRangeStart(loc); + DS.SetRangeEnd(loc); + + // Form the declarator. + Declarator D(DS, Declarator::TypeNameContext); + + // If we have a typedef of an Objective-C class type that is missing a '*', + // add the '*'. + if (type->getAs<ObjCInterfaceType>()) { + SourceLocation starLoc = PP.getLocForEndOfToken(loc); + ParsedAttributes parsedAttrs(attrFactory); + D.AddTypeInfo(DeclaratorChunk::getPointer(/*typeQuals=*/0, starLoc, + SourceLocation(), + SourceLocation(), + SourceLocation(), + SourceLocation()), + parsedAttrs, + starLoc); + + // Diagnose the missing '*'. + Diag(loc, diag::err_objc_type_arg_missing_star) + << type + << FixItHint::CreateInsertion(starLoc, " *"); + } + + // Convert this to a type. + return ActOnTypeName(S, D); + }; + + // Local function that updates the declaration specifiers with + // type argument information. + auto resolvedAsTypeDecls = [&] { + assert(numTypeDeclsResolved == identifiers.size() && "Unresolved type decl"); + // Map type declarations to type arguments. + SmallVector<ParsedType, 4> typeArgs; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + // Map type reference to a type. + TypeResult type = resolveTypeReference(typeDecls[i], identifierLocs[i]); + if (!type.isUsable()) + return; + + typeArgs.push_back(type.get()); + } + + // Record the Objective-C type arguments. + DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc); + }; + + // If all of the identifiers can be resolved as type names or + // Objective-C class names, we have type arguments. + if (numTypeDeclsResolved == identifiers.size()) + return resolvedAsTypeDecls(); + + // Error recovery: some names weren't found, or we have a mix of + // type and protocol names. Go resolve all of the unresolved names + // and complain if we can't find a consistent answer. + LookupNameKind lookupKind = LookupAnyName; + for (unsigned i = 0, n = identifiers.size(); i != n; ++i) { + // If we already have a protocol or type. Check whether it is the + // right thing. + if (protocols[i] || typeDecls[i]) { + // If we haven't figured out whether we want types or protocols + // yet, try to figure it out from this name. + if (lookupKind == LookupAnyName) { + // If this name refers to both a protocol and a type (e.g., \c + // NSObject), don't conclude anything yet. + if (protocols[i] && typeDecls[i]) + continue; + + // Otherwise, let this name decide whether we'll be correcting + // toward types or protocols. + lookupKind = protocols[i] ? LookupObjCProtocolName + : LookupOrdinaryName; + continue; + } + + // If we want protocols and we have a protocol, there's nothing + // more to do. + if (lookupKind == LookupObjCProtocolName && protocols[i]) + continue; + + // If we want types and we have a type declaration, there's + // nothing more to do. + if (lookupKind == LookupOrdinaryName && typeDecls[i]) + continue; + + // We have a conflict: some names refer to protocols and others + // refer to types. + Diag(identifierLocs[i], diag::err_objc_type_args_and_protocols) + << (protocols[i] != nullptr) + << identifiers[i] + << identifiers[0] + << SourceRange(identifierLocs[0]); + + return; + } + + // Perform typo correction on the name. + TypoCorrection corrected = CorrectTypo( + DeclarationNameInfo(identifiers[i], identifierLocs[i]), lookupKind, S, + nullptr, + llvm::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(Context, + lookupKind), + CTK_ErrorRecovery); + if (corrected) { + // Did we find a protocol? + if (auto proto = corrected.getCorrectionDeclAs<ObjCProtocolDecl>()) { + diagnoseTypo(corrected, + PDiag(diag::err_undeclared_protocol_suggest) + << identifiers[i]); + lookupKind = LookupObjCProtocolName; + protocols[i] = proto; + ++numProtocolsResolved; + continue; + } + + // Did we find a type? + if (auto typeDecl = corrected.getCorrectionDeclAs<TypeDecl>()) { + diagnoseTypo(corrected, + PDiag(diag::err_unknown_typename_suggest) + << identifiers[i]); + lookupKind = LookupOrdinaryName; + typeDecls[i] = typeDecl; + ++numTypeDeclsResolved; + continue; + } + + // Did we find an Objective-C class? + if (auto objcClass = corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) { + diagnoseTypo(corrected, + PDiag(diag::err_unknown_type_or_class_name_suggest) + << identifiers[i] << true); + lookupKind = LookupOrdinaryName; + typeDecls[i] = objcClass; + ++numTypeDeclsResolved; + continue; + } + } + + // We couldn't find anything. + Diag(identifierLocs[i], + (lookupKind == LookupAnyName ? diag::err_objc_type_arg_missing + : lookupKind == LookupObjCProtocolName ? diag::err_undeclared_protocol + : diag::err_unknown_typename)) + << identifiers[i]; + return; + } + + // If all of the names were (corrected to) protocols, these were + // protocol qualifiers. + if (numProtocolsResolved == identifiers.size()) + return resolvedAsProtocols(); + + // Otherwise, all of the names were (corrected to) types. + assert(numTypeDeclsResolved == identifiers.size() && "Not all types?"); + return resolvedAsTypeDecls(); +} + /// DiagnoseClassExtensionDupMethods - Check for duplicate declaration of /// a class method in its extension. /// @@ -1374,8 +1760,9 @@ Decl *Sema::ActOnStartClassImplementation( true); IDecl->startDefinition(); if (SDecl) { - IDecl->setSuperClass(SDecl); - IDecl->setSuperClassLoc(SuperClassLoc); + IDecl->setSuperClass(Context.getTrivialTypeSourceInfo( + Context.getObjCInterfaceType(SDecl), + SuperClassLoc)); IDecl->setEndOfDefinitionLoc(SuperClassLoc); } else { IDecl->setEndOfDefinitionLoc(ClassLoc); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 01a4d488057..c6b53d03890 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5826,36 +5826,6 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, return ResultTy; } -/// \brief Returns true if QT is quelified-id and implements 'NSObject' and/or -/// 'NSCopying' protocols (and nothing else); or QT is an NSObject and optionally -/// implements 'NSObject' and/or NSCopying' protocols (and nothing else). -static bool isObjCPtrBlockCompatible(Sema &S, ASTContext &C, QualType QT) { - if (QT->isObjCIdType()) - return true; - - const ObjCObjectPointerType *OPT = QT->getAs<ObjCObjectPointerType>(); - if (!OPT) - return false; - - if (ObjCInterfaceDecl *ID = OPT->getInterfaceDecl()) - if (ID->getIdentifier() != &C.Idents.get("NSObject")) - return false; - - ObjCProtocolDecl* PNSCopying = - S.LookupProtocol(&C.Idents.get("NSCopying"), SourceLocation()); - ObjCProtocolDecl* PNSObject = - S.LookupProtocol(&C.Idents.get("NSObject"), SourceLocation()); - - for (auto *Proto : OPT->quals()) { - if ((PNSCopying && declaresSameEntity(Proto, PNSCopying)) || - (PNSObject && declaresSameEntity(Proto, PNSObject))) - ; - else - return false; - } - return true; -} - /// \brief Return the resulting type when the operands are both block pointers. static QualType checkConditionalBlockPointerCompatibility(Sema &S, ExprResult &LHS, @@ -7008,8 +6978,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, } // Only under strict condition T^ is compatible with an Objective-C pointer. - if (RHSType->isBlockPointerType() && - isObjCPtrBlockCompatible(*this, Context, LHSType)) { + if (RHSType->isBlockPointerType() && + LHSType->isBlockCompatibleObjCPointerType(Context)) { maybeExtendBlockObject(*this, RHS); Kind = CK_BlockPointerToObjCPointerCast; return Compatible; diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 0e1751a503b..7280f588c8b 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -959,8 +959,10 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) { ObjCProtocolDecl *PQ[] = {NSCopyingPDecl}; QIDNSCopying = - Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl**) PQ,1); + Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { }, + llvm::makeArrayRef( + (ObjCProtocolDecl**) PQ, + 1)); QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying); } } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 8d76f692025..9170ac760d4 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -738,6 +738,160 @@ static void diagnoseAndRemoveTypeQualifiers(Sema &S, const DeclSpec &DS, } } +/// Apply Objective-C type arguments to the given type. +static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, + ArrayRef<ParsedType> typeArgs, + SourceRange typeArgsRange) { + // We can only apply type arguments to an Objective-C class type. + const auto *objcObjectType = type->getAs<ObjCObjectType>(); + if (!objcObjectType || !objcObjectType->getInterface()) { + S.Diag(loc, diag::err_objc_type_args_non_class) + << type + << typeArgsRange; + return type; + } + + // The class type must be parameterized. + ObjCInterfaceDecl *objcClass = objcObjectType->getInterface(); + ObjCTypeParamList *typeParams = objcClass->getTypeParamList(); + if (!typeParams) { + S.Diag(loc, diag::err_objc_type_args_non_parameterized_class) + << objcClass->getDeclName() + << FixItHint::CreateRemoval(typeArgsRange); + return type; + } + + // The type must not already be specialized. + if (objcObjectType->isSpecialized()) { + S.Diag(loc, diag::err_objc_type_args_specialized_class) + << type + << FixItHint::CreateRemoval(typeArgsRange); + return type; + } + + // Make sure that we have the right number of type arguments. + if (typeArgs.size() != typeParams->size()) { + S.Diag(loc, diag::err_objc_type_args_wrong_arity) + << (typeArgs.size() < typeParams->size()) + << objcClass->getDeclName() + << (unsigned)typeArgs.size() + << (unsigned)typeParams->size(); + S.Diag(objcClass->getLocation(), diag::note_previous_decl) + << objcClass; + return type; + } + + // Check the type arguments. + SmallVector<QualType, 4> finalTypeArgs; + for (unsigned i = 0, n = typeArgs.size(); i != n; ++i) { + TypeSourceInfo *typeArgInfo = nullptr; + QualType typeArg = S.GetTypeFromParser(typeArgs[i], &typeArgInfo); + finalTypeArgs.push_back(typeArg); + + // Objective-C object pointer types must be substitutable for the bounds. + if (const auto *typeArgObjC = typeArg->getAs<ObjCObjectPointerType>()) { + // Retrieve the bound. + ObjCTypeParamDecl *typeParam = typeParams->begin()[i]; + QualType bound = typeParam->getUnderlyingType(); + const auto *boundObjC = bound->getAs<ObjCObjectPointerType>(); + + // Determine whether the type argument is substitutable for the bound. + if (typeArgObjC->isObjCIdType()) { + // When the type argument is 'id', the only acceptable type + // parameter bound is 'id'. + if (boundObjC->isObjCIdType()) + continue; + } else if (S.Context.canAssignObjCInterfaces(boundObjC, typeArgObjC)) { + // Otherwise, we follow the assignability rules. + continue; + } + + // Diagnose the mismatch. + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), + diag::err_objc_type_arg_does_not_match_bound) + << typeArg << bound << typeParam->getDeclName(); + S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here) + << typeParam->getDeclName(); + + return type; + } + + // Block pointer types are permitted for unqualified 'id' bounds. + if (typeArg->isBlockPointerType()) { + // Retrieve the bound. + ObjCTypeParamDecl *typeParam = typeParams->begin()[i]; + QualType bound = typeParam->getUnderlyingType(); + if (bound->isBlockCompatibleObjCPointerType(S.Context)) + continue; + + // Diagnose the mismatch. + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), + diag::err_objc_type_arg_does_not_match_bound) + << typeArg << bound << typeParam->getDeclName(); + S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here) + << typeParam->getDeclName(); + + return type; + } + + // Dependent types will be checked at instantiation time. + if (typeArg->isDependentType()) { + continue; + } + + // Diagnose non-id-compatible type arguments. + S.Diag(typeArgInfo->getTypeLoc().getLocStart(), + diag::err_objc_type_arg_not_id_compatible) + << typeArg + << typeArgInfo->getTypeLoc().getSourceRange(); + return type; + } + + // Success. Form the specialized type. + return S.Context.getObjCObjectType(type, finalTypeArgs, { }); +} + +/// Apply Objective-C protocol qualifiers to the given type. +static QualType applyObjCProtocolQualifiers( + Sema &S, SourceLocation loc, SourceRange range, QualType type, + ArrayRef<ObjCProtocolDecl *> protocols, + const SourceLocation *protocolLocs) { + ASTContext &ctx = S.Context; + if (const ObjCObjectType *objT = dyn_cast<ObjCObjectType>(type.getTypePtr())){ + // FIXME: Check for protocols to which the class type is already + // known to conform. + + return ctx.getObjCObjectType(objT->getBaseType(), + objT->getTypeArgsAsWritten(), + protocols); + } + + if (type->isObjCObjectType()) { + // Silently overwrite any existing protocol qualifiers. + // TODO: determine whether that's the right thing to do. + + // FIXME: Check for protocols to which the class type is already + // known to conform. + return ctx.getObjCObjectType(type, { }, protocols); + } + + // id<protocol-list> + if (type->isObjCIdType()) { + type = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, protocols); + return ctx.getObjCObjectPointerType(type); + } + + // Class<protocol-list> + if (type->isObjCClassType()) { + type = ctx.getObjCObjectType(ctx.ObjCBuiltinClassTy, { }, protocols); + return ctx.getObjCObjectPointerType(type); + } + + S.Diag(loc, diag::err_invalid_protocol_qualifiers) + << range; + return type; +} + /// \brief Convert the specified declspec to the appropriate type /// object. /// \param state Specifies the declarator containing the declaration specifier @@ -803,9 +957,10 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { case DeclSpec::TST_unspecified: // "<proto1,proto2>" is an objc qualified ID with a missing id. if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { - Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl*const*)PQ, - DS.getNumProtocolQualifiers()); + Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { }, + llvm::makeArrayRef( + (ObjCProtocolDecl*const*)PQ, + DS.getNumProtocolQualifiers())); Result = Context.getObjCObjectPointerType(Result); break; } @@ -967,37 +1122,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); Result = S.GetTypeFromParser(DS.getRepAsType()); - if (Result.isNull()) + if (Result.isNull()) { declarator.setInvalidType(true); - else if (DeclSpec::ProtocolQualifierListTy PQ - = DS.getProtocolQualifiers()) { - if (const ObjCObjectType *ObjT = Result->getAs<ObjCObjectType>()) { - // Silently drop any existing protocol qualifiers. - // TODO: determine whether that's the right thing to do. - if (ObjT->getNumProtocols()) - Result = ObjT->getBaseType(); - - if (DS.getNumProtocolQualifiers()) - Result = Context.getObjCObjectType(Result, - (ObjCProtocolDecl*const*) PQ, - DS.getNumProtocolQualifiers()); - } else if (Result->isObjCIdType()) { - // id<protocol-list> - Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl*const*) PQ, - DS.getNumProtocolQualifiers()); - Result = Context.getObjCObjectPointerType(Result); - } else if (Result->isObjCClassType()) { - // Class<protocol-list> - Result = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, - (ObjCProtocolDecl*const*) PQ, - DS.getNumProtocolQualifiers()); - Result = Context.getObjCObjectPointerType(Result); - } else { - S.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) - << DS.getSourceRange(); - declarator.setInvalidType(true); - } } else if (S.getLangOpts().OpenCL) { if (const AtomicType *AT = Result->getAs<AtomicType>()) { const BuiltinType *BT = AT->getValueType()->getAs<BuiltinType>(); @@ -1022,6 +1148,21 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { declarator.setInvalidType(true); } } + } else { + // Apply Objective-C type arguments. + if (DS.hasObjCTypeArgs()) { + Result = applyObjCTypeArgs(S, DeclLoc, Result, DS.getObjCTypeArgs(), + DS.getObjCTypeArgsRange()); + } + + // Apply Objective-C protocol qualifiers. + if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { + Result = applyObjCProtocolQualifiers( + S, DeclLoc, DS.getSourceRange(), Result, + llvm::makeArrayRef((ObjCProtocolDecl * const *)PQ, + DS.getNumProtocolQualifiers()), + DS.getProtocolLocs()); + } } // TypeQuals handled by caller. @@ -4138,18 +4279,33 @@ namespace { Visit(TL.getBaseLoc()); } + // Type arguments. + if (TL.getNumTypeArgs() > 0) { + assert(TL.getNumTypeArgs() == DS.getObjCTypeArgs().size()); + TL.setTypeArgsLAngleLoc(DS.getObjCTypeArgsLAngleLoc()); + TL.setTypeArgsRAngleLoc(DS.getObjCTypeArgsRAngleLoc()); + for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) { + TypeSourceInfo *typeArgInfo = nullptr; + (void)Sema::GetTypeFromParser(DS.getObjCTypeArgs()[i], &typeArgInfo); + TL.setTypeArgTInfo(i, typeArgInfo); + } + } else { + TL.setTypeArgsLAngleLoc(SourceLocation()); + TL.setTypeArgsRAngleLoc(SourceLocation()); + } + // Protocol qualifiers. if (DS.getProtocolQualifiers()) { assert(TL.getNumProtocols() > 0); assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers()); - TL.setLAngleLoc(DS.getProtocolLAngleLoc()); - TL.setRAngleLoc(DS.getSourceRange().getEnd()); + TL.setProtocolLAngleLoc(DS.getProtocolLAngleLoc()); + TL.setProtocolRAngleLoc(DS.getSourceRange().getEnd()); for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i) TL.setProtocolLoc(i, DS.getProtocolLocs()[i]); } else { assert(TL.getNumProtocols() == 0); - TL.setLAngleLoc(SourceLocation()); - TL.setRAngleLoc(SourceLocation()); + TL.setProtocolLAngleLoc(SourceLocation()); + TL.setProtocolRAngleLoc(SourceLocation()); } } void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 48a898cb30d..89464c443e8 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -5263,11 +5263,15 @@ QualType ASTReader::readTypeRecord(unsigned Index) { case TYPE_OBJC_OBJECT: { unsigned Idx = 0; QualType Base = readType(*Loc.F, Record, Idx); + unsigned NumTypeArgs = Record[Idx++]; + SmallVector<QualType, 4> TypeArgs; + for (unsigned I = 0; I != NumTypeArgs; ++I) + TypeArgs.push_back(readType(*Loc.F, Record, Idx)); unsigned NumProtos = Record[Idx++]; SmallVector<ObjCProtocolDecl*, 4> Protos; for (unsigned I = 0; I != NumProtos; ++I) Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx)); - return Context.getObjCObjectType(Base, Protos.data(), NumProtos); + return Context.getObjCObjectType(Base, TypeArgs, Protos); } case TYPE_OBJC_OBJECT_POINTER: { @@ -5646,8 +5650,12 @@ void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { } void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { TL.setHasBaseTypeAsWritten(Record[Idx++]); - TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); - TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setTypeArgsLAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setTypeArgsRAngleLoc(ReadSourceLocation(Record, Idx)); + for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) + TL.setTypeArgTInfo(i, Reader.GetTypeSourceInfo(F, Record, Idx)); + TL.setProtocolLAngleLoc(ReadSourceLocation(Record, Idx)); + TL.setProtocolRAngleLoc(ReadSourceLocation(Record, Idx)); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) TL.setProtocolLoc(i, ReadSourceLocation(Record, Idx)); } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index e01ea2b8a59..69d173d3c85 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -953,8 +953,7 @@ void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { ObjCInterfaceDecl::DefinitionData &Data = ID->data(); // Read the superclass. - Data.SuperClass = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx); - Data.SuperClassLoc = ReadSourceLocation(Record, Idx); + Data.SuperClassTInfo = GetTypeSourceInfo(Record, Idx); Data.EndLoc = ReadSourceLocation(Record, Idx); Data.HasDesignatedInitializers = Record[Idx++]; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 0d15b17c7ce..dd56de38419 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -421,6 +421,9 @@ void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) { Writer.AddTypeRef(T->getBaseType(), Record); + Record.push_back(T->getTypeArgs().size()); + for (auto TypeArg : T->getTypeArgs()) + Writer.AddTypeRef(TypeArg, Record); Record.push_back(T->getNumProtocols()); for (const auto *I : T->quals()) Writer.AddDeclRef(I, Record); @@ -648,8 +651,12 @@ void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { } void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { Record.push_back(TL.hasBaseTypeAsWritten()); - Writer.AddSourceLocation(TL.getLAngleLoc(), Record); - Writer.AddSourceLocation(TL.getRAngleLoc(), Record); + Writer.AddSourceLocation(TL.getTypeArgsLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getTypeArgsRAngleLoc(), Record); + for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) + Writer.AddTypeSourceInfo(TL.getTypeArgTInfo(i), Record); + Writer.AddSourceLocation(TL.getProtocolLAngleLoc(), Record); + Writer.AddSourceLocation(TL.getProtocolRAngleLoc(), Record); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) Writer.AddSourceLocation(TL.getProtocolLoc(i), Record); } diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 5e9151eed5e..00f8daa676e 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -604,8 +604,7 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { // Write the DefinitionData ObjCInterfaceDecl::DefinitionData &Data = D->data(); - Writer.AddDeclRef(D->getSuperClass(), Record); - Writer.AddSourceLocation(D->getSuperClassLoc(), Record); + Writer.AddTypeSourceInfo(D->getSuperClassTInfo(), Record); Writer.AddSourceLocation(D->getEndOfDefinitionLoc(), Record); Record.push_back(Data.HasDesignatedInitializers); diff --git a/clang/test/Index/annotate-parameterized-classes.m b/clang/test/Index/annotate-parameterized-classes.m new file mode 100644 index 00000000000..6a53fed4bd7 --- /dev/null +++ b/clang/test/Index/annotate-parameterized-classes.m @@ -0,0 +1,42 @@ +@protocol NSObject +@end + +@interface NSObject +@end + +@interface A<T : id, U : NSObject *> : NSObject +@end + +@interface A<T : id, U : NSObject *> (Cat1) +@end + +typedef A<id<NSObject>, NSObject *> ASpecialization1; + +@interface B<T : id, U : NSObject *> : A<T, U> +@end + +// RUN: c-index-test -test-annotate-tokens=%s:7:1:9:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-INTERFACE-DECL %s +// CHECK-INTERFACE-DECL: Identifier: "T" [7:14 - 7:15] TemplateTypeParameter=T:7:14 +// FIXME: Should be a type reference +// CHECK-INTERFACE-DECL: Identifier: "id" [7:18 - 7:20] TemplateTypeParameter=T:7:14 +// CHECK-INTERFACE-DECL: Identifier: "U" [7:22 - 7:23] TemplateTypeParameter=U:7:22 +// FIXME: Should be a class reference +// CHECK-INTERFACE-DECL: Identifier: "NSObject" [7:26 - 7:34] TemplateTypeParameter=U:7:22 + +// RUN: c-index-test -test-annotate-tokens=%s:10:1:12:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-CATEGORY-DECL %s +// CHECK-CATEGORY-DECL: Identifier: "T" [10:14 - 10:15] TemplateTypeParameter=T:10:14 +// FIXME: Should be a type reference +// CHECK-CATEGORY-DECL: Identifier: "id" [10:18 - 10:20] TemplateTypeParameter=T:10:14 +// CHECK-CATEGORY-DECL: Identifier: "U" [10:22 - 10:23] TemplateTypeParameter=U:10:22 +// FIXME: Should be a class reference +// CHECK-CATEGORY-DECL: Identifier: "NSObject" [10:26 - 10:34] TemplateTypeParameter=U:10:22 + +// RUN: c-index-test -test-annotate-tokens=%s:13:1:14:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-SPECIALIZATION %s +// CHECK-SPECIALIZATION: Identifier: "id" [13:11 - 13:13] TypeRef=id:0:0 +// CHECK-SPECIALIZATION: Identifier: "NSObject" [13:14 - 13:22] ObjCProtocolRef=NSObject:1:11 +// CHECK-SPECIALIZATION: Identifier: "NSObject" [13:25 - 13:33] ObjCClassRef=NSObject:4:12 + +// RUN: c-index-test -test-annotate-tokens=%s:15:1:16:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-SUPER %s +// CHECK-SUPER: Identifier: "A" [15:40 - 15:41] ObjCSuperClassRef=A:7:12 +// CHECK-SUPER: Identifier: "T" [15:42 - 15:43] TypeRef=T:15:14 +// CHECK-SUPER: Identifier: "U" [15:45 - 15:46] TypeRef=U:15:22 diff --git a/clang/test/Index/complete-method-decls.m b/clang/test/Index/complete-method-decls.m index 0e3780ba3d5..a74020a5ed8 100644 --- a/clang/test/Index/complete-method-decls.m +++ b/clang/test/Index/complete-method-decls.m @@ -208,8 +208,7 @@ typedef A *MyObjectRef; // RUN: c-index-test -code-completion-at=%s:85:2 %s | FileCheck -check-prefix=CHECK-CLASSTY %s // CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text Class<P1>}{RightParen )}{TypedText meth} -// FIXME: It should be "MyObject <P1> *"" -// CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text A<P1> *}{RightParen )}{TypedText meth2} +// CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text MyObject<P1> *}{RightParen )}{TypedText meth2} // CHECK-CLASSTY: ObjCInstanceMethodDecl:{LeftParen (}{Text MyObjectRef}{RightParen )}{TypedText meth3} // RUN: c-index-test -code-completion-at=%s:93:2 %s | FileCheck -check-prefix=CHECK-NULLABILITY %s diff --git a/clang/test/PCH/objc_parameterized_classes.m b/clang/test/PCH/objc_parameterized_classes.m index a541c33fbf2..f4fd0926be3 100644 --- a/clang/test/PCH/objc_parameterized_classes.m +++ b/clang/test/PCH/objc_parameterized_classes.m @@ -19,6 +19,8 @@ __attribute__((objc_root_class)) @interface PC1<T, U : NSObject *> (Cat1) @end +typedef PC1<id, NSObject *> PC1Specialization1; + #else @interface PC1<T : NSObject *, // expected-error{{type bound 'NSObject *' for type parameter 'T' conflicts with implicit bound 'id}} @@ -27,4 +29,6 @@ __attribute__((objc_root_class)) // expected-note@15{{type parameter 'U' declared here}} @end +typedef PC1Specialization1<id, NSObject *> PC1Specialization2; // expected-error{{type arguments cannot be applied to already-specialized class type 'PC1Specialization1' (aka 'PC1<id,NSObject *>')}} + #endif diff --git a/clang/test/Parser/objcxx11-protocol-in-template.mm b/clang/test/Parser/objcxx11-protocol-in-template.mm index 8cb499396d4..c5c3b6c75a4 100644 --- a/clang/test/Parser/objcxx11-protocol-in-template.mm +++ b/clang/test/Parser/objcxx11-protocol-in-template.mm @@ -4,12 +4,7 @@ template<class T> class vector {}; @protocol P @end -#if __cplusplus >= 201103L - // expected-no-diagnostics -#else - // expected-error@14{{a space is required between consecutive right angle brackets}} - // expected-error@15{{a space is required between consecutive right angle brackets}} -#endif +// expected-no-diagnostics vector<id<P>> v; vector<vector<id<P>>> v2; diff --git a/clang/test/SemaObjC/interface-1.m b/clang/test/SemaObjC/interface-1.m index 79fbad8ba4b..0e47fa08bd7 100644 --- a/clang/test/SemaObjC/interface-1.m +++ b/clang/test/SemaObjC/interface-1.m @@ -3,7 +3,7 @@ @interface NSWhatever : NSObject // expected-error {{cannot find interface declaration for 'NSObject'}} -<NSCopying> // expected-error {{cannot find protocol declaration for 'NSCopying'}} +<NSCopying> // expected-error {{no type or protocol named 'NSCopying'}} @end diff --git a/clang/test/SemaObjC/parameterized_classes.m b/clang/test/SemaObjC/parameterized_classes.m index e6eae442142..bf81ad9a078 100644 --- a/clang/test/SemaObjC/parameterized_classes.m +++ b/clang/test/SemaObjC/parameterized_classes.m @@ -1,13 +1,16 @@ -// RUN: %clang_cc1 %s -verify +// RUN: %clang_cc1 -fblocks %s -verify -@protocol NSObject +@protocol NSObject // expected-note{{'NSObject' declared here}} +@end + +@protocol NSCopying // expected-note{{'NSCopying' declared here}} @end __attribute__((objc_root_class)) @interface NSObject <NSObject> // expected-note{{'NSObject' defined here}} @end -@interface NSString : NSObject +@interface NSString : NSObject <NSCopying> @end // -------------------------------------------------------------------------- @@ -15,13 +18,14 @@ __attribute__((objc_root_class)) // -------------------------------------------------------------------------- // Parse type parameters with a bound -@interface PC1<T, U : NSObject*> : NSObject +@interface PC1<T, U : NSObject*> : NSObject // expected-note{{'PC1' declared here}} // expected-note@-1{{type parameter 'T' declared here}} // expected-note@-2{{type parameter 'U' declared here}} +// expected-note@-3{{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 '> >')}} +@interface PC2<T : id<NSObject>> : NSObject @end // Parse multiple type parameters. @@ -29,11 +33,11 @@ __attribute__((objc_root_class)) @end // Parse multiple type parameters--grammatically ambiguous with protocol refs. -@interface PC4<T, U, V> : NSObject +@interface PC4<T, U, V> : NSObject // expected-note 2{{'PC4' declared here}} @end // Parse a type parameter list without a superclass. -@interface PC5<T : id> // expected-error{{parameterized Objective-C class 'PC5' must have a superclass}} +@interface PC5<T : id> @end // Parse a type parameter with name conflicts. @@ -92,6 +96,7 @@ __attribute__((objc_root_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}} +// expected-note@-1{{'NSObject' declared here}} // Parameterized forward declaration preceding the definition (that is // not parameterized). @@ -190,3 +195,131 @@ void test_PC20_unspecialized(PC20 *pc20) { 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 *')}} } + +// -------------------------------------------------------------------------- +// Parsing type arguments. +// -------------------------------------------------------------------------- + +typedef NSString * ObjCStringRef; // expected-note{{'ObjCStringRef' declared here}} + +// Type arguments with a mix of identifiers and type-names. +typedef PC4<id, NSObject *, NSString *> typeArgs1; + +// Type arguments with only identifiers. +typedef PC4<id, id, id> typeArgs2; + +// Type arguments with only identifiers; one is ambiguous (resolved as +// types). +typedef PC4<NSObject, id, id> typeArgs3; // expected-error{{type argument 'NSObject' must be a pointer (requires a '*')}} + +// Type arguments with only identifiers; one is ambiguous (resolved as +// protocol qualifiers). +typedef PC4<NSObject, NSCopying> protocolQuals1; + +// Type arguments and protocol qualifiers. +typedef PC4<id, NSObject *, id><NSObject, NSCopying> typeArgsAndProtocolQuals1; + +// Type arguments and protocol qualifiers in the wrong order. +typedef PC4<NSObject, NSCopying><id, NSObject *, id> typeArgsAndProtocolQuals2; // expected-error{{protocol qualifiers must precede type arguments}} + +// Type arguments and protocol qualifiers (identifiers). +typedef PC4<id, NSObject, id><NSObject, NSCopying> typeArgsAndProtocolQuals3; // expected-error{{type argument 'NSObject' must be a pointer (requires a '*')}} + +// Typo correction: protocol bias. +typedef PC4<NSCopying, NSObjec> protocolQuals2; // expected-error{{cannot find protocol declaration for 'NSObjec'; did you mean 'NSObject'?}} + +// Typo correction: type bias. +typedef PC4<id, id, NSObjec> typeArgs4; // expected-error{{unknown class name 'NSObjec'; did you mean 'NSObject'?}} +// expected-error@-1{{type argument 'NSObject' must be a pointer (requires a '*')}} + +// Typo correction: bias set by correction itself to a protocol. +typedef PC4<NSObject, NSObject, NSCopyin> protocolQuals3; // expected-error{{cannot find protocol declaration for 'NSCopyin'; did you mean 'NSCopying'?}} + +// Typo correction: bias set by correction itself to a type. +typedef PC4<NSObject, NSObject, ObjCStringref> typeArgs5; // expected-error{{unknown type name 'ObjCStringref'; did you mean 'ObjCStringRef'?}} +// expected-error@-1{{type argument 'NSObject' must be a pointer (requires a '*')}} +// expected-error@-2{{type argument 'NSObject' must be a pointer (requires a '*')}} + +// Type/protocol conflict. +typedef PC4<NSCopying, ObjCStringRef> typeArgsProtocolQualsConflict1; // expected-error{{angle brackets contain both a type ('ObjCStringRef') and a protocol ('NSCopying')}} + +// Handling the '>>' in type argument lists. +typedef PC4<id<NSCopying>, NSObject *, id<NSObject>> typeArgs6; + +// -------------------------------------------------------------------------- +// Checking type arguments. +// -------------------------------------------------------------------------- + +@interface PC15<T : id, U : NSObject *, V : id<NSCopying>> : NSObject +// expected-note@-1{{type parameter 'V' declared here}} +// expected-note@-2{{type parameter 'V' declared here}} +// expected-note@-3{{type parameter 'U' declared here}} +@end + +typedef PC4<NSString *> tooFewTypeArgs1; // expected-error{{too few type arguments for class 'PC4' (have 1, expected 3)}} + +typedef PC4<NSString *, NSString *, NSString *, NSString *> tooManyTypeArgs1; // expected-error{{too many type arguments for class 'PC4' (have 4, expected 3)}} + +typedef PC15<int (^)(int, int), // block pointers as 'id' + NSString *, // subclass + NSString *> typeArgs7; // class that conforms to the protocol + +typedef PC15<NSObject *, NSObject *, id<NSCopying>> typeArgs8; + +typedef PC15<NSObject *, NSObject *, + NSObject *> typeArgs8b; // expected-error{{type argument 'NSObject *' does not satisy the bound ('id<NSCopying>') of type parameter 'V'}} + +typedef PC15<id, + id, // expected-error{{type argument 'id' does not satisy the bound ('NSObject *') of type parameter 'U'}} + id> typeArgs9; + +typedef PC15<id, NSObject *, + id> typeArgs10; // expected-error{{type argument 'id' does not satisy the bound ('id<NSCopying>') of type parameter 'V'}} + +typedef PC15<id, + int (^)(int, int), // okay + id<NSCopying, NSObject>> typeArgs11; + +typedef PC15<id, NSString *, int (^)(int, int)> typeArgs12; // okay + +typedef NSObject<id, id> typeArgs13; // expected-error{{type arguments cannot be applied to non-parameterized class 'NSObject'}} + +typedef id<id, id> typeArgs14; // expected-error{{type arguments cannot be applied to non-class type 'id'}} + +typedef PC1<NSObject *, NSString *> typeArgs15; + +typedef PC1<NSObject *, NSString *><NSCopying> typeArgsAndProtocolQuals4; + +typedef typeArgs15<NSCopying> typeArgsAndProtocolQuals5; + +typedef typeArgs15<NSObject *, NSString *> typeArgs16; // expected-error{{type arguments cannot be applied to already-specialized class type 'typeArgs15' (aka 'PC1<NSObject *,NSString *>')}} + +typedef typeArgs15<NSObject> typeArgsAndProtocolQuals6; + +void testSpecializedTypePrinting() { + int *ip; + + ip = (typeArgs15*)0; // expected-warning{{'typeArgs15 *' (aka 'PC1<NSObject *,NSString *> *')}} + ip = (typeArgsAndProtocolQuals4*)0; // expected-warning{{'typeArgsAndProtocolQuals4 *' (aka 'PC1<NSObject *,NSString *><NSCopying> *')}} + ip = (typeArgsAndProtocolQuals5*)0; // expected-warning{{'typeArgsAndProtocolQuals5 *' (aka 'typeArgs15<NSCopying> *')}} + ip = (typeArgsAndProtocolQuals6)0; // expected-error{{used type 'typeArgsAndProtocolQuals6' (aka 'typeArgs15<NSObject>')}} + ip = (typeArgsAndProtocolQuals6*)0;// expected-warning{{'typeArgsAndProtocolQuals6 *' (aka 'typeArgs15<NSObject> *')}} +} + +// -------------------------------------------------------------------------- +// Specialized superclasses +// -------------------------------------------------------------------------- +@interface PC21<T : NSObject *> : PC1<T, T> +@end + +@interface PC22<T : NSObject *> : PC1<T> // expected-error{{too few type arguments for class 'PC1' (have 1, expected 2)}} +@end + +@interface PC23<T : NSObject *> : PC1<T, U> // expected-error{{unknown type name 'U'}} +@end + +@interface PC24<T> : PC1<T, T> // expected-error{{type argument 'T' (aka 'id') does not satisy the bound ('NSObject *') of type parameter 'U'}} +@end + +@interface NSFoo : PC1<NSObject *, NSObject *> // okay +@end diff --git a/clang/test/SemaObjCXX/parameterized_classes.mm b/clang/test/SemaObjCXX/parameterized_classes.mm new file mode 100644 index 00000000000..48542634bdd --- /dev/null +++ b/clang/test/SemaObjCXX/parameterized_classes.mm @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -std=c++11 %s -verify + +// expected-no-diagnostics +@protocol NSObject +@end + +@protocol NSCopying +@end + +__attribute__((objc_root_class)) +@interface NSObject <NSObject> +@end + +@interface NSString : NSObject +@end + +// -------------------------------------------------------------------------- +// Parsing parameterized classes. +// -------------------------------------------------------------------------- +@interface PC1<T, U, V> : NSObject +@end + +// -------------------------------------------------------------------------- +// Parsing type arguments. +// -------------------------------------------------------------------------- +typedef PC1<::NSString *, NSString *, id<NSCopying>> typeArgs1; diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 6c887e18896..a2467ebad4a 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1021,6 +1021,9 @@ bool CursorVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) { TU))) return true; + if (VisitObjCTypeParamList(ND->getTypeParamList())) + return true; + ObjCCategoryDecl::protocol_loc_iterator PL = ND->protocol_loc_begin(); for (ObjCCategoryDecl::protocol_iterator I = ND->protocol_begin(), E = ND->protocol_end(); I != E; ++I, ++PL) @@ -1080,12 +1083,37 @@ bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) { return false; } +bool CursorVisitor::VisitObjCTypeParamList(ObjCTypeParamList *typeParamList) { + if (!typeParamList) + return false; + + for (auto *typeParam : *typeParamList) { + // Visit the type parameter. + if (Visit(MakeCXCursor(typeParam, TU, RegionOfInterest))) + return true; + + // Visit the bound, if it's explicit. + if (typeParam->hasExplicitBound()) { + if (auto TInfo = typeParam->getTypeSourceInfo()) { + if (Visit(TInfo->getTypeLoc())) + return true; + } + } + } + + return false; +} + bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { if (!D->isThisDeclarationADefinition()) { // Forward declaration is treated like a reference. return Visit(MakeCursorObjCClassRef(D, D->getLocation(), TU)); } + // Objective-C type parameters. + if (VisitObjCTypeParamList(D->getTypeParamListAsWritten())) + return true; + // Issue callbacks for super class. if (D->getSuperClass() && Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(), @@ -1093,6 +1121,10 @@ bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { TU))) return true; + if (TypeSourceInfo *SuperClassTInfo = D->getSuperClassTInfo()) + if (Visit(SuperClassTInfo->getTypeLoc())) + return true; + ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(); for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I, ++PL) @@ -1486,6 +1518,11 @@ bool CursorVisitor::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { if (TL.hasBaseTypeAsWritten() && Visit(TL.getBaseLoc())) return true; + for (unsigned I = 0, N = TL.getNumTypeArgs(); I != N; ++I) { + if (Visit(TL.getTypeArgTInfo(I)->getTypeLoc())) + return true; + } + for (unsigned I = 0, N = TL.getNumProtocols(); I != N; ++I) { if (Visit(MakeCursorObjCProtocolRef(TL.getProtocol(I), TL.getProtocolLoc(I), TU))) @@ -4411,7 +4448,12 @@ static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor, *BestCursor = getTypeRefedCallExprCursor(*BestCursor); return CXChildVisit_Recurse; } - + + // If we already have an Objective-C superclass reference, don't + // update it further. + if (BestCursor->kind == CXCursor_ObjCSuperClassRef) + return CXChildVisit_Break; + *BestCursor = cursor; return CXChildVisit_Recurse; } diff --git a/clang/tools/libclang/CursorVisitor.h b/clang/tools/libclang/CursorVisitor.h index 1b2a922204f..2a0f5205984 100644 --- a/clang/tools/libclang/CursorVisitor.h +++ b/clang/tools/libclang/CursorVisitor.h @@ -222,6 +222,7 @@ public: bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID); bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD); + bool VisitObjCTypeParamList(ObjCTypeParamList *typeParamList); bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); bool VisitObjCImplDecl(ObjCImplDecl *D); bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); |