From e31b88833ac0a3f0b9a77d49ec8e7a9437f0e991 Mon Sep 17 00:00:00 2001 From: Kaelyn Uhrain Date: Fri, 13 Jan 2012 01:32:50 +0000 Subject: [PATCH] Fix up the calls to CorrectTypo in Sema*ObjC.cpp to use callback objects, and add a basic CorrectionCandidateCallback template class to simplify the fixups. llvm-svn: 148085 --- clang/include/clang/Sema/TypoCorrection.h | 20 +++++- clang/lib/Sema/SemaDeclObjC.cpp | 55 +++++++++++------ clang/lib/Sema/SemaExprObjC.cpp | 74 +++++++++++++---------- 3 files changed, 99 insertions(+), 50 deletions(-) diff --git a/clang/include/clang/Sema/TypoCorrection.h b/clang/include/clang/Sema/TypoCorrection.h index bcf58649776d..c0c7790bb028 100644 --- a/clang/include/clang/Sema/TypoCorrection.h +++ b/clang/include/clang/Sema/TypoCorrection.h @@ -110,6 +110,12 @@ public: CorrectionDecls.front() == 0; } + // Check if this TypoCorrection is the given keyword. + template + bool isKeyword(const char (&Str)[StrLen]) const { + return isKeyword() && getCorrectionAsIdentifierInfo()->isStr(Str); + } + // Returns true if the correction either is a keyword or has a known decl. bool isResolved() const { return !CorrectionDecls.empty(); } @@ -135,8 +141,8 @@ private: unsigned EditDistance; }; -// @brief Base class for callback objects used by Sema::CorrectTypo to check the -// validity of a potential typo correction. +/// @brief Base class for callback objects used by Sema::CorrectTypo to check +/// the validity of a potential typo correction. class CorrectionCandidateCallback { public: CorrectionCandidateCallback() @@ -163,6 +169,16 @@ class CorrectionCandidateCallback { bool IsObjCIvarLookup; }; +/// @brief Simple template class for restricting typo correction candidates +/// to ones having a single Decl* of the given type. +template +class DeclFilterCCC : public CorrectionCandidateCallback { + public: + virtual bool ValidateCandidate(const TypoCorrection &candidate) { + return candidate.getCorrectionDeclAs(); + } +}; + } #endif diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 6a55de0c4579..c20f8f787efc 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -347,6 +347,28 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { } } +namespace { + +// Callback to only accept typo corrections that are Objective-C classes. +// If an ObjCInterfaceDecl* is given to the constructor, then the validation +// function will reject corrections to that class. +class ObjCInterfaceValidatorCCC : public CorrectionCandidateCallback { + public: + ObjCInterfaceValidatorCCC() : CurrentIDecl(0) {} + explicit ObjCInterfaceValidatorCCC(ObjCInterfaceDecl *IDecl) + : CurrentIDecl(IDecl) {} + + virtual bool ValidateCandidate(const TypoCorrection &candidate) { + ObjCInterfaceDecl *ID = candidate.getCorrectionDeclAs(); + return ID && !declaresSameEntity(ID, CurrentIDecl); + } + + private: + ObjCInterfaceDecl *CurrentIDecl; +}; + +} + Decl *Sema:: ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, @@ -396,20 +418,17 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, LookupOrdinaryName); if (!PrevDecl) { - // Try to correct for a typo in the superclass name. - TypoCorrection Corrected = CorrectTypo( + // Try to correct for a typo in the superclass name without correcting + // to the class we're defining. + ObjCInterfaceValidatorCCC Validator(IDecl); + if (TypoCorrection Corrected = CorrectTypo( DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope, - NULL, NULL, false, CTC_NoKeywords); - if ((PrevDecl = Corrected.getCorrectionDeclAs())) { - if (declaresSameEntity(PrevDecl, IDecl)) { - // Don't correct to the class we're defining. - PrevDecl = 0; - } else { - Diag(SuperLoc, diag::err_undef_superclass_suggest) - << SuperName << ClassName << PrevDecl->getDeclName(); - Diag(PrevDecl->getLocation(), diag::note_previous_decl) - << PrevDecl->getDeclName(); - } + NULL, &Validator)) { + PrevDecl = Corrected.getCorrectionDeclAs(); + Diag(SuperLoc, diag::err_undef_superclass_suggest) + << SuperName << ClassName << PrevDecl->getDeclName(); + Diag(PrevDecl->getLocation(), diag::note_previous_decl) + << PrevDecl->getDeclName(); } } @@ -633,9 +652,10 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first, ProtocolId[i].second); if (!PDecl) { + DeclFilterCCC Validator; TypoCorrection Corrected = CorrectTypo( DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second), - LookupObjCProtocolName, TUScope, NULL, NULL, false, CTC_NoKeywords); + LookupObjCProtocolName, TUScope, NULL, &Validator); if ((PDecl = Corrected.getCorrectionDeclAs())) { Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest) << ProtocolId[i].first << Corrected.getCorrection(); @@ -870,15 +890,16 @@ Decl *Sema::ActOnStartClassImplementation( } else { // We did not find anything with the name ClassName; try to correct for // typos in the class name. - TypoCorrection Corrected = CorrectTypo( + ObjCInterfaceValidatorCCC Validator; + if (TypoCorrection Corrected = CorrectTypo( DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope, - NULL, NULL, false, CTC_NoKeywords); - if ((IDecl = Corrected.getCorrectionDeclAs())) { + NULL, &Validator)) { // Suggest the (potentially) correct interface name. However, put the // fix-it hint itself in a separate note, since changing the name in // the warning would make the fix-it change semantics.However, don't // provide a code-modification hint or use the typo name for recovery, // because this is just a warning. The program may actually be correct. + IDecl = Corrected.getCorrectionDeclAs(); DeclarationName CorrectedName = Corrected.getCorrection(); Diag(ClassLoc, diag::warn_undef_interface_suggest) << ClassName << CorrectedName; diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index e9742a988ff9..00c98bea2e8d 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -703,11 +703,12 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, } // Attempt to correct for typos in property names. - TypoCorrection Corrected = CorrectTypo( + DeclFilterCCC Validator; + if (TypoCorrection Corrected = CorrectTypo( DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL, - NULL, IFace, false, CTC_NoKeywords, OPT); - if (ObjCPropertyDecl *Property = - Corrected.getCorrectionDeclAs()) { + NULL, &Validator, IFace, false, OPT)) { + ObjCPropertyDecl *Property = + Corrected.getCorrectionDeclAs(); DeclarationName TypoResult = Corrected.getCorrection(); Diag(MemberLoc, diag::err_property_not_found_suggest) << MemberName << QualType(OPT, 0) << TypoResult @@ -847,6 +848,24 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, << &propertyName << Context.getObjCInterfaceType(IFace)); } +namespace { + +class ObjCInterfaceOrSuperCCC : public CorrectionCandidateCallback { + public: + ObjCInterfaceOrSuperCCC(ObjCMethodDecl *Method) { + // Determine whether "super" is acceptable in the current context. + if (Method && Method->getClassInterface()) + WantObjCSuper = Method->getClassInterface()->getSuperClass(); + } + + virtual bool ValidateCandidate(const TypoCorrection &candidate) { + return candidate.getCorrectionDeclAs() || + candidate.isKeyword("super"); + } +}; + +} + Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, IdentifierInfo *Name, SourceLocation NameLoc, @@ -916,39 +935,32 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, } } - // Determine our typo-correction context. - CorrectTypoContext CTC = CTC_Expression; - if (ObjCMethodDecl *Method = getCurMethodDecl()) - if (Method->getClassInterface() && - Method->getClassInterface()->getSuperClass()) - CTC = CTC_ObjCMessageReceiver; - + ObjCInterfaceOrSuperCCC Validator(getCurMethodDecl()); if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, NULL, - NULL, false, CTC)) { - if (NamedDecl *ND = Corrected.getCorrectionDecl()) { - // If we found a declaration, correct when it refers to an Objective-C - // class. - if (ObjCInterfaceDecl *Class = dyn_cast(ND)) { - Diag(NameLoc, diag::err_unknown_receiver_suggest) - << Name << Corrected.getCorrection() - << FixItHint::CreateReplacement(SourceRange(NameLoc), - ND->getNameAsString()); - Diag(ND->getLocation(), diag::note_previous_decl) - << Corrected.getCorrection(); - - QualType T = Context.getObjCInterfaceType(Class); - TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc); - ReceiverType = CreateParsedType(T, TSInfo); - return ObjCClassMessage; - } - } else if (Corrected.isKeyword() && - Corrected.getCorrectionAsIdentifierInfo()->isStr("super")) { - // If we've found the keyword "super", this is a send to super. + &Validator)) { + if (Corrected.isKeyword()) { + // If we've found the keyword "super" (the only keyword that would be + // returned by CorrectTypo), this is a send to super. Diag(NameLoc, diag::err_unknown_receiver_suggest) << Name << Corrected.getCorrection() << FixItHint::CreateReplacement(SourceRange(NameLoc), "super"); return ObjCSuperMessage; + } else if (ObjCInterfaceDecl *Class = + Corrected.getCorrectionDeclAs()) { + // If we found a declaration, correct when it refers to an Objective-C + // class. + Diag(NameLoc, diag::err_unknown_receiver_suggest) + << Name << Corrected.getCorrection() + << FixItHint::CreateReplacement(SourceRange(NameLoc), + Class->getNameAsString()); + Diag(Class->getLocation(), diag::note_previous_decl) + << Corrected.getCorrection(); + + QualType T = Context.getObjCInterfaceType(Class); + TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc); + ReceiverType = CreateParsedType(T, TSInfo); + return ObjCClassMessage; } }