Convert SemaExprMember.cpp to pass a callback object to CorrectTypo,
improving the typo correction results in certain situations.
This is also the first typo correction callback conversion to affect
an existing unit test. :)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148140 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index 478b2dd..0080156 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -509,6 +509,20 @@
return true;
}
+namespace {
+
+// Callback to only accept typo corrections that are either a ValueDecl or a
+// FunctionTemplateDecl.
+class RecordMemberExprValidatorCCC : public CorrectionCandidateCallback {
+ public:
+ virtual bool ValidateCandidate(const TypoCorrection &candidate) {
+ NamedDecl *ND = candidate.getCorrectionDecl();
+ return ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND));
+ }
+};
+
+}
+
static bool
LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
SourceRange BaseRange, const RecordType *RTy,
@@ -559,13 +573,12 @@
// We didn't find anything with the given name, so try to correct
// for typos.
DeclarationName Name = R.getLookupName();
+ RecordMemberExprValidatorCCC Validator;
TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
R.getLookupKind(), NULL,
- &SS, DC, false,
- Sema::CTC_MemberLookup);
- NamedDecl *ND = Corrected.getCorrectionDecl();
+ &SS, &Validator, DC);
R.clear();
- if (ND && (isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND))) {
+ if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
std::string CorrectedStr(
Corrected.getAsString(SemaRef.getLangOptions()));
std::string CorrectedQuotedStr(
@@ -1094,12 +1107,12 @@
if (!IV) {
// Attempt to correct for typos in ivar names.
- LookupResult Res(*this, R.getLookupName(), R.getNameLoc(),
- LookupMemberName);
- TypoCorrection Corrected = CorrectTypo(
- R.getLookupNameInfo(), LookupMemberName, NULL, NULL, IDecl, false,
- IsArrow ? CTC_ObjCIvarLookup : CTC_ObjCPropertyLookup);
- if ((IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>())) {
+ DeclFilterCCC<ObjCIvarDecl> Validator;
+ Validator.IsObjCIvarLookup = IsArrow;
+ if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
+ LookupMemberName, NULL, NULL,
+ &Validator, IDecl)) {
+ IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>();
Diag(R.getNameLoc(),
diag::err_typecheck_member_reference_ivar_suggest)
<< IDecl->getDeclName() << MemberName << IV->getDeclName()
@@ -1115,8 +1128,6 @@
<< FixItHint::CreateReplacement(OpLoc, ".");
return ExprError();
}
- Res.clear();
- Res.setLookupName(Member);
Diag(MemberLoc, diag::err_typecheck_member_reference_ivar)
<< IDecl->getDeclName() << MemberName
diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp
index db5a051..dbddd1c 100644
--- a/test/SemaCXX/member-expr.cpp
+++ b/test/SemaCXX/member-expr.cpp
@@ -94,11 +94,11 @@
namespace PR7508 {
struct A {
struct CleanupScope {};
- void PopCleanupBlock();
+ void PopCleanupBlock(); // expected-note{{'PopCleanupBlock' declared here}}
};
void foo(A &a) {
- a.PopCleanupScope(); // expected-error{{no member named 'PopCleanupScope' in 'PR7508::A'}}
+ a.PopCleanupScope(); // expected-error{{no member named 'PopCleanupScope' in 'PR7508::A'; did you mean 'PopCleanupBlock'?}}
}
}
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index a4cbbb8..bc3433b 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -37,10 +37,14 @@
// refer to a base class or non-static data member.
struct BaseType { };
struct Derived : public BaseType { // expected-note {{base class 'BaseType' specified here}}
- static int base_type;
+ static int base_type; // expected-note {{'base_type' declared here}}
Derived() : basetype() {} // expected-error{{initializer 'basetype' does not name a non-static data member or base class; did you mean the base class 'BaseType'?}}
};
+int get_type(struct Derived *st) {
+ return st->Base_Type; // expected-error{{no member named 'Base_Type' in 'Derived'; did you mean 'base_type'?}}
+}
+
// In this example, somename should not be corrected to the cached correction
// "some_name" since "some_name" is a class and a namespace name is needed.
class some_name {}; // expected-note {{'some_name' declared here}}