From: Douglas Gregor Date: Wed, 1 Dec 2010 23:49:52 +0000 (+0000) Subject: Extend ExternalASTSource with the ability to lazily complete the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=26ac3f30ecef21749c00a4b1a08dd15d772dd5aa;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@120627 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 621fa9d4c0..16d3a10359 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -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::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; } diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h index 557f8ab36c..7b23766b07 100644 --- a/include/clang/AST/ExternalASTSource.h +++ b/include/clang/AST/ExternalASTSource.h @@ -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. diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 5e57cf87b9..ea8fd4ae89 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -153,6 +153,9 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { ObjCPropertyDecl * ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass( IdentifierInfo *PropertyId) const { + if (ExternallyCompleted) + LoadExternalDefinition(); + if (ObjCPropertyDecl *PD = ObjCPropertyDecl::findPropertyDecl(cast(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(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(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)