Skip to content

Commit

Permalink
ObjectiveC generics: Add ObjCTypeParamType in the type system.
Browse files Browse the repository at this point in the history
We also need to add ObjCTypeParamTypeLoc. ObjCTypeParamType supports the
representation of "T <protocol>" where T is a type parameter. Before this,
we use TypedefType to represent the type parameter for ObjC.

ObjCTypeParamType has "ObjCTypeParamDecl *OTPDecl" and it extends from
ObjCProtocolQualifiers. It is a non-canonical type and is canonicalized
to the underlying type with the protocol qualifiers.

rdar://24619481
rdar://25060179

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

llvm-svn: 281355
  • Loading branch information
manman-ren committed Sep 13, 2016
1 parent bd28a85 commit e6be26c
Show file tree
Hide file tree
Showing 22 changed files with 411 additions and 1 deletion.
5 changes: 5 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Expand Up @@ -114,6 +114,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<DependentTypeOfExprType> DependentTypeOfExprTypes;
mutable llvm::FoldingSet<DependentDecltypeType> DependentDecltypeTypes;
mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
mutable llvm::FoldingSet<ObjCTypeParamType> ObjCTypeParamTypes;
mutable llvm::FoldingSet<SubstTemplateTypeParmType>
SubstTemplateTypeParmTypes;
mutable llvm::FoldingSet<SubstTemplateTypeParmPackType>
Expand Down Expand Up @@ -1328,6 +1329,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
ArrayRef<QualType> typeArgs,
ArrayRef<ObjCProtocolDecl *> protocols,
bool isKindOf) const;

QualType getObjCTypeParamType(const ObjCTypeParamDecl *Decl,
ArrayRef<ObjCProtocolDecl *> protocols,
QualType Canonical = QualType()) const;

bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl);
/// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Expand Up @@ -1044,6 +1044,8 @@ DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, {

DEF_TRAVERSE_TYPE(PackExpansionType, { TRY_TO(TraverseType(T->getPattern())); })

DEF_TRAVERSE_TYPE(ObjCTypeParamType, {})

DEF_TRAVERSE_TYPE(ObjCInterfaceType, {})

DEF_TRAVERSE_TYPE(ObjCObjectType, {
Expand Down Expand Up @@ -1275,6 +1277,8 @@ DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, {
DEF_TRAVERSE_TYPELOC(PackExpansionType,
{ TRY_TO(TraverseTypeLoc(TL.getPatternLoc())); })

DEF_TRAVERSE_TYPELOC(ObjCTypeParamType, {})

DEF_TRAVERSE_TYPELOC(ObjCInterfaceType, {})

DEF_TRAVERSE_TYPELOC(ObjCObjectType, {
Expand Down
49 changes: 49 additions & 0 deletions clang/include/clang/AST/Type.h
Expand Up @@ -88,6 +88,7 @@ namespace clang {
class ObjCInterfaceDecl;
class ObjCProtocolDecl;
class ObjCMethodDecl;
class ObjCTypeParamDecl;
class UnresolvedUsingTypenameDecl;
class Expr;
class Stmt;
Expand Down Expand Up @@ -4752,6 +4753,49 @@ class ObjCProtocolQualifiers {
}
};

/// Represents a type parameter type in Objective C. It can take
/// a list of protocols.
class ObjCTypeParamType : public Type,
public ObjCProtocolQualifiers<ObjCTypeParamType>,
public llvm::FoldingSetNode {
friend class ASTContext;
friend class ObjCProtocolQualifiers<ObjCTypeParamType>;

/// The number of protocols stored on this type.
unsigned NumProtocols : 6;

ObjCTypeParamDecl *OTPDecl;
/// The protocols are stored after the ObjCTypeParamType node. In the
/// canonical type, the list of protocols are sorted alphabetically
/// and uniqued.
ObjCProtocolDecl **getProtocolStorageImpl();
/// Return the number of qualifying protocols in this interface type,
/// or 0 if there are none.
unsigned getNumProtocolsImpl() const {
return NumProtocols;
}
void setNumProtocolsImpl(unsigned N) {
NumProtocols = N;
}
ObjCTypeParamType(const ObjCTypeParamDecl *D,
QualType can,
ArrayRef<ObjCProtocolDecl *> protocols);
public:
bool isSugared() const { return true; }
QualType desugar() const { return getCanonicalTypeInternal(); }

static bool classof(const Type *T) {
return T->getTypeClass() == ObjCTypeParam;
}

void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID,
const ObjCTypeParamDecl *OTPDecl,
ArrayRef<ObjCProtocolDecl *> protocols);

ObjCTypeParamDecl *getDecl() const { return OTPDecl; }
};

/// Represents a class type in Objective C.
///
/// Every Objective C type is a combination of a base type, a set of
Expand Down Expand Up @@ -4959,6 +5003,11 @@ inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorageImpl() {
getTypeArgStorage() + ObjCObjectTypeBits.NumTypeArgs);
}

inline ObjCProtocolDecl **ObjCTypeParamType::getProtocolStorageImpl() {
return reinterpret_cast<ObjCProtocolDecl**>(
static_cast<ObjCTypeParamType*>(this)+1);
}

/// Interfaces are the core concept in Objective-C for object oriented design.
/// They basically correspond to C++ classes. There are two kinds of interface
/// types: normal interfaces like `NSString`, and qualified interfaces, which
Expand Down
83 changes: 83 additions & 0 deletions clang/include/clang/AST/TypeLoc.h
Expand Up @@ -693,6 +693,89 @@ class TemplateTypeParmTypeLoc :
TemplateTypeParmDecl *getDecl() const { return getTypePtr()->getDecl(); }
};

struct ObjCTypeParamTypeLocInfo {
SourceLocation NameLoc;
};

/// ProtocolLAngleLoc, ProtocolRAngleLoc, and the source locations for
/// protocol qualifiers are stored after Info.
class ObjCTypeParamTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
ObjCTypeParamTypeLoc,
ObjCTypeParamType,
ObjCTypeParamTypeLocInfo> {
// SourceLocations are stored after Info, one for each protocol qualifier.
SourceLocation *getProtocolLocArray() const {
return (SourceLocation*)this->getExtraLocalData() + 2;
}

public:
ObjCTypeParamDecl *getDecl() const { return getTypePtr()->getDecl(); }

SourceLocation getNameLoc() const {
return this->getLocalData()->NameLoc;
}

void setNameLoc(SourceLocation Loc) {
this->getLocalData()->NameLoc = Loc;
}

SourceLocation getProtocolLAngleLoc() const {
return getNumProtocols() ?
*((SourceLocation*)this->getExtraLocalData()) :
SourceLocation();
}
void setProtocolLAngleLoc(SourceLocation Loc) {
*((SourceLocation*)this->getExtraLocalData()) = Loc;
}

SourceLocation getProtocolRAngleLoc() const {
return getNumProtocols() ?
*((SourceLocation*)this->getExtraLocalData() + 1) :
SourceLocation();
}
void setProtocolRAngleLoc(SourceLocation Loc) {
*((SourceLocation*)this->getExtraLocalData() + 1) = Loc;
}

unsigned getNumProtocols() const {
return this->getTypePtr()->getNumProtocols();
}

SourceLocation getProtocolLoc(unsigned i) const {
assert(i < getNumProtocols() && "Index is out of bounds!");
return getProtocolLocArray()[i];
}
void setProtocolLoc(unsigned i, SourceLocation Loc) {
assert(i < getNumProtocols() && "Index is out of bounds!");
getProtocolLocArray()[i] = Loc;
}

ObjCProtocolDecl *getProtocol(unsigned i) const {
assert(i < getNumProtocols() && "Index is out of bounds!");
return *(this->getTypePtr()->qual_begin() + i);
}

ArrayRef<SourceLocation> getProtocolLocs() const {
return llvm::makeArrayRef(getProtocolLocArray(), getNumProtocols());
}

void initializeLocal(ASTContext &Context, SourceLocation Loc);

unsigned getExtraLocalDataSize() const {
if (!this->getNumProtocols()) return 0;
return this->getNumProtocols() * sizeof(SourceLocation) ;
}
unsigned getExtraLocalDataAlignment() const {
return llvm::alignOf<SourceLocation>();
}
SourceRange getLocalSourceRange() const {
SourceLocation start = getNameLoc();
SourceLocation end = getProtocolRAngleLoc();
if (end.isInvalid()) return SourceRange(start, start);
return SourceRange(start, end);
}
};

/// \brief Wrapper for substituted template type parameters.
class SubstTemplateTypeParmTypeLoc :
public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/TypeNodes.def
Expand Up @@ -101,6 +101,7 @@ DEPENDENT_TYPE(InjectedClassName, Type)
DEPENDENT_TYPE(DependentName, Type)
DEPENDENT_TYPE(DependentTemplateSpecialization, Type)
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(PackExpansion, Type)
NON_CANONICAL_TYPE(ObjCTypeParam, Type)
TYPE(ObjCObject, Type)
TYPE(ObjCInterface, ObjCObjectType)
TYPE(ObjCObjectPointer, Type)
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -7534,6 +7534,14 @@ class Sema {
ArrayRef<SourceLocation> ProtocolLocs,
SourceLocation ProtocolRAngleLoc);

/// Build an Objective-C type parameter type.
QualType BuildObjCTypeParamType(const ObjCTypeParamDecl *Decl,
SourceLocation ProtocolLAngleLoc,
ArrayRef<ObjCProtocolDecl *> Protocols,
ArrayRef<SourceLocation> ProtocolLocs,
SourceLocation ProtocolRAngleLoc,
bool FailOnError = false);

/// Build an Objective-C object pointer type.
QualType BuildObjCObjectType(QualType BaseType,
SourceLocation Loc,
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Serialization/ASTBitCodes.h
Expand Up @@ -902,7 +902,9 @@ namespace clang {
/// \brief An AdjustedType record.
TYPE_ADJUSTED = 42,
/// \brief A PipeType record.
TYPE_PIPE = 43
TYPE_PIPE = 43,
/// \brief An ObjCTypeParamType record.
TYPE_OBJC_TYPE_PARAM = 44
};

/// \brief The type IDs for special types constructed by semantic
Expand Down
38 changes: 38 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Expand Up @@ -1860,6 +1860,9 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
case Type::Paren:
return getTypeInfo(cast<ParenType>(T)->getInnerType().getTypePtr());

case Type::ObjCTypeParam:
return getTypeInfo(cast<ObjCTypeParamType>(T)->desugar().getTypePtr());

case Type::Typedef: {
const TypedefNameDecl *Typedef = cast<TypedefType>(T)->getDecl();
TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr());
Expand Down Expand Up @@ -3941,6 +3944,41 @@ ASTContext::applyObjCProtocolQualifiers(QualType type,
return type;
}

QualType
ASTContext::getObjCTypeParamType(const ObjCTypeParamDecl *Decl,
ArrayRef<ObjCProtocolDecl *> protocols,
QualType Canonical) const {
// Look in the folding set for an existing type.
llvm::FoldingSetNodeID ID;
ObjCTypeParamType::Profile(ID, Decl, protocols);
void *InsertPos = nullptr;
if (ObjCTypeParamType *TypeParam =
ObjCTypeParamTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(TypeParam, 0);

if (Canonical.isNull()) {
// We canonicalize to the underlying type.
Canonical = getCanonicalType(Decl->getUnderlyingType());
if (!protocols.empty()) {
// Apply the protocol qualifers.
bool hasError;
Canonical = applyObjCProtocolQualifiers(Canonical, protocols, hasError,
true/*allowOnPointerType*/);
assert(!hasError && "Error when apply protocol qualifier to bound type");
}
}

unsigned size = sizeof(ObjCTypeParamType);
size += protocols.size() * sizeof(ObjCProtocolDecl *);
void *mem = Allocate(size, TypeAlignment);
ObjCTypeParamType *newType = new (mem)
ObjCTypeParamType(Decl, Canonical, protocols);

Types.push_back(newType);
ObjCTypeParamTypes.InsertNode(newType, InsertPos);
return QualType(newType, 0);
}

/// ObjCObjectAdoptsQTypeProtocols - Checks that protocols in IC's
/// protocol list adopt all protocols in QT's qualified-id protocol
/// list.
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/AST/ASTImporter.cpp
Expand Up @@ -897,6 +897,23 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
break;
}

case Type::ObjCTypeParam: {
const ObjCTypeParamType *Obj1 = cast<ObjCTypeParamType>(T1);
const ObjCTypeParamType *Obj2 = cast<ObjCTypeParamType>(T2);
if (!IsStructurallyEquivalent(Context, Obj1->getDecl(),
Obj2->getDecl()))
return false;

if (Obj1->getNumProtocols() != Obj2->getNumProtocols())
return false;
for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) {
if (!IsStructurallyEquivalent(Context,
Obj1->getProtocol(I),
Obj2->getProtocol(I)))
return false;
}
break;
}
case Type::ObjCObject: {
const ObjCObjectType *Obj1 = cast<ObjCObjectType>(T1);
const ObjCObjectType *Obj2 = cast<ObjCObjectType>(T2);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Expand Up @@ -1839,6 +1839,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
case Type::ObjCObject:
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
case Type::ObjCTypeParam:
case Type::Atomic:
case Type::Pipe:
llvm_unreachable("type is illegal as a nested name specifier");
Expand Down
27 changes: 27 additions & 0 deletions clang/lib/AST/Type.cpp
Expand Up @@ -531,6 +531,18 @@ bool Type::isObjCInertUnsafeUnretainedType() const {
}
}

ObjCTypeParamType::ObjCTypeParamType(const ObjCTypeParamDecl *D,
QualType can,
ArrayRef<ObjCProtocolDecl *> protocols)
: Type(ObjCTypeParam, can, can->isDependentType(),
can->isInstantiationDependentType(),
can->isVariablyModifiedType(),
/*ContainsUnexpandedParameterPack=*/false),
OTPDecl(const_cast<ObjCTypeParamDecl*>(D))
{
initialize(protocols);
}

ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
ArrayRef<QualType> typeArgs,
ArrayRef<ObjCProtocolDecl *> protocols,
Expand Down Expand Up @@ -879,6 +891,7 @@ struct SimpleTransformVisitor
}

TRIVIAL_TYPE_CLASS(Typedef)
TRIVIAL_TYPE_CLASS(ObjCTypeParam)

QualType VisitAdjustedType(const AdjustedType *T) {
QualType originalType = recurse(T->getOriginalType());
Expand Down Expand Up @@ -3208,6 +3221,20 @@ void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) {
isKindOfTypeAsWritten());
}

void ObjCTypeParamType::Profile(llvm::FoldingSetNodeID &ID,
const ObjCTypeParamDecl *OTPDecl,
ArrayRef<ObjCProtocolDecl *> protocols) {
ID.AddPointer(OTPDecl);
ID.AddInteger(protocols.size());
for (auto proto : protocols)
ID.AddPointer(proto);
}

void ObjCTypeParamType::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getDecl(),
llvm::makeArrayRef(qual_begin(), getNumProtocols()));
}

namespace {

/// \brief The cached properties of a type.
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/AST/TypeLoc.cpp
Expand Up @@ -388,6 +388,17 @@ TypeLoc TypeLoc::findExplicitQualifierLoc() const {
return TypeLoc();
}

void ObjCTypeParamTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
setNameLoc(Loc);
if (!getNumProtocols()) return;

setProtocolLAngleLoc(Loc);
setProtocolRAngleLoc(Loc);
for (unsigned i = 0, e = getNumProtocols(); i != e; ++i)
setProtocolLoc(i, Loc);
}

void ObjCObjectTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
setHasBaseTypeAsWritten(true);
Expand Down

0 comments on commit e6be26c

Please sign in to comment.