AST import of Objective-C categories.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96551 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2010-02-18 01:47:50 +00:00
Родитель afad76f613
Коммит b4677b62a8
4 изменённых файлов: 146 добавлений и 4 удалений

Просмотреть файл

@ -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<ObjCInterfaceDecl>(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<ObjCProtocolDecl *, 4> Protocols;
llvm::SmallVector<SourceLocation, 4> 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<ObjCProtocolDecl>(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<ObjCCategoryImplDecl>(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();

Просмотреть файл

@ -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

Просмотреть файл

@ -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

9
test/ASTMerge/category.m Normal file
Просмотреть файл

@ -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.