From: Douglas Gregor Date: Thu, 18 Feb 2010 01:47:50 +0000 (+0000) Subject: AST import of Objective-C categories. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b4677b62a8e9bba0913dfe1456bd9d689cdbccac;p=clang AST import of Objective-C categories. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96551 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index cfcf460e93..cde3402f7a 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -95,6 +95,7 @@ namespace { Decl *VisitImplicitParamDecl(ImplicitParamDecl *D); Decl *VisitParmVarDecl(ParmVarDecl *D); Decl *VisitObjCMethodDecl(ObjCMethodDecl *D); + Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D); Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D); Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); Decl *VisitObjCPropertyDecl(ObjCPropertyDecl *D); @@ -2159,8 +2160,84 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { return ToMethod; } +Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { + // Import the major distinguishing characteristics of a category. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + ObjCInterfaceDecl *ToInterface + = cast_or_null(Importer.Import(D->getClassInterface())); + if (!ToInterface) + return 0; + + // Determine if we've already encountered this category. + ObjCCategoryDecl *MergeWithCategory + = ToInterface->FindCategoryDeclaration(Name.getAsIdentifierInfo()); + ObjCCategoryDecl *ToCategory = MergeWithCategory; + if (!ToCategory) { + ToCategory = ObjCCategoryDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getAtLoc()), + Loc, + Importer.Import(D->getCategoryNameLoc()), + Name.getAsIdentifierInfo()); + ToCategory->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(ToCategory); + Importer.Imported(D, ToCategory); + + // Link this category into its class's category list. + ToCategory->setClassInterface(ToInterface); + ToCategory->insertNextClassCategory(); + + // Import protocols + llvm::SmallVector Protocols; + llvm::SmallVector ProtocolLocs; + ObjCCategoryDecl::protocol_loc_iterator FromProtoLoc + = D->protocol_loc_begin(); + for (ObjCCategoryDecl::protocol_iterator FromProto = D->protocol_begin(), + FromProtoEnd = D->protocol_end(); + FromProto != FromProtoEnd; + ++FromProto, ++FromProtoLoc) { + ObjCProtocolDecl *ToProto + = cast_or_null(Importer.Import(*FromProto)); + if (!ToProto) + return 0; + Protocols.push_back(ToProto); + ProtocolLocs.push_back(Importer.Import(*FromProtoLoc)); + } + + // FIXME: If we're merging, make sure that the protocol list is the same. + ToCategory->setProtocolList(Protocols.data(), Protocols.size(), + ProtocolLocs.data(), Importer.getToContext()); + + } else { + Importer.Imported(D, ToCategory); + } + + // Import all of the members of this category. + for (DeclContext::decl_iterator FromMem = D->decls_begin(), + FromMemEnd = D->decls_end(); + FromMem != FromMemEnd; + ++FromMem) + Importer.Import(*FromMem); + + // If we have an implementation, import it as well. + if (D->getImplementation()) { + ObjCCategoryImplDecl *Impl + = cast(Importer.Import(D->getImplementation())); + if (!Impl) + return 0; + + ToCategory->setImplementation(Impl); + } + + return ToCategory; +} + Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { - // Import the major distinguishing characteristics of an @protocol. + // Import the major distinguishing characteristics of a protocol. DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; @@ -2213,7 +2290,7 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { Importer.Imported(D, ToProto); } - // Import all of the members of this class. + // Import all of the members of this protocol. for (DeclContext::decl_iterator FromMem = D->decls_begin(), FromMemEnd = D->decls_end(); FromMem != FromMemEnd; @@ -2288,8 +2365,6 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { ToIface->setProtocolList(Protocols.data(), Protocols.size(), ProtocolLocs.data(), Importer.getToContext()); - // FIXME: Import categories - // Import @end range ToIface->setAtEndRange(Importer.Import(D->getAtEndRange())); } else { @@ -2323,6 +2398,12 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { } } + // Import categories. When the categories themselves are imported, they'll + // hook themselves into this interface. + for (ObjCCategoryDecl *FromCat = D->getCategoryList(); FromCat; + FromCat = FromCat->getNextClassCategory()) + Importer.Import(FromCat); + // Import all of the members of this class. for (DeclContext::decl_iterator FromMem = D->decls_begin(), FromMemEnd = D->decls_end(); diff --git a/test/ASTMerge/Inputs/category1.m b/test/ASTMerge/Inputs/category1.m new file mode 100644 index 0000000000..ade1c6c66d --- /dev/null +++ b/test/ASTMerge/Inputs/category1.m @@ -0,0 +1,25 @@ +@interface I1 +@end + +// Matching category +@interface I1 (Cat1) +- (int)method0; +@end + +// Matching class extension +@interface I1 () +- (int)method1; +@end + +// Mismatched category +@interface I1 (Cat2) +- (int)method2; +@end + +@interface I2 +@end + +// Mismatched class extension +@interface I2 () +- (int)method3; +@end diff --git a/test/ASTMerge/Inputs/category2.m b/test/ASTMerge/Inputs/category2.m new file mode 100644 index 0000000000..f66c208680 --- /dev/null +++ b/test/ASTMerge/Inputs/category2.m @@ -0,0 +1,27 @@ +typedef int Int; + +@interface I1 +@end + +// Matching category +@interface I1 (Cat1) +- (Int)method0; +@end + +// Matching class extension +@interface I1 () +- (Int)method1; +@end + +// Mismatched category +@interface I1 (Cat2) +- (float)method2; +@end + +@interface I2 +@end + +// Mismatched class extension +@interface I2 () +- (float)method3; +@end diff --git a/test/ASTMerge/category.m b/test/ASTMerge/category.m new file mode 100644 index 0000000000..bf0d11b612 --- /dev/null +++ b/test/ASTMerge/category.m @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/category1.m +// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/category2.m +// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s + +// CHECK: category2.m:18:1: error: instance method 'method2' has incompatible result types in different translation units ('float' vs. 'int') +// CHECK: category1.m:16:1: note: instance method 'method2' also declared here +// CHECK: category2.m:26:1: error: instance method 'method3' has incompatible result types in different translation units ('float' vs. 'int') +// CHECK: category1.m:24:1: note: instance method 'method3' also declared here +// CHECK: 4 diagnostics generated.