зеркало из 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">;
|
||||
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)
|
||||
Diag(SelLoc, diag::warn_undeclared_selector) << Sel;
|
||||
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
|
Загрузка…
Ссылка в новой задаче