]> granicus.if.org Git - clang/commitdiff
Objective-C [qoi]: Provide fixit hint when message with typo
authorFariborz Jahanian <fjahanian@apple.com>
Mon, 17 Jun 2013 17:10:54 +0000 (17:10 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Mon, 17 Jun 2013 17:10:54 +0000 (17:10 +0000)
is sent to a receiver object. This is wip. // rdar://7853549

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184086 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaDeclObjC.cpp
lib/Sema/SemaExprObjC.cpp
test/FixIt/selector-fixit.m
test/SemaObjC/call-super-2.m
test/SemaObjC/protocol-id-test-1.m

index eddf1e2e950d7102252160abd957682da4edf899..cb207a6c6dc110c6f34b326fb5a0ab8651990e3f 100644 (file)
@@ -4601,6 +4601,9 @@ def warn_instance_method_on_class_found : Warning<
 def warn_inst_method_not_found : Warning<
   "instance method %objcinstance0 not found (return type defaults to 'id')">,
   InGroup<MethodAccess>;
+def warn_method_not_found_with_typo : Warning<
+  "%select{instance|class}0 method %1 not found (return type defaults to 'id')"
+  "; did you mean %2?">, InGroup<MethodAccess>;
 def error_no_super_class_message : Error<
   "no @interface declaration found in class messaging of %0">;
 def error_root_class_cannot_use_super : Error<
index 03952feea35dc377ed0276db181935bd8fb30c05..ca20c04fa60ecdfa99005cb63d2b9303cd677316 100644 (file)
@@ -2672,7 +2672,8 @@ public:
                                     warn, /*instance*/false);
   }
 
-  const ObjCMethodDecl *SelectorsForTypoCorrection(Selector Sel);
+  const ObjCMethodDecl *SelectorsForTypoCorrection(Selector Sel,
+                              QualType ObjectType=QualType());
   
   /// DiagnoseMismatchedMethodsInGlobalPool - This routine goes through list of
   /// methods in global pool and issues diagnostic on identical selectors which
index 07282935c8a446cf7607be7ea57644c14b438c5b..b3102efe475829d6523b11c6ddde5f397cf95191 100644 (file)
@@ -2295,8 +2295,18 @@ HelperSelectorsForTypoCorrection(
   }
 }
 
+static bool HelperIsMethodInObjCType(Sema &S, Selector Sel,
+                                     QualType ObjectType) {
+  if (ObjectType.isNull())
+    return true;
+  if (S.LookupMethodInObjectType(Sel, ObjectType, true/*Instance method*/))
+    return true;
+  return S.LookupMethodInObjectType(Sel, ObjectType, false/*Class method*/) != 0;
+}
+
 const ObjCMethodDecl *
-Sema::SelectorsForTypoCorrection(Selector Sel) {
+Sema::SelectorsForTypoCorrection(Selector Sel,
+                                 QualType ObjectType) {
   unsigned NumArgs = Sel.getNumArgs();
   SmallVector<const ObjCMethodDecl *, 8> Methods;
   
@@ -2305,12 +2315,14 @@ Sema::SelectorsForTypoCorrection(Selector Sel) {
     // instance methods
     for (ObjCMethodList *M = &b->second.first; M; M=M->getNext())
       if (M->Method &&
-          (M->Method->getSelector().getNumArgs() == NumArgs))
+          (M->Method->getSelector().getNumArgs() == NumArgs) &&
+          HelperIsMethodInObjCType(*this, M->Method->getSelector(), ObjectType))
         Methods.push_back(M->Method);
     // class methods
     for (ObjCMethodList *M = &b->second.second; M; M=M->getNext())
       if (M->Method &&
-          (M->Method->getSelector().getNumArgs() == NumArgs))
+          (M->Method->getSelector().getNumArgs() == NumArgs) &&
+          HelperIsMethodInObjCType(*this, M->Method->getSelector(), ObjectType))
         Methods.push_back(M->Method);
   }
   
index b21f8e70f5def34ad76f7cda0ffd51f6927c14b3..5b994cbe784247a2d08c07a69a5ef3e35aaec534 100644 (file)
@@ -1232,8 +1232,22 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
       DiagID = isClassMessage ? diag::warn_class_method_not_found
                               : diag::warn_inst_method_not_found;
     if (!getLangOpts().DebuggerSupport) {
-      Diag(SelLoc, DiagID)
-        << Sel << isClassMessage << SourceRange(SelectorLocs.front(), 
+      const ObjCMethodDecl *OMD = 0;
+      if (const ObjCObjectPointerType *ObjCPtr =
+          ReceiverType->getAsObjCInterfacePointerType()) {
+        QualType ObjectType = QualType(ObjCPtr->getInterfaceType(), 0);
+        OMD = SelectorsForTypoCorrection(Sel, ObjectType);
+      }
+      if (OMD) {
+        Selector MatchedSel = OMD->getSelector();
+        SourceRange SelectorRange(SelectorLocs.front(), SelectorLocs.back());
+        Diag(SelLoc, diag::warn_method_not_found_with_typo)
+          << isClassMessage << Sel << MatchedSel
+          << FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString());
+      }
+      else
+        Diag(SelLoc, DiagID)
+          << Sel << isClassMessage << SourceRange(SelectorLocs.front(), 
                                                 SelectorLocs.back());
       // Find the class to which we are sending this message.
       if (ReceiverType->isObjCObjectPointerType()) {
index a8b38c6b9efbe9203c348a542b0cdefb4f42cbd9..ed7c7186ffe0920e3e4d3f7eada45c51ed7af3f2 100644 (file)
 }
 
 @end
+
+// rdar://7853549
+@interface rdar7853549 : NSObject
+- (int) bounds;
+@end
+
+@implementation rdar7853549
+- (int) bounds { return 0; }
+- (void)PrivateMeth { int bounds = [self bonds]; }
+@end
index 25cfbdd0879be78792e0f32e7824cd7ce61b19a5..071f9fdfd8175a1d3ccdfa4b216c970d7c330be5 100644 (file)
@@ -68,7 +68,7 @@ id objc_getClass(const char *s);
 }
 - (int) instance_func1
 {
-   int i = (size_t)[self instance_func0];     // expected-warning {{instance method '-instance_func0' not found (return type defaults to 'id')}}
+   int i = (size_t)[self instance_func0];     // expected-warning {{instance method 'instance_func0' not found (return type defaults to 'id'); did you mean 'instance_func3'?}}
    return i + (size_t)[super instance_func0]; // expected-warning {{'Object' may not respond to 'instance_func0'}}
 }
 - (int) instance_func2
index 36e23ed9f29d1853c1f9c15d6138843a503b01f7..6583b3c7ea4cbcc82386fbef2c2b9bc8e7d1b490 100644 (file)
@@ -12,5 +12,5 @@
 @end
 
 @implementation INTF
-- (void)IMeth {INTF<P> *pi;  [pi Meth]; } // expected-warning {{method '-Meth' not found (return type defaults to 'id')}}
+- (void)IMeth {INTF<P> *pi;  [pi Meth]; } // expected-warning {{instance method 'Meth' not found (return type defaults to 'id'); did you mean 'IMeth'?}}
 @end