Propagate isAddressOfMember into typo correction so that we don't correct &qualified-id into &unqualified-id. Also make sure to set the naming class when we find the qualified-id in a different class than the nested name specifier specified so far. Fixes PR19681!

llvm-svn: 211551
This commit is contained in:
Nick Lewycky 2014-06-23 22:57:51 +00:00
parent 4377656e12
commit 9ea8efaf92
5 changed files with 52 additions and 9 deletions

View File

@ -250,8 +250,8 @@ public:
CorrectionCandidateCallback()
: WantTypeSpecifiers(true), WantExpressionKeywords(true),
WantCXXNamedCasts(true), WantRemainingKeywords(true),
WantObjCSuper(false),
IsObjCIvarLookup(false) {}
WantObjCSuper(false), IsObjCIvarLookup(false),
IsAddressOfOperand(false) {}
virtual ~CorrectionCandidateCallback() {}
@ -287,6 +287,7 @@ public:
// Temporary hack for the one case where a CorrectTypoContext enum is used
// when looking up results.
bool IsObjCIvarLookup;
bool IsAddressOfOperand;
};
/// @brief Simple template class for restricting typo correction candidates

View File

@ -435,7 +435,8 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
if (isa<TypeDecl>(ND))
return WantTypeSpecifiers;
return AllowNonTypes;
return AllowNonTypes &&
CorrectionCandidateCallback::ValidateCandidate(candidate);
}
private:
@ -813,6 +814,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
SourceLocation TemplateKWLoc;
CastExpressionIdValidator Validator(isTypeCast != NotTypeCast,
isTypeCast != IsTypeCast);
Validator.IsAddressOfOperand = isAddressOfOperand;
Name.setIdentifier(&II, ILoc);
Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
Name, Tok.is(tok::l_paren),

View File

@ -1883,6 +1883,17 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
}
}
R.addDecl(ND);
if (getLangOpts().CPlusPlus && ND->isCXXClassMember()) {
CXXRecordDecl *Record = nullptr;
if (Corrected.getCorrectionSpecifier()) {
const Type *Ty = Corrected.getCorrectionSpecifier()->getAsType();
Record = Ty->getAsCXXRecordDecl();
}
if (!Record)
Record = cast<CXXRecordDecl>(
ND->getDeclContext()->getRedeclContext());
R.setNamingClass(Record);
}
AcceptableWithRecovery =
isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND);
@ -2100,6 +2111,9 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
// If this name wasn't predeclared and if this is not a function
// call, diagnose the problem.
CorrectionCandidateCallback DefaultValidator;
DefaultValidator.IsAddressOfOperand = IsAddressOfOperand;
assert((!CCC || CCC->IsAddressOfOperand == IsAddressOfOperand) &&
"Typo correction callback misconfigured");
if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator))
return ExprError();

View File

@ -4454,14 +4454,27 @@ bool CorrectionCandidateCallback::ValidateCandidate(const TypoCorrection &candid
return WantTypeSpecifiers || WantExpressionKeywords || WantCXXNamedCasts ||
WantRemainingKeywords || WantObjCSuper;
for (TypoCorrection::const_decl_iterator CDecl = candidate.begin(),
CDeclEnd = candidate.end();
CDecl != CDeclEnd; ++CDecl) {
if (!isa<TypeDecl>(*CDecl))
return true;
bool HasNonType = false;
bool HasStaticMethod = false;
bool HasNonStaticMethod = false;
for (Decl *D : candidate) {
if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
D = FTD->getTemplatedDecl();
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
if (Method->isStatic())
HasStaticMethod = true;
else
HasNonStaticMethod = true;
}
if (!isa<TypeDecl>(D))
HasNonType = true;
}
return WantTypeSpecifiers;
if (IsAddressOfOperand && HasNonStaticMethod && !HasStaticMethod &&
!candidate.getCorrectionSpecifier())
return false;
return WantTypeSpecifiers || HasNonType;
}
FunctionCallFilterCCC::FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,

View File

@ -287,3 +287,16 @@ void test() {
if (p) // expected-error-re {{use of undeclared identifier 'p'{{$}}}}
return;
}
namespace PR19681 {
struct TypoA {};
struct TypoB {
void test();
private:
template<typename T> void private_memfn(T); // expected-note{{declared here}}
};
void TypoB::test() {
// FIXME: should suggest 'PR19681::TypoB::private_memfn' instead of '::PR19681::TypoB::private_memfn'
(void)static_cast<void(TypoB::*)(int)>(&TypoA::private_memfn); // expected-error{{no member named 'private_memfn' in 'PR19681::TypoA'; did you mean '::PR19681::TypoB::private_memfn'?}}
}
}