diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2011-07-24 20:53:26 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2011-07-24 20:53:26 +0000 |
commit | eee3ef177a171c06f826c331e7a9e256d01eaeb0 (patch) | |
tree | 6d361dd21e7528f13178711bc5bcf999d345fd54 /lib/Sema/SemaDeclObjC.cpp | |
parent | 335608a778db3398aca12e3c855ecfa5ff11c5c9 (diff) |
objc: clang should warn if redeclaration of methods
declared in protocol in the class qualified by the
protocol have type conflicts. To reduce amount of
noise, this is done when class is implemented.
// rdar://9352731
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@135890 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDeclObjC.cpp')
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 122 |
1 files changed, 113 insertions, 9 deletions
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index da3bedd12a..e9a39b614e 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1074,13 +1074,14 @@ static SourceRange getTypeRange(TypeSourceInfo *TSI) { static void CheckMethodOverrideReturn(Sema &S, ObjCMethodDecl *MethodImpl, ObjCMethodDecl *MethodDecl, - bool IsProtocolMethodDecl) { + bool IsProtocolMethodDecl, + bool IsDeclaration) { if (IsProtocolMethodDecl && (MethodDecl->getObjCDeclQualifier() != MethodImpl->getObjCDeclQualifier())) { S.Diag(MethodImpl->getLocation(), diag::warn_conflicting_ret_type_modifiers) - << MethodImpl->getDeclName() + << MethodImpl->getDeclName() << IsDeclaration << getTypeRange(MethodImpl->getResultTypeSourceInfo()); S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration) << getTypeRange(MethodDecl->getResultTypeSourceInfo()); @@ -1113,6 +1114,7 @@ static void CheckMethodOverrideReturn(Sema &S, << MethodImpl->getDeclName() << MethodDecl->getResultType() << MethodImpl->getResultType() + << IsDeclaration << getTypeRange(MethodImpl->getResultTypeSourceInfo()); S.Diag(MethodDecl->getLocation(), diag::note_previous_definition) << getTypeRange(MethodDecl->getResultTypeSourceInfo()); @@ -1123,14 +1125,15 @@ static void CheckMethodOverrideParam(Sema &S, ObjCMethodDecl *MethodDecl, ParmVarDecl *ImplVar, ParmVarDecl *IfaceVar, - bool IsProtocolMethodDecl) { + bool IsProtocolMethodDecl, + bool IsDeclaration) { if (IsProtocolMethodDecl && (ImplVar->getObjCDeclQualifier() != IfaceVar->getObjCDeclQualifier())) { S.Diag(ImplVar->getLocation(), diag::warn_conflicting_param_modifiers) << getTypeRange(ImplVar->getTypeSourceInfo()) - << MethodImpl->getDeclName(); + << MethodImpl->getDeclName() << IsDeclaration; S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration) << getTypeRange(IfaceVar->getTypeSourceInfo()); } @@ -1162,7 +1165,8 @@ static void CheckMethodOverrideParam(Sema &S, S.Diag(ImplVar->getLocation(), DiagID) << getTypeRange(ImplVar->getTypeSourceInfo()) - << MethodImpl->getDeclName() << IfaceTy << ImplTy; + << MethodImpl->getDeclName() << IfaceTy << ImplTy + << IsDeclaration; S.Diag(IfaceVar->getLocation(), diag::note_previous_definition) << getTypeRange(IfaceVar->getTypeSourceInfo()); } @@ -1239,22 +1243,24 @@ static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl, void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, ObjCMethodDecl *MethodDecl, - bool IsProtocolMethodDecl) { + bool IsProtocolMethodDecl, + bool IsDeclaration) { if (getLangOptions().ObjCAutoRefCount && checkMethodFamilyMismatch(*this, ImpMethodDecl, MethodDecl)) return; CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl, - IsProtocolMethodDecl); + IsProtocolMethodDecl, IsDeclaration); for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(), IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end(); IM != EM; ++IM, ++IF) CheckMethodOverrideParam(*this, ImpMethodDecl, MethodDecl, *IM, *IF, - IsProtocolMethodDecl); + IsProtocolMethodDecl, IsDeclaration); if (ImpMethodDecl->isVariadic() != MethodDecl->isVariadic()) { - Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic); + Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic) + << IsDeclaration; Diag(MethodDecl->getLocation(), diag::note_previous_declaration); } } @@ -1427,6 +1433,11 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, IMPDecl, (*PI), IncompleteImpl, false); + + // Check for any type mismtch of methods declared in class + // and methods declared in protocol. + MatchMethodsInClassAndItsProtocol(I); + if (I->getSuperClass()) MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, IMPDecl, @@ -1434,6 +1445,99 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap, } } +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; + } + 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 (ClsMap.empty()) + break; + } + if (InsMap.empty() && ClsMap.empty()) + return; + + for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), + PE = PDecl->protocol_end(); PI != PE; ++PI) + MatchMethodsInClassAndOneProtocol(S, InsMap, ClsMap, IDecl, (*PI)); +} + +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()); + + 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)); + } +} + + void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl* CDecl, bool IncompleteImpl) { |