Split ObjCInterfaceDecl::ReferencedProtocols into two lists: ReferencedProtocols and AllReferencedProtocols. ReferencedProtocols

(and thus protocol_begin(), protocol_end()) now only contains the list of protocols that were directly referenced in
an @interface declaration.  'all_referenced_protocol_[begin,end]()' now returns the set of protocols that were referenced
in both the @interface and class extensions.  The latter is needed for semantic analysis/codegen, while the former is
needed to maintain the lexical information of the original source.

Fixes <rdar://problem/8380046>.

llvm-svn: 112691
This commit is contained in:
Ted Kremenek 2010-09-01 01:21:15 +00:00
parent 6961e87847
commit 0ef508d301
12 changed files with 140 additions and 59 deletions

View File

@ -443,8 +443,11 @@ class ObjCInterfaceDecl : public ObjCContainerDecl {
/// Class's super class.
ObjCInterfaceDecl *SuperClass;
/// Protocols referenced in interface header declaration
/// Protocols referenced in the @interface declaration
ObjCProtocolList ReferencedProtocols;
/// Protocols reference in both the @interface and class extensions.
ObjCList<ObjCProtocolDecl> AllReferencedProtocols;
/// List of categories defined for this class.
/// FIXME: Why is this a linked list??
@ -489,23 +492,44 @@ public:
}
typedef ObjCProtocolList::iterator protocol_iterator;
protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();}
protocol_iterator protocol_end() const { return ReferencedProtocols.end(); }
protocol_iterator protocol_begin() const {
return ReferencedProtocols.begin();
}
protocol_iterator protocol_end() const {
return ReferencedProtocols.end();
}
typedef ObjCProtocolList::loc_iterator protocol_loc_iterator;
protocol_loc_iterator protocol_loc_begin() const {
return ReferencedProtocols.loc_begin();
}
protocol_loc_iterator protocol_loc_end() const {
return ReferencedProtocols.loc_end();
}
unsigned protocol_size() const { return ReferencedProtocols.size(); }
typedef ObjCList<ObjCProtocolDecl>::iterator all_protocol_iterator;
all_protocol_iterator all_referenced_protocol_begin() const {
return AllReferencedProtocols.empty() ? protocol_begin()
: AllReferencedProtocols.begin();
}
all_protocol_iterator all_referenced_protocol_end() const {
return AllReferencedProtocols.empty() ? protocol_end()
: 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()); }
unsigned ivar_size() const {
return std::distance(ivar_begin(), ivar_end());
}
bool ivar_empty() const { return ivar_begin() == ivar_end(); }
ObjCIvarDecl *all_declared_ivar_begin();
@ -522,7 +546,6 @@ public:
/// into the protocol list for this class.
void mergeClassExtensionProtocolList(ObjCProtocolDecl *const* List,
unsigned Num,
const SourceLocation *Locs,
ASTContext &C);
bool isForwardDecl() const { return ForwardDecl; }
@ -604,6 +627,9 @@ public:
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const ObjCInterfaceDecl *D) { return true; }
static bool classofKind(Kind K) { return K == ObjCInterface; }
friend class ASTDeclReader;
friend class ASTDeclWriter;
};
/// ObjCIvarDecl - Represents an ObjC instance variable. In general, ObjC

View File

@ -897,8 +897,10 @@ void ASTContext::DeepCollectObjCIvars(const ObjCInterfaceDecl *OI,
void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols) {
if (const ObjCInterfaceDecl *OI = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(),
PE = OI->protocol_end(); P != PE; ++P) {
// We can use protocol_iterator here instead of
// all_referenced_protocol_iterator since we are walking all categories.
for (ObjCInterfaceDecl::all_protocol_iterator P = OI->all_referenced_protocol_begin(),
PE = OI->all_referenced_protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
Protocols.insert(Proto);
for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
@ -918,7 +920,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
SD = SD->getSuperClass();
}
} else if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) {
for (ObjCInterfaceDecl::protocol_iterator P = OC->protocol_begin(),
for (ObjCCategoryDecl::protocol_iterator P = OC->protocol_begin(),
PE = OC->protocol_end(); P != PE; ++P) {
ObjCProtocolDecl *Proto = (*P);
Protocols.insert(Proto);

View File

@ -2553,6 +2553,8 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
llvm::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;

View File

@ -120,8 +120,9 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
return P;
// Look through protocols.
for (ObjCInterfaceDecl::protocol_iterator
I = OID->protocol_begin(), E = OID->protocol_end(); I != E; ++I)
for (ObjCInterfaceDecl::all_protocol_iterator
I = OID->all_referenced_protocol_begin(),
E = OID->all_referenced_protocol_end(); I != E; ++I)
if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
return P;
@ -157,8 +158,9 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
return PD;
// Look through protocols.
for (ObjCInterfaceDecl::protocol_iterator
I = protocol_begin(), E = protocol_end(); I != E; ++I)
for (ObjCInterfaceDecl::all_protocol_iterator
I = all_referenced_protocol_begin(),
E = all_referenced_protocol_end(); I != E; ++I)
if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId))
return P;
@ -167,23 +169,23 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ObjCProtocolDecl *const* ExtList, unsigned ExtNum,
const SourceLocation *Locs,
ASTContext &C)
{
if (ReferencedProtocols.empty()) {
ReferencedProtocols.set(ExtList, ExtNum, Locs, C);
if (AllReferencedProtocols.empty() && ReferencedProtocols.empty()) {
AllReferencedProtocols.set(ExtList, ExtNum, C);
return;
}
// Check for duplicate protocol in class's protocol list.
// This is (O)2. But it is extremely rare and number of protocols in
// This is O(n*m). But it is extremely rare and number of protocols in
// class or its extension are very few.
llvm::SmallVector<ObjCProtocolDecl*, 8> ProtocolRefs;
llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
for (unsigned i = 0; i < ExtNum; i++) {
bool protocolExists = false;
ObjCProtocolDecl *ProtoInExtension = ExtList[i];
for (protocol_iterator p = protocol_begin(), e = protocol_end();
p != e; p++) {
for (all_protocol_iterator
p = all_referenced_protocol_begin(),
e = all_referenced_protocol_end(); p != e; ++p) {
ObjCProtocolDecl *Proto = (*p);
if (C.ProtocolCompatibleWithProtocol(ProtoInExtension, Proto)) {
protocolExists = true;
@ -192,22 +194,20 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
}
// Do we want to warn on a protocol in extension class which
// already exist in the class? Probably not.
if (!protocolExists) {
if (!protocolExists)
ProtocolRefs.push_back(ProtoInExtension);
ProtocolLocs.push_back(Locs[i]);
}
}
if (ProtocolRefs.empty())
return;
// Merge ProtocolRefs into class's protocol list;
protocol_loc_iterator pl = protocol_loc_begin();
for (protocol_iterator p = protocol_begin(), e = protocol_end();
p != e; ++p, ++pl) {
for (all_protocol_iterator p = all_referenced_protocol_begin(),
e = all_referenced_protocol_end(); p != e; ++p) {
ProtocolRefs.push_back(*p);
ProtocolLocs.push_back(*pl);
}
unsigned NumProtoRefs = ProtocolRefs.size();
setProtocolList(ProtocolRefs.data(), NumProtoRefs, ProtocolLocs.data(), C);
AllReferencedProtocols.set(ProtocolRefs.data(), ProtocolRefs.size(), C);
}
/// getFirstClassExtension - Find first class extension of the given class.

View File

@ -1990,8 +1990,9 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(llvm::Twine Name,
Prop));
}
if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) {
for (ObjCInterfaceDecl::protocol_iterator P = OID->protocol_begin(),
E = OID->protocol_end(); P != E; ++P)
for (ObjCInterfaceDecl::all_protocol_iterator
P = OID->all_referenced_protocol_begin(),
E = OID->all_referenced_protocol_end(); P != E; ++P)
PushProtocolProperties(PropertySet, Properties, Container, (*P),
ObjCTypes);
}
@ -2179,8 +2180,8 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
const_cast<ObjCInterfaceDecl*>(ID->getClassInterface());
llvm::Constant *Protocols =
EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getName(),
Interface->protocol_begin(),
Interface->protocol_end());
Interface->all_referenced_protocol_begin(),
Interface->all_referenced_protocol_end());
unsigned Flags = eClassFlags_Factory;
if (ID->getNumIvarInitializers())
Flags |= eClassFlags_HasCXXStructors;
@ -4804,8 +4805,8 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer");
Values[ 6] = EmitProtocolList("\01l_OBJC_CLASS_PROTOCOLS_$_"
+ OID->getName(),
OID->protocol_begin(),
OID->protocol_end());
OID->all_referenced_protocol_begin(),
OID->all_referenced_protocol_end());
if (flags & CLS_META)
Values[ 7] = llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);

View File

@ -2686,9 +2686,9 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
}
// Look through protocols.
for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(),
E = IFace->protocol_end();
I != E; ++I)
for (ObjCInterfaceDecl::all_protocol_iterator
I = IFace->all_referenced_protocol_begin(),
E = IFace->all_referenced_protocol_end(); I != E; ++I)
AddObjCProperties(*I, AllowCategories, CurContext, Results);
// Look in the superclass.
@ -2698,8 +2698,8 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
} else if (const ObjCCategoryDecl *Category
= dyn_cast<ObjCCategoryDecl>(Container)) {
// Look through protocols.
for (ObjCInterfaceDecl::protocol_iterator P = Category->protocol_begin(),
PEnd = Category->protocol_end();
for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
PEnd = Category->protocol_end();
P != PEnd; ++P)
AddObjCProperties(*P, AllowCategories, CurContext, Results);
}

View File

@ -485,8 +485,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
// Protocols in the class extension belong to the class.
if (CDecl->IsClassExtension())
IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs,
NumProtoRefs, ProtoLocs,
Context);
NumProtoRefs, Context);
}
CheckObjCDeclScope(CDecl);
@ -924,8 +923,9 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
}
if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) {
// Check for any implementation of a methods declared in protocol.
for (ObjCInterfaceDecl::protocol_iterator PI = I->protocol_begin(),
E = I->protocol_end(); PI != E; ++PI)
for (ObjCInterfaceDecl::all_protocol_iterator
PI = I->all_referenced_protocol_begin(),
E = I->all_referenced_protocol_end(); PI != E; ++PI)
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl,
(*PI), IncompleteImpl, false);
@ -971,8 +971,9 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
// implemented in the implementation class.
if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) {
for (ObjCInterfaceDecl::protocol_iterator PI = I->protocol_begin(),
E = I->protocol_end(); PI != E; ++PI)
for (ObjCInterfaceDecl::all_protocol_iterator
PI = I->all_referenced_protocol_begin(),
E = I->all_referenced_protocol_end(); PI != E; ++PI)
CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
InsMap, ClsMap, I);
// Check class extensions (unnamed categories)

View File

@ -2502,8 +2502,9 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
}
// Traverse protocols.
for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(),
E = IFace->protocol_end(); I != E; ++I) {
for (ObjCInterfaceDecl::all_protocol_iterator
I = IFace->all_referenced_protocol_begin(),
E = IFace->all_referenced_protocol_end(); I != E; ++I) {
ShadowContextRAII Shadow(Visited);
LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer,
Visited);

View File

@ -731,15 +731,17 @@ void Sema::CompareProperties(Decl *CDecl, Decl *ClassOrProtocol) {
}
if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(),
E = MDecl->protocol_end(); P != E; ++P)
for (ObjCInterfaceDecl::all_protocol_iterator
P = MDecl->all_referenced_protocol_begin(),
E = MDecl->all_referenced_protocol_end(); P != E; ++P)
// Match properties of class IDecl with those of protocol (*P).
MatchOneProtocolPropertiesInClass(IDecl, *P);
// Go thru the list of protocols for this class and recursively match
// their properties with those declared in the class.
for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(),
E = IDecl->protocol_end(); P != E; ++P)
for (ObjCInterfaceDecl::all_protocol_iterator
P = IDecl->all_referenced_protocol_begin(),
E = IDecl->all_referenced_protocol_end(); P != E; ++P)
CompareProperties(IDecl, *P);
} else {
ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
@ -812,8 +814,9 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
PropMap[Prop->getIdentifier()] = Prop;
}
// scan through class's protocols.
for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
E = IDecl->protocol_end(); PI != E; ++PI)
for (ObjCInterfaceDecl::all_protocol_iterator
PI = IDecl->all_referenced_protocol_begin(),
E = IDecl->all_referenced_protocol_end(); PI != E; ++PI)
CollectImmediateProperties((*PI), PropMap, SuperPropMap);
}
if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
@ -824,7 +827,7 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
PropMap[Prop->getIdentifier()] = Prop;
}
// scan through class's protocols.
for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(),
for (ObjCCategoryDecl::protocol_iterator PI = CATDecl->protocol_begin(),
E = CATDecl->protocol_end(); PI != E; ++PI)
CollectImmediateProperties((*PI), PropMap, SuperPropMap);
}
@ -859,8 +862,9 @@ static void CollectClassPropertyImplementations(ObjCContainerDecl *CDecl,
ObjCPropertyDecl *Prop = (*P);
PropMap[Prop->getIdentifier()] = Prop;
}
for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
E = IDecl->protocol_end(); PI != E; ++PI)
for (ObjCInterfaceDecl::all_protocol_iterator
PI = IDecl->all_referenced_protocol_begin(),
E = IDecl->all_referenced_protocol_end(); PI != E; ++PI)
CollectClassPropertyImplementations((*PI), PropMap);
}
else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
@ -902,8 +906,9 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl,
return Prop;
}
// scan through class's protocols.
for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
E = IDecl->protocol_end(); PI != E; ++PI) {
for (ObjCInterfaceDecl::all_protocol_iterator
PI = IDecl->all_referenced_protocol_begin(),
E = IDecl->all_referenced_protocol_end(); PI != E; ++PI) {
ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II);
if (Prop)
return Prop;

View File

@ -374,6 +374,8 @@ void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
ID->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr());
ID->setSuperClass(cast_or_null<ObjCInterfaceDecl>
(Reader.GetDecl(Record[Idx++])));
// Read the directly referenced protocols and their SourceLocations.
unsigned NumProtocols = Record[Idx++];
llvm::SmallVector<ObjCProtocolDecl *, 16> Protocols;
Protocols.reserve(NumProtocols);
@ -385,6 +387,17 @@ void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
ProtoLocs.push_back(SourceLocation::getFromRawEncoding(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(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
ID->AllReferencedProtocols.set(Protocols.data(), NumProtocols,
*Reader.getContext());
// Read the ivars.
unsigned NumIvars = Record[Idx++];
llvm::SmallVector<ObjCIvarDecl *, 16> IVars;
IVars.reserve(NumIvars);

View File

@ -343,7 +343,9 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
VisitObjCContainerDecl(D);
Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record);
Writer.AddDeclRef(D->getSuperClass(), Record);
Record.push_back(D->protocol_size());
// 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)
@ -352,6 +354,16 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
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);
// 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)

View File

@ -15,6 +15,17 @@
}
@end
// From: <rdar://problem/8380046>
@protocol Prot8380046
@end
@interface R8380046
@end
@interface R8380046 () <Prot8380046>
@end
// CHECK: local-symbols.m:6:12: ObjCInterfaceDecl=Foo:6:12 Extent=[6:1 - 10:5]
// CHECK: local-symbols.m:7:6: ObjCIvarDecl=x:7:6 (Definition) Extent=[7:6 - 7:7]
// CHECK: local-symbols.m:7:3: TypeRef=id:0:0 Extent=[7:3 - 7:5]
@ -23,4 +34,11 @@
// CHECK: local-symbols.m:12:1: ObjCImplementationDecl=Foo:12:1 (Definition) Extent=[12:1 - 16:2]
// CHECK: local-symbols.m:13:1: ObjCInstanceMethodDecl=bar:13:1 (Definition) Extent=[13:1 - 15:2]
// CHECK: local-symbols.m:13:4: TypeRef=id:0:0 Extent=[13:4 - 13:6]
// CHECK: local-symbols.m:14:10: UnexposedExpr= Extent=[14:10 - 14:11]
// CHECK: local-symbols.m:14:10: UnexposedExpr= Extent=[14:10 - 14:11]
// CHECK: local-symbols.m:20:1: ObjCProtocolDecl=Prot8380046:20:1 (Definition) Extent=[20:1 - 21:5]
// CHECK: local-symbols.m:23:12: ObjCInterfaceDecl=R8380046:23:12 Extent=[23:1 - 24:5]
// CHECK: local-symbols.m:26:12: ObjCCategoryDecl=:26:12 Extent=[26:1 - 27:5]
// CHECK: local-symbols.m:26:12: ObjCClassRef=R8380046:23:12 Extent=[26:12 - 26:20]
// CHECK: local-symbols.m:26:25: ObjCProtocolRef=Prot8380046:20:1 Extent=[26:25 - 26:36]