Teach the AST importer about redeclaration chains for Objective-C

classes and protocols, implementing lazy-import semantics for both.

llvm-svn: 148816
This commit is contained in:
Douglas Gregor 2012-01-24 17:42:07 +00:00
parent 681db34eae
commit 2aa53777e7
1 changed files with 201 additions and 156 deletions

View File

@ -90,6 +90,10 @@ namespace clang {
bool ForceImport = false); bool ForceImport = false);
bool ImportDefinition(EnumDecl *From, EnumDecl *To, bool ImportDefinition(EnumDecl *From, EnumDecl *To,
bool ForceImport = false); bool ForceImport = false);
bool ImportDefinition(ObjCInterfaceDecl *From, ObjCInterfaceDecl *To,
bool ForceImport = false);
bool ImportDefinition(ObjCProtocolDecl *From, ObjCProtocolDecl *To,
bool ForceImport = false);
TemplateParameterList *ImportTemplateParameterList( TemplateParameterList *ImportTemplateParameterList(
TemplateParameterList *Params); TemplateParameterList *Params);
TemplateArgument ImportTemplateArgument(const TemplateArgument &From); TemplateArgument ImportTemplateArgument(const TemplateArgument &From);
@ -3098,7 +3102,56 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
return ToCategory; return ToCategory;
} }
bool ASTNodeImporter::ImportDefinition(ObjCProtocolDecl *From,
ObjCProtocolDecl *To,
bool ForceImport) {
if (To->getDefinition()) {
ImportDeclContext(From);
return false;
}
// Start the protocol definition
To->startDefinition();
// Import protocols
SmallVector<ObjCProtocolDecl *, 4> Protocols;
SmallVector<SourceLocation, 4> ProtocolLocs;
ObjCProtocolDecl::protocol_loc_iterator
FromProtoLoc = From->protocol_loc_begin();
for (ObjCProtocolDecl::protocol_iterator FromProto = From->protocol_begin(),
FromProtoEnd = From->protocol_end();
FromProto != FromProtoEnd;
++FromProto, ++FromProtoLoc) {
ObjCProtocolDecl *ToProto
= cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto));
if (!ToProto)
return true;
Protocols.push_back(ToProto);
ProtocolLocs.push_back(Importer.Import(*FromProtoLoc));
}
// FIXME: If we're merging, make sure that the protocol list is the same.
To->setProtocolList(Protocols.data(), Protocols.size(),
ProtocolLocs.data(), Importer.getToContext());
// Import all of the members of this protocol.
ImportDeclContext(From);
return false;
}
Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
// If this protocol has a definition in the translation unit we're coming
// from, but this particular declaration is not that definition, import the
// definition and map to that.
ObjCProtocolDecl *Definition = D->getDefinition();
if (Definition && Definition != D) {
Decl *ImportedDef = Importer.Import(Definition);
if (!ImportedDef)
return 0;
return Importer.Imported(D, ImportedDef);
}
// Import the major distinguishing characteristics of a protocol. // Import the major distinguishing characteristics of a protocol.
DeclContext *DC, *LexicalDC; DeclContext *DC, *LexicalDC;
DeclarationName Name; DeclarationName Name;
@ -3118,7 +3171,6 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
} }
ObjCProtocolDecl *ToProto = MergeWithProtocol; ObjCProtocolDecl *ToProto = MergeWithProtocol;
if (!ToProto || !ToProto->hasDefinition()) {
if (!ToProto) { if (!ToProto) {
ToProto = ObjCProtocolDecl::Create(Importer.getToContext(), DC, ToProto = ObjCProtocolDecl::Create(Importer.getToContext(), DC,
Name.getAsIdentifierInfo(), Loc, Name.getAsIdentifierInfo(), Loc,
@ -3127,42 +3179,123 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
ToProto->setLexicalDeclContext(LexicalDC); ToProto->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToProto); LexicalDC->addDeclInternal(ToProto);
} }
if (!ToProto->hasDefinition())
ToProto->startDefinition();
Importer.Imported(D, ToProto); Importer.Imported(D, ToProto);
if (D->isThisDeclarationADefinition() && ImportDefinition(D, ToProto))
return 0;
return ToProto;
}
bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From,
ObjCInterfaceDecl *To,
bool ForceImport) {
if (To->getDefinition()) {
// Check consistency of superclass.
ObjCInterfaceDecl *FromSuper = From->getSuperClass();
if (FromSuper) {
FromSuper = cast_or_null<ObjCInterfaceDecl>(Importer.Import(FromSuper));
if (!FromSuper)
return true;
}
ObjCInterfaceDecl *ToSuper = To->getSuperClass();
if ((bool)FromSuper != (bool)ToSuper ||
(FromSuper && !declaresSameEntity(FromSuper, ToSuper))) {
Importer.ToDiag(To->getLocation(),
diag::err_odr_objc_superclass_inconsistent)
<< To->getDeclName();
if (ToSuper)
Importer.ToDiag(To->getSuperClassLoc(), diag::note_odr_objc_superclass)
<< To->getSuperClass()->getDeclName();
else
Importer.ToDiag(To->getLocation(),
diag::note_odr_objc_missing_superclass);
if (From->getSuperClass())
Importer.FromDiag(From->getSuperClassLoc(),
diag::note_odr_objc_superclass)
<< From->getSuperClass()->getDeclName();
else
Importer.FromDiag(From->getLocation(),
diag::note_odr_objc_missing_superclass);
}
ImportDeclContext(From);
return false;
}
// Start the definition.
To->startDefinition();
// If this class has a superclass, import it.
if (From->getSuperClass()) {
ObjCInterfaceDecl *Super = cast_or_null<ObjCInterfaceDecl>(
Importer.Import(From->getSuperClass()));
if (!Super)
return true;
To->setSuperClass(Super);
To->setSuperClassLoc(Importer.Import(From->getSuperClassLoc()));
}
// Import protocols // Import protocols
SmallVector<ObjCProtocolDecl *, 4> Protocols; SmallVector<ObjCProtocolDecl *, 4> Protocols;
SmallVector<SourceLocation, 4> ProtocolLocs; SmallVector<SourceLocation, 4> ProtocolLocs;
ObjCProtocolDecl::protocol_loc_iterator ObjCInterfaceDecl::protocol_loc_iterator
FromProtoLoc = D->protocol_loc_begin(); FromProtoLoc = From->protocol_loc_begin();
for (ObjCProtocolDecl::protocol_iterator FromProto = D->protocol_begin(),
FromProtoEnd = D->protocol_end(); for (ObjCInterfaceDecl::protocol_iterator FromProto = From->protocol_begin(),
FromProtoEnd = From->protocol_end();
FromProto != FromProtoEnd; FromProto != FromProtoEnd;
++FromProto, ++FromProtoLoc) { ++FromProto, ++FromProtoLoc) {
ObjCProtocolDecl *ToProto ObjCProtocolDecl *ToProto
= cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto)); = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto));
if (!ToProto) if (!ToProto)
return 0; return true;
Protocols.push_back(ToProto); Protocols.push_back(ToProto);
ProtocolLocs.push_back(Importer.Import(*FromProtoLoc)); ProtocolLocs.push_back(Importer.Import(*FromProtoLoc));
} }
// FIXME: If we're merging, make sure that the protocol list is the same. // FIXME: If we're merging, make sure that the protocol list is the same.
ToProto->setProtocolList(Protocols.data(), Protocols.size(), To->setProtocolList(Protocols.data(), Protocols.size(),
ProtocolLocs.data(), Importer.getToContext()); ProtocolLocs.data(), Importer.getToContext());
} else {
Importer.Imported(D, ToProto); // Import categories. When the categories themselves are imported, they'll
// hook themselves into this interface.
for (ObjCCategoryDecl *FromCat = From->getCategoryList(); FromCat;
FromCat = FromCat->getNextClassCategory())
Importer.Import(FromCat);
// If we have an @implementation, import it as well.
if (From->getImplementation()) {
ObjCImplementationDecl *Impl = cast_or_null<ObjCImplementationDecl>(
Importer.Import(From->getImplementation()));
if (!Impl)
return true;
To->setImplementation(Impl);
} }
// Import all of the members of this protocol. // Import all of the members of this class.
ImportDeclContext(D); ImportDeclContext(From);
return ToProto; return false;
} }
Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
// If this class has a definition in the translation unit we're coming from,
// but this particular declaration is not that definition, import the
// definition and map to that.
ObjCInterfaceDecl *Definition = D->getDefinition();
if (Definition && Definition != D) {
Decl *ImportedDef = Importer.Import(Definition);
if (!ImportedDef)
return 0;
return Importer.Imported(D, ImportedDef);
}
// Import the major distinguishing characteristics of an @interface. // Import the major distinguishing characteristics of an @interface.
DeclContext *DC, *LexicalDC; DeclContext *DC, *LexicalDC;
DeclarationName Name; DeclarationName Name;
@ -3170,6 +3303,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
return 0; return 0;
// Look for an existing interface with the same name.
ObjCInterfaceDecl *MergeWithIface = 0; ObjCInterfaceDecl *MergeWithIface = 0;
llvm::SmallVector<NamedDecl *, 2> FoundDecls; llvm::SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls); DC->localUncachedLookup(Name, FoundDecls);
@ -3181,8 +3315,8 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
break; break;
} }
// Create an interface declaration, if one does not already exist.
ObjCInterfaceDecl *ToIface = MergeWithIface; ObjCInterfaceDecl *ToIface = MergeWithIface;
if (!ToIface || !ToIface->hasDefinition()) {
if (!ToIface) { if (!ToIface) {
ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC, ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getAtStartLoc()), Importer.Import(D->getAtStartLoc()),
@ -3194,114 +3328,9 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
} }
Importer.Imported(D, ToIface); Importer.Imported(D, ToIface);
if (D->hasDefinition()) { if (D->isThisDeclarationADefinition() && ImportDefinition(D, ToIface))
if (!ToIface->hasDefinition())
ToIface->startDefinition();
if (D->getSuperClass()) {
ObjCInterfaceDecl *Super
= cast_or_null<ObjCInterfaceDecl>(
Importer.Import(D->getSuperClass()));
if (!Super)
return 0; return 0;
ToIface->setSuperClass(Super);
ToIface->setSuperClassLoc(Importer.Import(D->getSuperClassLoc()));
}
// Import protocols
SmallVector<ObjCProtocolDecl *, 4> Protocols;
SmallVector<SourceLocation, 4> ProtocolLocs;
ObjCInterfaceDecl::protocol_loc_iterator
FromProtoLoc = D->protocol_loc_begin();
for (ObjCInterfaceDecl::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.
ToIface->setProtocolList(Protocols.data(), Protocols.size(),
ProtocolLocs.data(), Importer.getToContext());
}
// Import @end range
ToIface->setAtEndRange(Importer.Import(D->getAtEndRange()));
} else {
Importer.Imported(D, ToIface);
if (D->hasDefinition()) {
// Check for consistency of superclasses.
DeclarationName FromSuperName, ToSuperName;
// If the superclass hasn't been imported yet, do so before checking.
ObjCInterfaceDecl *DSuperClass = D->getSuperClass();
ObjCInterfaceDecl *ToIfaceSuperClass = ToIface->getSuperClass();
if (DSuperClass && !ToIfaceSuperClass) {
Decl *ImportedSuperClass = Importer.Import(DSuperClass);
ObjCInterfaceDecl *ImportedSuperIface
= cast<ObjCInterfaceDecl>(ImportedSuperClass);
ToIface->setSuperClass(ImportedSuperIface);
}
if (D->getSuperClass())
FromSuperName = Importer.Import(D->getSuperClass()->getDeclName());
if (ToIface->getSuperClass())
ToSuperName = ToIface->getSuperClass()->getDeclName();
if (FromSuperName != ToSuperName) {
Importer.ToDiag(ToIface->getLocation(),
diag::err_odr_objc_superclass_inconsistent)
<< ToIface->getDeclName();
if (ToIface->getSuperClass())
Importer.ToDiag(ToIface->getSuperClassLoc(),
diag::note_odr_objc_superclass)
<< ToIface->getSuperClass()->getDeclName();
else
Importer.ToDiag(ToIface->getLocation(),
diag::note_odr_objc_missing_superclass);
if (D->getSuperClass())
Importer.FromDiag(D->getSuperClassLoc(),
diag::note_odr_objc_superclass)
<< D->getSuperClass()->getDeclName();
else
Importer.FromDiag(D->getLocation(),
diag::note_odr_objc_missing_superclass);
return 0;
}
}
}
if (!D->hasDefinition())
return ToIface;
// 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.
ImportDeclContext(D);
// If we have an @implementation, import it as well.
if ( D->getImplementation()) {
ObjCImplementationDecl *Impl = cast_or_null<ObjCImplementationDecl>(
Importer.Import(D->getImplementation()));
if (!Impl)
return 0;
ToIface->setImplementation(Impl);
}
return ToIface; return ToIface;
} }
@ -4392,6 +4421,22 @@ void ASTImporter::ImportDefinition(Decl *From) {
} }
} }
if (ObjCInterfaceDecl *ToIFace = dyn_cast<ObjCInterfaceDecl>(To)) {
if (!ToIFace->getDefinition()) {
Importer.ImportDefinition(cast<ObjCInterfaceDecl>(FromDC), ToIFace,
/*ForceImport=*/true);
return;
}
}
if (ObjCProtocolDecl *ToProto = dyn_cast<ObjCProtocolDecl>(To)) {
if (!ToProto->getDefinition()) {
Importer.ImportDefinition(cast<ObjCProtocolDecl>(FromDC), ToProto,
/*ForceImport=*/true);
return;
}
}
Importer.ImportDeclContext(FromDC, true); Importer.ImportDeclContext(FromDC, true);
} }
} }