objective-c: Methods declared in methods must type match

those declated in its protocols. First half or // rdar://6191214

llvm-svn: 136794
This commit is contained in:
Fariborz Jahanian 2011-08-03 18:21:12 +00:00
parent f169c394ca
commit 2bda1b65b1
3 changed files with 123 additions and 89 deletions

View File

@ -1785,7 +1785,8 @@ public:
ObjCInterfaceDecl *IDecl); ObjCInterfaceDecl *IDecl);
typedef llvm::DenseSet<Selector, llvm::DenseMapInfo<Selector> > SelectorSet; typedef llvm::DenseSet<Selector, llvm::DenseMapInfo<Selector> > SelectorSet;
typedef llvm::DenseMap<Selector, ObjCMethodDecl*> ProtocolsMethodsMap;
/// CheckProtocolMethodDefs - This routine checks unimplemented /// CheckProtocolMethodDefs - This routine checks unimplemented
/// methods declared in protocol, and those referenced by it. /// methods declared in protocol, and those referenced by it.
/// \param IDecl - Used for checking for methods which may have been /// \param IDecl - Used for checking for methods which may have been

View File

@ -1498,12 +1498,6 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
IMPDecl, IMPDecl,
(*PI), IncompleteImpl, false, WarnExactMatch); (*PI), IncompleteImpl, false, WarnExactMatch);
// Check for any type mismtch of methods declared in class
// and methods declared in protocol. Do this only when the class
// is being implementaed.
if (isa<ObjCImplementationDecl>(IMPDecl))
MatchMethodsInClassAndItsProtocol(I);
// FIXME. For now, we are not checking for extact match of methods // FIXME. For now, we are not checking for extact match of methods
// in category implementation and its primary class's super class. // in category implementation and its primary class's super class.
if (!WarnExactMatch && I->getSuperClass()) if (!WarnExactMatch && I->getSuperClass())
@ -1513,99 +1507,113 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
} }
} }
/// MatchMethodsInClassAndOneProtocol - This routine goes thru list of methods
/// declared in the class, and its class extensions. For each method which is
/// also declared in one of its qualifying protocols, they must type match or
/// it issues a warning.
static void MatchMethodsInClassAndOneProtocol(Sema &S, static void MatchMethodsInClassAndOneProtocol(Sema &S,
Sema::SelectorSet &InsMap,
Sema::SelectorSet &ClsMap,
const ObjCContainerDecl *IDecl, const ObjCContainerDecl *IDecl,
const ObjCProtocolDecl *PDecl) { Sema::ProtocolsMethodsMap &InstMethodsInProtocols,
if (!InsMap.empty()) Sema::ProtocolsMethodsMap &ClsMethodsInProtocols) {
for (ObjCInterfaceDecl::instmeth_iterator IM = PDecl->instmeth_begin(), for (ObjCInterfaceDecl::instmeth_iterator IM = IDecl->instmeth_begin(),
E = PDecl->instmeth_end(); IM != E; ++IM) { E = IDecl->instmeth_end(); IM != E; ++IM) {
Selector Sel = (*IM)->getSelector(); Selector Sel = (*IM)->getSelector();
if (InsMap.count(Sel)) { if (ObjCMethodDecl *ProtoMethodDecl = InstMethodsInProtocols[Sel]) {
ObjCMethodDecl *ProtoMethodDecl = PDecl->getInstanceMethod(Sel); ObjCMethodDecl *ClsMethodDecl = (*IM);
ObjCMethodDecl *ClsMethodDecl = IDecl->getInstanceMethod(Sel); S.WarnConflictingTypedMethods(ClsMethodDecl,
if (ProtoMethodDecl && ClsMethodDecl) ProtoMethodDecl, true, true);
S.WarnConflictingTypedMethods(
ClsMethodDecl,
ProtoMethodDecl, true, true);
InsMap.erase(Sel);
}
if (InsMap.empty())
break;
} }
if (!ClsMap.empty()) }
for (ObjCInterfaceDecl::classmeth_iterator IM = PDecl->classmeth_begin(), for (ObjCInterfaceDecl::classmeth_iterator IM = IDecl->classmeth_begin(),
E = PDecl->classmeth_end(); IM != E; ++IM) { E = IDecl->classmeth_end(); IM != E; ++IM) {
Selector Sel = (*IM)->getSelector(); Selector Sel = (*IM)->getSelector();
if (ClsMap.count(Sel)) { if (ObjCMethodDecl *ProtoMethodDecl = ClsMethodsInProtocols[Sel]) {
ObjCMethodDecl *ProtoMethodDecl = PDecl->getClassMethod(Sel); ObjCMethodDecl *ClsMethodDecl = (*IM);
ObjCMethodDecl *ClsMethodDecl = IDecl->getClassMethod(Sel); S.WarnConflictingTypedMethods(ClsMethodDecl,
if (ProtoMethodDecl && ClsMethodDecl) ProtoMethodDecl, true, true);
S.WarnConflictingTypedMethods(
ClsMethodDecl,
ProtoMethodDecl, true, true);
ClsMap.erase(Sel);
}
if (ClsMap.empty())
break;
} }
if (InsMap.empty() && ClsMap.empty()) }
return;
for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), if (const ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl>(IDecl)) {
PE = PDecl->protocol_end(); PI != PE; ++PI) for (const ObjCCategoryDecl *ClsExtDecl = I->getFirstClassExtension();
MatchMethodsInClassAndOneProtocol(S, InsMap, ClsMap, IDecl, (*PI)); ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension())
MatchMethodsInClassAndOneProtocol(S, ClsExtDecl, InstMethodsInProtocols,
ClsMethodsInProtocols);
}
}
/// CollectMethodsInProtocols - This routine collects all methods declared
/// in class's list and nested qualified protocols. Instance methods and
/// class methods have separate containers as they have identical selectors.
static void CollectMethodsInProtocols(const ObjCContainerDecl *ContDecl,
Sema::ProtocolsMethodsMap &InstMethodsInProtocols,
Sema::ProtocolsMethodsMap &ClsMethodsInProtocols) {
if (const ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(ContDecl)) {
for (ObjCInterfaceDecl::all_protocol_iterator
PI = CDecl->all_referenced_protocol_begin(),
E = CDecl->all_referenced_protocol_end(); PI != E; ++PI) {
ObjCProtocolDecl *PDecl = (*PI);
for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
E = PDecl->instmeth_end(); I != E; ++I) {
ObjCMethodDecl *method = *I;
ObjCMethodDecl *&ProtocolEntry =
InstMethodsInProtocols[method->getSelector()];
if (!ProtocolEntry)
ProtocolEntry = method;
}
for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(),
E = PDecl->classmeth_end(); I != E; ++I) {
ObjCMethodDecl *method = *I;
ObjCMethodDecl *&ProtocolEntry =
ClsMethodsInProtocols[method->getSelector()];
if (!ProtocolEntry)
ProtocolEntry = method;
}
for (ObjCProtocolDecl::protocol_iterator P = PDecl->protocol_begin(),
PE = PDecl->protocol_end(); P != PE; ++P)
CollectMethodsInProtocols(*P, InstMethodsInProtocols,
ClsMethodsInProtocols);
}
if (CDecl->getSuperClass())
CollectMethodsInProtocols(CDecl->getSuperClass(), InstMethodsInProtocols,
ClsMethodsInProtocols);
}
if (const ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(ContDecl)) {
for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(),
E = PDecl->instmeth_end(); I != E; ++I) {
ObjCMethodDecl *method = *I;
ObjCMethodDecl *&ProtocolEntry =
InstMethodsInProtocols[method->getSelector()];
if (!ProtocolEntry)
ProtocolEntry = method;
}
for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(),
E = PDecl->classmeth_end(); I != E; ++I) {
ObjCMethodDecl *method = *I;
ObjCMethodDecl *&ProtocolEntry =
ClsMethodsInProtocols[method->getSelector()];
if (!ProtocolEntry)
ProtocolEntry = method;
}
}
} }
/// MatchMethodsInClassAndItsProtocol - Check that any redeclaration of /// MatchMethodsInClassAndItsProtocol - Check that any redeclaration of
/// method in protocol in its qualified class match in their type and /// method in protocol in its qualified class match in their type and
/// issue warnings otherwise. /// issue warnings otherwise.
void Sema::MatchMethodsInClassAndItsProtocol(const ObjCInterfaceDecl *CDecl) { void Sema::MatchMethodsInClassAndItsProtocol(const ObjCInterfaceDecl *CDecl) {
if (CDecl->all_referenced_protocol_begin() == ProtocolsMethodsMap InstMethodsInProtocols, ClsMethodsInProtocols;
CDecl->all_referenced_protocol_end()) CollectMethodsInProtocols(CDecl, InstMethodsInProtocols,
ClsMethodsInProtocols);
if (InstMethodsInProtocols.empty() && ClsMethodsInProtocols.empty())
return; return;
MatchMethodsInClassAndOneProtocol(*this, CDecl, InstMethodsInProtocols,
SelectorSet InsMap, ClsMap; ClsMethodsInProtocols);
for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(),
E = CDecl->instmeth_end(); I != E; ++I)
if (!InsMap.count((*I)->getSelector()))
InsMap.insert((*I)->getSelector());
for (ObjCInterfaceDecl::classmeth_iterator
I = CDecl->classmeth_begin(), E = CDecl->classmeth_end(); I != E; ++I)
if (!ClsMap.count((*I)->getSelector()))
ClsMap.insert((*I)->getSelector());
if (!InsMap.empty() || !ClsMap.empty())
for (ObjCInterfaceDecl::all_protocol_iterator
PI = CDecl->all_referenced_protocol_begin(),
E = CDecl->all_referenced_protocol_end(); PI != E; ++PI)
MatchMethodsInClassAndOneProtocol(*this, InsMap, ClsMap, CDecl, (*PI));
// Also for class extensions
if (!CDecl->getFirstClassExtension())
return;
for (const ObjCCategoryDecl *ClsExtDecl = CDecl->getFirstClassExtension();
ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
InsMap.clear();
ClsMap.clear();
for (ObjCCategoryDecl::instmeth_iterator I = ClsExtDecl->instmeth_begin(),
E = ClsExtDecl->instmeth_end(); I != E; ++I)
if (!InsMap.count((*I)->getSelector()))
InsMap.insert((*I)->getSelector());
for (ObjCCategoryDecl::classmeth_iterator I = ClsExtDecl->classmeth_begin(),
E = ClsExtDecl->classmeth_end(); I != E; ++I)
if (!ClsMap.count((*I)->getSelector()))
ClsMap.insert((*I)->getSelector());
if (InsMap.empty() && ClsMap.empty())
continue;
for (ObjCInterfaceDecl::all_protocol_iterator
PI = CDecl->all_referenced_protocol_begin(),
E = CDecl->all_referenced_protocol_end(); PI != E; ++PI)
MatchMethodsInClassAndOneProtocol(*this, InsMap, ClsMap, ClsExtDecl, (*PI));
}
} }
/// CheckCategoryVsClassMethodMatches - Checks that methods implemented in /// CheckCategoryVsClassMethodMatches - Checks that methods implemented in
@ -1670,6 +1678,13 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl, CDecl, IMPDecl, CDecl,
IncompleteImpl, true); IncompleteImpl, true);
// Check for any type mismtch of methods declared in class
// and methods declared in protocol. Do this only when the class
// is being implementaed.
if (isa<ObjCImplementationDecl>(IMPDecl))
if (const ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl>(CDecl))
MatchMethodsInClassAndItsProtocol(I);
// check all methods implemented in category against those declared // check all methods implemented in category against those declared
// in its primary class. // in its primary class.
if (ObjCCategoryImplDecl *CatDecl = if (ObjCCategoryImplDecl *CatDecl =

View File

@ -44,3 +44,21 @@
- (void) bak {} - (void) bak {}
@end @end
// rdar://6911214
@protocol Xint
-(void) setX: (int) arg0; // expected-note {{previous definition is here}}
+(void) setX: (int) arg0; // expected-note {{previous definition is here}}
@end
@interface A <Xint>
@end
@interface C : A
-(void) setX: (C*) arg0; // expected-warning {{conflicting parameter types in declaration of 'setX:': 'int' vs 'C *'}}
+(void) setX: (C*) arg0; // expected-warning {{conflicting parameter types in declaration of 'setX:': 'int' vs 'C *'}}
@end
@implementation C
-(void) setX: (C*) arg0 {}
+(void) setX: (C*) arg0 {}
@end