diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-04-14 02:46:37 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-04-14 02:46:37 +0000 |
commit | 47bd54392a4fd0f10e04de6a0420fd4838caaa0e (patch) | |
tree | a70cfcbd611a1a518bc3bee7617695e13984cb96 | |
parent | 1dbca6ea983231b4cab1a8f1edda8f6e13c21f12 (diff) |
Implement typo correction for Objective-C message sends when the
receiver is a mis-typed class name. Previously, we would give a non-specific
typo-correction diagnostic from the expression-parsing code, but there
was no fix-it because it was too late to recover. Now, we give a nice
diagnostic
honk.m:6:4: error: unknown receiver 'Hnk'; did you mean 'Honk'?
[Hnk method];
^~~
Honk
honk.m:1:1: note: 'Honk' declared here
@interface Honk
^
which includes a fix-it.
We still need to recover better from mis-typing "super".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101211 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 6 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 55 | ||||
-rw-r--r-- | test/FixIt/typo.m | 5 |
4 files changed, 65 insertions, 3 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index a09f18c5d9..bb468ddb23 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2017,6 +2017,8 @@ def warn_bad_receiver_type : Warning< "receiver type %0 is not 'id' or interface pointer, consider " "casting it to 'id'">; def err_bad_receiver_type : Error<"bad receiver type %0">; +def err_unknown_receiver_suggest : Error< + "unknown receiver %0; did you mean %1?">; def error_objc_throw_expects_object : Error< "@throw requires an Objective-C object type (%0 invalid)">; def error_objc_synchronized_expects_object : Error< diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index c997630213..9cf12608e7 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3863,6 +3863,12 @@ public: SourceLocation receiverNameLoc, SourceLocation propertyNameLoc); + virtual ObjCMessageKind getObjCMessageKind(Scope *S, + IdentifierInfo *&Name, + SourceLocation NameLoc, + bool IsSuper, + bool HasTrailingDot); + // ActOnClassMessage - used for both unary and keyword messages. // ArgExprs is optional - if it is present, the number of expressions // is obtained from NumArgs. diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 26d115667c..cbb49114fe 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -486,6 +486,61 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, << &propertyName << Context.getObjCInterfaceType(IFace)); } +Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, + IdentifierInfo *&Name, + SourceLocation NameLoc, + bool IsSuper, + bool HasTrailingDot) { + // If the identifier is "super" and there is no trailing dot, we're + // messaging super. + if (IsSuper && !HasTrailingDot && S->isInObjcMethodScope()) + return ObjCSuperMessage; + + LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); + LookupName(Result, S); + + switch (Result.getResultKind()) { + case LookupResult::NotFound: + // Break out; we'll perform typo correction below. + break; + + case LookupResult::NotFoundInCurrentInstantiation: + case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: + case LookupResult::Ambiguous: + Result.suppressDiagnostics(); + return ObjCInstanceMessage; + + case LookupResult::Found: { + // We found something. If it's a type, then we have a class + // message. Otherwise, it's an instance message. + NamedDecl *ND = Result.getFoundDecl(); + if (isa<ObjCInterfaceDecl>(ND) || isa<TypeDecl>(ND) || + isa<UnresolvedUsingTypenameDecl>(ND)) + return ObjCClassMessage; + + return ObjCInstanceMessage; + } + } + + if (CorrectTypo(Result, S, 0) && Result.isSingleResult()) { + NamedDecl *ND = Result.getFoundDecl(); + if (isa<ObjCInterfaceDecl>(ND)) { + Diag(NameLoc, diag::err_unknown_receiver_suggest) + << Name << Result.getLookupName() + << FixItHint::CreateReplacement(SourceRange(NameLoc), + ND->getNameAsString()); + Diag(ND->getLocation(), diag::note_previous_decl) + << ND->getDeclName(); + + Name = ND->getIdentifier(); + return ObjCClassMessage; + } + } + + // Fall back: let the parser try to parse it as an instance message. + return ObjCInstanceMessage; +} // ActOnClassMessage - used for both unary and keyword messages. // ArgExprs is optional - if it is present, the number of expressions diff --git a/test/FixIt/typo.m b/test/FixIt/typo.m index 86dd383c90..19602fcc8e 100644 --- a/test/FixIt/typo.m +++ b/test/FixIt/typo.m @@ -2,7 +2,7 @@ // FIXME: the test below isn't testing quite what we want... // RUN: %clang_cc1 -fsyntax-only -fixit -o - %s | %clang_cc1 -fsyntax-only -pedantic -Werror -x objective-c - -@interface NSString +@interface NSString // expected-note{{'NSString' declared here}} + (int)method:(int)x; @end @@ -57,8 +57,7 @@ void test() { @end void test_message_send(B* b) { - // FIXME: Not providing fix-its - [NSstring method:17]; // expected-error{{use of undeclared identifier 'NSstring'; did you mean 'NSString'?}} + [NSstring method:17]; // expected-error{{unknown receiver 'NSstring'; did you mean 'NSString'?}} } @interface Collide // expected-note{{'Collide' declared here}} |