From d395e34ae7aeeeaf9a37a12bc0f6de87158c95c3 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Mon, 17 Jun 2013 17:10:54 +0000 Subject: [PATCH] Objective-C [qoi]: Provide fixit hint when message with typo 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 | 3 +++ include/clang/Sema/Sema.h | 3 ++- lib/Sema/SemaDeclObjC.cpp | 18 +++++++++++++++--- lib/Sema/SemaExprObjC.cpp | 18 ++++++++++++++++-- test/FixIt/selector-fixit.m | 10 ++++++++++ test/SemaObjC/call-super-2.m | 2 +- test/SemaObjC/protocol-id-test-1.m | 2 +- 7 files changed, 48 insertions(+), 8 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index eddf1e2e95..cb207a6c6d 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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; +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; def error_no_super_class_message : Error< "no @interface declaration found in class messaging of %0">; def error_root_class_cannot_use_super : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 03952feea3..ca20c04fa6 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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 diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 07282935c8..b3102efe47 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -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 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); } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index b21f8e70f5..5b994cbe78 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -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()) { diff --git a/test/FixIt/selector-fixit.m b/test/FixIt/selector-fixit.m index a8b38c6b9e..ed7c7186ff 100644 --- a/test/FixIt/selector-fixit.m +++ b/test/FixIt/selector-fixit.m @@ -28,3 +28,13 @@ } @end + +// rdar://7853549 +@interface rdar7853549 : NSObject +- (int) bounds; +@end + +@implementation rdar7853549 +- (int) bounds { return 0; } +- (void)PrivateMeth { int bounds = [self bonds]; } +@end diff --git a/test/SemaObjC/call-super-2.m b/test/SemaObjC/call-super-2.m index 25cfbdd087..071f9fdfd8 100644 --- a/test/SemaObjC/call-super-2.m +++ b/test/SemaObjC/call-super-2.m @@ -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 diff --git a/test/SemaObjC/protocol-id-test-1.m b/test/SemaObjC/protocol-id-test-1.m index 36e23ed9f2..6583b3c7ea 100644 --- a/test/SemaObjC/protocol-id-test-1.m +++ b/test/SemaObjC/protocol-id-test-1.m @@ -12,5 +12,5 @@ @end @implementation INTF -- (void)IMeth {INTF

*pi; [pi Meth]; } // expected-warning {{method '-Meth' not found (return type defaults to 'id')}} +- (void)IMeth {INTF

*pi; [pi Meth]; } // expected-warning {{instance method 'Meth' not found (return type defaults to 'id'); did you mean 'IMeth'?}} @end -- 2.40.0