Move the definition-specific data of ObjCInterfaceDecl into a

separately-allocated DefinitionData structure, which we manage the
same way as CXXRecordDecl::DefinitionData. This prepares the way for
making ObjCInterfaceDecls redeclarable, to more accurately model
forward declarations of Objective-C classes and eliminate the mutation
of ObjCInterfaceDecl that causes us serious trouble in the AST reader.

Note that ObjCInterfaceDecl's accessors are fairly robust against
being applied to forward declarations, because Clang (and Sema in
particular) doesn't perform RequireCompleteType/hasDefinition() checks
everywhere it has to. Each of these overly-robust cases is marked with
a FIXME, which we can tackle over time.




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146644 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2011-12-15 05:27:12 +00:00
Родитель fa39f5b76b
Коммит 2e5c15be82
11 изменённых файлов: 443 добавлений и 242 удалений

Просмотреть файл

@ -545,45 +545,63 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
/// TypeDecl. It is a cache maintained by ASTContext::getObjCInterfaceType
mutable const Type *TypeForDecl;
friend class ASTContext;
struct DefinitionData {
/// Class's super class.
ObjCInterfaceDecl *SuperClass;
/// Class's super class.
ObjCInterfaceDecl *SuperClass;
/// Protocols referenced in the @interface declaration
ObjCProtocolList ReferencedProtocols;
/// Protocols referenced in the @interface declaration
ObjCProtocolList ReferencedProtocols;
/// Protocols reference in both the @interface and class extensions.
ObjCList<ObjCProtocolDecl> AllReferencedProtocols;
/// Protocols reference in both the @interface and class extensions.
ObjCList<ObjCProtocolDecl> AllReferencedProtocols;
/// \brief List of categories and class extensions defined for this class.
///
/// Categories are stored as a linked list in the AST, since the categories
/// and class extensions come long after the initial interface declaration,
/// and we avoid dynamically-resized arrays in the AST wherever possible.
ObjCCategoryDecl *CategoryList;
/// \brief List of categories and class extensions defined for this class.
///
/// Categories are stored as a linked list in the AST, since the categories
/// and class extensions come long after the initial interface declaration,
/// and we avoid dynamically-resized arrays in the AST wherever possible.
ObjCCategoryDecl *CategoryList;
/// IvarList - List of all ivars defined by this class; including class
/// extensions and implementation. This list is built lazily.
ObjCIvarDecl *IvarList;
/// IvarList - List of all ivars defined by this class; including class
/// extensions and implementation. This list is built lazily.
ObjCIvarDecl *IvarList;
/// \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 SuperClassLoc; // location of the super class identifier.
};
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
SourceLocation CLoc, bool FD, bool isInternal);
void LoadExternalDefinition() const;
/// \brief Contains a pointer to the data associated with this class,
/// which will be NULL if this class has not yet been defined.
DefinitionData *Definition;
/// \brief The location of the last location in this declaration, e.g.,
/// the '>', '}', or identifier.
/// FIXME: This seems like the wrong location to care about.
SourceLocation EndLoc;
/// \brief True if it was initially declared with @class.
/// Differs with \see ForwardDecl in that \see ForwardDecl will change to
/// false when we see the @interface, but InitiallyForwardDecl will remain
/// true.
bool InitiallyForwardDecl : 1;
bool ForwardDecl:1; // declared with @class.
/// \brief Indicates that the contents of this Objective-C class will be
/// completed by the external AST source when required.
mutable bool ExternallyCompleted : 1;
DefinitionData &data() const {
assert(Definition != 0 && "Declaration is not a definition!");
return *Definition;
}
SourceLocation SuperClassLoc; // location of the super class identifier.
SourceLocation EndLoc; // marks the '>', '}', or identifier.
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
SourceLocation CLoc, bool FD, bool isInternal);
void LoadExternalDefinition() const;
/// \brief Allocate the definition data for this class.
void allocateDefinitionData();
public:
static ObjCInterfaceDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation atLoc,
@ -604,10 +622,10 @@ public:
void setExternallyCompleted();
const ObjCProtocolList &getReferencedProtocols() const {
if (ExternallyCompleted)
if (data().ExternallyCompleted)
LoadExternalDefinition();
return ReferencedProtocols;
return data().ReferencedProtocols;
}
ObjCImplementationDecl *getImplementation() const;
@ -626,55 +644,93 @@ public:
typedef ObjCProtocolList::iterator protocol_iterator;
protocol_iterator protocol_begin() const {
if (ExternallyCompleted)
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return protocol_iterator();
if (data().ExternallyCompleted)
LoadExternalDefinition();
return ReferencedProtocols.begin();
return data().ReferencedProtocols.begin();
}
protocol_iterator protocol_end() const {
if (ExternallyCompleted)
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return protocol_iterator();
if (data().ExternallyCompleted)
LoadExternalDefinition();
return ReferencedProtocols.end();
return data().ReferencedProtocols.end();
}
typedef ObjCProtocolList::loc_iterator protocol_loc_iterator;
protocol_loc_iterator protocol_loc_begin() const {
if (ExternallyCompleted)
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return protocol_loc_iterator();
if (data().ExternallyCompleted)
LoadExternalDefinition();
return ReferencedProtocols.loc_begin();
return data().ReferencedProtocols.loc_begin();
}
protocol_loc_iterator protocol_loc_end() const {
if (ExternallyCompleted)
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return protocol_loc_iterator();
if (data().ExternallyCompleted)
LoadExternalDefinition();
return ReferencedProtocols.loc_end();
return data().ReferencedProtocols.loc_end();
}
typedef ObjCList<ObjCProtocolDecl>::iterator all_protocol_iterator;
all_protocol_iterator all_referenced_protocol_begin() const {
if (ExternallyCompleted)
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return all_protocol_iterator();
if (data().ExternallyCompleted)
LoadExternalDefinition();
return AllReferencedProtocols.empty() ? protocol_begin()
: AllReferencedProtocols.begin();
return data().AllReferencedProtocols.empty()
? protocol_begin()
: data().AllReferencedProtocols.begin();
}
all_protocol_iterator all_referenced_protocol_end() const {
if (ExternallyCompleted)
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return all_protocol_iterator();
if (data().ExternallyCompleted)
LoadExternalDefinition();
return AllReferencedProtocols.empty() ? protocol_end()
: AllReferencedProtocols.end();
return data().AllReferencedProtocols.empty()
? protocol_end()
: data().AllReferencedProtocols.end();
}
typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator;
ivar_iterator ivar_begin() const { return ivar_iterator(decls_begin()); }
ivar_iterator ivar_end() const { return ivar_iterator(decls_end()); }
ivar_iterator ivar_begin() const {
if (const ObjCInterfaceDecl *Def = getDefinition())
return ivar_iterator(Def->decls_begin());
// FIXME: Should make sure no callers ever do this.
return ivar_iterator();
}
ivar_iterator ivar_end() const {
if (const ObjCInterfaceDecl *Def = getDefinition())
return ivar_iterator(Def->decls_end());
// FIXME: Should make sure no callers ever do this.
return ivar_iterator();
}
unsigned ivar_size() const {
return std::distance(ivar_begin(), ivar_end());
@ -688,13 +744,13 @@ public:
// the ivar chain is essentially a cached property of ObjCInterfaceDecl.
return const_cast<ObjCInterfaceDecl *>(this)->all_declared_ivar_begin();
}
void setIvarList(ObjCIvarDecl *ivar) { IvarList = ivar; }
void setIvarList(ObjCIvarDecl *ivar) { data().IvarList = ivar; }
/// setProtocolList - Set the list of protocols that this interface
/// implements.
void setProtocolList(ObjCProtocolDecl *const* List, unsigned Num,
const SourceLocation *Locs, ASTContext &C) {
ReferencedProtocols.set(List, Num, Locs, C);
data().ReferencedProtocols.set(List, Num, Locs, C);
}
/// mergeClassExtensionProtocolList - Merge class extension's protocol list
@ -706,30 +762,63 @@ public:
/// \brief True if it was initially declared with @class.
/// Differs with \see isForwardDecl in that \see isForwardDecl will change to
/// false when we see the @interface, but this will remain true.
bool isInitiallyForwardDecl() const { return InitiallyForwardDecl; }
bool isForwardDecl() const { return ForwardDecl; }
void completedForwardDecl();
ObjCInterfaceDecl *getSuperClass() const {
if (ExternallyCompleted)
LoadExternalDefinition();
return SuperClass;
bool isInitiallyForwardDecl() const {
return InitiallyForwardDecl;
}
void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; }
/// \brief Determine whether this declaration is a forward declaration of
/// the class.
bool isForwardDecl() const { return Definition == 0; }
ObjCCategoryDecl* getCategoryList() const {
if (ExternallyCompleted)
/// \brief Determine whether this class has been defined.
bool hasDefinition() const { return Definition != 0; }
/// \brief Retrieve the definition of this class, or NULL if this class
/// has been forward-declared (with @class) but not yet defined (with
/// @interface).
ObjCInterfaceDecl *getDefinition() {
return hasDefinition()? this : 0;
}
/// \brief Retrieve the definition of this class, or NULL if this class
/// has been forward-declared (with @class) but not yet defined (with
/// @interface).
const ObjCInterfaceDecl *getDefinition() const {
return hasDefinition()? this : 0;
}
/// \brief Starts the definition of this Objective-C class, taking it from
/// a forward declaration (@class) to a definition (@interface).
void startDefinition();
ObjCInterfaceDecl *getSuperClass() const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
if (data().ExternallyCompleted)
LoadExternalDefinition();
return CategoryList;
return data().SuperClass;
}
void setSuperClass(ObjCInterfaceDecl * superCls) {
data().SuperClass = superCls;
}
ObjCCategoryDecl* getCategoryList() const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
if (data().ExternallyCompleted)
LoadExternalDefinition();
return data().CategoryList;
}
void setCategoryList(ObjCCategoryDecl *category) {
CategoryList = category;
data().CategoryList = category;
}
ObjCCategoryDecl* getFirstClassExtension() const;
@ -744,6 +833,7 @@ public:
while (I != NULL) {
if (declaresSameEntity(this, I))
return true;
I = I->getSuperClass();
}
return false;
@ -787,8 +877,8 @@ public:
SourceLocation getLocEnd() const { return EndLoc; }
void setLocEnd(SourceLocation LE) { EndLoc = LE; }
void setSuperClassLoc(SourceLocation Loc) { SuperClassLoc = Loc; }
SourceLocation getSuperClassLoc() const { return SuperClassLoc; }
void setSuperClassLoc(SourceLocation Loc) { data().SuperClassLoc = Loc; }
SourceLocation getSuperClassLoc() const { return data().SuperClassLoc; }
/// isImplicitInterfaceDecl - check that this is an implicitly declared
/// ObjCInterfaceDecl node. This is for legacy objective-c @implementation

Просмотреть файл

@ -329,14 +329,16 @@ private:
/// haven't been loaded yet.
DeclContextVisibleUpdatesPending PendingVisibleUpdates;
typedef SmallVector<CXXRecordDecl *, 4> ForwardRefs;
typedef llvm::DenseMap<const CXXRecordDecl *, ForwardRefs>
typedef SmallVector<Decl *, 4> ForwardRefs;
typedef llvm::DenseMap<const Decl *, ForwardRefs>
PendingForwardRefsMap;
/// \brief Forward references that have a definition but the definition decl
/// is still initializing. When the definition gets read it will update
/// the DefinitionData pointer of all pending references.
PendingForwardRefsMap PendingForwardRefs;
typedef llvm::DenseMap<serialization::DeclID, serialization::DeclID>
FirstLatestDeclIDMap;
/// \brief Map of first declarations from a chained PCH that point to the

Просмотреть файл

@ -3178,7 +3178,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
}
ObjCInterfaceDecl *ToIface = MergeWithIface;
if (!ToIface || ToIface->isForwardDecl()) {
if (!ToIface || !ToIface->hasDefinition()) {
if (!ToIface) {
ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getAtStartLoc()),
@ -3187,88 +3187,98 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
D->isImplicitInterfaceDecl());
ToIface->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToIface);
if (D->isInitiallyForwardDecl() && !D->isForwardDecl())
ToIface->completedForwardDecl();
}
Importer.Imported(D, ToIface);
if (D->getSuperClass()) {
ObjCInterfaceDecl *Super
= cast_or_null<ObjCInterfaceDecl>(Importer.Import(D->getSuperClass()));
if (!Super)
return 0;
if (D->hasDefinition()) {
if (!ToIface->hasDefinition())
ToIface->startDefinition();
ToIface->setSuperClass(Super);
ToIface->setSuperClassLoc(Importer.Import(D->getSuperClassLoc()));
if (D->getSuperClass()) {
ObjCInterfaceDecl *Super
= cast_or_null<ObjCInterfaceDecl>(
Importer.Import(D->getSuperClass()));
if (!Super)
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 protocols
SmallVector<ObjCProtocolDecl *, 4> Protocols;
SmallVector<SourceLocation, 4> ProtocolLocs;
ObjCInterfaceDecl::protocol_loc_iterator
FromProtoLoc = D->protocol_loc_begin();
// FIXME: Should we be usng all_referenced_protocol_begin() here?
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);
// 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->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(),
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)
<< D->getSuperClass()->getDeclName();
else
Importer.FromDiag(D->getLocation(),
<< ToIface->getSuperClass()->getDeclName();
else
Importer.ToDiag(ToIface->getLocation(),
diag::note_odr_objc_missing_superclass);
return 0;
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;
@ -3279,7 +3289,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
ImportDeclContext(D);
// If we have an @implementation, import it as well.
if (D->getImplementation()) {
if ( D->getImplementation()) {
ObjCImplementationDecl *Impl = cast_or_null<ObjCImplementationDecl>(
Importer.Import(D->getImplementation()));
if (!Impl)

Просмотреть файл

@ -154,7 +154,11 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
ObjCPropertyDecl *
ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
IdentifierInfo *PropertyId) const {
if (ExternallyCompleted)
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
if (data().ExternallyCompleted)
LoadExternalDefinition();
if (ObjCPropertyDecl *PD =
@ -175,11 +179,12 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ObjCProtocolDecl *const* ExtList, unsigned ExtNum,
ASTContext &C)
{
if (ExternallyCompleted)
if (data().ExternallyCompleted)
LoadExternalDefinition();
if (AllReferencedProtocols.empty() && ReferencedProtocols.empty()) {
AllReferencedProtocols.set(ExtList, ExtNum, C);
if (data().AllReferencedProtocols.empty() &&
data().ReferencedProtocols.empty()) {
data().AllReferencedProtocols.set(ExtList, ExtNum, C);
return;
}
@ -214,12 +219,16 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ProtocolRefs.push_back(*p);
}
AllReferencedProtocols.set(ProtocolRefs.data(), ProtocolRefs.size(), C);
data().AllReferencedProtocols.set(ProtocolRefs.data(), ProtocolRefs.size(),C);
}
void ObjCInterfaceDecl::completedForwardDecl() {
assert(isForwardDecl() && "Only valid to call for forward refs");
ForwardDecl = false;
void ObjCInterfaceDecl::allocateDefinitionData() {
assert(!hasDefinition() && "ObjC class already has a definition");
Definition = new (getASTContext()) DefinitionData();
}
void ObjCInterfaceDecl::startDefinition() {
allocateDefinitionData();
if (ASTMutationListener *L = getASTContext().getASTMutationListener())
L->CompletedObjCForwardRef(this);
}
@ -244,7 +253,11 @@ const ObjCCategoryDecl* ObjCCategoryDecl::getNextClassExtension() const {
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
ObjCInterfaceDecl *&clsDeclared) {
if (ExternallyCompleted)
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
if (data().ExternallyCompleted)
LoadExternalDefinition();
ObjCInterfaceDecl* ClassDecl = this;
@ -271,7 +284,11 @@ ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
/// the it returns NULL.
ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass(
const IdentifierInfo*ICName) {
if (ExternallyCompleted)
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
if (data().ExternallyCompleted)
LoadExternalDefinition();
ObjCInterfaceDecl* ClassDecl = this;
@ -287,10 +304,14 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass(
/// the class, its categories, and its super classes (using a linear search).
ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
bool isInstance) const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
const ObjCInterfaceDecl* ClassDecl = this;
ObjCMethodDecl *MethodDecl = 0;
if (ExternallyCompleted)
if (data().ExternallyCompleted)
LoadExternalDefinition();
while (ClassDecl != NULL) {
@ -328,7 +349,11 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod(
const Selector &Sel,
bool Instance) {
if (ExternallyCompleted)
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
if (data().ExternallyCompleted)
LoadExternalDefinition();
ObjCMethodDecl *Method = 0;
@ -651,16 +676,14 @@ ObjCInterfaceDecl::
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
SourceLocation CLoc, bool FD, bool isInternal)
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, atLoc),
TypeForDecl(0), SuperClass(0),
CategoryList(0), IvarList(0),
InitiallyForwardDecl(FD), ForwardDecl(FD),
ExternallyCompleted(false) {
TypeForDecl(0), Definition(), InitiallyForwardDecl(FD)
{
setImplicit(isInternal);
}
void ObjCInterfaceDecl::LoadExternalDefinition() const {
assert(ExternallyCompleted && "Class is not externally completed");
ExternallyCompleted = false;
assert(data().ExternallyCompleted && "Class is not externally completed");
data().ExternallyCompleted = false;
getASTContext().getExternalSource()->CompleteType(
const_cast<ObjCInterfaceDecl *>(this));
}
@ -668,13 +691,17 @@ void ObjCInterfaceDecl::LoadExternalDefinition() const {
void ObjCInterfaceDecl::setExternallyCompleted() {
assert(getASTContext().getExternalSource() &&
"Class can't be externally completed without an external source");
assert(!ForwardDecl &&
assert(hasDefinition() &&
"Forward declarations can't be externally completed");
ExternallyCompleted = true;
data().ExternallyCompleted = true;
}
ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const {
if (ExternallyCompleted)
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
if (data().ExternallyCompleted)
LoadExternalDefinition();
return getASTContext().getObjCImplementation(
@ -689,14 +716,18 @@ void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) {
/// its extensions and its implementation. Lazily build the list on first
/// access.
ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
if (IvarList)
return IvarList;
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
if (data().IvarList)
return data().IvarList;
ObjCIvarDecl *curIvar = 0;
if (!ivar_empty()) {
ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
IvarList = (*I); ++I;
for (curIvar = IvarList; I != E; curIvar = *I, ++I)
data().IvarList = (*I); ++I;
for (curIvar = data().IvarList; I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
}
@ -705,9 +736,9 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
if (!CDecl->ivar_empty()) {
ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(),
E = CDecl->ivar_end();
if (!IvarList) {
IvarList = (*I); ++I;
curIvar = IvarList;
if (!data().IvarList) {
data().IvarList = (*I); ++I;
curIvar = data().IvarList;
}
for ( ;I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
@ -718,15 +749,15 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
if (!ImplDecl->ivar_empty()) {
ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
E = ImplDecl->ivar_end();
if (!IvarList) {
IvarList = (*I); ++I;
curIvar = IvarList;
if (!data().IvarList) {
data().IvarList = (*I); ++I;
curIvar = data().IvarList;
}
for ( ;I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
}
}
return IvarList;
return data().IvarList;
}
/// FindCategoryDeclaration - Finds category declaration in the list of
@ -735,7 +766,7 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
///
ObjCCategoryDecl *
ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const {
if (ExternallyCompleted)
if (data().ExternallyCompleted)
LoadExternalDefinition();
for (ObjCCategoryDecl *Category = getCategoryList();
@ -770,6 +801,9 @@ ObjCMethodDecl *ObjCInterfaceDecl::getCategoryClassMethod(Selector Sel) const {
bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
bool lookupCategory,
bool RHSIsQualifiedID) {
if (!hasDefinition())
return false;
ObjCInterfaceDecl *IDecl = this;
// 1st, look up the class.
const ObjCList<ObjCProtocolDecl> &Protocols =
@ -997,9 +1031,11 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
if (IDecl) {
// Link this category into its class's category list.
CatDecl->NextClassCategory = IDecl->getCategoryList();
IDecl->setCategoryList(CatDecl);
if (ASTMutationListener *L = C.getASTMutationListener())
L->AddedObjCCategoryToInterface(CatDecl, IDecl);
if (IDecl->hasDefinition()) {
IDecl->setCategoryList(CatDecl);
if (ASTMutationListener *L = C.getASTMutationListener())
L->AddedObjCCategoryToInterface(CatDecl, IDecl);
}
}
return CatDecl;

Просмотреть файл

@ -905,6 +905,11 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
else
Out << "@interface " << I;
if (OID->isForwardDecl()) {
Out << "@end";
return;
}
// Protocols?
const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
if (!Protocols.empty()) {

Просмотреть файл

@ -4558,7 +4558,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
}
ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container);
if (!IFace)
if (!IFace || !IFace->hasDefinition())
return;
// Add methods in protocols.
@ -5783,6 +5783,9 @@ static void FindImplementableMethods(ASTContext &Context,
bool InOriginalClass = true) {
if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)) {
// Recurse into protocols.
if (!IFace->hasDefinition())
return;
const ObjCList<ObjCProtocolDecl> &Protocols
= IFace->getReferencedProtocols();
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),

Просмотреть файл

@ -368,10 +368,10 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
ObjCInterfaceDecl* IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
if (IDecl) {
// Class already seen. Is it a forward declaration?
if (!IDecl->isForwardDecl()) {
if (ObjCInterfaceDecl *Def = IDecl->getDefinition()) {
IDecl->setInvalidDecl();
Diag(AtInterfaceLoc, diag::err_duplicate_class_def)<<IDecl->getDeclName();
Diag(IDecl->getLocation(), diag::note_previous_definition);
Diag(Def->getLocation(), diag::note_previous_definition);
// Create a new one; the other may be in a different DeclContex, (e.g.
// this one may be in a LinkageSpecDecl while the other is not) which
@ -392,8 +392,6 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IDecl->setLexicalDeclContext(CurContext);
CurContext->addDecl(IDecl);
IDecl->completedForwardDecl();
if (AttrList)
ProcessDeclAttributeList(TUScope, IDecl, AttrList);
}
@ -406,6 +404,9 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
PushOnScopeChains(IDecl, TUScope);
}
if (!IDecl->hasDefinition())
IDecl->startDefinition();
if (SuperName) {
// Check if a different kind of symbol declared in this scope.
PrevDecl = LookupSingleName(TUScope, SuperName, SuperLoc,
@ -942,6 +943,7 @@ Decl *Sema::ActOnStartClassImplementation(
// copy them over.
IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
ClassName, ClassLoc, false, true);
IDecl->startDefinition();
IDecl->setSuperClass(SDecl);
IDecl->setLocEnd(ClassLoc);
@ -950,8 +952,8 @@ Decl *Sema::ActOnStartClassImplementation(
// Mark the interface as being completed, even if it was just as
// @class ....;
// declaration; the user cannot reopen it.
if (IDecl->isForwardDecl())
IDecl->completedForwardDecl();
if (!IDecl->hasDefinition())
IDecl->startDefinition();
}
ObjCImplementationDecl* IMPDecl =
@ -2540,7 +2542,9 @@ private:
void searchFrom(ObjCInterfaceDecl *iface) {
// A method in a class declaration overrides declarations from
if (!iface->hasDefinition())
return;
// - categories,
for (ObjCCategoryDecl *category = iface->getCategoryList();
category; category = category->getNextClassCategory())

Просмотреть файл

@ -512,6 +512,9 @@ ObjCMethodDecl *Sema::LookupPrivateClassMethod(Selector Sel,
ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel,
ObjCInterfaceDecl *ClassDecl) {
if (!ClassDecl->hasDefinition())
return 0;
ObjCMethodDecl *Method = 0;
while (ClassDecl && !Method) {
// If we have implementations in scope, check "private" methods.
@ -1339,12 +1342,10 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
return ExprError();
forwardClass = OCIType->getInterfaceDecl();
Method = 0;
} else {
Method = ClassDecl->lookupInstanceMethod(Sel);
}
// FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be
// faster than the following method (which can do *many* linear searches).
// The idea is to add class info to MethodPool.
Method = ClassDecl->lookupInstanceMethod(Sel);
if (!Method)
// Search protocol qualifiers.

Просмотреть файл

@ -556,43 +556,80 @@ void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) {
void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
VisitObjCContainerDecl(ID);
ID->setTypeForDecl(Reader.readType(F, Record, Idx).getTypePtrOrNull());
ID->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx));
// Read the directly referenced protocols and their SourceLocations.
unsigned NumProtocols = Record[Idx++];
SmallVector<ObjCProtocolDecl *, 16> Protocols;
Protocols.reserve(NumProtocols);
for (unsigned I = 0; I != NumProtocols; ++I)
Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
SmallVector<SourceLocation, 16> ProtoLocs;
ProtoLocs.reserve(NumProtocols);
for (unsigned I = 0; I != NumProtocols; ++I)
ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(),
Reader.getContext());
ObjCInterfaceDecl *Def = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
if (ID == Def) {
// Read the definition.
ID->allocateDefinitionData();
ObjCInterfaceDecl::DefinitionData &Data = ID->data();
// Read the superclass.
Data.SuperClass = ReadDeclAs<ObjCInterfaceDecl>(Record, Idx);
Data.SuperClassLoc = ReadSourceLocation(Record, Idx);
// Read the directly referenced protocols and their SourceLocations.
unsigned NumProtocols = Record[Idx++];
SmallVector<ObjCProtocolDecl *, 16> Protocols;
Protocols.reserve(NumProtocols);
for (unsigned I = 0; I != NumProtocols; ++I)
Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
SmallVector<SourceLocation, 16> ProtoLocs;
ProtoLocs.reserve(NumProtocols);
for (unsigned I = 0; I != NumProtocols; ++I)
ProtoLocs.push_back(ReadSourceLocation(Record, Idx));
ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(),
Reader.getContext());
// Read the transitive closure of protocols referenced by this class.
NumProtocols = Record[Idx++];
Protocols.clear();
Protocols.reserve(NumProtocols);
for (unsigned I = 0; I != NumProtocols; ++I)
Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
ID->AllReferencedProtocols.set(Protocols.data(), NumProtocols,
Reader.getContext());
// Read the transitive closure of protocols referenced by this class.
NumProtocols = Record[Idx++];
Protocols.clear();
Protocols.reserve(NumProtocols);
for (unsigned I = 0; I != NumProtocols; ++I)
Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>(Record, Idx));
ID->data().AllReferencedProtocols.set(Protocols.data(), NumProtocols,
Reader.getContext());
// Read the ivars.
unsigned NumIvars = Record[Idx++];
SmallVector<ObjCIvarDecl *, 16> IVars;
IVars.reserve(NumIvars);
for (unsigned I = 0; I != NumIvars; ++I)
IVars.push_back(ReadDeclAs<ObjCIvarDecl>(Record, Idx));
ID->setCategoryList(ReadDeclAs<ObjCCategoryDecl>(Record, Idx));
// Read the ivars.
unsigned NumIvars = Record[Idx++];
SmallVector<ObjCIvarDecl *, 16> IVars;
IVars.reserve(NumIvars);
for (unsigned I = 0; I != NumIvars; ++I)
IVars.push_back(ReadDeclAs<ObjCIvarDecl>(Record, Idx));
// Read the categories.
ID->setCategoryList(ReadDeclAs<ObjCCategoryDecl>(Record, Idx));
// We will rebuild this list lazily.
ID->setIvarList(0);
// If there are any pending forward references, make their definition data
// pointers point at the newly-allocated data.
ASTReader::PendingForwardRefsMap::iterator
FindI = Reader.PendingForwardRefs.find(ID);
if (FindI != Reader.PendingForwardRefs.end()) {
ASTReader::ForwardRefs &Refs = FindI->second;
for (ASTReader::ForwardRefs::iterator I = Refs.begin(),
E = Refs.end();
I != E; ++I)
cast<ObjCInterfaceDecl>(*I)->Definition = ID->Definition;
#ifndef NDEBUG
// We later check whether PendingForwardRefs is empty to make sure all
// pending references were linked.
Reader.PendingForwardRefs.erase(ID);
#endif
} else if (Def) {
if (Def->Definition) {
ID->Definition = Def->Definition;
} else {
// The definition is still initializing.
Reader.PendingForwardRefs[Def].push_back(ID);
}
}
}
// We will rebuild this list lazily.
ID->setIvarList(0);
ID->InitiallyForwardDecl = Record[Idx++];
ID->ForwardDecl = Record[Idx++];
ID->setSuperClassLoc(ReadSourceLocation(Record, Idx));
ID->setLocEnd(ReadSourceLocation(Record, Idx));
}
@ -972,7 +1009,7 @@ void ASTDeclReader::InitializeCXXDefinitionData(CXXRecordDecl *D,
ASTReader::ForwardRefs &Refs = FindI->second;
for (ASTReader::ForwardRefs::iterator
I = Refs.begin(), E = Refs.end(); I != E; ++I)
(*I)->DefinitionData = D->DefinitionData;
cast<CXXRecordDecl>(*I)->DefinitionData = D->DefinitionData;
#ifndef NDEBUG
// We later check whether PendingForwardRefs is empty to make sure all
// pending references were linked.

Просмотреть файл

@ -449,36 +449,46 @@ void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) {
void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
VisitObjCContainerDecl(D);
Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
Writer.AddDeclRef(D->getSuperClass(), Record);
// Write out the protocols that are directly referenced by the @interface.
Record.push_back(D->ReferencedProtocols.size());
for (ObjCInterfaceDecl::protocol_iterator P = D->protocol_begin(),
PEnd = D->protocol_end();
P != PEnd; ++P)
Writer.AddDeclRef(*P, Record);
for (ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
PLEnd = D->protocol_loc_end();
PL != PLEnd; ++PL)
Writer.AddSourceLocation(*PL, Record);
// Write out the protocols that are transitively referenced.
Record.push_back(D->AllReferencedProtocols.size());
for (ObjCList<ObjCProtocolDecl>::iterator
P = D->AllReferencedProtocols.begin(),
PEnd = D->AllReferencedProtocols.end();
P != PEnd; ++P)
Writer.AddDeclRef(*P, Record);
ObjCInterfaceDecl *Def = D->getDefinition();
Writer.AddDeclRef(Def, Record);
if (D == Def) {
// Write the DefinitionData
ObjCInterfaceDecl::DefinitionData &Data = D->data();
Writer.AddDeclRef(D->getSuperClass(), Record);
Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
// Write out the protocols that are directly referenced by the @interface.
Record.push_back(Data.ReferencedProtocols.size());
for (ObjCInterfaceDecl::protocol_iterator P = D->protocol_begin(),
PEnd = D->protocol_end();
P != PEnd; ++P)
Writer.AddDeclRef(*P, Record);
for (ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
PLEnd = D->protocol_loc_end();
PL != PLEnd; ++PL)
Writer.AddSourceLocation(*PL, Record);
// Write out the protocols that are transitively referenced.
Record.push_back(Data.AllReferencedProtocols.size());
for (ObjCList<ObjCProtocolDecl>::iterator
P = Data.AllReferencedProtocols.begin(),
PEnd = Data.AllReferencedProtocols.end();
P != PEnd; ++P)
Writer.AddDeclRef(*P, Record);
// Write out the ivars.
Record.push_back(D->ivar_size());
for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(),
IEnd = D->ivar_end(); I != IEnd; ++I)
Writer.AddDeclRef(*I, Record);
Writer.AddDeclRef(D->getCategoryList(), Record);
}
// Write out the ivars.
Record.push_back(D->ivar_size());
for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(),
IEnd = D->ivar_end(); I != IEnd; ++I)
Writer.AddDeclRef(*I, Record);
Writer.AddDeclRef(D->getCategoryList(), Record);
Record.push_back(D->isInitiallyForwardDecl());
Record.push_back(D->isForwardDecl());
Writer.AddSourceLocation(D->getSuperClassLoc(), Record);
Writer.AddSourceLocation(D->getLocEnd(), Record);
Code = serialization::DECL_OBJC_INTERFACE;
}

Просмотреть файл

@ -369,7 +369,10 @@ bool IndexingContext::handleObjCInterface(const ObjCInterfaceDecl *D) {
markEntityOccurrenceInFile(SuperD, SuperLoc);
}
ObjCProtocolListInfo ProtInfo(D->getReferencedProtocols(), *this, SA);
ObjCProtocolList EmptyProtoList;
ObjCProtocolListInfo ProtInfo(D->hasDefinition()? D->getReferencedProtocols()
: EmptyProtoList,
*this, SA);
ObjCInterfaceDeclInfo InterInfo(D);
InterInfo.ObjCProtoListInfo = ProtInfo.getListInfo();