]> granicus.if.org Git - clang/commitdiff
Extend ExternalASTSource with the ability to lazily complete the
authorDouglas Gregor <dgregor@apple.com>
Wed, 1 Dec 2010 23:49:52 +0000 (23:49 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 1 Dec 2010 23:49:52 +0000 (23:49 +0000)
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

include/clang/AST/DeclObjC.h
include/clang/AST/ExternalASTSource.h
lib/AST/DeclObjC.cpp

index 621fa9d4c08a454502deaf065249efe77fc2dfa4..16d3a103594e66c8932b72da75cebcb27186cdc8 100644 (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;
   }
index 557f8ab36c2d69e85a044c32b7cf471341ae2905..7b23766b0714632447a973e2caf30e85202a6231 100644 (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.
index 5e57cf87b9ea1324b5a63010d135d5c5c3806b9d..ea8fd4ae89dd68c364a9d9cccf84ddcc30777443 100644 (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)