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;
}
// 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.
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 C>
class DeclFilterCCC : public CorrectionCandidateCallback {
public:
virtual bool ValidateCandidate(const TypoCorrection &candidate) {
return candidate.getCorrectionDeclAs<C>();
}
};
}
#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::
ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
@ -396,22 +418,19 @@ 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<ObjCInterfaceDecl>())) {
if (declaresSameEntity(PrevDecl, IDecl)) {
// Don't correct to the class we're defining.
PrevDecl = 0;
} else {
NULL, &Validator)) {
PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
Diag(SuperLoc, diag::err_undef_superclass_suggest)
<< SuperName << ClassName << PrevDecl->getDeclName();
Diag(PrevDecl->getLocation(), diag::note_previous_decl)
<< PrevDecl->getDeclName();
}
}
}
if (declaresSameEntity(PrevDecl, IDecl)) {
Diag(SuperLoc, diag::err_recursive_superclass)
@ -633,9 +652,10 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first,
ProtocolId[i].second);
if (!PDecl) {
DeclFilterCCC<ObjCProtocolDecl> 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<ObjCProtocolDecl>())) {
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<ObjCInterfaceDecl>())) {
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<ObjCInterfaceDecl>();
DeclarationName CorrectedName = Corrected.getCorrection();
Diag(ClassLoc, diag::warn_undef_interface_suggest)
<< ClassName << CorrectedName;

View File

@ -703,11 +703,12 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
}
// Attempt to correct for typos in property names.
TypoCorrection Corrected = CorrectTypo(
DeclFilterCCC<ObjCPropertyDecl> Validator;
if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL,
NULL, IFace, false, CTC_NoKeywords, OPT);
if (ObjCPropertyDecl *Property =
Corrected.getCorrectionDeclAs<ObjCPropertyDecl>()) {
NULL, &Validator, IFace, false, OPT)) {
ObjCPropertyDecl *Property =
Corrected.getCorrectionDeclAs<ObjCPropertyDecl>();
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<ObjCInterfaceDecl>() ||
candidate.isKeyword("super");
}
};
}
Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
IdentifierInfo *Name,
SourceLocation NameLoc,
@ -916,25 +935,26 @@ 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()) {
&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<ObjCInterfaceDecl>()) {
// If we found a declaration, correct when it refers to an Objective-C
// class.
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)
Class->getNameAsString());
Diag(Class->getLocation(), diag::note_previous_decl)
<< Corrected.getCorrection();
QualType T = Context.getObjCInterfaceType(Class);
@ -942,14 +962,6 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
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)
<< Name << Corrected.getCorrection()
<< FixItHint::CreateReplacement(SourceRange(NameLoc), "super");
return ObjCSuperMessage;
}
}
// Fall back: let the parser try to parse it as an instance message.