Objective-C: Provide fixit with suggested spelling correction

for -Wundeclared-selector warnings. // rdar://14039037



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183331 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Fariborz Jahanian 2013-06-05 18:46:14 +00:00
Родитель 993b39f4cd
Коммит 9464a08a74
5 изменённых файлов: 98 добавлений и 2 удалений

Просмотреть файл

@ -811,6 +811,9 @@ def error_dealloc_bad_result_type : Error<
"instead of %0">;
def warn_undeclared_selector : Warning<
"undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore;
def warn_undeclared_selector_with_typo : Warning<
"undeclared selector %0; did you mean %1?">,
InGroup<UndeclaredSelector>, DefaultIgnore;
def warn_implicit_atomic_property : Warning<
"property is assumed atomic by default">, InGroup<ImplicitAtomic>, DefaultIgnore;
def note_auto_readonly_iboutlet_fixup_suggest : Note<

Просмотреть файл

@ -2669,6 +2669,8 @@ public:
warn, /*instance*/false);
}
const ObjCMethodDecl *SelectorsForTypoCorrection(Selector Sel);
/// DiagnoseMismatchedMethodsInGlobalPool - This routine goes through list of
/// methods in global pool and issues diagnostic on identical selectors which
/// have mismathched types.

Просмотреть файл

@ -2271,6 +2271,57 @@ ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {
return 0;
}
static void
HelperSelectorsForTypoCorrection(
SmallVectorImpl<const ObjCMethodDecl *> &BestMethod,
StringRef Typo, const ObjCMethodDecl * Method) {
const unsigned MaxEditDistance = 1;
unsigned BestEditDistance = MaxEditDistance + 1;
StringRef MethodName = Method->getSelector().getAsString();
unsigned MinPossibleEditDistance = abs((int)MethodName.size() - (int)Typo.size());
if (MinPossibleEditDistance > 0 &&
Typo.size() / MinPossibleEditDistance < 1)
return;
unsigned EditDistance = Typo.edit_distance(MethodName, true, MaxEditDistance);
if (EditDistance > MaxEditDistance)
return;
if (EditDistance == BestEditDistance)
BestMethod.push_back(Method);
else if (EditDistance < BestEditDistance) {
BestMethod.clear();
BestMethod.push_back(Method);
BestEditDistance = EditDistance;
}
}
const ObjCMethodDecl *
Sema::SelectorsForTypoCorrection(Selector Sel) {
unsigned NumArgs = Sel.getNumArgs();
SmallVector<const ObjCMethodDecl *, 8> Methods;
for (GlobalMethodPool::iterator b = MethodPool.begin(),
e = MethodPool.end(); b != e; b++) {
// instance methods
for (ObjCMethodList *M = &b->second.first; M; M=M->getNext())
if (M->Method &&
(M->Method->getSelector().getNumArgs() == NumArgs))
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))
Methods.push_back(M->Method);
}
SmallVector<const ObjCMethodDecl *, 8> SelectedMethods;
for (unsigned i = 0, e = Methods.size(); i < e; i++) {
HelperSelectorsForTypoCorrection(SelectedMethods,
Sel.getAsString(), Methods[i]);
}
return (SelectedMethods.size() == 1) ? SelectedMethods[0] : NULL;
}
static void
HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S,
ObjCMethodList &MethList) {

Просмотреть файл

@ -968,8 +968,18 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
if (!Method)
Method = LookupFactoryMethodInGlobalPool(Sel,
SourceRange(LParenLoc, RParenLoc));
if (!Method)
if (!Method) {
if (const ObjCMethodDecl *OM = SelectorsForTypoCorrection(Sel)) {
Selector MatchedSel = OM->getSelector();
SourceRange SelectorRange(LParenLoc.getLocWithOffset(1),
RParenLoc.getLocWithOffset(-1));
Diag(SelLoc, diag::warn_undeclared_selector_with_typo)
<< Sel << MatchedSel
<< FixItHint::CreateReplacement(SelectorRange, MatchedSel.getAsString());
} else
Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
}
if (!Method ||
Method->getImplementationControl() != ObjCMethodDecl::Optional) {

Просмотреть файл

@ -0,0 +1,30 @@
// RUN: cp %s %t
// RUN: %clang_cc1 -x objective-c -Wundeclared-selector -fixit %t
// RUN: %clang_cc1 -x objective-c -Wundeclared-selector -Werror %t
// rdar://14039037
@interface NSObject @end
@interface LogoutController : NSObject
- (void)close;
- (void)closed;
- (void) open : (id) file_id;
@end
@implementation LogoutController
- (void)close { }
- (void)closed { }
- (SEL)Meth
{
return @selector(cloze);
}
- (void) open : (id) file_id {}
- (SEL)Meth1
{
return @selector(ope:);
}
@end