зеркало из https://github.com/microsoft/clang-1.git
objective-c: diagnose protocol inconsistencies in following
situation. When a class explicitly or implicitly (through inheritance) "conformsTo" two protocols which conflict (have methods which conflict). This is 2nd part of // rdar://6191214. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@136927 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
fc54016ead
Коммит
6a3bec320e
|
@ -557,6 +557,11 @@ 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<void*>(InfoPtr);
|
||||
}
|
||||
|
|
|
@ -493,6 +493,23 @@ public:
|
|||
/// a potentially evaluated expression.
|
||||
typedef SmallVector<std::pair<SourceLocation, Decl *>, 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<PROTOCOL_METHODS, 16> MethodsInProtocols;
|
||||
|
||||
/// \brief A set of diagnostics that may be emitted.
|
||||
typedef SmallVector<std::pair<SourceLocation, PartialDiagnostic>, 10>
|
||||
|
@ -1780,7 +1797,12 @@ 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);
|
||||
|
||||
|
@ -1904,10 +1926,16 @@ 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
|
||||
|
|
|
@ -1281,6 +1281,35 @@ void Sema::WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethodDecl,
|
|||
}
|
||||
}
|
||||
|
||||
/// 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;
|
||||
Diag(MethodDecl->getLocation(), diag::note_previous_declaration);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// WarnExactTypedMethods - This routine issues a warning if method
|
||||
/// implementation declaration matches exactly that of its declaration.
|
||||
void Sema::WarnExactTypedMethods(ObjCMethodDecl *ImpMethodDecl,
|
||||
|
@ -1565,6 +1594,41 @@ static void CollectMethodsInOneProtocol(const ObjCProtocolDecl *PDecl,
|
|||
}
|
||||
}
|
||||
|
||||
/// 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<ObjCInterfaceDecl>(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<ObjCProtocolDecl>(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.
|
||||
|
@ -1609,6 +1673,65 @@ void Sema::MatchMethodsInClassAndItsProtocol(const ObjCInterfaceDecl *CDecl) {
|
|||
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;
|
||||
while (lo < hi) {
|
||||
ObjCMethodDecl *targetMethod = Methods[lo].Method;
|
||||
for (int j = lo+1; j <= hi; j++) {
|
||||
// match two methods;
|
||||
ObjCMethodDecl *otherMethod = Methods[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.
|
||||
|
@ -1675,8 +1798,10 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
|
|||
// 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))
|
||||
if (const ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
|
||||
MatchIdenticalSelectorsInProtocols(I);
|
||||
MatchMethodsInClassAndItsProtocol(I);
|
||||
}
|
||||
|
||||
// check all methods implemented in category against those declared
|
||||
// in its primary class.
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
@protocol Bar
|
||||
@required
|
||||
- (unsigned char) baz; // expected-note {{previous definition is here}}
|
||||
- (char) ok;
|
||||
- (char) ok; // expected-note {{previous definition is here}}
|
||||
- (void) also_ok;
|
||||
@end
|
||||
|
||||
|
@ -17,11 +17,11 @@
|
|||
|
||||
@protocol Baz <Bar, Bar1>
|
||||
- (void) bar : (unsigned char)arg; // expected-note {{previous definition is here}}
|
||||
- (void) ok;
|
||||
- (void) ok; // expected-warning {{conflicting return type in declaration of 'ok': 'char' vs 'void'}}
|
||||
- (char) bak; // expected-note {{previous definition is here}}
|
||||
@end
|
||||
|
||||
@interface Foo <Baz>
|
||||
@interface Foo <Baz> // expected-note {{class is declared here}}
|
||||
- (void) baz; // expected-warning {{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;
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
// rdar://6191214
|
||||
|
||||
@protocol Xint
|
||||
-(void) setX: (int) arg0; // expected-warning 2 {{conflicting parameter types in declaration of 'setX:': 'float' vs 'int'}} \
|
||||
// expected-note {{previous definition is here}}
|
||||
+(int) C; // expected-warning 2 {{conflicting return type in declaration of 'C': 'float' vs 'int'}} \
|
||||
// expected-note {{previous definition is here}}
|
||||
@end
|
||||
|
||||
@protocol Xfloat
|
||||
-(void) setX: (float) arg0; // expected-note 2 {{previous definition is here}} \
|
||||
// expected-warning {{conflicting parameter types in declaration of 'setX:': 'int' vs 'float'}}
|
||||
+(float) C; // expected-warning {{conflicting return type in declaration of 'C': 'int' vs 'float'}} \
|
||||
// expected-note 2 {{previous definition is here}}
|
||||
@end
|
||||
|
||||
@interface A <Xint, Xfloat> // expected-note {{class is declared here}}
|
||||
@end
|
||||
|
||||
@implementation A
|
||||
-(void) setX: (int) arg0 { }
|
||||
+(int) C {return 0; }
|
||||
@end
|
||||
|
||||
@interface B <Xfloat, Xint> // expected-note {{class is declared here}}
|
||||
@end
|
||||
|
||||
@implementation B
|
||||
-(void) setX: (float) arg0 { }
|
||||
+ (float) C {return 0.0; }
|
||||
@end
|
||||
|
||||
@protocol Xint_float<Xint, Xfloat>
|
||||
@end
|
||||
|
||||
@interface C<Xint_float> // expected-note {{class is declared here}}
|
||||
@end
|
||||
|
||||
@implementation C
|
||||
-(void) setX: (int) arg0 { }
|
||||
+ (int) C {return 0;}
|
||||
@end
|
Загрузка…
Ссылка в новой задаче