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
This commit is contained in:
Kaelyn Uhrain 2012-01-13 01:32:50 +00:00
parent 04ea962144
commit e31b88833a
3 changed files with 99 additions and 50 deletions

View File

@ -110,6 +110,12 @@ public:
CorrectionDecls.front() == 0; CorrectionDecls.front() == 0;
} }
// Check if this TypoCorrection is the given keyword.
template<std::size_t StrLen>
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. // Returns true if the correction either is a keyword or has a known decl.
bool isResolved() const { return !CorrectionDecls.empty(); } bool isResolved() const { return !CorrectionDecls.empty(); }
@ -135,8 +141,8 @@ private:
unsigned EditDistance; unsigned EditDistance;
}; };
// @brief Base class for callback objects used by Sema::CorrectTypo to check the /// @brief Base class for callback objects used by Sema::CorrectTypo to check
// validity of a potential typo correction. /// the validity of a potential typo correction.
class CorrectionCandidateCallback { class CorrectionCandidateCallback {
public: public:
CorrectionCandidateCallback() CorrectionCandidateCallback()
@ -163,6 +169,16 @@ class CorrectionCandidateCallback {
bool IsObjCIvarLookup; bool IsObjCIvarLookup;
}; };
/// @brief Simple template class for restricting typo correction candidates
/// to ones having a single Decl* of the given type.
template <class C>
class DeclFilterCCC : public CorrectionCandidateCallback {
public:
virtual bool ValidateCandidate(const TypoCorrection &candidate) {
return candidate.getCorrectionDeclAs<C>();
}
};
} }
#endif #endif

View File

@ -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<ObjCInterfaceDecl>();
return ID && !declaresSameEntity(ID, CurrentIDecl);
}
private:
ObjCInterfaceDecl *CurrentIDecl;
};
}
Decl *Sema:: Decl *Sema::
ActOnStartClassInterface(SourceLocation AtInterfaceLoc, ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc,
@ -396,20 +418,17 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
LookupOrdinaryName); LookupOrdinaryName);
if (!PrevDecl) { if (!PrevDecl) {
// Try to correct for a typo in the superclass name. // Try to correct for a typo in the superclass name without correcting
TypoCorrection Corrected = CorrectTypo( // to the class we're defining.
ObjCInterfaceValidatorCCC Validator(IDecl);
if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope, DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope,
NULL, NULL, false, CTC_NoKeywords); NULL, &Validator)) {
if ((PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) { PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
if (declaresSameEntity(PrevDecl, IDecl)) { Diag(SuperLoc, diag::err_undef_superclass_suggest)
// Don't correct to the class we're defining. << SuperName << ClassName << PrevDecl->getDeclName();
PrevDecl = 0; Diag(PrevDecl->getLocation(), diag::note_previous_decl)
} else { << PrevDecl->getDeclName();
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, ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first,
ProtocolId[i].second); ProtocolId[i].second);
if (!PDecl) { if (!PDecl) {
DeclFilterCCC<ObjCProtocolDecl> Validator;
TypoCorrection Corrected = CorrectTypo( TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second), DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second),
LookupObjCProtocolName, TUScope, NULL, NULL, false, CTC_NoKeywords); LookupObjCProtocolName, TUScope, NULL, &Validator);
if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>())) { if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>())) {
Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest) Diag(ProtocolId[i].second, diag::err_undeclared_protocol_suggest)
<< ProtocolId[i].first << Corrected.getCorrection(); << ProtocolId[i].first << Corrected.getCorrection();
@ -870,15 +890,16 @@ Decl *Sema::ActOnStartClassImplementation(
} else { } else {
// We did not find anything with the name ClassName; try to correct for // We did not find anything with the name ClassName; try to correct for
// typos in the class name. // typos in the class name.
TypoCorrection Corrected = CorrectTypo( ObjCInterfaceValidatorCCC Validator;
if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope, DeclarationNameInfo(ClassName, ClassLoc), LookupOrdinaryName, TUScope,
NULL, NULL, false, CTC_NoKeywords); NULL, &Validator)) {
if ((IDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>())) {
// Suggest the (potentially) correct interface name. However, put the // Suggest the (potentially) correct interface name. However, put the
// fix-it hint itself in a separate note, since changing the name in // 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 // the warning would make the fix-it change semantics.However, don't
// provide a code-modification hint or use the typo name for recovery, // provide a code-modification hint or use the typo name for recovery,
// because this is just a warning. The program may actually be correct. // because this is just a warning. The program may actually be correct.
IDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
DeclarationName CorrectedName = Corrected.getCorrection(); DeclarationName CorrectedName = Corrected.getCorrection();
Diag(ClassLoc, diag::warn_undef_interface_suggest) Diag(ClassLoc, diag::warn_undef_interface_suggest)
<< ClassName << CorrectedName; << ClassName << CorrectedName;

View File

@ -703,11 +703,12 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
} }
// Attempt to correct for typos in property names. // Attempt to correct for typos in property names.
TypoCorrection Corrected = CorrectTypo( DeclFilterCCC<ObjCPropertyDecl> Validator;
if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL, DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL,
NULL, IFace, false, CTC_NoKeywords, OPT); NULL, &Validator, IFace, false, OPT)) {
if (ObjCPropertyDecl *Property = ObjCPropertyDecl *Property =
Corrected.getCorrectionDeclAs<ObjCPropertyDecl>()) { Corrected.getCorrectionDeclAs<ObjCPropertyDecl>();
DeclarationName TypoResult = Corrected.getCorrection(); DeclarationName TypoResult = Corrected.getCorrection();
Diag(MemberLoc, diag::err_property_not_found_suggest) Diag(MemberLoc, diag::err_property_not_found_suggest)
<< MemberName << QualType(OPT, 0) << TypoResult << MemberName << QualType(OPT, 0) << TypoResult
@ -847,6 +848,24 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
<< &propertyName << Context.getObjCInterfaceType(IFace)); << &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<ObjCInterfaceDecl>() ||
candidate.isKeyword("super");
}
};
}
Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
IdentifierInfo *Name, IdentifierInfo *Name,
SourceLocation NameLoc, SourceLocation NameLoc,
@ -916,39 +935,32 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
} }
} }
// Determine our typo-correction context. ObjCInterfaceOrSuperCCC Validator(getCurMethodDecl());
CorrectTypoContext CTC = CTC_Expression;
if (ObjCMethodDecl *Method = getCurMethodDecl())
if (Method->getClassInterface() &&
Method->getClassInterface()->getSuperClass())
CTC = CTC_ObjCMessageReceiver;
if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
Result.getLookupKind(), S, NULL, Result.getLookupKind(), S, NULL,
NULL, false, CTC)) { &Validator)) {
if (NamedDecl *ND = Corrected.getCorrectionDecl()) { if (Corrected.isKeyword()) {
// If we found a declaration, correct when it refers to an Objective-C // If we've found the keyword "super" (the only keyword that would be
// class. // returned by CorrectTypo), this is a send to super.
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(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.
Diag(NameLoc, diag::err_unknown_receiver_suggest) Diag(NameLoc, diag::err_unknown_receiver_suggest)
<< Name << Corrected.getCorrection() << Name << Corrected.getCorrection()
<< FixItHint::CreateReplacement(SourceRange(NameLoc), "super"); << FixItHint::CreateReplacement(SourceRange(NameLoc), "super");
return ObjCSuperMessage; return ObjCSuperMessage;
} else if (ObjCInterfaceDecl *Class =
Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
// 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;
} }
} }