[cfe-commits] r136927 - in /cfe/trunk: include/clang/Basic/IdentifierTable.h include/clang/Sema/Sema.h lib/Sema/SemaDeclObjC.cpp test/SemaObjC/class-protocol-method-match.m test/SemaObjC/qualified-protocol-method-conflicts.m

Fariborz Jahanian fjahanian at apple.com
Thu Aug 4 14:28:44 PDT 2011


Author: fjahanian
Date: Thu Aug  4 16:28:44 2011
New Revision: 136927

URL: http://llvm.org/viewvc/llvm-project?rev=136927&view=rev
Log:
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.

Added:
    cfe/trunk/test/SemaObjC/qualified-protocol-method-conflicts.m
Modified:
    cfe/trunk/include/clang/Basic/IdentifierTable.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/test/SemaObjC/class-protocol-method-match.m

Modified: cfe/trunk/include/clang/Basic/IdentifierTable.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/IdentifierTable.h?rev=136927&r1=136926&r2=136927&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/IdentifierTable.h (original)
+++ cfe/trunk/include/clang/Basic/IdentifierTable.h Thu Aug  4 16:28:44 2011
@@ -557,6 +557,11 @@
   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);
   }

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=136927&r1=136926&r2=136927&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Aug  4 16:28:44 2011
@@ -493,6 +493,23 @@
   /// 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 @@
   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 @@
                                   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

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=136927&r1=136926&r2=136927&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Thu Aug  4 16:28:44 2011
@@ -1281,6 +1281,35 @@
   }
 }
 
+/// 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 @@
   }
 }
 
+/// 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 @@
                                     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 @@
   // 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.

Modified: cfe/trunk/test/SemaObjC/class-protocol-method-match.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/class-protocol-method-match.m?rev=136927&r1=136926&r2=136927&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/class-protocol-method-match.m (original)
+++ cfe/trunk/test/SemaObjC/class-protocol-method-match.m Thu Aug  4 16:28:44 2011
@@ -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
 
- at interface Foo <Baz>
+ at 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;

Added: cfe/trunk/test/SemaObjC/qualified-protocol-method-conflicts.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/qualified-protocol-method-conflicts.m?rev=136927&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/qualified-protocol-method-conflicts.m (added)
+++ cfe/trunk/test/SemaObjC/qualified-protocol-method-conflicts.m Thu Aug  4 16:28:44 2011
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1  -fsyntax-only -verify %s
+// rdar://6191214
+
+ at 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}}
+ at end
+
+ at 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}}
+ at end
+
+ at interface A <Xint, Xfloat> // expected-note {{class is declared here}}
+ at end
+
+ at implementation A
+-(void) setX: (int) arg0 { }
++(int) C {return 0; }
+ at end
+
+ at interface B <Xfloat, Xint> // expected-note {{class is declared here}}
+ at end
+
+ at implementation B 
+-(void) setX: (float) arg0 { }
++ (float) C {return 0.0; }
+ at end
+
+ at protocol Xint_float<Xint, Xfloat>
+ at end
+
+ at interface C<Xint_float> // expected-note {{class is declared here}}
+ at end
+
+ at implementation C
+-(void) setX: (int) arg0 { }
++ (int) C {return 0;}
+ at end





More information about the cfe-commits mailing list