From 730cfb18463d8c2f6d0e4d4380fdd67e4abe5d97 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Wed, 10 Aug 2011 17:16:30 +0000 Subject: [PATCH] objective-c: Using existing infrastructure for finding overridden methods to diagnose their type mismatch. This is a general solution for previous fixes for // rdar://6191214 and // rdar://9352731 and removes lots of duplicate code. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@137222 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticGroups.td | 1 + include/clang/Basic/DiagnosticSemaKinds.td | 54 ++- include/clang/Basic/IdentifierTable.h | 5 - include/clang/Sema/Sema.h | 51 +-- lib/Sema/SemaDeclObjC.cpp | 317 +++--------------- test/SemaObjC/class-protocol-method-match.m | 50 +-- test/SemaObjC/dist-object-modifiers.m | 4 +- .../qualified-protocol-method-conflicts.m | 28 +- 8 files changed, 133 insertions(+), 377 deletions(-) diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 7c5c217ce3..86b5da7884 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -187,6 +187,7 @@ def Selector : DiagGroup<"selector">; def NonfragileAbi2 : DiagGroup<"nonfragile-abi2">; def Protocol : DiagGroup<"protocol">; def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">; +def OverridingMethodMismatch : DiagGroup<"overriding-method-mismatch">; def : DiagGroup<"variadic-macros">; def VariadicMacros : DiagGroup<"variadic-macros">; def VectorConversions : DiagGroup<"vector-conversions">; // clang specific diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 6fa36f03e2..81fb8b651e 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -383,32 +383,72 @@ def note_undef_method_impl : Note<"method definition for %0 not found">; def note_required_for_protocol_at : Note<"required for direct or indirect protocol %0">; +def warn_conflicting_overriding_ret_types : Warning< + "conflicting return type in " + "declaration of %0: %1 vs %2">, + InGroup, DefaultIgnore; + def warn_conflicting_ret_types : Warning< "conflicting return type in " - "%select{implementation|declaration}3 of %0: %1 vs %2">; + "implementation of %0: %1 vs %2">; + +def warn_conflicting_overriding_ret_type_modifiers : Warning< + "conflicting distributed object modifiers on return type " + "in declaration of %0">, + InGroup, DefaultIgnore; + def warn_conflicting_ret_type_modifiers : Warning< "conflicting distributed object modifiers on return type " - "in %select{implementation|declaration}1 of %0">, + "in implementation of %0">, InGroup>; + +def warn_non_covariant_overriding_ret_types : Warning< + "conflicting return type in " + "declaration of %0: %1 vs %2">, + InGroup, DefaultIgnore; + def warn_non_covariant_ret_types : Warning< "conflicting return type in " - "%select{implementation|declaration}3 of %0: %1 vs %2">, + "implementation of %0: %1 vs %2">, InGroup>, DefaultIgnore; +def warn_conflicting_overriding_param_types : Warning< + "conflicting parameter types in " + "declaration of %0: %1 vs %2">, + InGroup, DefaultIgnore; + def warn_conflicting_param_types : Warning< "conflicting parameter types in " - "%select{implementation|declaration}3 of %0: %1 vs %2">; + "implementation of %0: %1 vs %2">; def warn_conflicting_param_modifiers : Warning< "conflicting distributed object modifiers on parameter type " - "in %select{implementation|declaration}1 of %0">, + "in implementation of %0">, InGroup>; + +def warn_conflicting_overriding_param_modifiers : Warning< + "conflicting distributed object modifiers on parameter type " + "in declaration of %0">, + InGroup, DefaultIgnore; + +def warn_non_contravariant_overriding_param_types : Warning< + "conflicting parameter types in " + "declaration of %0: %1 vs %2">, + InGroup, DefaultIgnore; + def warn_non_contravariant_param_types : Warning< "conflicting parameter types in " - "%select{implementation|declaration}3 of %0: %1 vs %2">, + "implementation of %0: %1 vs %2">, InGroup>, DefaultIgnore; + +def warn_conflicting_overriding_variadic :Warning< + "conflicting variadic declaration of method and its " + "implementation">, + InGroup, DefaultIgnore; + def warn_conflicting_variadic :Warning< "conflicting variadic declaration of method and its " - "%select{implementation|declaration}0">; + "implementation">; + def warn_category_method_impl_match:Warning< "category is implementing a method which will also be implemented" " by its primary class">, InGroup; diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index c9fa74ce42..017af5caee 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -557,11 +557,6 @@ public: bool operator!=(Selector RHS) const { return InfoPtr != RHS.InfoPtr; } - - bool operator < (Selector RHS) const { - return InfoPtr < RHS.InfoPtr; - } - void *getAsOpaquePtr() const { return reinterpret_cast(InfoPtr); } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 90d0195cff..1258d596cc 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -493,39 +493,6 @@ public: /// a potentially evaluated expression. typedef SmallVector, 10> PotentiallyReferencedDecls; - - // FIXME. Improve on accessibility. - class PROTOCOL_METHODS { - public: - Selector Sel; - ObjCMethodDecl *Method; - PROTOCOL_METHODS(Selector S, ObjCMethodDecl *M) - : Sel(S), Method(M) {} - // Allow sorting based on selector's opaque pointer. - bool operator<(const PROTOCOL_METHODS &b) const { - return Sel < b.Sel; - } - }; - - /// \brief The set of protocols declared in protocols qualifying a - /// class. - typedef SmallVector MethodsInProtocols; - - class IDENTICAL_SELECTOR_METHODS { - public: - SourceLocation Loc; - ObjCMethodDecl *Method; - IDENTICAL_SELECTOR_METHODS(SourceLocation L, ObjCMethodDecl *M) - : Loc(L), Method(M) {} - // Allow sorting based on selector's source location. - bool operator<(const IDENTICAL_SELECTOR_METHODS &i) const { - return !(Loc < i.Loc); - } - }; - - /// \brief Methods with identical selectors to be type-matched against - /// one another. - typedef SmallVector IdenticalSelectorMethods; /// \brief A set of diagnostics that may be emitted. typedef SmallVector, 10> @@ -1813,12 +1780,7 @@ public: void WarnExactTypedMethods(ObjCMethodDecl *Method, ObjCMethodDecl *MethodDecl, bool IsProtocolMethodDecl); - - /// WarnOnMismatchedProtocolMethods - Issues warning on type mismatched - /// protocols methods and then returns true(matched), or false(mismatched). - bool WarnOnMismatchedProtocolMethods(ObjCMethodDecl *Method, - ObjCMethodDecl *MethodDecl); - + bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl, ObjCInterfaceDecl *IDecl); @@ -1942,17 +1904,6 @@ public: bool ImmediateClass, bool WarnExactMatch=false); - /// MatchIdenticalSelectorsInProtocols - Check that mathods with - /// identical selectors in all protocols of this class type match. - /// Issue warning if they don't. - void MatchIdenticalSelectorsInProtocols(const ObjCInterfaceDecl *CDecl); - - /// MatchMethodsInClassAndItsProtocol - Check that any redeclaration of - /// method in protocol in its qualified class match in their type and - /// issue warnings otherwise. - void MatchMethodsInClassAndItsProtocol(const ObjCInterfaceDecl *CDecl); - - /// CheckCategoryVsClassMethodMatches - Checks that methods implemented in /// category matches with those implemented in its primary class and /// warns each time an exact match is found. diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 084ca0b77b..68177f8950 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -1075,15 +1075,17 @@ static bool CheckMethodOverrideReturn(Sema &S, ObjCMethodDecl *MethodImpl, ObjCMethodDecl *MethodDecl, bool IsProtocolMethodDecl, - bool IsDeclaration, + bool IsOverridingMode, bool Warn) { if (IsProtocolMethodDecl && (MethodDecl->getObjCDeclQualifier() != MethodImpl->getObjCDeclQualifier())) { if (Warn) { - S.Diag(MethodImpl->getLocation(), - diag::warn_conflicting_ret_type_modifiers) - << MethodImpl->getDeclName() << IsDeclaration + S.Diag(MethodImpl->getLocation(), + (IsOverridingMode ? + diag::warn_conflicting_overriding_ret_type_modifiers + : diag::warn_conflicting_ret_type_modifiers)) + << MethodImpl->getDeclName() << getTypeRange(MethodImpl->getResultTypeSourceInfo()); S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration) << getTypeRange(MethodDecl->getResultTypeSourceInfo()); @@ -1098,7 +1100,9 @@ static bool CheckMethodOverrideReturn(Sema &S, if (!Warn) return false; - unsigned DiagID = diag::warn_conflicting_ret_types; + unsigned DiagID = + IsOverridingMode ? diag::warn_conflicting_overriding_ret_types + : diag::warn_conflicting_ret_types; // Mismatches between ObjC pointers go into a different warning // category, and sometimes they're even completely whitelisted. @@ -1113,7 +1117,9 @@ static bool CheckMethodOverrideReturn(Sema &S, if (isObjCTypeSubstitutable(S.Context, IfacePtrTy, ImplPtrTy, false)) return false; - DiagID = diag::warn_non_covariant_ret_types; + DiagID = + IsOverridingMode ? diag::warn_non_covariant_overriding_ret_types + : diag::warn_non_covariant_ret_types; } } @@ -1121,9 +1127,10 @@ static bool CheckMethodOverrideReturn(Sema &S, << MethodImpl->getDeclName() << MethodDecl->getResultType() << MethodImpl->getResultType() - << IsDeclaration << getTypeRange(MethodImpl->getResultTypeSourceInfo()); - S.Diag(MethodDecl->getLocation(), diag::note_previous_definition) + S.Diag(MethodDecl->getLocation(), + IsOverridingMode ? diag::note_previous_declaration + : diag::note_previous_definition) << getTypeRange(MethodDecl->getResultTypeSourceInfo()); return false; } @@ -1134,16 +1141,21 @@ static bool CheckMethodOverrideParam(Sema &S, ParmVarDecl *ImplVar, ParmVarDecl *IfaceVar, bool IsProtocolMethodDecl, - bool IsDeclaration, + bool IsOverridingMode, bool Warn) { if (IsProtocolMethodDecl && (ImplVar->getObjCDeclQualifier() != IfaceVar->getObjCDeclQualifier())) { if (Warn) { - S.Diag(ImplVar->getLocation(), + if (IsOverridingMode) + S.Diag(ImplVar->getLocation(), + diag::warn_conflicting_overriding_param_modifiers) + << getTypeRange(ImplVar->getTypeSourceInfo()) + << MethodImpl->getDeclName(); + else S.Diag(ImplVar->getLocation(), diag::warn_conflicting_param_modifiers) << getTypeRange(ImplVar->getTypeSourceInfo()) - << MethodImpl->getDeclName() << IsDeclaration; + << MethodImpl->getDeclName(); S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration) << getTypeRange(IfaceVar->getTypeSourceInfo()); } @@ -1159,7 +1171,9 @@ static bool CheckMethodOverrideParam(Sema &S, if (!Warn) return false; - unsigned DiagID = diag::warn_conflicting_param_types; + unsigned DiagID = + IsOverridingMode ? diag::warn_conflicting_overriding_param_types + : diag::warn_conflicting_param_types; // Mismatches between ObjC pointers go into a different warning // category, and sometimes they're even completely whitelisted. @@ -1174,15 +1188,18 @@ static bool CheckMethodOverrideParam(Sema &S, if (isObjCTypeSubstitutable(S.Context, ImplPtrTy, IfacePtrTy, true)) return false; - DiagID = diag::warn_non_contravariant_param_types; + DiagID = + IsOverridingMode ? diag::warn_non_contravariant_overriding_param_types + : diag::warn_non_contravariant_param_types; } } S.Diag(ImplVar->getLocation(), DiagID) << getTypeRange(ImplVar->getTypeSourceInfo()) - << MethodImpl->getDeclName() << IfaceTy << ImplTy - << IsDeclaration; - S.Diag(IfaceVar->getLocation(), diag::note_previous_definition) + << MethodImpl->getDeclName() << IfaceTy << ImplTy; + S.Diag(IfaceVar->getLocation(), + (IsOverridingMode ? diag::note_previous_declaration + : diag::note_previous_definition)) << getTypeRange(IfaceVar->getTypeSourceInfo()); return false; } @@ -1260,54 +1277,31 @@ static bool checkMethodFamilyMismatch(Sema &S, ObjCMethodDecl *impl, void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl, ObjCMethodDecl *MethodDecl, bool IsProtocolMethodDecl, - bool IsDeclaration) { + bool IsOverridingMode) { if (getLangOptions().ObjCAutoRefCount && + !IsOverridingMode && checkMethodFamilyMismatch(*this, ImpMethodDecl, MethodDecl)) return; CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl, - IsProtocolMethodDecl, IsDeclaration, true); + IsProtocolMethodDecl, IsOverridingMode, + true); for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(), IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end(); - IM != EM; ++IM, ++IF) + IM != EM; ++IM, ++IF) { CheckMethodOverrideParam(*this, ImpMethodDecl, MethodDecl, *IM, *IF, - IsProtocolMethodDecl, IsDeclaration, true); - - if (ImpMethodDecl->isVariadic() != MethodDecl->isVariadic()) { - Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic) - << IsDeclaration; - Diag(MethodDecl->getLocation(), diag::note_previous_declaration); + IsProtocolMethodDecl, IsOverridingMode, true); } -} -/// WarnOnMismatchedProtocolMethods - Issues warning on type mismatched -/// protocols methods and then returns true(matched), or false(mismatched). -bool Sema::WarnOnMismatchedProtocolMethods(ObjCMethodDecl *ImpMethodDecl, - ObjCMethodDecl *MethodDecl) { - - bool match = CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl, - true, - true, true); - if (!match) - return false; - - for (ObjCMethodDecl::param_iterator IM = ImpMethodDecl->param_begin(), - IF = MethodDecl->param_begin(), EM = ImpMethodDecl->param_end(); - IM != EM; ++IM, ++IF) { - match = CheckMethodOverrideParam(*this, ImpMethodDecl, MethodDecl, *IM, *IF, - true, true, true); - if (!match) - return false; - } - if (ImpMethodDecl->isVariadic() != MethodDecl->isVariadic()) { - Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic) - << true; + if (IsOverridingMode) + Diag(ImpMethodDecl->getLocation(), + diag::warn_conflicting_overriding_variadic); + else + Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic); Diag(MethodDecl->getLocation(), diag::note_previous_declaration); - return false; } - return true; } /// WarnExactTypedMethods - This routine issues a warning if method @@ -1539,214 +1533,6 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet &InsMap, } } -/// MatchMethodsInClassAndProtocols - 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 MatchMethodsInClassAndProtocols(Sema &S, - const ObjCContainerDecl *IDecl, - 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 (const ObjCInterfaceDecl *I = dyn_cast(IDecl)) { - for (const ObjCCategoryDecl *ClsExtDecl = I->getFirstClassExtension(); - ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) - MatchMethodsInClassAndProtocols(S, ClsExtDecl, InstMethodsInProtocols, - ClsMethodsInProtocols); - } -} - -/// CollectMethodsInOneProtocol - This routine collects all methods declared -/// in a given protocol. -static void CollectMethodsInOneProtocol(const ObjCProtocolDecl *PDecl, - Sema::ProtocolsMethodsMap &InstMethodsInProtocols, - Sema::ProtocolsMethodsMap &ClsMethodsInProtocols) { - 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; - } -} - -/// CollectAllMethodsInProtocols - Helper routine to collect all methods -/// declared in given class's immediate and nested protocols. -static void CollectAllMethodsInProtocols(const ObjCContainerDecl *ContDecl, - Sema::MethodsInProtocols &InstMethodsInProtocols, - Sema::MethodsInProtocols & ClsMethodsInProtocols) { - if (const ObjCInterfaceDecl *CDecl = dyn_cast(ContDecl)) { - for (ObjCInterfaceDecl::all_protocol_iterator - PI = CDecl->all_referenced_protocol_begin(), - E = CDecl->all_referenced_protocol_end(); PI != E; ++PI) - CollectAllMethodsInProtocols(*PI, InstMethodsInProtocols, - ClsMethodsInProtocols); - } - - if (const ObjCProtocolDecl *PDecl = dyn_cast(ContDecl)) { - for (ObjCProtocolDecl::instmeth_iterator I = PDecl->instmeth_begin(), - E = PDecl->instmeth_end(); I != E; ++I) { - ObjCMethodDecl *method = *I; - InstMethodsInProtocols.push_back(Sema::PROTOCOL_METHODS(method->getSelector(), - method)); - } - for (ObjCProtocolDecl::classmeth_iterator I = PDecl->classmeth_begin(), - E = PDecl->classmeth_end(); I != E; ++I) { - ObjCMethodDecl *method = *I; - ClsMethodsInProtocols.push_back(Sema::PROTOCOL_METHODS(method->getSelector(), - method)); - } - - for (ObjCProtocolDecl::protocol_iterator - PI = PDecl->protocol_begin(), - E = PDecl->protocol_end(); PI != E; ++PI) - CollectAllMethodsInProtocols(*PI, 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(ContDecl)) { - for (ObjCInterfaceDecl::all_protocol_iterator - PI = CDecl->all_referenced_protocol_begin(), - E = CDecl->all_referenced_protocol_end(); PI != E; ++PI) { - ObjCProtocolDecl *PDecl = (*PI); - CollectMethodsInOneProtocol(PDecl, InstMethodsInProtocols, - ClsMethodsInProtocols); - - 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(ContDecl)) - CollectMethodsInOneProtocol(PDecl, InstMethodsInProtocols, - ClsMethodsInProtocols); - -} - -/// 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) { - ProtocolsMethodsMap InstMethodsInProtocols, ClsMethodsInProtocols; - CollectMethodsInProtocols(CDecl, InstMethodsInProtocols, - ClsMethodsInProtocols); - - if (InstMethodsInProtocols.empty() && ClsMethodsInProtocols.empty()) - return; - MatchMethodsInClassAndProtocols(*this, CDecl, InstMethodsInProtocols, - ClsMethodsInProtocols); -} - -/// MatchMethodsWithIdenticalSelectors - Helper routine to go through list -/// of identical selector lists and issue warning for any type mismatche -/// of these methods. -static bool MatchMethodsWithIdenticalSelectors(Sema &S, - const Sema::MethodsInProtocols Methods) { - bool res = true; - int size = Methods.size(); - int i = 0; - while (i < size) { - int upper = i; - while (upper < size && - (Methods[i].Sel == Methods[upper].Sel)) - upper++; - if (upper > i) { - int lo = i; - int hi = upper - 1; - - if (lo < hi) { - Sema::IdenticalSelectorMethods SelectedMethods; - for (int l = lo; l <= hi; l++) { - ObjCMethodDecl *method = Methods[l].Method; - Sema::IDENTICAL_SELECTOR_METHODS - SelectedMethod(method->getLocation(), method); - SelectedMethods.push_back(SelectedMethod); - } - llvm::array_pod_sort(SelectedMethods.begin(), SelectedMethods.end()); - lo = 0; hi = SelectedMethods.size()-1; - while (lo < hi) { - ObjCMethodDecl *targetMethod = SelectedMethods[lo].Method; - for (int j = lo+1; j <= hi; j++) { - // match two methods; - ObjCMethodDecl *otherMethod = SelectedMethods[j].Method; - if (!S.WarnOnMismatchedProtocolMethods(targetMethod, otherMethod)) - res = false; - } - ++lo; - } - } - } - i += upper; - } - return res; -} - -/// MatchIdenticalSelectorsInProtocols - Main routine to go through list of -/// class's protocols (and their protocols) and make sure that methods -/// type match across all protocols and issue warnings if they don't. -/// FIXME. This may move to static analyzer if performance is proven -/// prohibitive. -void Sema::MatchIdenticalSelectorsInProtocols(const ObjCInterfaceDecl *CDecl) { - Sema::MethodsInProtocols InsMethods; - Sema::MethodsInProtocols ClsMethods; - CollectAllMethodsInProtocols(CDecl, InsMethods, ClsMethods); - - bool match = true; - if (!InsMethods.empty()) { - llvm::array_pod_sort(InsMethods.begin(), InsMethods.end()); - if (!MatchMethodsWithIdenticalSelectors(*this, InsMethods)) - match = false; - } - - if (!ClsMethods.empty()) { - llvm::array_pod_sort(ClsMethods.begin(), ClsMethods.end()); - if (!MatchMethodsWithIdenticalSelectors(*this, ClsMethods)) - match = false; - } - if (!match) - Diag(CDecl->getLocation() ,diag::note_class_declared); -} - - /// CheckCategoryVsClassMethodMatches - Checks that methods implemented in /// category matches with those implemented in its primary class and /// warns each time an exact match is found. @@ -1809,14 +1595,6 @@ 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(IMPDecl)) - if (const ObjCInterfaceDecl *I = dyn_cast(CDecl)) { - MatchIdenticalSelectorsInProtocols(I); - MatchMethodsInClassAndItsProtocol(I); - } // check all methods implemented in category against those declared // in its primary class. @@ -2828,6 +2606,13 @@ Decl *Sema::ActOnMethodDeclaration( // Then merge the declarations. mergeObjCMethodDecls(ObjCMethod, overridden); + + // Check for overriding methods + if (isa(ObjCMethod->getDeclContext()) || + isa(ObjCMethod->getDeclContext())) { + WarnConflictingTypedMethods(ObjCMethod, overridden, + isa(overridden->getDeclContext()), true); + } } bool ARCError = false; diff --git a/test/SemaObjC/class-protocol-method-match.m b/test/SemaObjC/class-protocol-method-match.m index 4022ce3aee..04243e9677 100644 --- a/test/SemaObjC/class-protocol-method-match.m +++ b/test/SemaObjC/class-protocol-method-match.m @@ -1,64 +1,48 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -Woverriding-method-mismatch -fsyntax-only -verify %s // rdar://9352731 @protocol Bar @required -- (unsigned char) baz; // expected-note {{previous definition is here}} -- (char) ok; // expected-note {{previous definition is here}} +- (bycopy id)bud; // expected-note {{previous declaration is here}} +- (unsigned char) baz; // expected-note {{previous declaration is here}} +- (char) ok; - (void) also_ok; @end @protocol Bar1 @required -- (unsigned char) baz; -- (unsigned char) also_ok; +- (unsigned char) baz; // expected-note {{previous declaration is here}} +- (unsigned char) also_ok; // expected-note {{previous declaration is here}} - (void) ban : (int) arg, ...; // expected-note {{previous declaration is here}} @end @protocol Baz -- (void) bar : (unsigned char)arg; // expected-note {{previous definition is here}} -- (void) ok; // expected-warning {{conflicting return type in declaration of 'ok': 'char' vs 'void'}} -- (char) bak; // expected-note {{previous definition is here}} +- (void) bar : (unsigned char)arg; // expected-note {{previous declaration is here}} +- (void) ok; +- (char) bak; // expected-note {{previous declaration is here}} @end -@interface Foo // expected-note {{class is declared here}} -- (void) baz; // expected-warning {{conflicting return type in declaration of 'baz': 'unsigned char' vs 'void'}} +@interface Foo +- (id)bud; // expected-warning {{conflicting distributed object modifiers on return type in declaration of 'bud'}} +- (void) baz; // expected-warning 2 {{conflicting return type in declaration of 'baz': 'unsigned char' vs 'void'}} - (void) bar : (unsigned char*)arg; // expected-warning {{conflicting parameter types in declaration of 'bar:': 'unsigned char' vs 'unsigned char *'}} - (void) ok; -- (void) also_ok; +- (void) also_ok; // expected-warning {{conflicting return type in declaration of 'also_ok': 'unsigned char' vs 'void'}} - (void) still_ok; -- (void) ban : (int) arg; // expected-warning {{conflicting variadic declaration of method and its declaration}} +- (void) ban : (int) arg; // expected-warning {{conflicting variadic declaration of method and its implementation}} @end @interface Foo() -- (void) bak; // expected-warning {{conflicting return type in declaration of 'bak': 'char' vs 'void'}} +- (void) bak; @end @implementation Foo +- (bycopy id)bud { return 0; } - (void) baz {} - (void) bar : (unsigned char*)arg {} - (void) ok {} - (void) also_ok {} - (void) still_ok {} - (void) ban : (int) arg {} -- (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 -@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 {} +- (void) bak {} // expected-warning {{conflicting return type in declaration of 'bak': 'char' vs 'void'}} @end diff --git a/test/SemaObjC/dist-object-modifiers.m b/test/SemaObjC/dist-object-modifiers.m index 77e9938177..98a9ce6cdc 100644 --- a/test/SemaObjC/dist-object-modifiers.m +++ b/test/SemaObjC/dist-object-modifiers.m @@ -4,12 +4,12 @@ @protocol P - (bycopy id)serverPID; // expected-note {{previous declaration is here}} - (void)doStuff:(bycopy id)clientId; // expected-note {{previous declaration is here}} -- (bycopy id)Ok; // expected-note {{previous declaration is here}} +- (bycopy id)Ok; + (oneway id) stillMore : (byref id)Arg : (bycopy oneway id)Arg1; // expected-note 3 {{previous declaration is here}} @end @interface I

-- (id)Ok; // expected-warning {{conflicting distributed object modifiers on return type in declaration of 'Ok'}} +- (id)Ok; @end @implementation I diff --git a/test/SemaObjC/qualified-protocol-method-conflicts.m b/test/SemaObjC/qualified-protocol-method-conflicts.m index da83c8338c..0cff3ff468 100644 --- a/test/SemaObjC/qualified-protocol-method-conflicts.m +++ b/test/SemaObjC/qualified-protocol-method-conflicts.m @@ -1,39 +1,39 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -Woverriding-method-mismatch -fsyntax-only -verify %s // rdar://6191214 @protocol Xint --(void) setX: (int) arg0; // expected-note 3 {{previous definition is here}} -+(int) C; // expected-note 3 {{previous definition is here}} +-(void) setX: (int) arg0; // expected-note {{previous declaration is here}} ++(int) C; // expected-note {{previous declaration is here}} @end @protocol Xfloat --(void) setX: (float) arg0; // expected-warning 3 {{conflicting parameter types in declaration of 'setX:': 'int' vs 'float'}} -+(float) C; // expected-warning 3 {{conflicting return type in declaration of 'C': 'int' vs 'float'}} +-(void) setX: (float) arg0; // expected-note 2 {{previous declaration is here}} ++(float) C; // expected-note 2 {{previous declaration is here}} @end -@interface A // expected-note {{class is declared here}} +@interface A @end @implementation A --(void) setX: (int) arg0 { } -+(int) C {return 0; } +-(void) setX: (int) arg0 { } // expected-warning {{conflicting parameter types in declaration of 'setX:': 'float' vs 'int'}} ++(int) C {return 0; } // expected-warning {{conflicting return type in declaration of 'C': 'float' vs 'int'}} @end -@interface B // expected-note {{class is declared here}} +@interface B @end @implementation B --(void) setX: (float) arg0 { } -+ (float) C {return 0.0; } +-(void) setX: (float) arg0 { } // expected-warning {{conflicting parameter types in declaration of 'setX:': 'int' vs 'float'}} ++ (float) C {return 0.0; } // expected-warning {{conflicting return type in declaration of 'C': 'int' vs 'float'}} @end @protocol Xint_float @end -@interface C // expected-note {{class is declared here}} +@interface C @end @implementation C --(void) setX: (int) arg0 { } -+ (int) C {return 0;} +-(void) setX: (int) arg0 { } // expected-warning {{conflicting parameter types in declaration of 'setX:': 'float' vs 'int'}} ++ (int) C {return 0;} // expected-warning {{conflicting return type in declaration of 'C': 'float' vs 'int'}} @end -- 2.40.0