[cfe-commits] r136426 - in /cfe/trunk: include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/Sema/SemaDeclObjC.cpp test/SemaObjC/arc.m test/SemaObjC/incomplete-implementation.m test/SemaObjC/protocol-implementing-class-methods.m test/SemaObjC/related-result-type-inference.m
Fariborz Jahanian
fjahanian at apple.com
Thu Jul 28 16:19:50 PDT 2011
Author: fjahanian
Date: Thu Jul 28 18:19:50 2011
New Revision: 136426
URL: http://llvm.org/viewvc/llvm-project?rev=136426&view=rev
Log:
objective-c: warn if implementation of a method in category
masks an existing method in its primary class, class extensions,
and primary class's non-optional protocol methods; as primary
class, or one of its subclass's will implement this method.
This warning has potential of being noisy so it has its own
group. // rdar://7020493
Added:
cfe/trunk/test/SemaObjC/protocol-implementing-class-methods.m
Modified:
cfe/trunk/include/clang/Basic/DiagnosticGroups.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclObjC.cpp
cfe/trunk/test/SemaObjC/arc.m
cfe/trunk/test/SemaObjC/incomplete-implementation.m
cfe/trunk/test/SemaObjC/related-result-type-inference.m
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=136426&r1=136425&r2=136426&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Thu Jul 28 18:19:50 2011
@@ -302,3 +302,4 @@
def ObjCNonUnifiedException : DiagGroup<"objc-nonunified-exceptions">;
+def ObjCProtocolMethodImpl : DiagGroup<"objc-protocol-method-implementation">;
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=136426&r1=136425&r2=136426&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jul 28 18:19:50 2011
@@ -409,6 +409,9 @@
def warn_conflicting_variadic :Warning<
"conflicting variadic declaration of method and its "
"%select{implementation|declaration}0">;
+def warn_category_method_impl_match:Warning<
+ "category is implementing a method which will also be implemented"
+ " by its primary class">, InGroup<ObjCProtocolMethodImpl>;
def warn_implements_nscopying : Warning<
"default assign attribute on property %0 which implements "
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=136426&r1=136425&r2=136426&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Jul 28 18:19:50 2011
@@ -1775,6 +1775,12 @@
bool IsProtocolMethodDecl,
bool IsDeclaration = false);
+ /// WarnExactTypedMethods - This routine issues a warning if method
+ /// implementation declaration matches exactly that of its declaration.
+ void WarnExactTypedMethods(ObjCMethodDecl *Method,
+ ObjCMethodDecl *MethodDecl,
+ bool IsProtocolMethodDecl);
+
bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl,
ObjCInterfaceDecl *IDecl);
@@ -1894,13 +1900,19 @@
ObjCImplDecl* IMPDecl,
ObjCContainerDecl* IDecl,
bool &IncompleteImpl,
- bool ImmediateClass);
+ bool ImmediateClass,
+ bool WarnExactMatch=false);
/// 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.
+ void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP);
+
private:
/// AddMethodToGlobalPool - Add an instance or factory method to the global
/// pool. See descriptoin of AddInstanceMethodToGlobalPool.
Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=136426&r1=136425&r2=136426&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Thu Jul 28 18:19:50 2011
@@ -1071,25 +1071,32 @@
return (TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange());
}
-static void CheckMethodOverrideReturn(Sema &S,
+static bool CheckMethodOverrideReturn(Sema &S,
ObjCMethodDecl *MethodImpl,
ObjCMethodDecl *MethodDecl,
bool IsProtocolMethodDecl,
- bool IsDeclaration) {
+ bool IsDeclaration,
+ bool Warn) {
if (IsProtocolMethodDecl &&
(MethodDecl->getObjCDeclQualifier() !=
MethodImpl->getObjCDeclQualifier())) {
- S.Diag(MethodImpl->getLocation(),
- diag::warn_conflicting_ret_type_modifiers)
- << MethodImpl->getDeclName() << IsDeclaration
- << getTypeRange(MethodImpl->getResultTypeSourceInfo());
- S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration)
- << getTypeRange(MethodDecl->getResultTypeSourceInfo());
+ if (Warn) {
+ S.Diag(MethodImpl->getLocation(),
+ diag::warn_conflicting_ret_type_modifiers)
+ << MethodImpl->getDeclName() << IsDeclaration
+ << getTypeRange(MethodImpl->getResultTypeSourceInfo());
+ S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration)
+ << getTypeRange(MethodDecl->getResultTypeSourceInfo());
+ }
+ else
+ return false;
}
if (S.Context.hasSameUnqualifiedType(MethodImpl->getResultType(),
MethodDecl->getResultType()))
- return;
+ return true;
+ if (!Warn)
+ return false;
unsigned DiagID = diag::warn_conflicting_ret_types;
@@ -1104,7 +1111,7 @@
// return types that are subclasses of the declared return type,
// or that are more-qualified versions of the declared type.
if (isObjCTypeSubstitutable(S.Context, IfacePtrTy, ImplPtrTy, false))
- return;
+ return false;
DiagID = diag::warn_non_covariant_ret_types;
}
@@ -1118,32 +1125,40 @@
<< getTypeRange(MethodImpl->getResultTypeSourceInfo());
S.Diag(MethodDecl->getLocation(), diag::note_previous_definition)
<< getTypeRange(MethodDecl->getResultTypeSourceInfo());
+ return false;
}
-static void CheckMethodOverrideParam(Sema &S,
+static bool CheckMethodOverrideParam(Sema &S,
ObjCMethodDecl *MethodImpl,
ObjCMethodDecl *MethodDecl,
ParmVarDecl *ImplVar,
ParmVarDecl *IfaceVar,
bool IsProtocolMethodDecl,
- bool IsDeclaration) {
+ bool IsDeclaration,
+ bool Warn) {
if (IsProtocolMethodDecl &&
(ImplVar->getObjCDeclQualifier() !=
IfaceVar->getObjCDeclQualifier())) {
- S.Diag(ImplVar->getLocation(),
- diag::warn_conflicting_param_modifiers)
- << getTypeRange(ImplVar->getTypeSourceInfo())
- << MethodImpl->getDeclName() << IsDeclaration;
- S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration)
- << getTypeRange(IfaceVar->getTypeSourceInfo());
+ if (Warn) {
+ S.Diag(ImplVar->getLocation(),
+ diag::warn_conflicting_param_modifiers)
+ << getTypeRange(ImplVar->getTypeSourceInfo())
+ << MethodImpl->getDeclName() << IsDeclaration;
+ S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration)
+ << getTypeRange(IfaceVar->getTypeSourceInfo());
+ }
+ else
+ return false;
}
QualType ImplTy = ImplVar->getType();
QualType IfaceTy = IfaceVar->getType();
if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy))
- return;
-
+ return true;
+
+ if (!Warn)
+ return false;
unsigned DiagID = diag::warn_conflicting_param_types;
// Mismatches between ObjC pointers go into a different warning
@@ -1157,7 +1172,7 @@
// implementation must accept any objects that the superclass
// accepts, however it may also accept others.
if (isObjCTypeSubstitutable(S.Context, ImplPtrTy, IfacePtrTy, true))
- return;
+ return false;
DiagID = diag::warn_non_contravariant_param_types;
}
@@ -1169,6 +1184,7 @@
<< IsDeclaration;
S.Diag(IfaceVar->getLocation(), diag::note_previous_definition)
<< getTypeRange(IfaceVar->getTypeSourceInfo());
+ return false;
}
/// In ARC, check whether the conventional meanings of the two methods
@@ -1250,13 +1266,13 @@
return;
CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl,
- IsProtocolMethodDecl, IsDeclaration);
+ IsProtocolMethodDecl, IsDeclaration, true);
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, IsDeclaration);
+ IsProtocolMethodDecl, IsDeclaration, true);
if (ImpMethodDecl->isVariadic() != MethodDecl->isVariadic()) {
Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_variadic)
@@ -1265,6 +1281,44 @@
}
}
+/// WarnExactTypedMethods - This routine issues a warning if method
+/// implementation declaration matches exactly that of its declaration.
+void Sema::WarnExactTypedMethods(ObjCMethodDecl *ImpMethodDecl,
+ ObjCMethodDecl *MethodDecl,
+ bool IsProtocolMethodDecl) {
+ // don't issue warning when protocol method is optional because primary
+ // class is not required to implement it and it is safe for protocol
+ // to implement it.
+ if (MethodDecl->getImplementationControl() == ObjCMethodDecl::Optional)
+ return;
+ // don't issue warning when primary class's method is
+ // depecated/unavailable.
+ if (MethodDecl->hasAttr<UnavailableAttr>() ||
+ MethodDecl->hasAttr<DeprecatedAttr>())
+ return;
+
+ bool match = CheckMethodOverrideReturn(*this, ImpMethodDecl, MethodDecl,
+ IsProtocolMethodDecl, false, false);
+ if (match)
+ 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,
+ IsProtocolMethodDecl, false, false);
+ if (!match)
+ break;
+ }
+ if (match)
+ match = (ImpMethodDecl->isVariadic() == MethodDecl->isVariadic());
+
+ if (match) {
+ Diag(ImpMethodDecl->getLocation(),
+ diag::warn_category_method_impl_match);
+ Diag(MethodDecl->getLocation(), diag::note_method_declared_at);
+ }
+}
+
/// FIXME: Type hierarchies in Objective-C can be deep. We could most likely
/// improve the efficiency of selector lookups and type checking by associating
/// with each protocol / interface / category the flattened instance tables. If
@@ -1368,7 +1422,8 @@
ObjCImplDecl* IMPDecl,
ObjCContainerDecl* CDecl,
bool &IncompleteImpl,
- bool ImmediateClass) {
+ bool ImmediateClass,
+ bool WarnExactMatch) {
// Check and see if instance methods in class interface have been
// implemented in the implementation class. If so, their types match.
for (ObjCInterfaceDecl::instmeth_iterator I = CDecl->instmeth_begin(),
@@ -1390,9 +1445,14 @@
assert(MethodDecl &&
"MethodDecl is null in ImplMethodsVsClassMethods");
// ImpMethodDecl may be null as in a @dynamic property.
- if (ImpMethodDecl)
- WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
- isa<ObjCProtocolDecl>(CDecl));
+ if (ImpMethodDecl) {
+ if (!WarnExactMatch)
+ WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
+ isa<ObjCProtocolDecl>(CDecl));
+ else
+ WarnExactTypedMethods(ImpMethodDecl, MethodDecl,
+ isa<ObjCProtocolDecl>(CDecl));
+ }
}
}
@@ -1412,8 +1472,12 @@
IMPDecl->getClassMethod((*I)->getSelector());
ObjCMethodDecl *MethodDecl =
CDecl->getClassMethod((*I)->getSelector());
- WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
- isa<ObjCProtocolDecl>(CDecl));
+ if (!WarnExactMatch)
+ WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl,
+ isa<ObjCProtocolDecl>(CDecl));
+ else
+ WarnExactTypedMethods(ImpMethodDecl, MethodDecl,
+ isa<ObjCProtocolDecl>(CDecl));
}
}
@@ -1424,7 +1488,7 @@
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl,
const_cast<ObjCCategoryDecl *>(ClsExtDecl),
- IncompleteImpl, false);
+ IncompleteImpl, false, WarnExactMatch);
// Check for any implementation of a methods declared in protocol.
for (ObjCInterfaceDecl::all_protocol_iterator
@@ -1432,13 +1496,17 @@
E = I->all_referenced_protocol_end(); PI != E; ++PI)
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl,
- (*PI), IncompleteImpl, false);
+ (*PI), IncompleteImpl, false, WarnExactMatch);
// Check for any type mismtch of methods declared in class
- // and methods declared in protocol.
- MatchMethodsInClassAndItsProtocol(I);
+ // and methods declared in protocol. Do this only when the class
+ // is being implementaed.
+ if (isa<ObjCImplementationDecl>(IMPDecl))
+ MatchMethodsInClassAndItsProtocol(I);
- if (I->getSuperClass())
+ // 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())
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl,
I->getSuperClass(), IncompleteImpl, false);
@@ -1490,6 +1558,9 @@
MatchMethodsInClassAndOneProtocol(S, InsMap, ClsMap, IDecl, (*PI));
}
+/// 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())
@@ -1537,6 +1608,38 @@
}
}
+/// CheckCategoryVsClassMethodMatches - Checks that methods implemented in
+/// category matches with those implemented in its primary class and
+/// warns each time an exact match is found.
+void Sema::CheckCategoryVsClassMethodMatches(
+ ObjCCategoryImplDecl *CatIMPDecl) {
+ llvm::DenseSet<Selector> InsMap, ClsMap;
+
+ for (ObjCImplementationDecl::instmeth_iterator
+ I = CatIMPDecl->instmeth_begin(),
+ E = CatIMPDecl->instmeth_end(); I!=E; ++I)
+ InsMap.insert((*I)->getSelector());
+
+ for (ObjCImplementationDecl::classmeth_iterator
+ I = CatIMPDecl->classmeth_begin(),
+ E = CatIMPDecl->classmeth_end(); I != E; ++I)
+ ClsMap.insert((*I)->getSelector());
+ if (InsMap.empty() && ClsMap.empty())
+ return;
+
+ // Get category's primary class.
+ ObjCCategoryDecl *CatDecl = CatIMPDecl->getCategoryDecl();
+ if (!CatDecl)
+ return;
+ ObjCInterfaceDecl *IDecl = CatDecl->getClassInterface();
+ if (!IDecl)
+ return;
+ llvm::DenseSet<Selector> InsMapSeen, ClsMapSeen;
+ bool IncompleteImpl = false;
+ MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
+ CatIMPDecl, IDecl,
+ IncompleteImpl, false, true /*WarnExactMatch*/);
+}
void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl* CDecl,
@@ -1567,6 +1670,11 @@
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
IMPDecl, CDecl,
IncompleteImpl, true);
+ // check all methods implemented in category against those declared
+ // in its primary class.
+ if (ObjCCategoryImplDecl *CatDecl =
+ dyn_cast<ObjCCategoryImplDecl>(IMPDecl))
+ CheckCategoryVsClassMethodMatches(CatDecl);
// Check the protocol list for unimplemented methods in the @implementation
// class.
Modified: cfe/trunk/test/SemaObjC/arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc.m?rev=136426&r1=136425&r2=136426&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/arc.m (original)
+++ cfe/trunk/test/SemaObjC/arc.m Thu Jul 28 18:19:50 2011
@@ -41,10 +41,10 @@
// rdar://8843638
@interface I
-- (id)retain;
-- (id)autorelease;
-- (oneway void)release;
-- (NSUInteger)retainCount;
+- (id)retain; // expected-note {{method declared here}}
+- (id)autorelease; // expected-note {{method declared here}}
+- (oneway void)release; // expected-note {{method declared here}}
+- (NSUInteger)retainCount; // expected-note {{method declared here}}
@end
@implementation I
@@ -55,10 +55,14 @@
@end
@implementation I(CAT)
-- (id)retain{return 0;} // expected-error {{ARC forbids implementation of 'retain'}}
-- (id)autorelease{return 0;} // expected-error {{ARC forbids implementation of 'autorelease'}}
-- (oneway void)release{} // expected-error {{ARC forbids implementation of 'release'}}
-- (NSUInteger)retainCount{ return 0; } // expected-error {{ARC forbids implementation of 'retainCount'}}
+- (id)retain{return 0;} // expected-error {{ARC forbids implementation of 'retain'}} \
+ // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
+- (id)autorelease{return 0;} // expected-error {{ARC forbids implementation of 'autorelease'}} \
+ // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
+- (oneway void)release{} // expected-error {{ARC forbids implementation of 'release'}} \
+ // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
+- (NSUInteger)retainCount{ return 0; } // expected-error {{ARC forbids implementation of 'retainCount'}} \
+ // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
@end
// rdar://8861761
Modified: cfe/trunk/test/SemaObjC/incomplete-implementation.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/incomplete-implementation.m?rev=136426&r1=136425&r2=136426&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/incomplete-implementation.m (original)
+++ cfe/trunk/test/SemaObjC/incomplete-implementation.m Thu Jul 28 18:19:50 2011
@@ -1,26 +1,27 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
@interface I
-- Meth; // expected-note{{method definition for 'Meth' not found}}
+- Meth; // expected-note{{method definition for 'Meth' not found}} \
+ // expected-note{{method declared here}}
@end
@implementation I // expected-warning{{incomplete implementation}}
@end
@implementation I(CAT)
-- Meth {return 0;}
+- Meth {return 0;} // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
@end
#pragma GCC diagnostic ignored "-Wincomplete-implementation"
@interface I2
-- Meth;
+- Meth; // expected-note{{method declared here}}
@end
@implementation I2
@end
@implementation I2(CAT)
-- Meth {return 0;}
+- Meth {return 0;} // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
@end
Added: cfe/trunk/test/SemaObjC/protocol-implementing-class-methods.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/protocol-implementing-class-methods.m?rev=136426&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/protocol-implementing-class-methods.m (added)
+++ cfe/trunk/test/SemaObjC/protocol-implementing-class-methods.m Thu Jul 28 18:19:50 2011
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar://7020493
+
+ at protocol P1
+ at optional
+- (int) PMeth;
+ at required
+- (void) : (double) arg; // expected-note {{method declared here}}
+ at end
+
+ at interface NSImage <P1>
+- (void) initialize; // expected-note {{method declared here}}
+ at end
+
+ at interface NSImage (AirPortUI)
+- (void) initialize;
+ at end
+
+ at interface NSImage()
+- (void) CEMeth; // expected-note {{method declared here}}
+ at end
+
+ at implementation NSImage (AirPortUI)
+- (void) initialize {NSImage *p=0; [p initialize]; } // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
+- (int) PMeth{ return 0; }
+- (void) : (double) arg{}; // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
+- (void) CEMeth {}; // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
+ at end
Modified: cfe/trunk/test/SemaObjC/related-result-type-inference.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/related-result-type-inference.m?rev=136426&r1=136425&r2=136426&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/related-result-type-inference.m (original)
+++ cfe/trunk/test/SemaObjC/related-result-type-inference.m Thu Jul 28 18:19:50 2011
@@ -149,8 +149,8 @@
@end
// <rdar://problem/9340699>
- at interface G
-- (id)_ABC_init __attribute__((objc_method_family(init)));
+ at interface G
+- (id)_ABC_init __attribute__((objc_method_family(init))); // expected-note {{method declared here}}
@end
@interface G (Additions)
@@ -158,7 +158,7 @@
@end
@implementation G (Additions)
-- (id)_ABC_init {
+- (id)_ABC_init { // expected-warning {{category is implementing a method which will also be implemented by its primary class}}
return 0;
}
- (id)_ABC_init2 {
More information about the cfe-commits
mailing list