From 49c6425ee697c54cc584376b1a7a7556947f8b84 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 11 Oct 2007 23:42:27 +0000 Subject: [PATCH] This patch implementa objective-c's @compatibilty-alias declaration. llvm-svn: 42883 --- clang/AST/Decl.cpp | 8 ++++ clang/Driver/ASTConsumers.cpp | 9 ++++ clang/Parse/ParseObjc.cpp | 15 ++++-- clang/Sema/Sema.h | 5 ++ clang/Sema/SemaDecl.cpp | 46 +++++++++++++++++++ clang/include/clang/AST/Decl.h | 4 +- clang/include/clang/AST/DeclObjC.h | 20 ++++++++ clang/include/clang/Basic/DiagnosticKinds.def | 7 ++- clang/include/clang/Parse/Action.h | 10 ++++ clang/test/Parser/objc-alias-printing.m | 18 ++++++++ clang/test/Sema/alias-test-1.m | 31 +++++++++++++ 11 files changed, 167 insertions(+), 6 deletions(-) create mode 100644 clang/test/Parser/objc-alias-printing.m create mode 100644 clang/test/Sema/alias-test-1.m diff --git a/clang/AST/Decl.cpp b/clang/AST/Decl.cpp index 20117795254b..987e4933a08d 100644 --- a/clang/AST/Decl.cpp +++ b/clang/AST/Decl.cpp @@ -35,6 +35,7 @@ static unsigned nCategoryDecls = 0; static unsigned nIvarDecls = 0; static unsigned nObjcImplementationDecls = 0; static unsigned nObjcCategoryImpl = 0; +static unsigned nObjcCompatibleAlias = 0; static bool StatSwitch = false; @@ -141,6 +142,10 @@ void Decl::PrintStats() { nObjcCategoryImpl, (int)sizeof(ObjcCategoryImplDecl), int(nObjcCategoryImpl*sizeof(ObjcCategoryImplDecl))); + fprintf(stderr, " %d compatibility alias decls, %d each (%d bytes)\n", + nObjcCompatibleAlias, (int)sizeof(ObjcCompatibleAliasDecl), + int(nObjcCompatibleAlias*sizeof(ObjcCompatibleAliasDecl))); + fprintf(stderr, "Total bytes = %d\n", int(nFuncs*sizeof(FunctionDecl)+nBlockVars*sizeof(BlockVarDecl)+ nFileVars*sizeof(FileVarDecl)+nParmVars*sizeof(ParmVarDecl)+ @@ -207,6 +212,9 @@ void Decl::addDeclKind(const Kind k) { case ObjcCategoryImpl: nObjcCategoryImpl++; break; + case CompatibleAlias: + nObjcCompatibleAlias++; + break; } } diff --git a/clang/Driver/ASTConsumers.cpp b/clang/Driver/ASTConsumers.cpp index 1ec2c72d522d..114940fa6baf 100644 --- a/clang/Driver/ASTConsumers.cpp +++ b/clang/Driver/ASTConsumers.cpp @@ -117,6 +117,12 @@ static void PrintObjcCategoryDecl(ObjcCategoryDecl *PID) { // FIXME: implement the rest... } +static void PrintObjcCompatibleAliasDecl(ObjcCompatibleAliasDecl *AID) { + std::string A = AID->getName(); + std::string I = AID->getClassInterface()->getName(); + fprintf(stderr, "@compatibility_alias %s %s;\n", A.c_str(), I.c_str()); +} + namespace { class ASTPrinter : public ASTConsumer { virtual void HandleTopLevelDecl(Decl *D) { @@ -153,6 +159,9 @@ namespace { } else if (ObjcCategoryDecl *OID = dyn_cast(D)) { PrintObjcCategoryDecl(OID); + } else if (ObjcCompatibleAliasDecl *OID = + dyn_cast(D)) { + PrintObjcCompatibleAliasDecl(OID); } else if (isa(D)) { fprintf(stderr, "@class [printing todo]\n"); } else if (ScopedDecl *SD = dyn_cast(D)) { diff --git a/clang/Parse/ParseObjc.cpp b/clang/Parse/ParseObjc.cpp index dad82eec52be..bfd6797c964c 100644 --- a/clang/Parse/ParseObjc.cpp +++ b/clang/Parse/ParseObjc.cpp @@ -923,15 +923,22 @@ Parser::DeclTy *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { Diag(Tok, diag::err_expected_ident); return 0; } - ConsumeToken(); // consume alias-name + IdentifierInfo *aliasId = Tok.getIdentifierInfo(); + SourceLocation aliasLoc = ConsumeToken(); // consume alias-name if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); return 0; } - ConsumeToken(); // consume class-name; - if (Tok.isNot(tok::semi)) + IdentifierInfo *classId = Tok.getIdentifierInfo(); + SourceLocation classLoc = ConsumeToken(); // consume class-name; + if (Tok.isNot(tok::semi)) { Diag(Tok, diag::err_expected_semi_after, "@compatibility_alias"); - return 0; + return 0; + } + DeclTy *ClsType = Actions.ActOnCompatiblityAlias(atLoc, + aliasId, aliasLoc, + classId, classLoc); + return ClsType; } /// property-synthesis: diff --git a/clang/Sema/Sema.h b/clang/Sema/Sema.h index c2ac6a23a749..80c4d7d55481 100644 --- a/clang/Sema/Sema.h +++ b/clang/Sema/Sema.h @@ -416,6 +416,11 @@ public: IdentifierInfo *SuperName, SourceLocation SuperLoc, IdentifierInfo **ProtocolNames, unsigned NumProtocols, AttributeList *AttrList); + + virtual DeclTy *ActOnCompatiblityAlias( + SourceLocation AtCompatibilityAliasLoc, + IdentifierInfo *AliasName, SourceLocation AliasLocation, + IdentifierInfo *ClassName, SourceLocation ClassLocation); virtual DeclTy *ActOnStartProtocolInterface( SourceLocation AtProtoInterfaceLoc, diff --git a/clang/Sema/SemaDecl.cpp b/clang/Sema/SemaDecl.cpp index a14026519891..0a63cb9106d7 100644 --- a/clang/Sema/SemaDecl.cpp +++ b/clang/Sema/SemaDecl.cpp @@ -31,6 +31,9 @@ Sema::DeclTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) const { if (Decl *IIDecl = II.getFETokenInfo()) if (isa(IIDecl) || isa(IIDecl)) return IIDecl; + else if (ObjcCompatibleAliasDecl *ADecl = + dyn_cast(IIDecl)) + return ADecl->getClassInterface(); return 0; } @@ -961,6 +964,49 @@ Sema::DeclTy *Sema::ActOnStartClassInterface( return IDecl; } +/// ActOnCompatiblityAlias - this action is called after complete parsing of +/// @compaatibility_alias declaration. It sets up the alias relationships. +Sema::DeclTy *Sema::ActOnCompatiblityAlias( + SourceLocation AtCompatibilityAliasLoc, + IdentifierInfo *AliasName, SourceLocation AliasLocation, + IdentifierInfo *ClassName, SourceLocation ClassLocation) { + // Look for previous declaration of alias name + ScopedDecl *ADecl = LookupScopedDecl(AliasName, Decl::IDNS_Ordinary, + AliasLocation, TUScope); + if (ADecl) { + if (isa(ADecl)) { + Diag(AliasLocation, diag::warn_previous_alias_decl); + Diag(ADecl->getLocation(), diag::warn_previous_declaration); + } + else { + Diag(AliasLocation, diag::err_conflicting_aliasing_type, + AliasName->getName()); + Diag(ADecl->getLocation(), diag::err_previous_declaration); + } + return 0; + } + // Check for class declaration + ScopedDecl *CDecl = LookupScopedDecl(ClassName, Decl::IDNS_Ordinary, + ClassLocation, TUScope); + if (!CDecl || !isa(CDecl)) { + Diag(ClassLocation, diag::warn_undef_interface, + ClassName->getName()); + if (CDecl) + Diag(CDecl->getLocation(), diag::warn_previous_declaration); + return 0; + } + // Everything checked out, instantiate a new alias declaration ast + ObjcCompatibleAliasDecl *AliasDecl = + new ObjcCompatibleAliasDecl(AtCompatibilityAliasLoc, + AliasName, + dyn_cast(CDecl)); + + // Chain & install the interface decl into the identifier. + AliasDecl->setNext(AliasName->getFETokenInfo()); + AliasName->setFETokenInfo(AliasDecl); + return AliasDecl; +} + Sema::DeclTy *Sema::ActOnStartProtocolInterface( SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 2ede710f5247..4fe9f75390ed 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -44,6 +44,7 @@ public: ObjcImplementation, ObjcProtocol, // ScopedDecl + CompatibleAlias, // TypeDecl ObjcInterface, Typedef, @@ -68,7 +69,7 @@ public: // of the class, to allow efficient classof. NamedFirst = Field, NamedLast = ParmVar, FieldFirst = Field, FieldLast = ObjcIvar, - ScopedFirst = ObjcInterface, ScopedLast = ParmVar, + ScopedFirst = CompatibleAlias, ScopedLast = ParmVar, TypeFirst = ObjcInterface, TypeLast = Class, TagFirst = Enum , TagLast = Class, RecordFirst = Struct , RecordLast = Class, @@ -124,6 +125,7 @@ public: case ParmVar: case EnumConstant: case ObjcInterface: + case CompatibleAlias: return IDNS_Ordinary; case Struct: case Union: diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index f70278a8feb7..987bf57cb59a 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -591,7 +591,27 @@ public: } static bool classof(const ObjcImplementationDecl *D) { return true; } }; + +/// ObjcCompatibleAliasDecl - Represents alias of a class. This alias is +/// declared as @compatibility_alias alias class. +class ObjcCompatibleAliasDecl : public ScopedDecl { + /// Class that this is an alias of. + ObjcInterfaceDecl *AliasedClass; +public: + ObjcCompatibleAliasDecl(SourceLocation L, IdentifierInfo *Id, + ObjcInterfaceDecl* aliasedClass) + : ScopedDecl(CompatibleAlias, L, Id, 0), + AliasedClass(aliasedClass) {} + + ObjcInterfaceDecl *getClassInterface() const { return AliasedClass; } + + static bool classof(const Decl *D) { + return D->getKind() == CompatibleAlias; + } + static bool classof(const ObjcCompatibleAliasDecl *D) { return true; } + +}; } // end namespace clang #endif diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index adc2425917b1..16fccb62bc2a 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -446,7 +446,12 @@ DIAG(err_undeclared_protocol, ERROR, "cannot find protocol declaration for '%0'") DIAG(err_missing_id_definition, ERROR, "cannot find definition of 'id'") - +DIAG(warn_previous_alias_decl, WARNING, + "previously declared alias is ignored") +DIAG(warn_previous_declaration, WARNING, + "previous declaration is here") +DIAG(err_conflicting_aliasing_type, ERROR, + "conflicting types for alias %0'") //===----------------------------------------------------------------------===// // Semantic Analysis diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 462192896b59..509e0a28139f 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -455,6 +455,16 @@ public: AttributeList *AttrList) { return 0; } + + /// ActOnCompatiblityAlias - this action is called after complete parsing of + /// @compaatibility_alias declaration. It sets up the alias relationships. + virtual DeclTy *ActOnCompatiblityAlias( + SourceLocation AtCompatibilityAliasLoc, + IdentifierInfo *AliasName, SourceLocation AliasLocation, + IdentifierInfo *ClassName, SourceLocation ClassLocation) { + return 0; + } + // ActOnStartProtocolInterface - this action is called immdiately after // parsing the prologue for a protocol interface. virtual DeclTy *ActOnStartProtocolInterface( diff --git a/clang/test/Parser/objc-alias-printing.m b/clang/test/Parser/objc-alias-printing.m new file mode 100644 index 000000000000..67e013f1d3db --- /dev/null +++ b/clang/test/Parser/objc-alias-printing.m @@ -0,0 +1,18 @@ +// RUN: clang -ast-print %s + +@protocol P1 @end +@protocol P2 @end + +@interface INTF @end + +@compatibility_alias alias INTF; + + +int foo () +{ + INTF *pi; + INTF *pi2; + alias *p; + alias *p2; + return pi2 == p2; +} diff --git a/clang/test/Sema/alias-test-1.m b/clang/test/Sema/alias-test-1.m new file mode 100644 index 000000000000..27ee196798fa --- /dev/null +++ b/clang/test/Sema/alias-test-1.m @@ -0,0 +1,31 @@ +// RUN: clang -fsyntax-only -verify %s + +@compatibility_alias alias4 foo; // expected-warning {{cannot find interface declaration for 'foo'}} + +@class class2; +@class class3; + +typedef int I; // expected-warning {{previous declaration is here}} + +@compatibility_alias alias1 I; // expected-warning {{cannot find interface declaration for 'I'}} + +@compatibility_alias alias class2; // expected-warning {{previous declaration is here}} +@compatibility_alias alias class3; // expected-warning {{previously declared alias is ignored}} + + +typedef int alias2; // expected-error {{previous declaration is here}} +@compatibility_alias alias2 class3; // expected-error {{conflicting types for alias alias2'}} + +alias *p; +class2 *p2; + +int foo () +{ + + if (p == p2) { + int alias = 1; + } + + alias *p3; + return p3 == p2; +}