atch for implementation of objective-c's -Wselector
warning flag in clang. Little more to do
for a PCH issue. Radar 6507158.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109129 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 2a17551..d4735bf 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -128,6 +128,9 @@
 
   // Synthesized declaration method for a property setter/getter
   bool IsSynthesized : 1;
+  
+  // Method has a definition.
+  bool IsDefined : 1;
 
   // NOTE: VC++ treats enums as signed, avoid using ImplementationControl enum
   /// @required/@optional
@@ -171,12 +174,14 @@
                  bool isInstance = true,
                  bool isVariadic = false,
                  bool isSynthesized = false,
+                 bool isDefined = false,
                  ImplementationControl impControl = None,
                  unsigned numSelectorArgs = 0)
   : NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
     DeclContext(ObjCMethod),
     IsInstance(isInstance), IsVariadic(isVariadic),
     IsSynthesized(isSynthesized),
+    IsDefined(isDefined),
     DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None),
     NumSelectorArgs(numSelectorArgs), MethodDeclType(T), 
     ResultTInfo(ResultTInfo),
@@ -203,6 +208,7 @@
                                 bool isInstance = true,
                                 bool isVariadic = false,
                                 bool isSynthesized = false,
+                                bool isDefined = false,
                                 ImplementationControl impControl = None,
                                 unsigned numSelectorArgs = 0);
 
@@ -296,6 +302,9 @@
 
   bool isSynthesized() const { return IsSynthesized; }
   void setSynthesized(bool isSynth) { IsSynthesized = isSynth; }
+  
+  bool isDefined() const { return IsDefined; }
+  void setDefined(bool isDefined) { IsDefined = isDefined; }
 
   // Related to protocols declared in  @protocol
   void setDeclImplementation(ImplementationControl ic) {
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 1416d71..033b6c4 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -134,6 +134,7 @@
 def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">;
 def Reorder : DiagGroup<"reorder">;
 def UndeclaredSelector : DiagGroup<"undeclared-selector">;
+def Selector : DiagGroup<"selector">;
 def Protocol : DiagGroup<"protocol">;
 def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">;
 def : DiagGroup<"variadic-macros">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 59bd8f8..6fb5318 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -400,6 +400,8 @@
   InGroup<ReadOnlySetterAttrs>, DefaultIgnore;
 def warn_undeclared_selector : Warning<
   "undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore;
+def warn_unimplemented_selector:  Warning<
+  "unimplemented selector %0">, InGroup<Selector>, DefaultIgnore;
 def warn_unimplemented_protocol_method : Warning<
   "method in protocol not implemented">, InGroup<Protocol>;
 
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 9cb47aa..2ca49ad 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -202,6 +202,8 @@
     return DeclGroupPtrTy();
   }
 
+  virtual void DiagnoseUseOfUnimplementedSelectors() {}
+
   /// getTypeName - Return non-null if the specified identifier is a type name
   /// in the current scope.
   ///
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 90a1cab..c23adb6 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -201,7 +201,7 @@
   /// the EOF was encountered.
   bool ParseTopLevelDecl(DeclGroupPtrTy &Result);
 
-  DeclGroupPtrTy RetrievePendingObjCImpDecl();
+  DeclGroupPtrTy FinishPendingObjCActions();
 
 private:
   //===--------------------------------------------------------------------===//
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 6b2c90c..befdc7a 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -2299,6 +2299,7 @@
                              D->isInstanceMethod(),
                              D->isVariadic(),
                              D->isSynthesized(),
+                             D->isDefined(),
                              D->getImplementationControl());
 
   // FIXME: When we decide to merge method definitions, we'll need to
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index fce24dc..c682cf1 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -339,12 +339,14 @@
                                        bool isInstance,
                                        bool isVariadic,
                                        bool isSynthesized,
+                                       bool isDefined,
                                        ImplementationControl impControl,
                                        unsigned numSelectorArgs) {
   return new (C) ObjCMethodDecl(beginLoc, endLoc,
                                 SelInfo, T, ResultTInfo, contextDecl,
                                 isInstance,
-                                isVariadic, isSynthesized, impControl,
+                                isVariadic, isSynthesized, isDefined,
+                                impControl,
                                 numSelectorArgs);
 }
 
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index f6788c6..057182d 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -1930,7 +1930,7 @@
                                                   D->getLocation(),
                                                   D->getLocation(), cxxSelector,
                                                   getContext().VoidTy, 0, 
-                                                  DC, true, false, true,
+                                                  DC, true, false, true, false,
                                                   ObjCMethodDecl::Required);
   D->addInstanceMethod(DTORMethod);
   CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false);
@@ -1942,7 +1942,7 @@
                                                 D->getLocation(),
                                                 D->getLocation(), cxxSelector,
                                                 getContext().getObjCIdType(), 0, 
-                                                DC, true, false, true,
+                                                DC, true, false, true, false,
                                                 ObjCMethodDecl::Required);
   D->addInstanceMethod(CTORMethod);
   CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true);
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index d1f8b3a..058b19d 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -324,6 +324,7 @@
   MD->setInstanceMethod(Record[Idx++]);
   MD->setVariadic(Record[Idx++]);
   MD->setSynthesized(Record[Idx++]);
+  MD->setDefined(Record[Idx++]);
   MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]);
   MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
   MD->setNumSelectorArgs(unsigned(Record[Idx++]));
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index f6c6cde..7c4a21a 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -312,6 +312,7 @@
   Record.push_back(D->isInstanceMethod());
   Record.push_back(D->isVariadic());
   Record.push_back(D->isSynthesized());
+  Record.push_back(D->isDefined());
   // FIXME: stable encoding for @required/@optional
   Record.push_back(D->getImplementationControl());
   // FIXME: stable encoding for in/out/inout/bycopy/byref/oneway
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 68473a5..a7e0856 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -1314,7 +1314,8 @@
   return Result;
 }
 
-Parser::DeclGroupPtrTy Parser::RetrievePendingObjCImpDecl() {
+Parser::DeclGroupPtrTy Parser::FinishPendingObjCActions() {
+  Actions.DiagnoseUseOfUnimplementedSelectors();
   if (PendingObjCImpDecl.empty())
     return Actions.ConvertDeclToDeclGroup(DeclPtrTy());
   DeclPtrTy ImpDecl = PendingObjCImpDecl.pop_back_val();
diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp
index bb0bd9e..73f1167 100644
--- a/lib/Sema/ParseAST.cpp
+++ b/lib/Sema/ParseAST.cpp
@@ -92,7 +92,7 @@
       Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>());
   };
   // Check for any pending objective-c implementation decl.
-  while ((ADecl = P.RetrievePendingObjCImpDecl()))
+  while ((ADecl = P.FinishPendingObjCActions()))
     Consumer->HandleTopLevelDecl(ADecl.getAsVal<DeclGroupRef>());
 
   // Process any TopLevelDecls generated by #pragma weak.
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 490ff65..0540dd9 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -606,6 +606,11 @@
   MethodPool InstanceMethodPool;
   MethodPool FactoryMethodPool;
 
+  /// Method selectors used in a @selector expression. Used for implementation 
+  /// of -Wselector.
+  llvm::DenseMap<Selector, SourceLocation> ReferencedSelectors;
+
+
   MethodPool::iterator ReadMethodPool(Selector Sel, bool isInstance);
 
   /// Private Helper predicate to check for 'self'.
@@ -798,6 +803,8 @@
 
   DeclGroupPtrTy ConvertDeclToDeclGroup(DeclPtrTy Ptr);
 
+  void DiagnoseUseOfUnimplementedSelectors();
+
   virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
                               Scope *S, CXXScopeSpec *SS,
                               bool isClassName = false,
@@ -1656,7 +1663,7 @@
   /// unit are added to a global pool. This allows us to efficiently associate
   /// a selector with a method declaraation for purposes of typechecking
   /// messages sent to "id" (where the class of the object is unknown).
-  void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method);
+  void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false);
 
   /// LookupInstanceMethodInGlobalPool - Returns the method and warns if
   /// there are multiple signatures.
@@ -1665,10 +1672,15 @@
 
   /// LookupFactoryMethodInGlobalPool - Returns the method and warns if
   /// there are multiple signatures.
-  ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R);
+  ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R,
+                                                  bool warn=true);
+
+  /// LookupImplementedMethodInGlobalPool - Returns the method which has an
+  /// implementation.
+  ObjCMethodDecl *LookupImplementedMethodInGlobalPool(Selector Sel);
 
   /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods.
-  void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method);
+  void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false);
 
   /// CollectIvarsToConstructOrDestruct - Collect those ivars which require
   /// initialization.
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 21aeb59..5f2f37e 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -32,10 +32,10 @@
 
   // Allow the rest of sema to find private method decl implementations.
   if (MDecl->isInstanceMethod())
-    AddInstanceMethodToGlobalPool(MDecl);
+    AddInstanceMethodToGlobalPool(MDecl, true);
   else
-    AddFactoryMethodToGlobalPool(MDecl);
-
+    AddFactoryMethodToGlobalPool(MDecl, true);
+  
   // Allow all of Sema to see that we are entering a method definition.
   PushDeclContext(FnBodyScope, MDecl);
   PushFunctionScope();
@@ -1130,7 +1130,7 @@
   return FactoryMethodPool.insert(std::make_pair(Sel, Methods.second)).first;
 }
 
-void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) {
+void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method, bool impl) {
   llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
     = InstanceMethodPool.find(Method->getSelector());
   if (Pos == InstanceMethodPool.end()) {
@@ -1140,7 +1140,7 @@
       Pos = InstanceMethodPool.insert(std::make_pair(Method->getSelector(),
                                                      ObjCMethodList())).first;
   }
-
+  Method->setDefined(impl);
   ObjCMethodList &Entry = Pos->second;
   if (Entry.Method == 0) {
     // Haven't seen a method with this selector name yet - add it.
@@ -1152,8 +1152,10 @@
   // We've seen a method with this name, see if we have already seen this type
   // signature.
   for (ObjCMethodList *List = &Entry; List; List = List->Next)
-    if (MatchTwoMethodDeclarations(Method, List->Method))
+    if (MatchTwoMethodDeclarations(Method, List->Method)) {
+      List->Method->setDefined(impl);
       return;
+    }
 
   // We have a new signature for an existing method - add it.
   // This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
@@ -1194,7 +1196,7 @@
   return MethList.Method;
 }
 
-void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) {
+void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method, bool impl) {
   llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
     = FactoryMethodPool.find(Method->getSelector());
   if (Pos == FactoryMethodPool.end()) {
@@ -1204,32 +1206,31 @@
       Pos = FactoryMethodPool.insert(std::make_pair(Method->getSelector(),
                                                     ObjCMethodList())).first;
   }
-
-  ObjCMethodList &FirstMethod = Pos->second;
-  if (!FirstMethod.Method) {
+  Method->setDefined(impl);
+  ObjCMethodList &Entry = Pos->second;
+  if (!Entry.Method) {
     // Haven't seen a method with this selector name yet - add it.
-    FirstMethod.Method = Method;
-    FirstMethod.Next = 0;
-  } else {
-    // We've seen a method with this name, now check the type signature(s).
-    bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method);
-
-    for (ObjCMethodList *Next = FirstMethod.Next; !match && Next;
-         Next = Next->Next)
-      match = MatchTwoMethodDeclarations(Method, Next->Method);
-
-    if (!match) {
-      // We have a new signature for an existing method - add it.
-      // This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
-      ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>();
-      ObjCMethodList *OMI = new (Mem) ObjCMethodList(Method, FirstMethod.Next);
-      FirstMethod.Next = OMI;
+    Entry.Method = Method;
+    Entry.Next = 0;
+    return;
+  } 
+  // We've seen a method with this name, see if we have already seen this type
+  // signature.
+  for (ObjCMethodList *List = &Entry; List; List = List->Next)
+    if (MatchTwoMethodDeclarations(Method, List->Method)) {
+      List->Method->setDefined(impl);
+      return;
     }
-  }
+  
+  // We have a new signature for an existing method - add it.
+  // This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
+  ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>();
+  Entry.Next = new (Mem) ObjCMethodList(Method, Entry.Next);
 }
 
 ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel,
-                                                      SourceRange R) {
+                                                      SourceRange R,
+                                                      bool warn) {
   llvm::DenseMap<Selector, ObjCMethodList>::iterator Pos
     = FactoryMethodPool.find(Sel);
   if (Pos == FactoryMethodPool.end()) {
@@ -1246,7 +1247,7 @@
     for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
       // This checks if the methods differ by size & alignment.
       if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true))
-        issueWarning = true;
+        issueWarning = warn;
   }
   if (issueWarning && (MethList.Method && MethList.Next)) {
     Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
@@ -1259,6 +1260,18 @@
   return MethList.Method;
 }
 
+ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {
+  SourceRange SR;
+  ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel,
+                                                            SR, false);
+  if (Method && Method->isDefined())
+    return Method;
+  Method = LookupFactoryMethodInGlobalPool(Sel, SR, false);
+  if (Method && Method->isDefined())
+    return Method;
+  return 0;
+}
+
 /// CompareMethodParamsInBaseAndSuper - This routine compares methods with
 /// identical selector names in current and its super classes and issues
 /// a warning if any of their argument types are incompatible.
@@ -1540,7 +1553,7 @@
                            ResultTInfo,
                            cast<DeclContext>(ClassDecl),
                            MethodType == tok::minus, isVariadic,
-                           false,
+                           false, false,
                            MethodDeclKind == tok::objc_optional ?
                            ObjCMethodDecl::Optional :
                            ObjCMethodDecl::Required);
@@ -1849,3 +1862,15 @@
   }
 }
 
+void Sema::DiagnoseUseOfUnimplementedSelectors() {
+  if (ReferencedSelectors.empty())
+    return;
+  for (llvm::DenseMap<Selector, SourceLocation>::iterator S = 
+        ReferencedSelectors.begin(),
+       E = ReferencedSelectors.end(); S != E; ++S) {
+    Selector Sel = (*S).first;
+    if (!LookupImplementedMethodInGlobalPool(Sel))
+      Diag((*S).second, diag::warn_unimplemented_selector) << Sel;
+  }
+  return;
+}
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 9f43471..5132464 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -163,6 +163,11 @@
   if (!Method)
     Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
 
+  llvm::DenseMap<Selector, SourceLocation>::iterator Pos
+    = ReferencedSelectors.find(Sel);
+  if (Pos == ReferencedSelectors.end())
+    ReferencedSelectors.insert(std::make_pair(Sel, SelLoc));
+
   QualType Ty = Context.getObjCSelType();
   return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc);
 }
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index e7358ed..6a7d8db 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -1084,7 +1084,8 @@
     // for this class.
     GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(),
                              property->getLocation(), property->getGetterName(),
-                             property->getType(), 0, CD, true, false, true,
+                             property->getType(), 0, CD, true, false, true, 
+                             false,
                              (property->getPropertyImplementation() ==
                               ObjCPropertyDecl::Optional) ?
                              ObjCMethodDecl::Optional :
@@ -1112,6 +1113,7 @@
                                property->getLocation(),
                                property->getSetterName(),
                                Context.VoidTy, 0, CD, true, false, true,
+                               false,
                                (property->getPropertyImplementation() ==
                                 ObjCPropertyDecl::Optional) ?
                                ObjCMethodDecl::Optional :