diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2007-12-17 21:03:50 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2007-12-17 21:03:50 +0000 |
commit | c569249ca0ab755ac79d8cbbfcb2bcae19743624 (patch) | |
tree | 3f2598d15d6ca1e52e8418bd4d1191f49a751019 | |
parent | 2f6974a14c28a9ea56232fdd926c430f755bdbbf (diff) |
Patch to implemented objective-c's dynamic object pointer qualified with
the protocol list (id<P,...> types).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@45121 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | AST/ASTContext.cpp | 45 | ||||
-rw-r--r-- | AST/Type.cpp | 27 | ||||
-rw-r--r-- | AST/TypeSerialization.cpp | 2 | ||||
-rw-r--r-- | CodeGen/CodeGenTypes.cpp | 4 | ||||
-rw-r--r-- | Driver/RewriteTest.cpp | 29 | ||||
-rw-r--r-- | Sema/SemaExpr.cpp | 30 | ||||
-rw-r--r-- | Sema/SemaType.cpp | 10 | ||||
-rw-r--r-- | clang.xcodeproj/project.pbxproj | 1 | ||||
-rw-r--r-- | include/clang/AST/ASTContext.h | 8 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 39 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 2 | ||||
-rw-r--r-- | test/Sema/id-test-3.m | 14 | ||||
-rw-r--r-- | test/Sema/protocol-id-test-1.m | 16 | ||||
-rw-r--r-- | test/Sema/protocol-id-test-2.m | 14 |
14 files changed, 226 insertions, 15 deletions
diff --git a/AST/ASTContext.cpp b/AST/ASTContext.cpp index 4351b89e96..92b691ee90 100644 --- a/AST/ASTContext.cpp +++ b/AST/ASTContext.cpp @@ -49,6 +49,7 @@ void ASTContext::PrintStats() const { unsigned NumTagStruct = 0, NumTagUnion = 0, NumTagEnum = 0, NumTagClass = 0; unsigned NumObjcInterfaces = 0, NumObjcQualifiedInterfaces = 0; + unsigned NumObjcQualifiedIds = 0; for (unsigned i = 0, e = Types.size(); i != e; ++i) { Type *T = Types[i]; @@ -83,6 +84,8 @@ void ASTContext::PrintStats() const { ++NumObjcInterfaces; else if (isa<ObjcQualifiedInterfaceType>(T)) ++NumObjcQualifiedInterfaces; + else if (isa<ObjcQualifiedIdType>(T)) + ++NumObjcQualifiedIds; else { QualType(T, 0).dump(); assert(0 && "Unknown type!"); @@ -106,6 +109,8 @@ void ASTContext::PrintStats() const { fprintf(stderr, " %d interface types\n", NumObjcInterfaces); fprintf(stderr, " %d protocol qualified interface types\n", NumObjcQualifiedInterfaces); + fprintf(stderr, " %d protocol qualified id types\n", + NumObjcQualifiedIds); fprintf(stderr, "Total bytes = %d\n", int(NumBuiltin*sizeof(BuiltinType)+ NumPointer*sizeof(PointerType)+NumArray*sizeof(ArrayType)+ NumComplex*sizeof(ComplexType)+NumVector*sizeof(VectorType)+ @@ -677,7 +682,7 @@ QualType ASTContext::getTypedefType(TypedefDecl *Decl) { if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); QualType Canonical = Decl->getUnderlyingType().getCanonicalType(); - Decl->TypeForDecl = new TypedefType(Decl, Canonical); + Decl->TypeForDecl = new TypedefType(Type::TypeName, Decl, Canonical); Types.push_back(Decl->TypeForDecl); return QualType(Decl->TypeForDecl, 0); } @@ -713,6 +718,29 @@ QualType ASTContext::getObjcQualifiedInterfaceType(ObjcInterfaceDecl *Decl, return QualType(QType, 0); } +/// getObjcQualifiedIdType - Return a +/// getObjcQualifiedIdType type for the given interface decl and +/// the conforming protocol list. +QualType ASTContext::getObjcQualifiedIdType(TypedefDecl *Decl, + ObjcProtocolDecl **Protocols, + unsigned NumProtocols) { + llvm::FoldingSetNodeID ID; + ObjcQualifiedIdType::Profile(ID, Protocols, NumProtocols); + + void *InsertPos = 0; + if (ObjcQualifiedIdType *QT = + ObjcQualifiedIdTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(QT, 0); + + // No Match; + QualType Canonical = Decl->getUnderlyingType().getCanonicalType(); + ObjcQualifiedIdType *QType = + new ObjcQualifiedIdType(Decl, Canonical, Protocols, NumProtocols); + Types.push_back(QType); + ObjcQualifiedIdTypes.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 @@ -1043,7 +1071,13 @@ void ASTContext::getObjcEncodingForType(QualType T, std::string& S) const } S += encoding; - } else if (const PointerType *PT = T->getAsPointerType()) { + } + else if (const ObjcQualifiedIdType *QIT = dyn_cast<ObjcQualifiedIdType>(T)) { + // Treat id<P...> same as 'id' for encoding purposes. + return getObjcEncodingForType(QIT->getDecl()->getUnderlyingType(), S); + + } + else if (const PointerType *PT = T->getAsPointerType()) { QualType PointeeTy = PT->getPointeeType(); if (isObjcIdType(PointeeTy) || PointeeTy->isObjcInterfaceType()) { S += '@'; @@ -1221,6 +1255,13 @@ bool ASTContext::QualifiedInterfaceTypesAreCompatible(QualType lhs, return true; } +// TODO: id<P1,...> vs. id<P,...> +#if 0 +bool ASTContext::QualifiedIdTypesAreCompatible(QualType lhs, + QualType rhs) { +} +#endif + bool ASTContext::vectorTypesAreCompatible(QualType lhs, QualType rhs) { const VectorType *lVector = lhs->getAsVectorType(); const VectorType *rVector = rhs->getAsVectorType(); diff --git a/AST/Type.cpp b/AST/Type.cpp index b1da04b0a3..63f3589769 100644 --- a/AST/Type.cpp +++ b/AST/Type.cpp @@ -539,6 +539,17 @@ void ObjcQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, &Protocols[0], getNumProtocols()); } +void ObjcQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID, + ObjcProtocolDecl **protocols, + unsigned NumProtocols) { + for (unsigned i = 0; i != NumProtocols; i++) + ID.AddPointer(protocols[i]); +} + +void ObjcQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, &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: @@ -780,6 +791,22 @@ void ObjcQualifiedInterfaceType::getAsStringInternal( InnerString = ObjcQIString + InnerString; } +void ObjcQualifiedIdType::getAsStringInternal( + std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + std::string ObjcQIString = "id"; + ObjcQIString += '<'; + int num = getNumProtocols(); + for (int i = 0; i < num; i++) { + ObjcQIString += getProtocols(i)->getName(); + if (i < num-1) + ObjcQIString += ','; + } + ObjcQIString += '>'; + InnerString = ObjcQIString + InnerString; +} + void TagType::getAsStringInternal(std::string &InnerString) const { if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. InnerString = ' ' + InnerString; diff --git a/AST/TypeSerialization.cpp b/AST/TypeSerialization.cpp index 10965c2421..a3b99ed8a5 100644 --- a/AST/TypeSerialization.cpp +++ b/AST/TypeSerialization.cpp @@ -224,7 +224,7 @@ Type* TypedefType::CreateImpl(ASTContext& Context, Deserializer& D) { std::vector<Type*>& Types = const_cast<std::vector<Type*>&>(Context.getTypes()); - TypedefType* T = new TypedefType(NULL,QualType::ReadVal(D)); + TypedefType* T = new TypedefType(Type::TypeName, NULL,QualType::ReadVal(D)); Types.push_back(T); D.ReadPtr(T->Decl); // May be backpatched. diff --git a/CodeGen/CodeGenTypes.cpp b/CodeGen/CodeGenTypes.cpp index cc40af8f94..ac223bcd24 100644 --- a/CodeGen/CodeGenTypes.cpp +++ b/CodeGen/CodeGenTypes.cpp @@ -251,6 +251,10 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { assert(0 && "FIXME: add missing functionality here"); break; + case Type::ObjcQualifiedId: + assert(0 && "FIXME: add missing functionality here"); + break; + case Type::Tagged: const TagType &TT = cast<TagType>(Ty); const TagDecl *TD = TT.getDecl(); diff --git a/Driver/RewriteTest.cpp b/Driver/RewriteTest.cpp index 37f2901ad2..30b1e98af0 100644 --- a/Driver/RewriteTest.cpp +++ b/Driver/RewriteTest.cpp @@ -490,7 +490,10 @@ void RewriteTest::RewriteForwardProtocolDecl(ObjcForwardProtocolDecl *PDecl) { void RewriteTest::RewriteObjcMethodDecl(ObjcMethodDecl *OMD, std::string &ResultStr) { ResultStr += "\nstatic "; - ResultStr += OMD->getResultType().getAsString(); + if (isa<ObjcQualifiedIdType>(OMD->getResultType())) + ResultStr += "id"; + else + ResultStr += OMD->getResultType().getAsString(); ResultStr += "\n"; // Unique method name @@ -548,7 +551,10 @@ void RewriteTest::RewriteObjcMethodDecl(ObjcMethodDecl *OMD, for (int i = 0; i < OMD->getNumParams(); i++) { ParmVarDecl *PDecl = OMD->getParamDecl(i); ResultStr += ", "; - ResultStr += PDecl->getType().getAsString(); + if (isa<ObjcQualifiedIdType>(PDecl->getType())) + ResultStr += "id"; + else + ResultStr += PDecl->getType().getAsString(); ResultStr += " "; ResultStr += PDecl->getName(); } @@ -989,10 +995,13 @@ static void scanToNextArgument(const char *&argRef) { } bool RewriteTest::needToScanForQualifiers(QualType T) { - // FIXME: we don't currently represent "id <Protocol>" in the type system. + if (T == Context->getObjcIdType()) return true; + if (isa<ObjcQualifiedIdType>(T)) + return true; + if (const PointerType *pType = T->getAsPointerType()) { Type *pointeeType = pType->getPointeeType().getTypePtr(); if (isa<ObjcQualifiedInterfaceType>(pointeeType)) @@ -1311,6 +1320,9 @@ ObjcInterfaceDecl *RewriteTest::isSuperReceiver(Expr *recExpr) { if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) { if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { if (!strcmp(PVD->getName(), "self")) { + // is this id<P1..> type? + if (isa<ObjcQualifiedIdType>(CE->getType())) + return 0; if (const PointerType *PT = CE->getType()->getAsPointerType()) { if (ObjcInterfaceType *IT = dyn_cast<ObjcInterfaceType>(PT->getPointeeType())) { @@ -1504,7 +1516,9 @@ Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) { // Make all implicit casts explicit...ICE comes in handy:-) if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) { // Reuse the ICE type, it is exactly what the doctor ordered. - userExpr = new CastExpr(ICE->getType(), userExpr, SourceLocation()); + userExpr = new CastExpr(isa<ObjcQualifiedIdType>(ICE->getType()) + ? Context->getObjcIdType() + : ICE->getType(), userExpr, SourceLocation()); } MsgExprs.push_back(userExpr); // We've transferred the ownership to MsgExprs. Null out the argument in @@ -1525,10 +1539,13 @@ Stmt *RewriteTest::RewriteMessageExpr(ObjCMessageExpr *Exp) { if (ObjcMethodDecl *mDecl = Exp->getMethodDecl()) { // Push any user argument types. for (int i = 0; i < mDecl->getNumParams(); i++) { - QualType t = mDecl->getParamDecl(i)->getType(); + QualType t = isa<ObjcQualifiedIdType>(mDecl->getParamDecl(i)->getType()) + ? Context->getObjcIdType() + : mDecl->getParamDecl(i)->getType(); ArgTypes.push_back(t); } - returnType = mDecl->getResultType(); + returnType = isa<ObjcQualifiedIdType>(mDecl->getResultType()) + ? Context->getObjcIdType() : mDecl->getResultType(); } else { returnType = Context->getObjcIdType(); } diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index dae5325ac4..45d0470544 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -2292,13 +2292,16 @@ Sema::ExprResult Sema::ActOnInstanceMessage( return true; } } else { + bool receiverIsQualId = + dyn_cast<ObjcQualifiedIdType>(RExpr->getType()) != 0; // FIXME (snaroff): checking in this code from Patrick. Needs to be // revisited. how do we get the ClassDecl from the receiver expression? - while (receiverType->isPointerType()) { - PointerType *pointerType = - static_cast<PointerType*>(receiverType.getTypePtr()); - receiverType = pointerType->getPointeeType(); - } + if (!receiverIsQualId) + while (receiverType->isPointerType()) { + PointerType *pointerType = + static_cast<PointerType*>(receiverType.getTypePtr()); + receiverType = pointerType->getPointeeType(); + } ObjcInterfaceDecl* ClassDecl; if (ObjcQualifiedInterfaceType *QIT = dyn_cast<ObjcQualifiedInterfaceType>(receiverType)) { @@ -2312,6 +2315,23 @@ Sema::ExprResult Sema::ActOnInstanceMessage( break; } } + if (!Method) + Diag(lbrac, diag::warn_method_not_found_in_protocol, + std::string("-"), Sel.getName(), + SourceRange(lbrac, rbrac)); + } + else if (ObjcQualifiedIdType *QIT = + dyn_cast<ObjcQualifiedIdType>(receiverType)) { + // search protocols + for (unsigned i = 0; i < QIT->getNumProtocols(); i++) { + ObjcProtocolDecl *PDecl = QIT->getProtocols(i); + if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) + break; + } + if (!Method) + Diag(lbrac, diag::warn_method_not_found_in_protocol, + std::string("-"), Sel.getName(), + SourceRange(lbrac, rbrac)); } else { assert(ObjcInterfaceType::classof(receiverType.getTypePtr()) && diff --git a/Sema/SemaType.cpp b/Sema/SemaType.cpp index 4eefabfe6c..c89018a677 100644 --- a/Sema/SemaType.cpp +++ b/Sema/SemaType.cpp @@ -113,6 +113,16 @@ static QualType ConvertDeclSpecToType(const DeclSpec &DS, ASTContext &Ctx) { reinterpret_cast<ObjcProtocolDecl**>(PPDecl), DS.NumProtocolQualifiers()); } + else if (TypedefDecl *typeDecl = dyn_cast<TypedefDecl>(D)) { + if (Ctx.getObjcIdType() == Ctx.getTypedefType(typeDecl) + && DS.getProtocolQualifiers()) { + // id<protocol-list> + Action::DeclTy **PPDecl = &(*DS.getProtocolQualifiers())[0]; + return Ctx.getObjcQualifiedIdType(typeDecl, + reinterpret_cast<ObjcProtocolDecl**>(PPDecl), + DS.NumProtocolQualifiers()); + } + } // TypeQuals handled by caller. return Ctx.getTypedefType(cast<TypedefDecl>(D)); } diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index 892e53b2a1..26353e5b1f 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -777,6 +777,7 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */; + compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; mainGroup = 08FB7794FE84155DC02AAC07 /* clang */; projectDirPath = ""; diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index f28ae3f4c2..058127544e 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -42,6 +42,7 @@ class ASTContext { llvm::FoldingSet<FunctionTypeNoProto> FunctionTypeNoProtos; llvm::FoldingSet<FunctionTypeProto> FunctionTypeProtos; llvm::FoldingSet<ObjcQualifiedInterfaceType> ObjcQualifiedInterfaceTypes; + llvm::FoldingSet<ObjcQualifiedIdType> ObjcQualifiedIdTypes; /// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts. /// This is lazily created. This is intentionally not serialized. llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> ASTRecordLayouts; @@ -168,6 +169,13 @@ public: /// the conforming protocol list. QualType getObjcQualifiedInterfaceType(ObjcInterfaceDecl *Decl, ObjcProtocolDecl **ProtocolList, unsigned NumProtocols); + + /// getObjcQualifiedIdType - Return an ObjcQualifiedIdType for a + /// given 'id' and conforming protocol list. + QualType getObjcQualifiedIdType(TypedefDecl *Decl, + ObjcProtocolDecl **ProtocolList, + unsigned NumProtocols); + /// getTypeOfType - GCC extension. QualType getTypeOfExpr(Expr *e); diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index da44891780..0661f57e69 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -220,6 +220,7 @@ public: FunctionNoProto, FunctionProto, TypeName, Tagged, ObjcInterface, ObjcQualifiedInterface, + ObjcQualifiedId, TypeOfExp, TypeOfTyp // GNU typeof extension. }; private: @@ -819,7 +820,9 @@ protected: class TypedefType : public Type { TypedefDecl *Decl; - TypedefType(TypedefDecl *D, QualType can) : Type(TypeName, can), Decl(D) { +protected: + TypedefType(TypeClass tc, TypedefDecl *D, QualType can) + : Type(tc, can), Decl(D) { assert(!isa<TypedefType>(can) && "Invalid canonical type"); } friend class ASTContext; // ASTContext creates these. @@ -951,6 +954,40 @@ public: } static bool classof(const ObjcQualifiedInterfaceType *) { return true; } }; + +/// ObjcQualifiedIdType - to represent id<protocol-list> +class ObjcQualifiedIdType : public TypedefType, + public llvm::FoldingSetNode { + // List of protocols for this protocol conforming 'id' type + // List is sorted on protocol name. No protocol is enterred more than once. + llvm::SmallVector<ObjcProtocolDecl*, 8> Protocols; + + ObjcQualifiedIdType(TypedefDecl *TD, QualType can, + ObjcProtocolDecl **Protos, unsigned NumP) : + TypedefType(ObjcQualifiedId, TD, can), + Protocols(Protos, Protos+NumP) { } + friend class ASTContext; // ASTContext creates these. +public: + + 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, + ObjcProtocolDecl **protocols, unsigned NumProtocols); + + static bool classof(const Type *T) { + return T->getTypeClass() == ObjcQualifiedId; + } + static bool classof(const ObjcQualifiedIdType *) { return true; } + +}; /// RecordType - This is a helper class that allows the use of isa/cast/dyncast /// to detect TagType objects of structs/unions/classes. diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 684141a367..811576e9e7 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -470,6 +470,8 @@ DIAG(err_statically_allocated_object, ERROR, "statically allocated Objective-C object '%0'") DIAG(warn_method_not_found, WARNING, "method '%0%1' not found (return type defaults to 'id')") +DIAG(warn_method_not_found_in_protocol, WARNING, + "method '%0%1' not found in protocol (return type defaults to 'id')") //===----------------------------------------------------------------------===// // Semantic Analysis diff --git a/test/Sema/id-test-3.m b/test/Sema/id-test-3.m new file mode 100644 index 0000000000..5331888779 --- /dev/null +++ b/test/Sema/id-test-3.m @@ -0,0 +1,14 @@ +// RUN: clang -rewrite-test %s + +@protocol P +- (id<P>) Meth: (id<P>) Arg; +@end + +@interface INTF<P> +- (id<P>)IMeth; +@end + +@implementation INTF +- (id<P>)IMeth { return [(id<P>)self Meth: 0]; } +- (id<P>) Meth : (id<P>) Arg {} +@end diff --git a/test/Sema/protocol-id-test-1.m b/test/Sema/protocol-id-test-1.m new file mode 100644 index 0000000000..765500e10d --- /dev/null +++ b/test/Sema/protocol-id-test-1.m @@ -0,0 +1,16 @@ +// RUN: clang -verify %s + +@interface FF +- (void) Meth; +@end + +@protocol P +@end + +@interface INTF<P> +- (void)IMeth; +@end + +@implementation INTF +- (void)IMeth {INTF<P> *pi; [pi Meth]; } // expected-warning {{method '-Meth' not found in protocol (return type defaults to 'id')}} +@end diff --git a/test/Sema/protocol-id-test-2.m b/test/Sema/protocol-id-test-2.m new file mode 100644 index 0000000000..525d2cca9e --- /dev/null +++ b/test/Sema/protocol-id-test-2.m @@ -0,0 +1,14 @@ +// RUN: clang -verify %s + +@protocol P +@end + +@interface INTF<P> +- (void)IMeth; + - (void) Meth; +@end + +@implementation INTF +- (void)IMeth { [(id<P>)self Meth]; } // expected-warning {{method '-Meth' not found in protocol (return type defaults to 'id')}} +- (void) Meth {} +@end |