Keep track of all declarations of an Objective-C class (both forward

declarations and definitions) as ObjCInterfaceDecls within the same
redeclaration chain. This new representation matches what we do for
C/C++ variables/functions/classes/templates/etc., and makes it
possible to answer the query "where are all of the declarations of
this class?"

llvm-svn: 146679
This commit is contained in:
Douglas Gregor 2011-12-15 20:29:51 +00:00
parent 918f976e66
commit dc9166c8e1
21 changed files with 117 additions and 132 deletions

View File

@ -583,7 +583,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
}; };
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
SourceLocation CLoc, bool FD, bool isInternal); SourceLocation CLoc, bool isInternal);
void LoadExternalDefinition() const; void LoadExternalDefinition() const;
@ -596,12 +596,6 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
/// FIXME: This seems like the wrong location to care about. /// FIXME: This seems like the wrong location to care about.
SourceLocation EndLoc; 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;
DefinitionData &data() const { DefinitionData &data() const {
assert(Data != 0 && "Declaration has no definition!"); assert(Data != 0 && "Declaration has no definition!");
return *Data; return *Data;
@ -620,13 +614,13 @@ public:
SourceLocation atLoc, SourceLocation atLoc,
IdentifierInfo *Id, IdentifierInfo *Id,
SourceLocation ClassLoc = SourceLocation(), SourceLocation ClassLoc = SourceLocation(),
bool ForwardDecl = false,
bool isInternal = false); bool isInternal = false);
virtual SourceRange getSourceRange() const { virtual SourceRange getSourceRange() const {
if (isForwardDecl()) if (isThisDeclarationADefinition())
return SourceRange(getAtStartLoc(), getLocation()); return ObjCContainerDecl::getSourceRange();
return ObjCContainerDecl::getSourceRange();
return SourceRange(getAtStartLoc(), getLocation());
} }
/// \brief Indicate that this Objective-C class is complete, but that /// \brief Indicate that this Objective-C class is complete, but that
@ -772,20 +766,10 @@ public:
unsigned Num, unsigned Num,
ASTContext &C); ASTContext &C);
/// \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;
}
/// \brief Determine whether this class has only ever been forward-declared.
bool isForwardDecl() const { return Data == 0; }
/// \brief Determine whether this particular declaration of this class is /// \brief Determine whether this particular declaration of this class is
/// actually also a definition. /// actually also a definition.
bool isThisDeclarationADefinition() const { bool isThisDeclarationADefinition() const {
return Data == 0 || Data->Definition != this; return Data && Data->Definition == this;
} }
/// \brief Determine whether this class has been defined. /// \brief Determine whether this class has been defined.
@ -927,6 +911,8 @@ public:
return getFirstDeclaration(); return getFirstDeclaration();
} }
void setPreviousDeclaration(ObjCInterfaceDecl *PrevDecl);
// Low-level accessor // Low-level accessor
const Type *getTypeForDecl() const { return TypeForDecl; } const Type *getTypeForDecl() const { return TypeForDecl; }
void setTypeForDecl(const Type *TD) const { TypeForDecl = TD; } void setTypeForDecl(const Type *TD) const { TypeForDecl = TD; }

View File

@ -80,7 +80,7 @@ bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject")) if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject"))
return false; // id/NSObject is not safe for weak. return false; // id/NSObject is not safe for weak.
if (!AllowOnUnknownClass && Class->isForwardDecl()) if (!AllowOnUnknownClass && !Class->hasDefinition())
return false; // forward classes are not verifiable, therefore not safe. return false; // forward classes are not verifiable, therefore not safe.
if (Class->isArcWeakrefUnavailable()) if (Class->isArcWeakrefUnavailable())
return false; return false;

View File

@ -3183,7 +3183,6 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC, ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), DC,
Importer.Import(D->getAtStartLoc()), Importer.Import(D->getAtStartLoc()),
Name.getAsIdentifierInfo(), Loc, Name.getAsIdentifierInfo(), Loc,
D->isInitiallyForwardDecl(),
D->isImplicitInterfaceDecl()); D->isImplicitInterfaceDecl());
ToIface->setLexicalDeclContext(LexicalDC); ToIface->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(ToIface); LexicalDC->addDeclInternal(ToIface);

View File

@ -675,16 +675,15 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(ASTContext &C,
SourceLocation atLoc, SourceLocation atLoc,
IdentifierInfo *Id, IdentifierInfo *Id,
SourceLocation ClassLoc, SourceLocation ClassLoc,
bool ForwardDecl, bool isInternal){ bool isInternal){
return new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc, ForwardDecl, return new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc, isInternal);
isInternal);
} }
ObjCInterfaceDecl:: ObjCInterfaceDecl::
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
SourceLocation CLoc, bool FD, bool isInternal) SourceLocation CLoc, bool isInternal)
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, atLoc), : ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, atLoc),
TypeForDecl(0), Data(), InitiallyForwardDecl(FD) TypeForDecl(0), Data()
{ {
setImplicit(isInternal); setImplicit(isInternal);
} }
@ -705,19 +704,20 @@ void ObjCInterfaceDecl::setExternallyCompleted() {
} }
ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const { ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const {
if (const ObjCInterfaceDecl *Def = getDefinition()) {
if (data().ExternallyCompleted)
LoadExternalDefinition();
return getASTContext().getObjCImplementation(
const_cast<ObjCInterfaceDecl*>(Def));
}
// FIXME: Should make sure no callers ever do this. // FIXME: Should make sure no callers ever do this.
if (!hasDefinition()) return 0;
return 0;
if (data().ExternallyCompleted)
LoadExternalDefinition();
return getASTContext().getObjCImplementation(
const_cast<ObjCInterfaceDecl*>(this));
} }
void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) { void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) {
getASTContext().setObjCImplementation(this, ImplD); getASTContext().setObjCImplementation(getDefinition(), ImplD);
} }
/// all_declared_ivar_begin - return first ivar declared in this class, /// all_declared_ivar_begin - return first ivar declared in this class,
@ -851,6 +851,14 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
return false; return false;
} }
void ObjCInterfaceDecl::setPreviousDeclaration(ObjCInterfaceDecl *PrevDecl) {
redeclarable_base::setPreviousDeclaration(PrevDecl);
// Inherit the 'Data' pointer from the previous declaration.
if (PrevDecl)
Data = PrevDecl->Data;
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// ObjCIvarDecl // ObjCIvarDecl
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -900,16 +900,16 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
std::string I = OID->getNameAsString(); std::string I = OID->getNameAsString();
ObjCInterfaceDecl *SID = OID->getSuperClass(); ObjCInterfaceDecl *SID = OID->getSuperClass();
if (!OID->isThisDeclarationADefinition()) {
Out << "@class " << I << ";";
return;
}
if (SID) if (SID)
Out << "@interface " << I << " : " << *SID; Out << "@interface " << I << " : " << *SID;
else else
Out << "@interface " << I; Out << "@interface " << I;
if (OID->isForwardDecl()) {
Out << "@end";
return;
}
// Protocols? // Protocols?
const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols(); const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols();
if (!Protocols.empty()) { if (!Protocols.empty()) {

View File

@ -755,7 +755,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
} }
void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) { void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) {
setPointer("typeptr", D->getTypeForDecl()); setPointer("typeptr", D->getTypeForDecl());
setFlag("forward_decl", D->isForwardDecl()); setFlag("forward_decl", !D->isThisDeclarationADefinition());
setFlag("implicit_interface", D->isImplicitInterfaceDecl()); setFlag("implicit_interface", D->isImplicitInterfaceDecl());
} }
void visitObjCInterfaceDeclChildren(ObjCInterfaceDecl *D) { void visitObjCInterfaceDeclChildren(ObjCInterfaceDecl *D) {

View File

@ -2161,7 +2161,7 @@ const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
const ASTRecordLayout & const ASTRecordLayout &
ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
const ObjCImplementationDecl *Impl) const { const ObjCImplementationDecl *Impl) const {
assert(!D->isForwardDecl() && "Invalid interface decl!"); assert(D->isThisDeclarationADefinition() && "Invalid interface decl!");
// Look up this layout, if already laid out, return what we have. // Look up this layout, if already laid out, return what we have.
ObjCContainerDecl *Key = ObjCContainerDecl *Key =

View File

@ -927,7 +927,7 @@ bool Type::isIncompleteType() const {
->isIncompleteType(); ->isIncompleteType();
case ObjCInterface: case ObjCInterface:
// ObjC interfaces are incomplete if they are @class, not @interface. // ObjC interfaces are incomplete if they are @class, not @interface.
return cast<ObjCInterfaceType>(CanonicalType)->getDecl()->isForwardDecl(); return !cast<ObjCInterfaceType>(CanonicalType)->getDecl()->hasDefinition();
} }
} }

View File

@ -115,7 +115,7 @@ bool cocoa::isCocoaObjectRef(QualType Ty) {
// Assume that anything declared with a forward declaration and no // Assume that anything declared with a forward declaration and no
// @interface subclasses NSObject. // @interface subclasses NSObject.
if (ID->isForwardDecl()) if (!ID->hasDefinition())
return true; return true;
for ( ; ID ; ID = ID->getSuperClass()) for ( ; ID ; ID = ID->getSuperClass())

View File

@ -1211,7 +1211,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// If this is just a forward declaration return a special forward-declaration // If this is just a forward declaration return a special forward-declaration
// debug type since we won't be able to lay out the entire type. // debug type since we won't be able to lay out the entire type.
if (ID->isForwardDecl()) { if (!ID->isThisDeclarationADefinition()) {
llvm::DIType FwdDecl = llvm::DIType FwdDecl =
DBuilder.createStructType(Unit, ID->getName(), DBuilder.createStructType(Unit, ID->getName(),
DefUnit, Line, 0, 0, DefUnit, Line, 0, 0,

View File

@ -653,8 +653,9 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
ConstantStringClassReference = FVD; ConstantStringClassReference = FVD;
return; return;
} }
} else if (ObjCInterfaceDecl *MD = dyn_cast<ObjCInterfaceDecl>(D)) { } else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
RewriteInterfaceDecl(MD); if (ID->isThisDeclarationADefinition())
RewriteInterfaceDecl(ID);
} else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) { } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(D)) {
RewriteCategoryDecl(CD); RewriteCategoryDecl(CD);
} else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) { } else if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) {
@ -673,9 +674,18 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
SourceLocation Loc = D->getLocation(); SourceLocation Loc = D->getLocation();
while (DI != DIEnd && while (DI != DIEnd &&
isa<ObjCClassDecl>(D) && D->getLocation() == Loc) { isa<ObjCClassDecl>(D) && D->getLocation() == Loc) {
ObjCClassDecl *Class = cast<ObjCClassDecl>(D);
DG.push_back(D); DG.push_back(D);
++DI; ++DI;
D = (*DI); D = (*DI);
// Following the ObjCClassDecl, we should have the corresponding
// ObjCInterfaceDecl. Skip over it.
if (DI != DIEnd && isa<ObjCInterfaceDecl>(D) &&
Class->getForwardInterfaceDecl() == D) {
++DI;
D = (*DI);
}
} }
RewriteForwardClassDecl(DG); RewriteForwardClassDecl(DG);
continue; continue;
@ -1179,7 +1189,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) { void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
std::string ResultStr; std::string ResultStr;
if (!ObjCForwardDecls.count(ClassDecl)) { if (!ObjCForwardDecls.count(ClassDecl->getCanonicalDecl())) {
// we haven't seen a forward decl - generate a typedef. // we haven't seen a forward decl - generate a typedef.
ResultStr = "#ifndef _REWRITER_typedef_"; ResultStr = "#ifndef _REWRITER_typedef_";
ResultStr += ClassDecl->getNameAsString(); ResultStr += ClassDecl->getNameAsString();
@ -1191,7 +1201,7 @@ void RewriteObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
ResultStr += ClassDecl->getNameAsString(); ResultStr += ClassDecl->getNameAsString();
ResultStr += ";\n#endif\n"; ResultStr += ";\n#endif\n";
// Mark this typedef as having been generated. // Mark this typedef as having been generated.
ObjCForwardDecls.insert(ClassDecl); ObjCForwardDecls.insert(ClassDecl->getCanonicalDecl());
} }
RewriteObjCInternalStruct(ClassDecl, ResultStr); RewriteObjCInternalStruct(ClassDecl, ResultStr);
@ -3130,7 +3140,7 @@ void RewriteObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
// If no ivars and no root or if its root, directly or indirectly, // If no ivars and no root or if its root, directly or indirectly,
// have no ivars (thus not synthesized) then no need to synthesize this class. // have no ivars (thus not synthesized) then no need to synthesize this class.
if ((CDecl->isForwardDecl() || NumIvars == 0) && if ((!CDecl->isThisDeclarationADefinition() || NumIvars == 0) &&
(!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) { (!RCDecl || !ObjCSynthesizedStructs.count(RCDecl))) {
endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts); endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
ReplaceText(LocStart, endBuf-startBuf, Result); ReplaceText(LocStart, endBuf-startBuf, Result);
@ -5357,7 +5367,7 @@ void RewriteObjCFragileABI::RewriteObjCClassMetaData(ObjCImplementationDecl *IDe
// Explicitly declared @interface's are already synthesized. // Explicitly declared @interface's are already synthesized.
if (CDecl->isImplicitInterfaceDecl()) { if (CDecl->isImplicitInterfaceDecl()) {
// FIXME: Implementation of a class with no @interface (legacy) doese not // FIXME: Implementation of a class with no @interface (legacy) does not
// produce correct synthesis as yet. // produce correct synthesis as yet.
RewriteObjCInternalStruct(CDecl, Result); RewriteObjCInternalStruct(CDecl, Result);
} }

View File

@ -318,15 +318,6 @@ static DeclMatchKind compareDeclarations(NamedDecl *Existing, NamedDecl *New) {
return DMK_Ignore; return DMK_Ignore;
} }
// If the declarations are both Objective-C classes, and one is a forward
// declaration and the other is not, take the full definition.
// FIXME: At some point, we'll actually have to detect collisions better.
// This logic, however, belongs in the AST reader, not here.
if (ObjCInterfaceDecl *ExistingIFace = dyn_cast<ObjCInterfaceDecl>(Existing))
if (ObjCInterfaceDecl *NewIFace = dyn_cast<ObjCInterfaceDecl>(New))
if (ExistingIFace->isForwardDecl() != NewIFace->isForwardDecl())
return ExistingIFace->isForwardDecl()? DMK_Replace : DMK_Ignore;
return DMK_Different; return DMK_Different;
} }

View File

@ -5487,14 +5487,14 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext,
D != DEnd; ++D) { D != DEnd; ++D) {
// Record any interfaces we find. // Record any interfaces we find.
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*D)) if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*D))
if ((!OnlyForwardDeclarations || Class->isForwardDecl()) && if ((!OnlyForwardDeclarations || !Class->hasDefinition()) &&
(!OnlyUnimplemented || !Class->getImplementation())) (!OnlyUnimplemented || !Class->getImplementation()))
Results.AddResult(Result(Class, 0), CurContext, 0, false); Results.AddResult(Result(Class, 0), CurContext, 0, false);
// Record any forward-declared interfaces we find. // Record any forward-declared interfaces we find.
if (ObjCClassDecl *Forward = dyn_cast<ObjCClassDecl>(*D)) { if (ObjCClassDecl *Forward = dyn_cast<ObjCClassDecl>(*D)) {
ObjCInterfaceDecl *IDecl = Forward->getForwardInterfaceDecl(); ObjCInterfaceDecl *IDecl = Forward->getForwardInterfaceDecl();
if ((!OnlyForwardDeclarations || IDecl->isForwardDecl()) && if ((!OnlyForwardDeclarations || !IDecl->hasDefinition()) &&
(!OnlyUnimplemented || !IDecl->getImplementation())) (!OnlyUnimplemented || !IDecl->getImplementation()))
Results.AddResult(Result(IDecl, 0), CurContext, Results.AddResult(Result(IDecl, 0), CurContext,
0, false); 0, false);

View File

@ -60,7 +60,7 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method,
// It's okay for the result type to still be a forward declaration // It's okay for the result type to still be a forward declaration
// if we're checking an interface declaration. // if we're checking an interface declaration.
if (resultClass->isForwardDecl()) { if (!resultClass->hasDefinition()) {
if (receiverTypeIfCall.isNull() && if (receiverTypeIfCall.isNull() &&
!isa<ObjCImplementationDecl>(method->getDeclContext())) !isa<ObjCImplementationDecl>(method->getDeclContext()))
return false; return false;
@ -365,45 +365,31 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
Diag(PrevDecl->getLocation(), diag::note_previous_definition); Diag(PrevDecl->getLocation(), diag::note_previous_definition);
} }
ObjCInterfaceDecl* IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl); // Create a declaration to describe this @interface.
if (IDecl) { ObjCInterfaceDecl *IDecl
// Class already seen. Is it a forward declaration? = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, ClassName,
if (ObjCInterfaceDecl *Def = IDecl->getDefinition()) { ClassLoc);
IDecl->setInvalidDecl();
Diag(AtInterfaceLoc, diag::err_duplicate_class_def)<<IDecl->getDeclName(); ObjCInterfaceDecl* PrevIDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
if (PrevIDecl) {
// Class already seen. Was it a definition?
if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) {
Diag(AtInterfaceLoc, diag::err_duplicate_class_def)
<< PrevIDecl->getDeclName();
Diag(Def->getLocation(), diag::note_previous_definition); Diag(Def->getLocation(), diag::note_previous_definition);
IDecl->setInvalidDecl();
// 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
// will break invariants.
IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc,
ClassName, ClassLoc);
if (AttrList)
ProcessDeclAttributeList(TUScope, IDecl, AttrList);
PushOnScopeChains(IDecl, TUScope);
} else {
IDecl->setLocation(ClassLoc);
IDecl->setAtStartLoc(AtInterfaceLoc);
// 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);
} }
} else {
IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc,
ClassName, ClassLoc);
if (AttrList)
ProcessDeclAttributeList(TUScope, IDecl, AttrList);
PushOnScopeChains(IDecl, TUScope); // Link to the previous declaration.
IDecl->setPreviousDeclaration(PrevIDecl);
} }
if (AttrList)
ProcessDeclAttributeList(TUScope, IDecl, AttrList);
PushOnScopeChains(IDecl, TUScope);
// Start the definition of this class. If we're in a redefinition case, there
// may already be a definition, so we'll end up adding to it.
if (!IDecl->hasDefinition()) if (!IDecl->hasDefinition())
IDecl->startDefinition(); IDecl->startDefinition();
@ -942,7 +928,7 @@ Decl *Sema::ActOnStartClassImplementation(
// FIXME: Do we support attributes on the @implementation? If so we should // FIXME: Do we support attributes on the @implementation? If so we should
// copy them over. // copy them over.
IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc, IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtClassImplLoc,
ClassName, ClassLoc, false, true); ClassName, ClassLoc, true);
IDecl->startDefinition(); IDecl->startDefinition();
IDecl->setSuperClass(SDecl); IDecl->setSuperClass(SDecl);
IDecl->setLocEnd(ClassLoc); IDecl->setLocEnd(ClassLoc);
@ -1781,22 +1767,29 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
PrevDecl = OI->getInterface(); 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 // Create a declaration to describe this forward declaration.
// the current DeclContext. This prevents clients that walk DeclContext ObjCInterfaceDecl *IDecl
// from seeing the imaginary ObjCInterfaceDecl until it is actually = ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
// declared later (if at all). We also take care to explicitly make IdentList[i], IdentLocs[i], true);
// sure this declaration is visible for name lookup. IDecl->setAtEndRange(IdentLocs[i]);
PushOnScopeChains(IDecl, TUScope, false); IDecl->setLocEnd(IdentLocs[i]);
CurContext->makeDeclVisibleInContext(IDecl, true);
} // If there was a previous declaration, link to it.
if (ObjCInterfaceDecl *PrevIDecl
= dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl))
IDecl->setPreviousDeclaration(PrevIDecl);
// Create the forward declaration. Note that we intentionally do this
// before we add the ObjCInterfaceDecl we just created, so that the
// rewriter sees the ObjCClassDecl first.
// FIXME: ObjCClassDecl should probably just go away.
ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc, ObjCClassDecl *CDecl = ObjCClassDecl::Create(Context, CurContext, AtClassLoc,
IDecl, IdentLocs[i]); IDecl, IdentLocs[i]);
CurContext->addDecl(CDecl); CurContext->addDecl(CDecl);
PushOnScopeChains(IDecl, TUScope);
CheckObjCDeclScope(CDecl); CheckObjCDeclScope(CDecl);
DeclsInGroup.push_back(CDecl); DeclsInGroup.push_back(CDecl);
} }

View File

@ -629,7 +629,6 @@ void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
} }
} }
ID->InitiallyForwardDecl = Record[Idx++];
ID->setLocEnd(ReadSourceLocation(Record, Idx)); ID->setLocEnd(ReadSourceLocation(Record, Idx));
} }

View File

@ -489,7 +489,6 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
Writer.AddDeclRef(D->getCategoryList(), Record); Writer.AddDeclRef(D->getCategoryList(), Record);
} }
Record.push_back(D->isInitiallyForwardDecl());
Writer.AddSourceLocation(D->getLocEnd(), Record); Writer.AddSourceLocation(D->getLocEnd(), Record);
Code = serialization::DECL_OBJC_INTERFACE; Code = serialization::DECL_OBJC_INTERFACE;
} }

View File

@ -16,7 +16,7 @@ void function(Foo * arg)
} }
// CHECK-scan: [1:1 - 8:1] Invalid Cursor => NoDeclFound // CHECK-scan: [1:1 - 8:1] Invalid Cursor => NoDeclFound
// CHECK-scan: [8:1 - 8:8] UnexposedDecl=[10:12] // CHECK-scan: [8:1 - 8:8] UnexposedDecl=[8:8]
// CHECK-scan: [8:8 - 8:11] ObjCClassRef=Foo:10:12 // CHECK-scan: [8:8 - 8:11] ObjCClassRef=Foo:10:12
// CHECK-scan: [8:11 - 10:1] Invalid Cursor => NoDeclFound // CHECK-scan: [8:11 - 10:1] Invalid Cursor => NoDeclFound
// CHECK-scan: [10:1 - 11:5] ObjCInterfaceDecl=Foo:10:12 // CHECK-scan: [10:1 - 11:5] ObjCInterfaceDecl=Foo:10:12

View File

@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s // RUN: %clang_cc1 -fsyntax-only -verify %s
@class FOO, BAR; // expected-note {{forward declaration of class here}}
@class FOO, BAR; @class FOO, BAR;
@class FOO, BAR; // expected-note {{forward declaration of class here}}
@interface INTF : FOO // expected-error {{attempting to use the forward class 'FOO' as superclass of 'INTF'}} @interface INTF : FOO // expected-error {{attempting to use the forward class 'FOO' as superclass of 'INTF'}}
@end @end

View File

@ -299,12 +299,7 @@ void CursorVisitor::visitDeclsFromFileRegion(FileID File,
// We handle forward decls via ObjCClassDecl. // We handle forward decls via ObjCClassDecl.
if (ObjCInterfaceDecl *InterD = dyn_cast<ObjCInterfaceDecl>(D)) { if (ObjCInterfaceDecl *InterD = dyn_cast<ObjCInterfaceDecl>(D)) {
if (InterD->isForwardDecl()) if (!InterD->isThisDeclarationADefinition())
continue;
// An interface that started as a forward decl may have changed location
// because its @interface was parsed.
if (InterD->isInitiallyForwardDecl() &&
!SM.isInFileID(SM.getFileLoc(InterD->getLocation()), File))
continue; continue;
} }
@ -3948,8 +3943,13 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
case CXCursor_ObjCProtocolRef: { case CXCursor_ObjCProtocolRef: {
return MakeCXCursor(getCursorObjCProtocolRef(C).first, tu); return MakeCXCursor(getCursorObjCProtocolRef(C).first, tu);
case CXCursor_ObjCClassRef: case CXCursor_ObjCClassRef: {
return MakeCXCursor(getCursorObjCClassRef(C).first, tu ); ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first;
if (ObjCInterfaceDecl *Def = Class->getDefinition())
return MakeCXCursor(Def, tu);
return MakeCXCursor(Class, tu);
}
case CXCursor_TypeRef: case CXCursor_TypeRef:
return MakeCXCursor(getCursorTypeRef(C).first, tu ); return MakeCXCursor(getCursorTypeRef(C).first, tu );
@ -4147,8 +4147,8 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
// the definition; when we were provided with the interface, // the definition; when we were provided with the interface,
// produce the @implementation as the definition. // produce the @implementation as the definition.
if (WasReference) { if (WasReference) {
if (!cast<ObjCInterfaceDecl>(D)->isForwardDecl()) if (ObjCInterfaceDecl *Def = cast<ObjCInterfaceDecl>(D)->getDefinition())
return C; return MakeCXCursor(Def, TU);
} else if (ObjCImplementationDecl *Impl } else if (ObjCImplementationDecl *Impl
= cast<ObjCInterfaceDecl>(D)->getImplementation()) = cast<ObjCInterfaceDecl>(D)->getImplementation())
return MakeCXCursor(Impl, TU); return MakeCXCursor(Impl, TU);
@ -4162,8 +4162,8 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::ObjCCompatibleAlias: case Decl::ObjCCompatibleAlias:
if (ObjCInterfaceDecl *Class if (ObjCInterfaceDecl *Class
= cast<ObjCCompatibleAliasDecl>(D)->getClassInterface()) = cast<ObjCCompatibleAliasDecl>(D)->getClassInterface())
if (!Class->isForwardDecl()) if (ObjCInterfaceDecl *Def = Class->getDefinition())
return MakeCXCursor(Class, TU); return MakeCXCursor(Def, TU);
return clang_getNullCursor(); return clang_getNullCursor();

View File

@ -97,7 +97,7 @@ public:
bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
// Forward decls are handled at VisitObjCClassDecl. // Forward decls are handled at VisitObjCClassDecl.
if (D->isForwardDecl()) if (!D->isThisDeclarationADefinition())
return true; return true;
IndexCtx.handleObjCInterface(D); IndexCtx.handleObjCInterface(D);

View File

@ -128,7 +128,7 @@ struct ObjCInterfaceDeclInfo : public ObjCContainerDeclInfo {
ObjCInterfaceDeclInfo(const ObjCInterfaceDecl *D) ObjCInterfaceDeclInfo(const ObjCInterfaceDecl *D)
: ObjCContainerDeclInfo(Info_ObjCInterface, : ObjCContainerDeclInfo(Info_ObjCInterface,
/*isForwardRef=*/false, /*isForwardRef=*/false,
/*isRedeclaration=*/D->isInitiallyForwardDecl(), /*isRedeclaration=*/D->getPreviousDeclaration() != 0,
/*isImplementation=*/false) { } /*isImplementation=*/false) { }
static bool classof(const DeclInfo *D) { static bool classof(const DeclInfo *D) {