ObjectiveC: Refactor applyObjCProtocolQualifiers.

To construct the canonical type of ObjCTypeParamType, we need to apply
qualifiers on ObjCObjectPointerType. The updated applyObjCProtocolQualifiers
handles this case by merging the protocol lists, constructing a new
ObjCObjectType, then a new ObjCObjectPointerType.

rdar://24619481
rdar://25060179

Differential Revision: http://reviews.llvm.org/D24059

llvm-svn: 281353
This commit is contained in:
Manman Ren 2016-09-13 17:03:12 +00:00
parent 662b51f606
commit 3569eb5267
3 changed files with 86 additions and 57 deletions

View File

@ -1030,6 +1030,14 @@ public:
/// replaced.
QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace) const;
/// \brief Apply Objective-C protocol qualifiers to the given type.
/// \param allowOnPointerType specifies if we can apply protocol
/// qualifiers on ObjCObjectPointerType. It can be set to true when
/// contructing the canonical type of a Objective-C type parameter.
QualType applyObjCProtocolQualifiers(QualType type,
ArrayRef<ObjCProtocolDecl *> protocols, bool &hasError,
bool allowOnPointerType = false) const;
/// \brief Return the uniqued reference to the type for an Objective-C
/// gc-qualified type.
///

View File

@ -3871,6 +3871,76 @@ QualType ASTContext::getObjCObjectType(
return QualType(T, 0);
}
/// Apply Objective-C protocol qualifiers to the given type.
/// If this is for the canonical type of a type parameter, we can apply
/// protocol qualifiers on the ObjCObjectPointerType.
QualType
ASTContext::applyObjCProtocolQualifiers(QualType type,
ArrayRef<ObjCProtocolDecl *> protocols, bool &hasError,
bool allowOnPointerType) const {
hasError = false;
// Apply protocol qualifiers to ObjCObjectPointerType.
if (allowOnPointerType) {
if (const ObjCObjectPointerType *objPtr =
dyn_cast<ObjCObjectPointerType>(type.getTypePtr())) {
const ObjCObjectType *objT = objPtr->getObjectType();
// Merge protocol lists and construct ObjCObjectType.
SmallVector<ObjCProtocolDecl*, 8> protocolsVec;
protocolsVec.append(objT->qual_begin(),
objT->qual_end());
protocolsVec.append(protocols.begin(), protocols.end());
ArrayRef<ObjCProtocolDecl *> protocols = protocolsVec;
type = getObjCObjectType(
objT->getBaseType(),
objT->getTypeArgsAsWritten(),
protocols,
objT->isKindOfTypeAsWritten());
return getObjCObjectPointerType(type);
}
}
// Apply protocol qualifiers to ObjCObjectType.
if (const ObjCObjectType *objT = dyn_cast<ObjCObjectType>(type.getTypePtr())){
// FIXME: Check for protocols to which the class type is already
// known to conform.
return getObjCObjectType(objT->getBaseType(),
objT->getTypeArgsAsWritten(),
protocols,
objT->isKindOfTypeAsWritten());
}
// If the canonical type is ObjCObjectType, ...
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 getObjCObjectType(type, { }, protocols, false);
}
// id<protocol-list>
if (type->isObjCIdType()) {
const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>();
type = getObjCObjectType(ObjCBuiltinIdTy, { }, protocols,
objPtr->isKindOfType());
return getObjCObjectPointerType(type);
}
// Class<protocol-list>
if (type->isObjCClassType()) {
const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>();
type = getObjCObjectType(ObjCBuiltinClassTy, { }, protocols,
objPtr->isKindOfType());
return getObjCObjectPointerType(type);
}
hasError = true;
return type;
}
/// ObjCObjectAdoptsQTypeProtocols - Checks that protocols in IC's
/// protocol list adopt all protocols in QT's qualified-id protocol
/// list.

View File

@ -1000,57 +1000,6 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
return S.Context.getObjCObjectType(type, finalTypeArgs, { }, false);
}
/// 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,
bool failOnError = false) {
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,
objT->isKindOfTypeAsWritten());
}
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, false);
}
// id<protocol-list>
if (type->isObjCIdType()) {
const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>();
type = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, protocols,
objPtr->isKindOfType());
return ctx.getObjCObjectPointerType(type);
}
// Class<protocol-list>
if (type->isObjCClassType()) {
const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>();
type = ctx.getObjCObjectType(ctx.ObjCBuiltinClassTy, { }, protocols,
objPtr->isKindOfType());
return ctx.getObjCObjectPointerType(type);
}
S.Diag(loc, diag::err_invalid_protocol_qualifiers)
<< range;
if (failOnError)
return QualType();
return type;
}
QualType Sema::BuildObjCObjectType(QualType BaseType,
SourceLocation Loc,
SourceLocation TypeArgsLAngleLoc,
@ -1072,12 +1021,14 @@ QualType Sema::BuildObjCObjectType(QualType BaseType,
}
if (!Protocols.empty()) {
Result = applyObjCProtocolQualifiers(*this, Loc,
SourceRange(ProtocolLAngleLoc,
ProtocolRAngleLoc),
Result, Protocols,
ProtocolLocs.data(),
FailOnError);
bool HasError;
Result = Context.applyObjCProtocolQualifiers(Result, Protocols,
HasError);
if (HasError) {
Diag(Loc, diag::err_invalid_protocol_qualifiers)
<< SourceRange(ProtocolLAngleLoc, ProtocolRAngleLoc);
if (FailOnError) Result = QualType();
}
if (FailOnError && Result.isNull())
return QualType();
}