]> granicus.if.org Git - clang/commitdiff
- Make ObjCInterfaceDecl redeclarable, and create separate decl nodes for forward...
authorSebastian Redl <sebastian.redl@getdesigned.at>
Mon, 9 Aug 2010 21:55:28 +0000 (21:55 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Mon, 9 Aug 2010 21:55:28 +0000 (21:55 +0000)
- Eagerly create ObjCInterfaceTypes for declarations.
- The two above changes lead to a 0.5% increase in memory use and no speed regression when parsing Cocoa.h. On the other hand, now chained PCH works when there's a forward declaration in one PCH and the interface definition in another.
- Add HandleInterestingDecl to ASTConsumer. PCHReader passes the "interesting" decls it finds to this function instead of HandleTopLevelDecl. The default implementation forwards to HandleTopLevelDecl, but ASTUnit's handler for example ignores them. This fixes a potential crash when lazy loading of PCH data would cause ASTUnit's "top level" declaration collection to change while being iterated.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@110610 91177308-0d34-0410-b5e6-96231b3b80d8

20 files changed:
include/clang/AST/ASTConsumer.h
include/clang/AST/ASTContext.h
include/clang/AST/DeclObjC.h
include/clang/AST/Type.h
lib/AST/ASTConsumer.cpp
lib/AST/ASTContext.cpp
lib/AST/ASTImporter.cpp
lib/AST/DeclObjC.cpp
lib/AST/DeclPrinter.cpp
lib/AST/Type.cpp
lib/Frontend/ASTUnit.cpp
lib/Frontend/PCHReader.cpp
lib/Frontend/PCHReaderDecl.cpp
lib/Frontend/PCHWriter.cpp
lib/Frontend/PCHWriterDecl.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaCodeComplete.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclObjC.cpp
test/Index/TestClassDecl.m

index b01f6c6001742182b56697519ad57e93cdfa19b6..3f964ad0e9df210f5ae2b38f04454efd08153ceb 100644 (file)
@@ -49,6 +49,11 @@ public:
   /// elements). Use Decl::getNextDeclarator() to walk the chain.
   virtual void HandleTopLevelDecl(DeclGroupRef D);
 
+  /// HandleInterestingDecl - Handle the specified interesting declaration. This
+  /// is called by the PCH reader when deserializing things that might interest
+  /// the consumer. The default implementation forwards to HandleTopLevelDecl.
+  virtual void HandleInterestingDecl(DeclGroupRef D);
+
   /// HandleTranslationUnit - This method is called when the ASTs for entire
   /// translation unit have been parsed.
   virtual void HandleTranslationUnit(ASTContext &Ctx) {}
index aa1985a88853a7efbd8c0e3b017780304f156b60..31686d89c279fb3c9f92ad900857db5e885f9cfa 100644 (file)
@@ -668,7 +668,10 @@ public:
                                                   unsigned NumArgs,
                                                   const TemplateArgument *Args);
 
-  QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl);
+  /// getObjCInterfaceType - Return the unique reference to the type for the
+  /// specified ObjC interface decl.
+  QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
+                                const ObjCInterfaceDecl *PrevDecl = 0);
 
   QualType getObjCObjectType(QualType Base,
                              ObjCProtocolDecl * const *Protocols,
index 8484216521be1a664db525560e2625ec68830d5b..1fe1cf7cb43e2fb28445342c5d3514f922253259 100644 (file)
@@ -450,7 +450,10 @@ public:
 ///   Unlike C++, ObjC is a single-rooted class model. In Cocoa, classes
 ///   typically inherit from NSObject (an exception is NSProxy).
 ///
-class ObjCInterfaceDecl : public ObjCContainerDecl {
+class ObjCInterfaceDecl : public ObjCContainerDecl,
+                          public Redeclarable<ObjCInterfaceDecl> {
+  typedef Redeclarable<ObjCInterfaceDecl> redeclarable_base;
+
   /// TypeForDecl - This indicates the Type object that represents this
   /// TypeDecl.  It is a cache maintained by ASTContext::getObjCInterfaceType
   mutable Type *TypeForDecl;
@@ -474,15 +477,52 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
   SourceLocation EndLoc; // marks the '>', '}', or identifier.
 
   ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
-                    SourceLocation CLoc, bool FD, bool isInternal);
+                    SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl,
+                    bool FD, bool isInternal);
+
+protected:
+  virtual ObjCInterfaceDecl *getNextRedeclaration() {
+    return RedeclLink.getNext();
+  }
 
 public:
+  typedef redeclarable_base::redecl_iterator redecl_iterator;
+  redecl_iterator redecls_begin() const {
+    return redeclarable_base::redecls_begin();
+  }
+  redecl_iterator redecls_end() const {
+    return redeclarable_base::redecls_end();
+  }
+
   static ObjCInterfaceDecl *Create(ASTContext &C, DeclContext *DC,
                                    SourceLocation atLoc,
                                    IdentifierInfo *Id,
-                                   SourceLocation ClassLoc = SourceLocation(),
+                                   SourceLocation ClassLoc,
+                                   ObjCInterfaceDecl *PrevDecl,
                                    bool ForwardDecl = false,
                                    bool isInternal = false);
+
+  static ObjCInterfaceDecl *Create(ASTContext &C, EmptyShell Empty);
+
+  void setPreviousDeclaration(ObjCInterfaceDecl *Prev) {
+    // Adopt a type pointer if it exists.
+    TypeForDecl = Prev->TypeForDecl;
+    redeclarable_base::setPreviousDeclaration(Prev);
+  }
+
+  virtual ObjCInterfaceDecl *getCanonicalDecl() {
+    return getFirstDeclaration();
+  }
+  const ObjCInterfaceDecl *getCanonicalDecl() const {
+    return const_cast<ObjCInterfaceDecl*>(this)->getCanonicalDecl();
+  }
+
+  /// Get the interface declaration that is a definition, if there is one.
+  ObjCInterfaceDecl *getDefinition();
+  const ObjCInterfaceDecl *getDefinition() const {
+    return const_cast<ObjCInterfaceDecl*>(this)->getDefinition();
+  }
+
   const ObjCProtocolList &getReferencedProtocols() const {
     return ReferencedProtocols;
   }
@@ -535,6 +575,7 @@ public:
                                        ASTContext &C);
 
   bool isForwardDecl() const { return ForwardDecl; }
+  bool isDefinition() const { return !ForwardDecl; }
   void setForwardDecl(bool val) { ForwardDecl = val; }
 
   ObjCInterfaceDecl *getSuperClass() const { return SuperClass; }
index 7a522f42fa33f530c9fecabe6d09bbcb07a0b341..6c4ad893b44f29daced1be4624ebc875cb2f5acc 100644 (file)
@@ -3038,7 +3038,7 @@ class ObjCInterfaceType : public ObjCObjectType {
   friend class ASTContext;  // ASTContext creates these.
 public:
   /// getDecl - Get the declaration of this interface.
-  ObjCInterfaceDecl *getDecl() const { return Decl; }
+  ObjCInterfaceDecl *getDecl() const;
 
   bool isSugared() const { return false; }
   QualType desugar() const { return QualType(this, 0); }
index f37cbdea54808f32984aac4b3e0dd4c1d809f53d..04a084a06a44029eb9d0057581b2be84c4714e98 100644 (file)
@@ -17,3 +17,6 @@ using namespace clang;
 
 void ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) {}
 
+void ASTConsumer::HandleInterestingDecl(DeclGroupRef D) {
+  HandleTopLevelDecl(D);
+}
index 7d159269c1be8c8c6046dd1499b7d07f9605c737..83cee5cc7838a48ac87b3c2acb3474e0f693f62e 100644 (file)
@@ -872,7 +872,7 @@ void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI,
 /// CollectNonClassIvars -
 /// This routine collects all other ivars which are not declared in the class.
 /// This includes synthesized ivars (via @synthesize) and those in
-//  class's @implementation.
+/// class's @implementation.
 ///
 void ASTContext::CollectNonClassIvars(const ObjCInterfaceDecl *OI,
                                 llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
@@ -2212,18 +2212,24 @@ QualType ASTContext::getObjCObjectPointerType(QualType ObjectT) {
   return QualType(QType, 0);
 }
 
-/// getObjCInterfaceType - Return the unique reference to the type for the
-/// specified ObjC interface decl. The list of protocols is optional.
-QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) {
-  if (Decl->TypeForDecl)
-    return QualType(Decl->TypeForDecl, 0);
+QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
+                                          const ObjCInterfaceDecl *PrevDecl) {
+  assert(Decl && "Passed null for Decl param");
 
-  // FIXME: redeclarations?
-  void *Mem = Allocate(sizeof(ObjCInterfaceType), TypeAlignment);
-  ObjCInterfaceType *T = new (Mem) ObjCInterfaceType(Decl);
-  Decl->TypeForDecl = T;
-  Types.push_back(T);
-  return QualType(T, 0);
+  if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
+
+  if (PrevDecl) {
+    assert(PrevDecl->TypeForDecl && "previous decl has no TypeForDecl");
+    Decl->TypeForDecl = PrevDecl->TypeForDecl;
+    return QualType(PrevDecl->TypeForDecl, 0);
+  }
+
+  assert(!Decl->getPreviousDeclaration() &&
+         "interface has previous declaration");
+
+  Decl->TypeForDecl = new (*this, TypeAlignment) ObjCInterfaceType(Decl);
+  Types.push_back(Decl->TypeForDecl);
+  return QualType(Decl->TypeForDecl, 0);
 }
 
 /// getTypeOfExprType - Unlike many "get<Type>" functions, we can't unique
index 5e8586f2a06985658bce87239eee0ea38cdd321e..6242d400419cd7062f6857e03dbbc9b6f10c32b5 100644 (file)
@@ -2467,6 +2467,18 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
 }
 
 Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+  // If this interface 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.
   DeclContext *DC, *LexicalDC;
   DeclarationName Name;
@@ -2491,7 +2503,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
       ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(),
                                           DC, Loc,
                                           Name.getAsIdentifierInfo(),
-                                          Importer.Import(D->getClassLoc()),
+                                          Importer.Import(D->getClassLoc()), 0,
                                           D->isForwardDecl(),
                                           D->isImplicitInterfaceDecl());
       ToIface->setForwardDecl(D->isForwardDecl());
index 32f9433d9a8a2a382ea1c9466ee01e0d6adcb41f..0720b203d62bfdd9f5664b615d0b21c2f165414c 100644 (file)
@@ -45,6 +45,14 @@ void ObjCProtocolList::set(ObjCProtocolDecl* const* InList, unsigned Elts,
 // ObjCInterfaceDecl
 //===----------------------------------------------------------------------===//
 
+ObjCInterfaceDecl *ObjCInterfaceDecl::getDefinition() {
+  for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+    if (I->isDefinition())
+      return *I;
+  }
+  return 0;
+}
+
 /// getIvarDecl - This method looks up an ivar in this ContextDecl.
 ///
 ObjCIvarDecl *
@@ -432,18 +440,30 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(ASTContext &C,
                                              SourceLocation atLoc,
                                              IdentifierInfo *Id,
                                              SourceLocation ClassLoc,
+                                             ObjCInterfaceDecl *PrevDecl,
                                              bool ForwardDecl, bool isInternal){
-  return new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc, ForwardDecl,
-                                     isInternal);
+  ObjCInterfaceDecl *D = new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc,
+                                                   PrevDecl, ForwardDecl,
+                                                   isInternal);
+  C.getObjCInterfaceType(D, PrevDecl);
+  return D;
+}
+
+ObjCInterfaceDecl *ObjCInterfaceDecl::Create(ASTContext &C, EmptyShell) {
+  return new (C) ObjCInterfaceDecl(0, SourceLocation(), 0, SourceLocation(),
+                                   0, false, false);
 }
 
 ObjCInterfaceDecl::
 ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
-                  SourceLocation CLoc, bool FD, bool isInternal)
+                  SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl,
+                  bool FD, bool isInternal)
   : ObjCContainerDecl(ObjCInterface, DC, atLoc, Id),
     TypeForDecl(0), SuperClass(0),
     CategoryList(0), ForwardDecl(FD), InternalInterface(isInternal),
     ClassLoc(CLoc) {
+  if (PrevDecl)
+    setPreviousDeclaration(PrevDecl);
 }
 
 ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const {
index fae1e724a1750a48333d13bac292ea1cb9ebeb57..d3ebc8f508ed9cf345f36990ed65164adcc15a00 100644 (file)
@@ -727,12 +727,19 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
 
 void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
   std::string I = OID->getNameAsString();
+
+  if (OID->isForwardDecl()) {
+    // These shouldn't be directly visited, but in case they are, write them
+    // as an @class declaration.
+    Out << "@class " << I;
+    return;
+  }
+
   ObjCInterfaceDecl *SID = OID->getSuperClass();
 
+  Out << "@interface " << I;
   if (SID)
-    Out << "@interface " << I << " : " << SID;
-  else
-    Out << "@interface " << I;
+    Out << " : " << SID;
 
   // Protocols?
   const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
index 31af6fb6619d98b887aa3478bdbf9f8cb4362a8f..4f884989ae2f678122633c5700944340ebc51872 100644 (file)
@@ -360,6 +360,17 @@ const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
   return 0;
 }
 
+ObjCInterfaceDecl *ObjCInterfaceType::getDecl() const {
+  for (ObjCInterfaceDecl::redecl_iterator I = Decl->redecls_begin(),
+                                          E = Decl->redecls_end();
+       I != E; ++I) {
+    if (I->isDefinition())
+      return *I;
+  }
+  // If we can't find a definition, return whatever we have.
+  return Decl;
+}
+
 const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const {
   if (const PointerType *PT = getAs<PointerType>())
     if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>())
index b287522806ed1ee8e7f0160124b4e3b576447702..cd78abdaeb88c600ee231a7ecd13720f43b16575 100644 (file)
@@ -320,6 +320,9 @@ public:
       Unit.addTopLevelDecl(D);
     }
   }
+
+  // We're not interested in "interesting" decls.
+  void HandleInterestingDecl(DeclGroupRef) {}
 };
 
 class TopLevelDeclTrackerAction : public ASTFrontendAction {
index 1bfc138d4fb9f9a8cacb02146554b9f5818561ce..68acbb2faf93f3611efe9893a4ac19152d72f998 100644 (file)
@@ -2262,7 +2262,7 @@ QualType PCHReader::ReadTypeRecord(unsigned Index) {
   SavedStreamPosition SavedPosition(DeclsCursor);
 
   ReadingKindTracker ReadingKind(Read_Type, *this);
-  
+
   // Note that we are loading a type record.
   Deserializing AType(this);
 
@@ -3027,7 +3027,7 @@ void PCHReader::PassInterestingDeclsToConsumer() {
   while (!InterestingDecls.empty()) {
     DeclGroupRef DG(InterestingDecls.front());
     InterestingDecls.pop_front();
-    Consumer->HandleTopLevelDecl(DG);
+    Consumer->HandleInterestingDecl(DG);
   }
 }
 
index 7aab7b7557c2a74270a27445799c19c944e5232c..2930ca73b9aea669aa59b318f44e642beb084d86 100644 (file)
@@ -34,7 +34,7 @@ namespace clang {
     const pch::DeclID ThisDeclID;
     const PCHReader::RecordData &Record;
     unsigned &Idx;
-    pch::TypeID TypeIDForTypeDecl;
+    pch::TypeID TypeIDForDecl;
 
     uint64_t GetCurrentCursorOffset();
 
@@ -43,7 +43,7 @@ namespace clang {
                   pch::DeclID thisDeclID, const PCHReader::RecordData &Record,
                   unsigned &Idx)
       : Reader(Reader), Cursor(Cursor), ThisDeclID(thisDeclID), Record(Record),
-        Idx(Idx), TypeIDForTypeDecl(0) { }
+        Idx(Idx), TypeIDForDecl(0) { }
 
     void Visit(Decl *D);
 
@@ -132,9 +132,11 @@ uint64_t PCHDeclReader::GetCurrentCursorOffset() {
 void PCHDeclReader::Visit(Decl *D) {
   DeclVisitor<PCHDeclReader, void>::Visit(D);
 
+  // if we have a fully initialized Decl, we can safely read its type now.
   if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
-    // if we have a fully initialized TypeDecl, we can safely read its type now.
-    TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtr());
+    TD->setTypeForDecl(Reader.GetType(TypeIDForDecl).getTypePtr());
+  } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
+    ID->setTypeForDecl(Reader.GetType(TypeIDForDecl).getTypePtr());
   } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
     // FunctionDecl's body was written last after all other Stmts/Exprs.
     if (Record[Idx++])
@@ -170,7 +172,7 @@ void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) {
 void PCHDeclReader::VisitTypeDecl(TypeDecl *TD) {
   VisitNamedDecl(TD);
   // Delay type reading until after we have fully initialized the decl.
-  TypeIDForTypeDecl = Record[Idx++];
+  TypeIDForDecl = Record[Idx++];
 }
 
 void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) {
@@ -367,7 +369,11 @@ void PCHDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
 
 void PCHDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
   VisitObjCContainerDecl(ID);
-  ID->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr());
+  ID->setForwardDecl(Record[Idx++]);
+  ID->setImplicitInterfaceDecl(Record[Idx++]);
+  VisitRedeclarable(ID);
+  // Must delay type reading until the redecl chain is complete.
+  TypeIDForDecl = Record[Idx++];
   ID->setSuperClass(cast_or_null<ObjCInterfaceDecl>
                        (Reader.GetDecl(Record[Idx++])));
   unsigned NumProtocols = Record[Idx++];
@@ -388,8 +394,6 @@ void PCHDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
     IVars.push_back(cast<ObjCIvarDecl>(Reader.GetDecl(Record[Idx++])));
   ID->setCategoryList(
                cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++])));
-  ID->setForwardDecl(Record[Idx++]);
-  ID->setImplicitInterfaceDecl(Record[Idx++]);
   ID->setClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
   ID->setSuperClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
   ID->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++]));
@@ -1459,7 +1463,7 @@ Decl *PCHReader::ReadDeclRecord(unsigned Index, pch::DeclID ID) {
                                Selector(), QualType(), 0, 0);
     break;
   case pch::DECL_OBJC_INTERFACE:
-    D = ObjCInterfaceDecl::Create(*Context, 0, SourceLocation(), 0);
+    D = ObjCInterfaceDecl::Create(*Context, Decl::EmptyShell());
     break;
   case pch::DECL_OBJC_IVAR:
     D = ObjCIvarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0,
index 0eed4ccd71ef2faf45f2a5c707c19fa167aa5d41..990641294af964097b54a027b5b3511240a191ce 100644 (file)
@@ -305,7 +305,9 @@ void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
 }
 
 void PCHTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
-  Writer.AddDeclRef(T->getDecl(), Record);
+  // The stored declaration must be the first, but getDecl() returns the
+  // definition.
+  Writer.AddDeclRef(T->getDecl()->getFirstDeclaration(), Record);
   Code = pch::TYPE_OBJC_INTERFACE;
 }
 
index a509ed1dce956c764a5acd3a7d3d4602034ff6f4..9917ad6419415a67a0c33437d501e8d3e7260ba3 100644 (file)
@@ -340,6 +340,9 @@ void PCHDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
 
 void PCHDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
   VisitObjCContainerDecl(D);
+  Record.push_back(D->isForwardDecl());
+  Record.push_back(D->isImplicitInterfaceDecl());
+  VisitRedeclarable(D);
   Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
   Writer.AddDeclRef(D->getSuperClass(), Record);
   Record.push_back(D->protocol_size());
@@ -356,8 +359,6 @@ void PCHDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
                                      IEnd = D->ivar_end(); I != IEnd; ++I)
     Writer.AddDeclRef(*I, Record);
   Writer.AddDeclRef(D->getCategoryList(), Record);
-  Record.push_back(D->isForwardDecl());
-  Record.push_back(D->isImplicitInterfaceDecl());
   Writer.AddSourceLocation(D->getClassLoc(), Record);
   Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
   Writer.AddSourceLocation(D->getLocEnd(), Record);
index aeb4db987db5de6776245836691deeaa18a1352a..11d7a9191f1029a43215c8ebb7aed6012194cc38 100644 (file)
@@ -89,7 +89,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
     ObjCInterfaceDecl *ProtocolDecl =
       ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(),
                                 &Context.Idents.get("Protocol"),
-                                SourceLocation(), true);
+                                SourceLocation(), 0, true);
     Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));
     PushOnScopeChains(ProtocolDecl, TUScope, false);
   }
index 52ac8dd64987cbf2ec4d68050af499ed15f518c4..f12e1839e55cf385ea05af93d0653a3b8fd96da3 100644 (file)
@@ -3748,20 +3748,28 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext,
   for (DeclContext::decl_iterator D = Ctx->decls_begin(), 
                                DEnd = Ctx->decls_end();
        D != DEnd; ++D) {
-    // Record any interfaces we find.
-    if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*D))
-      if ((!OnlyForwardDeclarations || Class->isForwardDecl()) &&
-          (!OnlyUnimplemented || !Class->getImplementation()))
-        Results.AddResult(Result(Class, 0), CurContext, 0, false);
+    // Record any interfaces we find. Forward declarations are never registered
+    // in the lexical contest, so if we're only looking for those, don't bother.
+    if (!OnlyForwardDeclarations)
+      if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*D))
+        if (!OnlyUnimplemented || !Class->getImplementation())
+          Results.AddResult(Result(Class, 0), CurContext, 0, false);
 
     // Record any forward-declared interfaces we find.
     if (ObjCClassDecl *Forward = dyn_cast<ObjCClassDecl>(*D)) {
       for (ObjCClassDecl::iterator C = Forward->begin(), CEnd = Forward->end();
-           C != CEnd; ++C)
-        if ((!OnlyForwardDeclarations || C->getInterface()->isForwardDecl()) &&
-            (!OnlyUnimplemented || !C->getInterface()->getImplementation()))
-          Results.AddResult(Result(C->getInterface(), 0), CurContext,
+           C != CEnd; ++C) {
+        ObjCInterfaceDecl *IDecl = C->getInterface();
+        ObjCInterfaceDecl *IDef = IDecl->getDefinition();
+        // If there's a definition, and we're looking for everything, then we
+        // already added the decl in question above.
+        if (!OnlyForwardDeclarations && !OnlyUnimplemented && IDef)
+          continue;
+        if ((!OnlyForwardDeclarations || !IDef) &&
+            (!OnlyUnimplemented || !IDef || !IDef->getImplementation()))
+          Results.AddResult(Result(IDecl, 0), CurContext,
                             0, false);
+      }
     }
   }
 }
index 200b8fd681086eca05e684b935010127db94c4a3..e6c5170357caf2991f3e18d7f8f75c57ae1a8ec5 100644 (file)
@@ -606,45 +606,6 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
   }
 }
 
-/// \brief Look for an Objective-C class in the translation unit.
-///
-/// \param Id The name of the Objective-C class we're looking for. If
-/// typo-correction fixes this name, the Id will be updated
-/// to the fixed name.
-///
-/// \param IdLoc The location of the name in the translation unit.
-///
-/// \param TypoCorrection If true, this routine will attempt typo correction
-/// if there is no class with the given name.
-///
-/// \returns The declaration of the named Objective-C class, or NULL if the
-/// class could not be found.
-ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
-                                              SourceLocation IdLoc,
-                                              bool TypoCorrection) {
-  // The third "scope" argument is 0 since we aren't enabling lazy built-in
-  // creation from this context.
-  NamedDecl *IDecl = LookupSingleName(TUScope, Id, IdLoc, LookupOrdinaryName);
-
-  if (!IDecl && TypoCorrection) {
-    // Perform typo correction at the given location, but only if we
-    // find an Objective-C class name.
-    LookupResult R(*this, Id, IdLoc, LookupOrdinaryName);
-    if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
-        (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
-      Diag(IdLoc, diag::err_undef_interface_suggest)
-        << Id << IDecl->getDeclName() 
-        << FixItHint::CreateReplacement(IdLoc, IDecl->getNameAsString());
-      Diag(IDecl->getLocation(), diag::note_previous_decl)
-        << IDecl->getDeclName();
-      
-      Id = IDecl->getIdentifier();
-    }
-  }
-
-  return dyn_cast_or_null<ObjCInterfaceDecl>(IDecl);
-}
-
 /// getNonFieldDeclScope - Retrieves the innermost scope, starting
 /// from S, where a non-field would be declared. This routine copes
 /// with the difference between C and C++ scoping rules in structs and
index 9e0d250536ff7c648f91535d5b34ba62346f08ab..283376bfde9104c86619717636e1120989caa0f4 100644 (file)
 #include "clang/Parse/DeclSpec.h"
 using namespace clang;
 
+/// \brief Look for an Objective-C class in the translation unit.
+///
+/// \param Id The name of the Objective-C class we're looking for. If
+/// typo-correction fixes this name, the Id will be updated
+/// to the fixed name.
+///
+/// \param IdLoc The location of the name in the translation unit.
+///
+/// \param TypoCorrection If true, this routine will attempt typo correction
+/// if there is no class with the given name.
+///
+/// \returns The declaration of the named Objective-C class, which is also the
+/// definition if one is available, or NULL if the class could not be found.
+ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
+                                              SourceLocation IdLoc,
+                                              bool TypoCorrection) {
+  // The third "scope" argument is 0 since we aren't enabling lazy built-in
+  // creation from this context.
+  NamedDecl *Decl = LookupSingleName(TUScope, Id, IdLoc, LookupOrdinaryName);
+
+  if (!Decl && TypoCorrection) {
+    // Perform typo correction at the given location, but only if we
+    // find an Objective-C class name.
+    LookupResult R(*this, Id, IdLoc, LookupOrdinaryName);
+    if (CorrectTypo(R, TUScope, 0, 0, false, CTC_NoKeywords) &&
+        (Decl = R.getAsSingle<ObjCInterfaceDecl>())) {
+      Diag(IdLoc, diag::err_undef_interface_suggest)
+        << Id << Decl->getDeclName() 
+        << FixItHint::CreateReplacement(IdLoc, Decl->getNameAsString());
+      Diag(Decl->getLocation(), diag::note_previous_decl)
+        << Decl->getDeclName();
+
+      Id = Decl->getIdentifier();
+    }
+  }
+
+  ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(Decl);
+  if (IDecl) {
+    if (ObjCInterfaceDecl *Def = IDecl->getDefinition())
+      IDecl = Def;
+  }
+  return IDecl;
+}
+
 /// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible
 /// and user declared, in the method definition's AST.
 void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) {
@@ -65,6 +109,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
                          SourceLocation EndProtoLoc, AttributeList *AttrList) {
   assert(ClassName && "Missing class identifier");
 
+  bool Invalid = false;
+
   // Check for another declaration kind with the same name.
   NamedDecl *PrevDecl = LookupSingleName(TUScope, ClassName, ClassLoc,
                                          LookupOrdinaryName, ForRedeclaration);
@@ -72,42 +118,35 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
   if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
     Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
     Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+    // Set the new decl invalid and ignore the old.
+    Invalid = true;
+    PrevDecl = 0;
   }
 
-  ObjCInterfaceDecl* IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
-  if (IDecl) {
+  ObjCInterfaceDecl *ODecl = cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+  if (ODecl) {
     // Class already seen. Is it a forward declaration?
-    if (!IDecl->isForwardDecl()) {
-      IDecl->setInvalidDecl();
-      Diag(AtInterfaceLoc, diag::err_duplicate_class_def)<<IDecl->getDeclName();
-      Diag(IDecl->getLocation(), diag::note_previous_definition);
+    if (ObjCInterfaceDecl *Def = ODecl->getDefinition()) {
+      Invalid = true;
+      Diag(AtInterfaceLoc, diag::err_duplicate_class_def) << Def->getDeclName();
+      Diag(Def->getLocation(), diag::note_previous_definition);
 
-      // Return the previous class interface.
-      // FIXME: don't leak the objects passed in!
-      return DeclPtrTy::make(IDecl);
-    } else {
-      IDecl->setLocation(AtInterfaceLoc);
-      IDecl->setForwardDecl(false);
-      IDecl->setClassLoc(ClassLoc);
-      
-      // Since this ObjCInterfaceDecl was created by a forward declaration,
-      // we now add it to the DeclContext since it wasn't added before
-      // (see ActOnForwardClassDeclaration).
-      IDecl->setLexicalDeclContext(CurContext);
-      CurContext->addDecl(IDecl);
-      
-      if (AttrList)
-        ProcessDeclAttributeList(TUScope, IDecl, AttrList);
+      // Return the previous class interface and ignore the new one.
+      return DeclPtrTy::make(ODecl);
     }
-  } else {
-    IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc,
-                                      ClassName, ClassLoc);
-    if (AttrList)
-      ProcessDeclAttributeList(TUScope, IDecl, AttrList);
-
-    PushOnScopeChains(IDecl, TUScope);
   }
 
+  ObjCInterfaceDecl *IDecl =
+      ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc,
+                                ClassName, ClassLoc, ODecl);
+  if (Invalid)
+    IDecl->setInvalidDecl();
+
+  if (AttrList)
+    ProcessDeclAttributeList(TUScope, IDecl, AttrList);
+
+  PushOnScopeChains(IDecl, TUScope);
+
   if (SuperName) {
     // Check if a different kind of symbol declared in this scope.
     PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc,
@@ -125,6 +164,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
       }
     }
 
+    // Since we just pushed IDecl on the scope chain, if PrevDecl is the same
+    // class, it will be the same declaration.
     if (PrevDecl == IDecl) {
       Diag(SuperLoc, diag::err_recursive_superclass)
         << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc);
@@ -140,11 +181,11 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
       if (PrevDecl && SuperClassDecl == 0) {
         // The previous declaration was not a class decl. Check if we have a
         // typedef. If we do, get the underlying class type.
-        if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(PrevDecl)) {
+        if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(PrevDecl)){
           QualType T = TDecl->getUnderlyingType();
           if (T->isObjCObjectType()) {
-            if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface())
-              SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl);
+            if (NamedDecl *NDecl = T->getAs<ObjCObjectType>()->getInterface())
+              SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(NDecl);
           }
         }
 
@@ -159,6 +200,11 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
         }
       }
 
+      if (SuperClassDecl) {
+        if (ObjCInterfaceDecl *Def = SuperClassDecl->getDefinition())
+          SuperClassDecl = Def;
+      }
+
       if (!dyn_cast_or_null<TypedefDecl>(PrevDecl)) {
         if (!SuperClassDecl)
           Diag(SuperLoc, diag::err_undef_superclass)
@@ -530,7 +576,7 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
                       IdentifierInfo *ClassName, SourceLocation ClassLoc,
                       IdentifierInfo *SuperClassname,
                       SourceLocation SuperClassLoc) {
-  ObjCInterfaceDecl* IDecl = 0;
+  ObjCInterfaceDecl *IDecl = 0, *ODecl = 0;
   // Check for another declaration kind with the same name.
   NamedDecl *PrevDecl
     = LookupSingleName(TUScope, ClassName, ClassLoc, LookupOrdinaryName,
@@ -538,11 +584,10 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
   if (PrevDecl && !isa<ObjCInterfaceDecl>(PrevDecl)) {
     Diag(ClassLoc, diag::err_redefinition_different_kind) << ClassName;
     Diag(PrevDecl->getLocation(), diag::note_previous_definition);
-  } else if ((IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl))) {
-    // If this is a forward declaration of an interface, warn.
-    if (IDecl->isForwardDecl()) {
+  } else if ((ODecl = cast_or_null<ObjCInterfaceDecl>(PrevDecl))) {
+    // If we can't find a definition of the interface, warn.
+    if (!(IDecl = ODecl->getDefinition())) {
       Diag(ClassLoc, diag::warn_undef_interface) << ClassName;
-      IDecl = 0;
     }
   } else {
     // We did not find anything with the name ClassName; try to correct for 
@@ -552,7 +597,7 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
         (IDecl = R.getAsSingle<ObjCInterfaceDecl>())) {
       // Suggest the (potentially) correct interface name. However, put the
       // fix-it hint itself in a separate note, since changing the name in 
-      // the warning would make the fix-it change semantics.However, don't
+      // the warning would make the fix-it change semantics. Also, don't
       // provide a code-modification hint or use the typo name for recovery,
       // because this is just a warning. The program may actually be correct.
       Diag(ClassLoc, diag::warn_undef_interface_suggest)
@@ -599,16 +644,11 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
     // FIXME: Do we support attributes on the @implementation? If so we should
     // copy them over.
     IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
-                                      ClassName, ClassLoc, false, true);
+                                      ClassName, ClassLoc, ODecl, false, true);
     IDecl->setSuperClass(SDecl);
     IDecl->setLocEnd(ClassLoc);
 
     PushOnScopeChains(IDecl, TUScope);
-  } else {
-    // Mark the interface as being completed, even if it was just as
-    //   @class ....;
-    // declaration; the user cannot reopen it.
-    IDecl->setForwardDecl(false);
   }
 
   ObjCImplementationDecl* IMPDecl =
@@ -619,15 +659,15 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation(
     return DeclPtrTy::make(IMPDecl);
 
   // Check that there is no duplicate implementation of this class.
-  if (IDecl->getImplementation()) {
-    // FIXME: Don't leak everything!
+  if (IDecl && IDecl->getImplementation()) {
     Diag(ClassLoc, diag::err_dup_implementation_class) << ClassName;
     Diag(IDecl->getImplementation()->getLocation(),
          diag::note_previous_definition);
-  } else { // add it to the list.
+  } else {
     IDecl->setImplementation(IMPDecl);
     PushOnScopeChains(IMPDecl, TUScope);
   }
+
   return DeclPtrTy::make(IMPDecl);
 }
 
@@ -1029,19 +1069,18 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
           PrevDecl = OI->getInterface();
       }
     }
-    ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
-    if (!IDecl) {  // Not already seen?  Make a forward decl.
-      IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
-                                        IdentList[i], IdentLocs[i], true);
-      
-      // Push the ObjCInterfaceDecl on the scope chain but do *not* add it to
-      // the current DeclContext.  This prevents clients that walk DeclContext
-      // from seeing the imaginary ObjCInterfaceDecl until it is actually
-      // declared later (if at all).  We also take care to explicitly make
-      // sure this declaration is visible for name lookup.
-      PushOnScopeChains(IDecl, TUScope, false);
-      CurContext->makeDeclVisibleInContext(IDecl, true);
-    }
+    ObjCInterfaceDecl *ODecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
+    ObjCInterfaceDecl *IDecl =
+        ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
+                                  IdentList[i], IdentLocs[i], ODecl, true);
+
+    // Push the ObjCInterfaceDecl on the scope chain but do *not* add it to
+    // the current DeclContext.  This prevents clients that walk DeclContext
+    // from seeing the imaginary ObjCInterfaceDecl until it is actually
+    // declared later (if at all).  We also take care to explicitly make
+    // sure this declaration is visible for name lookup.
+    PushOnScopeChains(IDecl, TUScope, false);
+    CurContext->makeDeclVisibleInContext(IDecl, true);
 
     Interfaces.push_back(IDecl);
   }
index b55c8623a514bccb5b96db3f5e930fb9eaf1e4ba..1f2e91e8da2211a50f19e0011a4716e9dc22fdd7 100644 (file)
@@ -17,7 +17,7 @@ void function(Foo * arg)
 
 // CHECK-scan: [1:1 - 8:1] Invalid Cursor => NoDeclFound
 // CHECK-scan: [8:1 - 8:8] UnexposedDecl=:8:1
-// CHECK-scan: [8:8 - 8:11] ObjCClassRef=Foo:10:12
+// CHECK-scan: [8:8 - 8:11] ObjCClassRef=Foo:8:8
 // CHECK-scan: [8:11 - 10:1] Invalid Cursor => NoDeclFound
 // CHECK-scan: [10:1 - 11:5] ObjCInterfaceDecl=Foo:10:12
 // CHECK-scan: [11:5 - 13:6] Invalid Cursor => NoDeclFound