зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
993b39f4cd
Коммит
9464a08a74
|
@ -811,6 +811,9 @@ def error_dealloc_bad_result_type : Error<
|
||||||
"instead of %0">;
|
"instead of %0">;
|
||||||
def warn_undeclared_selector : Warning<
|
def warn_undeclared_selector : Warning<
|
||||||
"undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore;
|
"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<
|
def warn_implicit_atomic_property : Warning<
|
||||||
"property is assumed atomic by default">, InGroup<ImplicitAtomic>, DefaultIgnore;
|
"property is assumed atomic by default">, InGroup<ImplicitAtomic>, DefaultIgnore;
|
||||||
def note_auto_readonly_iboutlet_fixup_suggest : Note<
|
def note_auto_readonly_iboutlet_fixup_suggest : Note<
|
||||||
|
|
|
@ -2669,6 +2669,8 @@ public:
|
||||||
warn, /*instance*/false);
|
warn, /*instance*/false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ObjCMethodDecl *SelectorsForTypoCorrection(Selector Sel);
|
||||||
|
|
||||||
/// DiagnoseMismatchedMethodsInGlobalPool - This routine goes through list of
|
/// DiagnoseMismatchedMethodsInGlobalPool - This routine goes through list of
|
||||||
/// methods in global pool and issues diagnostic on identical selectors which
|
/// methods in global pool and issues diagnostic on identical selectors which
|
||||||
/// have mismathched types.
|
/// have mismathched types.
|
||||||
|
|
|
@ -2271,6 +2271,57 @@ ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {
|
||||||
return 0;
|
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
|
static void
|
||||||
HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S,
|
HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S,
|
||||||
ObjCMethodList &MethList) {
|
ObjCMethodList &MethList) {
|
||||||
|
|
|
@ -968,8 +968,18 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
|
||||||
if (!Method)
|
if (!Method)
|
||||||
Method = LookupFactoryMethodInGlobalPool(Sel,
|
Method = LookupFactoryMethodInGlobalPool(Sel,
|
||||||
SourceRange(LParenLoc, RParenLoc));
|
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;
|
Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Method ||
|
if (!Method ||
|
||||||
Method->getImplementationControl() != ObjCMethodDecl::Optional) {
|
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
|
Загрузка…
Ссылка в новой задаче