aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFariborz Jahanian <fjahanian@apple.com>2011-08-03 18:21:12 +0000
committerFariborz Jahanian <fjahanian@apple.com>2011-08-03 18:21:12 +0000
commit74133075f5024ce87e4c1eb644d77c20e1c521f4 (patch)
tree726710578f2a5513ef1fe6080dd2d028f738fb75
parent43fd9388d374f29e908e611a686c6137553efa79 (diff)
objective-c: Methods declared in methods must type match
those declated in its protocols. First half or // rdar://6191214 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@136794 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Sema/Sema.h3
-rw-r--r--lib/Sema/SemaDeclObjC.cpp187
-rw-r--r--test/SemaObjC/class-protocol-method-match.m18
3 files changed, 121 insertions, 87 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index f15ebc6438..921cc716ef 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1785,7 +1785,8 @@ public:
ObjCInterfaceDecl *IDecl);
typedef llvm::DenseSet<Selector, llvm::DenseMapInfo<Selector> > SelectorSet;
-
+ typedef llvm::DenseMap<Selector, ObjCMethodDecl*> ProtocolsMethodsMap;
+
/// CheckProtocolMethodDefs - This routine checks unimplemented
/// methods declared in protocol, and those referenced by it.
/// \param IDecl - Used for checking for methods which may have been
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 0dc2279e37..cc86dcb9d6 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -1498,12 +1498,6 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
IMPDecl,
(*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
// in category implementation and its primary class's super class.
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,
- Sema::SelectorSet &InsMap,
- Sema::SelectorSet &ClsMap,
const ObjCContainerDecl *IDecl,
- const ObjCProtocolDecl *PDecl) {
- if (!InsMap.empty())
- for (ObjCInterfaceDecl::instmeth_iterator IM = PDecl->instmeth_begin(),
- E = PDecl->instmeth_end(); IM != E; ++IM) {
- Selector Sel = (*IM)->getSelector();
- if (InsMap.count(Sel)) {
- ObjCMethodDecl *ProtoMethodDecl = PDecl->getInstanceMethod(Sel);
- ObjCMethodDecl *ClsMethodDecl = IDecl->getInstanceMethod(Sel);
- if (ProtoMethodDecl && ClsMethodDecl)
- S.WarnConflictingTypedMethods(
- ClsMethodDecl,
- ProtoMethodDecl, true, true);
- InsMap.erase(Sel);
- }
- if (InsMap.empty())
- break;
+ Sema::ProtocolsMethodsMap &InstMethodsInProtocols,
+ Sema::ProtocolsMethodsMap &ClsMethodsInProtocols) {
+ for (ObjCInterfaceDecl::instmeth_iterator IM = IDecl->instmeth_begin(),
+ E = IDecl->instmeth_end(); IM != E; ++IM) {
+ Selector Sel = (*IM)->getSelector();
+ if (ObjCMethodDecl *ProtoMethodDecl = InstMethodsInProtocols[Sel]) {
+ ObjCMethodDecl *ClsMethodDecl = (*IM);
+ S.WarnConflictingTypedMethods(ClsMethodDecl,
+ ProtoMethodDecl, true, true);
+ }
+ }
+ for (ObjCInterfaceDecl::classmeth_iterator IM = IDecl->classmeth_begin(),
+ E = IDecl->classmeth_end(); IM != E; ++IM) {
+ Selector Sel = (*IM)->getSelector();
+ if (ObjCMethodDecl *ProtoMethodDecl = ClsMethodsInProtocols[Sel]) {
+ ObjCMethodDecl *ClsMethodDecl = (*IM);
+ S.WarnConflictingTypedMethods(ClsMethodDecl,
+ ProtoMethodDecl, true, true);
}
- if (!ClsMap.empty())
- for (ObjCInterfaceDecl::classmeth_iterator IM = PDecl->classmeth_begin(),
- E = PDecl->classmeth_end(); IM != E; ++IM) {
- Selector Sel = (*IM)->getSelector();
- if (ClsMap.count(Sel)) {
- ObjCMethodDecl *ProtoMethodDecl = PDecl->getClassMethod(Sel);
- ObjCMethodDecl *ClsMethodDecl = IDecl->getClassMethod(Sel);
- if (ProtoMethodDecl && ClsMethodDecl)
- S.WarnConflictingTypedMethods(
- ClsMethodDecl,
- ProtoMethodDecl, true, true);
- ClsMap.erase(Sel);
+ }
+
+ if (const ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl>(IDecl)) {
+ for (const ObjCCategoryDecl *ClsExtDecl = I->getFirstClassExtension();
+ 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;
}
- if (ClsMap.empty())
- break;
+ 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 (InsMap.empty() && ClsMap.empty())
- return;
+ if (CDecl->getSuperClass())
+ CollectMethodsInProtocols(CDecl->getSuperClass(), InstMethodsInProtocols,
+ ClsMethodsInProtocols);
+ }
- for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
- PE = PDecl->protocol_end(); PI != PE; ++PI)
- MatchMethodsInClassAndOneProtocol(S, InsMap, ClsMap, IDecl, (*PI));
+ 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
/// method in protocol in its qualified class match in their type and
/// issue warnings otherwise.
-void Sema::MatchMethodsInClassAndItsProtocol(const ObjCInterfaceDecl *CDecl) {
- if (CDecl->all_referenced_protocol_begin() ==
- CDecl->all_referenced_protocol_end())
- return;
-
- SelectorSet InsMap, ClsMap;
- 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());
+void Sema::MatchMethodsInClassAndItsProtocol(const ObjCInterfaceDecl *CDecl) {
+ ProtocolsMethodsMap InstMethodsInProtocols, ClsMethodsInProtocols;
+ CollectMethodsInProtocols(CDecl, InstMethodsInProtocols,
+ ClsMethodsInProtocols);
- 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())
+ if (InstMethodsInProtocols.empty() && ClsMethodsInProtocols.empty())
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));
- }
+ MatchMethodsInClassAndOneProtocol(*this, CDecl, InstMethodsInProtocols,
+ ClsMethodsInProtocols);
}
/// CheckCategoryVsClassMethodMatches - Checks that methods implemented in
@@ -1670,6 +1678,13 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl, CDecl,
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
// in its primary class.
if (ObjCCategoryImplDecl *CatDecl =
diff --git a/test/SemaObjC/class-protocol-method-match.m b/test/SemaObjC/class-protocol-method-match.m
index be1c1e03f3..bffdb79e07 100644
--- a/test/SemaObjC/class-protocol-method-match.m
+++ b/test/SemaObjC/class-protocol-method-match.m
@@ -44,3 +44,21 @@
- (void) bak {}
@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