forked from OSchip/llvm-project
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:
parent
4377656e12
commit
9ea8efaf92
|
@ -250,8 +250,8 @@ public:
|
||||||
CorrectionCandidateCallback()
|
CorrectionCandidateCallback()
|
||||||
: WantTypeSpecifiers(true), WantExpressionKeywords(true),
|
: WantTypeSpecifiers(true), WantExpressionKeywords(true),
|
||||||
WantCXXNamedCasts(true), WantRemainingKeywords(true),
|
WantCXXNamedCasts(true), WantRemainingKeywords(true),
|
||||||
WantObjCSuper(false),
|
WantObjCSuper(false), IsObjCIvarLookup(false),
|
||||||
IsObjCIvarLookup(false) {}
|
IsAddressOfOperand(false) {}
|
||||||
|
|
||||||
virtual ~CorrectionCandidateCallback() {}
|
virtual ~CorrectionCandidateCallback() {}
|
||||||
|
|
||||||
|
@ -287,6 +287,7 @@ public:
|
||||||
// Temporary hack for the one case where a CorrectTypoContext enum is used
|
// Temporary hack for the one case where a CorrectTypoContext enum is used
|
||||||
// when looking up results.
|
// when looking up results.
|
||||||
bool IsObjCIvarLookup;
|
bool IsObjCIvarLookup;
|
||||||
|
bool IsAddressOfOperand;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Simple template class for restricting typo correction candidates
|
/// @brief Simple template class for restricting typo correction candidates
|
||||||
|
|
|
@ -435,7 +435,8 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback {
|
||||||
|
|
||||||
if (isa<TypeDecl>(ND))
|
if (isa<TypeDecl>(ND))
|
||||||
return WantTypeSpecifiers;
|
return WantTypeSpecifiers;
|
||||||
return AllowNonTypes;
|
return AllowNonTypes &&
|
||||||
|
CorrectionCandidateCallback::ValidateCandidate(candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -813,6 +814,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
||||||
SourceLocation TemplateKWLoc;
|
SourceLocation TemplateKWLoc;
|
||||||
CastExpressionIdValidator Validator(isTypeCast != NotTypeCast,
|
CastExpressionIdValidator Validator(isTypeCast != NotTypeCast,
|
||||||
isTypeCast != IsTypeCast);
|
isTypeCast != IsTypeCast);
|
||||||
|
Validator.IsAddressOfOperand = isAddressOfOperand;
|
||||||
Name.setIdentifier(&II, ILoc);
|
Name.setIdentifier(&II, ILoc);
|
||||||
Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
|
Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,
|
||||||
Name, Tok.is(tok::l_paren),
|
Name, Tok.is(tok::l_paren),
|
||||||
|
|
|
@ -1883,6 +1883,17 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
R.addDecl(ND);
|
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 =
|
AcceptableWithRecovery =
|
||||||
isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND);
|
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
|
// If this name wasn't predeclared and if this is not a function
|
||||||
// call, diagnose the problem.
|
// call, diagnose the problem.
|
||||||
CorrectionCandidateCallback DefaultValidator;
|
CorrectionCandidateCallback DefaultValidator;
|
||||||
|
DefaultValidator.IsAddressOfOperand = IsAddressOfOperand;
|
||||||
|
assert((!CCC || CCC->IsAddressOfOperand == IsAddressOfOperand) &&
|
||||||
|
"Typo correction callback misconfigured");
|
||||||
if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator))
|
if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
|
|
|
@ -4454,14 +4454,27 @@ bool CorrectionCandidateCallback::ValidateCandidate(const TypoCorrection &candid
|
||||||
return WantTypeSpecifiers || WantExpressionKeywords || WantCXXNamedCasts ||
|
return WantTypeSpecifiers || WantExpressionKeywords || WantCXXNamedCasts ||
|
||||||
WantRemainingKeywords || WantObjCSuper;
|
WantRemainingKeywords || WantObjCSuper;
|
||||||
|
|
||||||
for (TypoCorrection::const_decl_iterator CDecl = candidate.begin(),
|
bool HasNonType = false;
|
||||||
CDeclEnd = candidate.end();
|
bool HasStaticMethod = false;
|
||||||
CDecl != CDeclEnd; ++CDecl) {
|
bool HasNonStaticMethod = false;
|
||||||
if (!isa<TypeDecl>(*CDecl))
|
for (Decl *D : candidate) {
|
||||||
return true;
|
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,
|
FunctionCallFilterCCC::FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
|
||||||
|
|
|
@ -287,3 +287,16 @@ void test() {
|
||||||
if (p) // expected-error-re {{use of undeclared identifier 'p'{{$}}}}
|
if (p) // expected-error-re {{use of undeclared identifier 'p'{{$}}}}
|
||||||
return;
|
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'?}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue