Extend ExternalASTSource with the ability to lazily complete the

definition of an Objective-C class. Unlike with C/C++ classes, we
don't have a well-defined point in Sema where Objective-C classes are
checked for completeness, nor do we need to involve Sema when
completing a class. Therefore, we take the appropriate of having the
external AST source mark a particular Objective-C class as having an
external declaration; when using one of the accessors of an
Objective-C class that has an external declaration, we request that
the external AST source fill in the Objective-C class definition.

llvm-svn: 120627
This commit is contained in:
Douglas Gregor 2010-12-01 23:49:52 +00:00
parent 560befce38
commit 73693023f0
3 changed files with 86 additions and 4 deletions

View File

@ -459,7 +459,11 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
bool ForwardDecl:1; // declared with @class.
bool InternalInterface:1; // true - no @interface for @implementation
/// \brief Indicates that the contents of this Objective-C class will be
/// completed by the external AST source when required.
mutable bool ExternallyCompleted : 1;
SourceLocation ClassLoc; // location of the class identifier.
SourceLocation SuperClassLoc; // location of the super class identifier.
SourceLocation EndLoc; // marks the '>', '}', or identifier.
@ -467,6 +471,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
SourceLocation CLoc, bool FD, bool isInternal);
void LoadExternalDefinition() const;
public:
static ObjCInterfaceDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation atLoc,
@ -474,7 +479,16 @@ public:
SourceLocation ClassLoc = SourceLocation(),
bool ForwardDecl = false,
bool isInternal = false);
/// \brief Indicate that this Objective-C class is complete, but that
/// the external AST source will be responsible for filling in its contents
/// when a complete class is required.
void setExternallyCompleted();
const ObjCProtocolList &getReferencedProtocols() const {
if (ExternallyCompleted)
LoadExternalDefinition();
return ReferencedProtocols;
}
@ -494,29 +508,47 @@ public:
typedef ObjCProtocolList::iterator protocol_iterator;
protocol_iterator protocol_begin() const {
if (ExternallyCompleted)
LoadExternalDefinition();
return ReferencedProtocols.begin();
}
protocol_iterator protocol_end() const {
if (ExternallyCompleted)
LoadExternalDefinition();
return ReferencedProtocols.end();
}
typedef ObjCProtocolList::loc_iterator protocol_loc_iterator;
protocol_loc_iterator protocol_loc_begin() const {
if (ExternallyCompleted)
LoadExternalDefinition();
return ReferencedProtocols.loc_begin();
}
protocol_loc_iterator protocol_loc_end() const {
if (ExternallyCompleted)
LoadExternalDefinition();
return ReferencedProtocols.loc_end();
}
typedef ObjCList<ObjCProtocolDecl>::iterator all_protocol_iterator;
all_protocol_iterator all_referenced_protocol_begin() const {
if (ExternallyCompleted)
LoadExternalDefinition();
return AllReferencedProtocols.empty() ? protocol_begin()
: AllReferencedProtocols.begin();
}
all_protocol_iterator all_referenced_protocol_end() const {
if (ExternallyCompleted)
LoadExternalDefinition();
return AllReferencedProtocols.empty() ? protocol_end()
: AllReferencedProtocols.end();
}
@ -551,10 +583,22 @@ public:
bool isForwardDecl() const { return ForwardDecl; }
void setForwardDecl(bool val) { ForwardDecl = val; }
ObjCInterfaceDecl *getSuperClass() const { return SuperClass; }
ObjCInterfaceDecl *getSuperClass() const {
if (ExternallyCompleted)
LoadExternalDefinition();
return SuperClass;
}
void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; }
ObjCCategoryDecl* getCategoryList() const { return CategoryList; }
ObjCCategoryDecl* getCategoryList() const {
if (ExternallyCompleted)
LoadExternalDefinition();
return CategoryList;
}
void setCategoryList(ObjCCategoryDecl *category) {
CategoryList = category;
}

View File

@ -147,6 +147,14 @@ public:
/// an incomplete type.
virtual void CompleteType(TagDecl *Tag) {}
/// \brief Gives the external AST source an opportunity to complete an
/// incomplete Objective-C class.
///
/// This routine will only be invoked if the "externally completed" bit is
/// set on the ObjCInterfaceDecl via the function
/// \c ObjCInterfaceDecl::setExternallyCompleted().
virtual void CompleteType(ObjCInterfaceDecl *Class) { }
/// \brief Notify ExternalASTSource that we started deserialization of
/// a decl or type so until FinishedDeserializing is called there may be
/// decls that are initializing. Must be paired with FinishedDeserializing.

View File

@ -153,6 +153,9 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
ObjCPropertyDecl *
ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
IdentifierInfo *PropertyId) const {
if (ExternallyCompleted)
LoadExternalDefinition();
if (ObjCPropertyDecl *PD =
ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId))
return PD;
@ -171,6 +174,9 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ObjCProtocolDecl *const* ExtList, unsigned ExtNum,
ASTContext &C)
{
if (ExternallyCompleted)
LoadExternalDefinition();
if (AllReferencedProtocols.empty() && ReferencedProtocols.empty()) {
AllReferencedProtocols.set(ExtList, ExtNum, C);
return;
@ -270,6 +276,9 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
const ObjCInterfaceDecl* ClassDecl = this;
ObjCMethodDecl *MethodDecl = 0;
if (ExternallyCompleted)
LoadExternalDefinition();
while (ClassDecl != NULL) {
if ((MethodDecl = ClassDecl->getMethod(Sel, isInstance)))
return MethodDecl;
@ -443,11 +452,29 @@ ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
: ObjCContainerDecl(ObjCInterface, DC, atLoc, Id),
TypeForDecl(0), SuperClass(0),
CategoryList(0), IvarList(0),
ForwardDecl(FD), InternalInterface(isInternal),
ForwardDecl(FD), InternalInterface(isInternal), ExternallyCompleted(false),
ClassLoc(CLoc) {
}
void ObjCInterfaceDecl::LoadExternalDefinition() const {
assert(ExternallyCompleted && "Class is not externally completed");
ExternallyCompleted = false;
getASTContext().getExternalSource()->CompleteType(
const_cast<ObjCInterfaceDecl *>(this));
}
void ObjCInterfaceDecl::setExternallyCompleted() {
assert(getASTContext().getExternalSource() &&
"Class can't be externally completed without an external source");
assert(!ForwardDecl &&
"Forward declarations can't be externally completed");
ExternallyCompleted = true;
}
ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const {
if (ExternallyCompleted)
LoadExternalDefinition();
return getASTContext().getObjCImplementation(
const_cast<ObjCInterfaceDecl*>(this));
}
@ -506,6 +533,9 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
///
ObjCCategoryDecl *
ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const {
if (ExternallyCompleted)
LoadExternalDefinition();
for (ObjCCategoryDecl *Category = getCategoryList();
Category; Category = Category->getNextClassCategory())
if (Category->getIdentifier() == CategoryId)