Patch to create protocol conforming class types.

llvm-svn: 42856
This commit is contained in:
Fariborz Jahanian 2007-10-11 00:55:41 +00:00
parent e99c8329af
commit 70e8f1024a
14 changed files with 176 additions and 47 deletions

View File

@ -610,6 +610,31 @@ QualType ASTContext::getObjcInterfaceType(ObjcInterfaceDecl *Decl) {
return QualType(Decl->TypeForDecl, 0);
}
/// getObjcQualifiedInterfaceType - Return a
/// ObjcQualifiedInterfaceType type for the given interface decl and
/// the conforming protocol list.
QualType ASTContext::getObjcQualifiedInterfaceType(ObjcInterfaceDecl *Decl,
ObjcProtocolDecl **Protocols, unsigned NumProtocols) {
ObjcInterfaceType *IType =
cast<ObjcInterfaceType>(getObjcInterfaceType(Decl));
llvm::FoldingSetNodeID ID;
ObjcQualifiedInterfaceType::Profile(ID, IType, Protocols, NumProtocols);
void *InsertPos = 0;
if (ObjcQualifiedInterfaceType *QT =
ObjcQualifiedInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(QT, 0);
// No Match;
ObjcQualifiedInterfaceType *QType = new ObjcQualifiedInterfaceType(IType);
for (unsigned i = 0; i != NumProtocols; i++)
QType->setProtocols(Protocols[i]);
Types.push_back(QType);
ObjcQualifiedInterfaceTypes.InsertNode(QType, InsertPos);
return QualType(QType, 0);
}
/// getTypeOfExpr - Unlike many "get<Type>" functions, we can't unique
/// TypeOfExpr AST's (since expression's are never shared). For example,
/// multiple declarations that refer to "typeof(x)" all contain different

View File

@ -618,6 +618,19 @@ void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic());
}
void ObjcQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
ObjcInterfaceType *interfaceType,
ObjcProtocolDecl **protocols,
unsigned NumProtocols) {
ID.AddPointer(interfaceType);
for (unsigned i = 0; i != NumProtocols; i++)
ID.AddPointer(protocols[i]);
}
void ObjcQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getInterfaceType(), &Protocols[0], getNumProtocols());
}
/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
/// potentially looking through *all* consequtive typedefs. This returns the
/// sum of the type qualifiers, so if you have:
@ -843,6 +856,18 @@ void ObjcInterfaceType::getAsStringInternal(std::string &InnerString) const {
InnerString = getDecl()->getIdentifier()->getName() + InnerString;
}
void ObjcQualifiedInterfaceType::getAsStringInternal(
std::string &InnerString) const {
InnerString = getInterfaceType()->getDecl()->getName() + '<';
int num = getNumProtocols();
for (int i = 0; i < num; i++) {
InnerString += getProtocols(i)->getName();
if (i < num-1)
InnerString += ',';
}
InnerString += '>';
}
void TagType::getAsStringInternal(std::string &InnerString) const {
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
InnerString = ' ' + InnerString;

View File

@ -403,18 +403,20 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) {
TypeRep);
if (isInvalid)
break;
else { // FIXME: restrict this to "id" and ObjC classnames.
DS.Range.setEnd(Tok.getLocation());
ConsumeToken(); // The identifier
if (Tok.is(tok::less)) {
llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
ParseObjCProtocolReferences(ProtocolRefs);
Actions.ActOnFindProtocolDeclaration(Loc,
&ProtocolRefs[0],
ProtocolRefs.size());
}
continue;
// FIXME: restrict this to "id" and ObjC classnames.
DS.Range.setEnd(Tok.getLocation());
ConsumeToken(); // The identifier
if (Tok.is(tok::less)) {
llvm::SmallVector<IdentifierInfo *, 8> ProtocolRefs;
ParseObjCProtocolReferences(ProtocolRefs);
llvm::SmallVector<DeclTy *, 8> *ProtocolDecl =
new llvm::SmallVector<DeclTy *, 8>;
DS.setProtocolQualifiers(ProtocolDecl);
Actions.FindProtocolDeclaration(Loc,
&ProtocolRefs[0], ProtocolRefs.size(),
*ProtocolDecl);
}
continue;
}
}
// FALL THROUGH.

View File

@ -378,9 +378,9 @@ Parser::DeclTy *Parser::ParseObjCMethodPrototype(DeclTy *IDecl,
assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-");
tok::TokenKind methodType = Tok.getKind();
SourceLocation methodLoc = ConsumeToken();
ConsumeToken();
DeclTy *MDecl = ParseObjCMethodDecl(methodType, methodLoc, MethodImplKind);
DeclTy *MDecl = ParseObjCMethodDecl(methodType, MethodImplKind);
// Since this rule is used for both method declarations and definitions,
// the caller is (optionally) responsible for consuming the ';'.
return MDecl;
@ -394,7 +394,7 @@ Parser::DeclTy *Parser::ParseObjCMethodPrototype(DeclTy *IDecl,
/// unsigned long const short volatile signed restrict _Complex
/// in out inout bycopy byref oneway int char float double void _Bool
///
IdentifierInfo *Parser::ParseObjCSelector() {
IdentifierInfo *Parser::ParseObjCSelector(SourceLocation &SelectorLoc) {
switch (Tok.getKind()) {
default:
return 0;
@ -438,7 +438,7 @@ IdentifierInfo *Parser::ParseObjCSelector() {
case tok::kw__Bool:
case tok::kw__Complex:
IdentifierInfo *II = Tok.getIdentifierInfo();
ConsumeToken();
SelectorLoc = ConsumeToken();
return II;
}
}
@ -526,15 +526,14 @@ Parser::TypeTy *Parser::ParseObjCTypeName() {
/// __attribute__((unused))
///
Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType,
SourceLocation mLoc,
tok::ObjCKeywordKind MethodImplKind)
{
// Parse the return type.
TypeTy *ReturnType = 0;
if (Tok.is(tok::l_paren))
ReturnType = ParseObjCTypeName();
IdentifierInfo *SelIdent = ParseObjCSelector();
SourceLocation mLoc;
IdentifierInfo *SelIdent = ParseObjCSelector(mLoc);
if (Tok.isNot(tok::colon)) {
if (!SelIdent) {
Diag(Tok, diag::err_expected_ident); // missing selector name.
@ -584,7 +583,8 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType,
ConsumeToken(); // Eat the identifier.
// Check for another keyword selector.
SelIdent = ParseObjCSelector();
SourceLocation Loc;
SelIdent = ParseObjCSelector(Loc);
if (!SelIdent && Tok.isNot(tok::colon))
break;
// We have a selector or a colon, continue parsing.
@ -1175,7 +1175,8 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() {
ReceiverExpr = Res.Val;
}
// Parse objc-selector
IdentifierInfo *selIdent = ParseObjCSelector();
SourceLocation Loc;
IdentifierInfo *selIdent = ParseObjCSelector(Loc);
llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
llvm::SmallVector<Action::ExprTy *, 12> KeyExprs;
@ -1201,7 +1202,7 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() {
KeyExprs.push_back(Res.Val);
// Check for another keyword selector.
selIdent = ParseObjCSelector();
selIdent = ParseObjCSelector(Loc);
if (!selIdent && Tok.isNot(tok::colon))
break;
// We have a selector or a colon, continue parsing.

View File

@ -449,9 +449,11 @@ public:
IdentifierInfo **IdentList,
unsigned NumElts);
virtual DeclTy **ActOnFindProtocolDeclaration(SourceLocation TypeLoc,
IdentifierInfo **ProtocolId,
unsigned NumProtocols);
virtual void FindProtocolDeclaration(SourceLocation TypeLoc,
IdentifierInfo **ProtocolId,
unsigned NumProtocols,
llvm::SmallVector<DeclTy *, 8> &
Protocols);
virtual void ActOnAddMethodsToObjcDecl(Scope* S, DeclTy *ClassDecl,
DeclTy **allMethods, unsigned allNum);

View File

@ -987,20 +987,22 @@ Sema::DeclTy *Sema::ActOnStartProtocolInterface(
return PDecl;
}
/// ActOnFindProtocolDeclaration - This routine looks for a previously
/// declared protocol and returns it. If not found, issues diagnostic.
/// Will build a list of previously protocol declarations found in the list.
Action::DeclTy **
Sema::ActOnFindProtocolDeclaration(SourceLocation TypeLoc,
IdentifierInfo **ProtocolId,
unsigned NumProtocols) {
/// FindProtocolDeclaration - This routine looks up protocols and
/// issuer error if they are not declared. It returns list of protocol
/// declarations in its 'Protocols' argument.
void
Sema::FindProtocolDeclaration(SourceLocation TypeLoc,
IdentifierInfo **ProtocolId,
unsigned NumProtocols,
llvm::SmallVector<DeclTy *,8> &Protocols) {
for (unsigned i = 0; i != NumProtocols; ++i) {
ObjcProtocolDecl *PDecl = ObjcProtocols[ProtocolId[i]];
if (!PDecl)
Diag(TypeLoc, diag::err_undeclared_protocol,
ProtocolId[i]->getName());
else
Protocols.push_back(PDecl);
}
return 0;
}
/// ActOnForwardProtocolDeclaration -

View File

@ -104,8 +104,15 @@ static QualType ConvertDeclSpecToType(const DeclSpec &DS, ASTContext &Ctx) {
"Can't handle qualifiers on typedef names yet!");
// FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so
// we have this "hack" for now...
if (isa<ObjcInterfaceDecl>(D))
return Ctx.getObjcInterfaceType(cast<ObjcInterfaceDecl>(D));
if (ObjcInterfaceDecl *ObjcIntDecl = dyn_cast<ObjcInterfaceDecl>(D)) {
if (DS.getProtocolQualifiers() == 0)
return Ctx.getObjcInterfaceType(ObjcIntDecl);
Action::DeclTy **PPDecl = &(*DS.getProtocolQualifiers())[0];
return Ctx.getObjcQualifiedInterfaceType(ObjcIntDecl,
reinterpret_cast<ObjcProtocolDecl**>(PPDecl),
DS.NumProtocolQualifiers());
}
// TypeQuals handled by caller.
return Ctx.getTypedefType(cast<TypedefDecl>(D));
}

View File

@ -739,6 +739,7 @@
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
compatibilityVersion = "Xcode 2.4";
hasScannedForEncodings = 1;
mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
projectDirPath = "";

View File

@ -38,6 +38,7 @@ class ASTContext {
llvm::FoldingSet<VectorType> VectorTypes;
llvm::FoldingSet<FunctionTypeNoProto> FunctionTypeNoProtos;
llvm::FoldingSet<FunctionTypeProto> FunctionTypeProtos;
llvm::FoldingSet<ObjcQualifiedInterfaceType> ObjcQualifiedInterfaceTypes;
llvm::DenseMap<const RecordDecl*, const RecordLayout*> RecordLayoutInfo;
RecordDecl *CFConstantStringTypeDecl;
public:
@ -118,6 +119,12 @@ public:
/// specified typename decl.
QualType getTypedefType(TypedefDecl *Decl);
QualType getObjcInterfaceType(ObjcInterfaceDecl *Decl);
/// getObjcQualifiedInterfaceType - Return a
/// ObjcQualifiedInterfaceType type for the given interface decl and
/// the conforming protocol list.
QualType getObjcQualifiedInterfaceType(ObjcInterfaceDecl *Decl,
ObjcProtocolDecl **ProtocolList, unsigned NumProtocols);
/// getTypeOfType - GCC extension.
QualType getTypeOfExpr(Expr *e);

View File

@ -47,6 +47,7 @@ namespace clang {
class FunctionType;
class OCUVectorType;
class BuiltinType;
class ObjcQualifiedInterfaceType;
/// QualType - For efficiency, we don't store CVR-qualified types as nodes on
/// their own: instead each reference to a type stores the qualifiers. This
@ -817,6 +818,7 @@ public:
class ObjcInterfaceType : public Type {
ObjcInterfaceDecl *Decl;
ObjcInterfaceType(ObjcInterfaceDecl *D) :
Type(ObjcInterface, QualType()), Decl(D) { }
friend class ASTContext; // ASTContext creates these.
@ -825,7 +827,7 @@ public:
ObjcInterfaceDecl *getDecl() const { return Decl; }
virtual void getAsStringInternal(std::string &InnerString) const;
static bool classof(const Type *T) {
return T->getTypeClass() == ObjcInterface;
}
@ -836,7 +838,7 @@ public:
/// conforming to a list of protocols; such as, INTF<Proto1, Proto2, Proto1>.
/// Duplicate protocols are removed and protocol list is canonicalized to be in
/// alphabetical order.
class ObjcQualifiedInterfaceType : public Type {
class ObjcQualifiedInterfaceType : public Type, public llvm::FoldingSetNode {
// Interface type for this protocol conforming object type
ObjcInterfaceType *InterfaceType;
@ -846,10 +848,29 @@ class ObjcQualifiedInterfaceType : public Type {
ObjcQualifiedInterfaceType(ObjcInterfaceType *T) :
Type(ObjcQualifiedInterface, QualType()), InterfaceType(T) { }
void setProtocols(ObjcProtocolDecl *pType) {
Protocols.push_back(pType);
}
friend class ASTContext; // ASTContext creates these.
public:
ObjcInterfaceType *getInterfaceType() const { return InterfaceType; }
ObjcProtocolDecl *getProtocols(unsigned i) const {
return Protocols[i];
}
unsigned getNumProtocols() const {
return Protocols.size();
}
virtual void getAsStringInternal(std::string &InnerString) const;
void Profile(llvm::FoldingSetNodeID &ID);
static void Profile(llvm::FoldingSetNodeID &ID,
ObjcInterfaceType *interfaceType,
ObjcProtocolDecl **protocols, unsigned NumProtocols);
static bool classof(const Type *T) {
return T->getTypeClass() == ObjcQualifiedInterface;
}

View File

@ -552,13 +552,14 @@ public:
return 0;
}
/// ActOnFindProtocolDeclaration - This routine looks for a previously
/// declared protocol and returns it. If not found, issues diagnostic.
/// Will build a list of previously protocol declarations found in the list.
virtual DeclTy **ActOnFindProtocolDeclaration(SourceLocation TypeLoc,
IdentifierInfo **ProtocolId,
unsigned NumProtocols) {
return 0;
/// FindProtocolDeclaration - This routine looks up protocols and
/// issues error if they are not declared. It returns list of valid
/// protocols found.
virtual void FindProtocolDeclaration(SourceLocation TypeLoc,
IdentifierInfo **ProtocolId,
unsigned NumProtocols,
llvm::SmallVector<DeclTy *, 8> &
Protocols) {
}

View File

@ -124,6 +124,9 @@ private:
// attributes.
AttributeList *AttrList;
// List of protocol qualifiers for objective-c classes.
llvm::SmallVector<Action::DeclTy *, 8> *ProtocolQualifiers;
// SourceLocation info. These are null if the item wasn't specified or if
// the setting was synthesized.
SourceLocation StorageClassSpecLoc, SCS_threadLoc;
@ -142,10 +145,12 @@ public:
TypeQualifiers(TSS_unspecified),
FS_inline_specified(false),
TypeRep(0),
AttrList(0) {
AttrList(0),
ProtocolQualifiers(0) {
}
~DeclSpec() {
delete AttrList;
delete ProtocolQualifiers;
}
// storage-class-specifier
SCS getStorageClassSpec() const { return StorageClassSpec; }
@ -248,6 +253,15 @@ public:
}
AttributeList *getAttributes() const { return AttrList; }
llvm::SmallVector<Action::DeclTy *, 8> *getProtocolQualifiers() const {
return ProtocolQualifiers;
}
void setProtocolQualifiers(llvm::SmallVector<Action::DeclTy *, 8> *protos) {
ProtocolQualifiers = protos;
}
unsigned NumProtocolQualifiers() const {
return ProtocolQualifiers ? ProtocolQualifiers->size() : 0;
}
/// Finish - This does final analysis of the declspec, issuing diagnostics for
/// things like "_Imaginary" (lacking an FP type). After calling this method,
/// DeclSpec is guaranteed self-consistent, even if an error occurred.

View File

@ -275,7 +275,7 @@ private:
DeclTy *ParseObjCTryStmt(SourceLocation atLoc);
DeclTy *ParseObjCThrowStmt(SourceLocation atLoc);
IdentifierInfo *ParseObjCSelector();
IdentifierInfo *ParseObjCSelector(SourceLocation &MethodLocation);
// Definitions for Objective-c context sensitive keywords recognition.
enum ObjCTypeQual {
objc_in=0, objc_out, objc_inout, objc_oneway, objc_bycopy, objc_byref,
@ -295,7 +295,7 @@ private:
void ParseObjCMethodRequirement();
DeclTy *ParseObjCMethodPrototype(DeclTy *classOrCat,
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword);
DeclTy *ParseObjCMethodDecl(tok::TokenKind mType, SourceLocation mLoc,
DeclTy *ParseObjCMethodDecl(tok::TokenKind mType,
tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword);
void ParseObjCPropertyAttribute(DeclTy *interfaceDecl);
void ParseObjCPropertyDecl(DeclTy *interfaceDecl);

View File

@ -0,0 +1,21 @@
// RUN: clang -fsyntax-only -verify %s
@protocol P1 @end
@protocol P2 @end
@protocol P3 @end
@interface INTF
- (INTF*) METH1; // expected-error {{previous declaration is here}}
- (INTF<P1>*) METH1; // expected-error {{duplicate declaration of method 'METH1'}}
- (INTF<P1,P2>*) METH2;
- (INTF<P2,P1>*) METH2; // expected-error {{previous declaration is here}}
- (INTF<P2,P1,P3>*) METH2; // expected-error {{duplicate declaration of method 'METH2'}}
- (INTF<P2,P1,P3>*) METH3;
- (INTF<P3,P1,P2, P3>*) METH3;
@end
INTF<P2,P1,P3>* p1;