forked from OSchip/llvm-project
Rework DiagnoseInvalidRedeclaration to add the ability to correct typos when
diagnosing invalid function redeclarations. llvm-svn: 137966
This commit is contained in:
parent
6afe390810
commit
fd81a350e2
|
@ -610,6 +610,8 @@ def err_tagless_friend_type_template : Error<
|
||||||
"friend type templates must use an elaborated type">;
|
"friend type templates must use an elaborated type">;
|
||||||
def err_no_matching_local_friend : Error<
|
def err_no_matching_local_friend : Error<
|
||||||
"no matching function found in local scope">;
|
"no matching function found in local scope">;
|
||||||
|
def err_no_matching_local_friend_suggest : Error<
|
||||||
|
"no matching function %0 found in local scope; did you mean %2">;
|
||||||
def err_partial_specialization_friend : Error<
|
def err_partial_specialization_friend : Error<
|
||||||
"partial specialization cannot be declared as a friend">;
|
"partial specialization cannot be declared as a friend">;
|
||||||
|
|
||||||
|
@ -3038,6 +3040,9 @@ def err_member_def_undefined_record : Error<
|
||||||
"out-of-line definition of %0 from class %1 without definition">;
|
"out-of-line definition of %0 from class %1 without definition">;
|
||||||
def err_member_def_does_not_match : Error<
|
def err_member_def_does_not_match : Error<
|
||||||
"out-of-line definition of %0 does not match any declaration in %1">;
|
"out-of-line definition of %0 does not match any declaration in %1">;
|
||||||
|
def err_member_def_does_not_match_suggest : Error<
|
||||||
|
"out-of-line definition of %0 does not match any declaration in %1; "
|
||||||
|
"did you mean %2">;
|
||||||
def err_member_def_does_not_match_ret_type : Error<
|
def err_member_def_does_not_match_ret_type : Error<
|
||||||
"out-of-line definition of %q0 differs from the declaration in the return type">;
|
"out-of-line definition of %q0 differs from the declaration in the return type">;
|
||||||
def err_nonstatic_member_out_of_line : Error<
|
def err_nonstatic_member_out_of_line : Error<
|
||||||
|
|
|
@ -4204,27 +4204,78 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
|
||||||
return AddedAny;
|
return AddedAny;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD) {
|
static void DiagnoseInvalidRedeclaration(Sema &S, FunctionDecl *NewFD,
|
||||||
LookupResult Prev(S, NewFD->getDeclName(), NewFD->getLocation(),
|
bool isFriendDecl) {
|
||||||
|
DeclarationName Name = NewFD->getDeclName();
|
||||||
|
DeclContext *DC = NewFD->getDeclContext();
|
||||||
|
LookupResult Prev(S, Name, NewFD->getLocation(),
|
||||||
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
|
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
|
||||||
llvm::SmallVector<unsigned, 1> MismatchedParams;
|
llvm::SmallVector<unsigned, 1> MismatchedParams;
|
||||||
S.LookupQualifiedName(Prev, NewFD->getDeclContext());
|
llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1> NearMatches;
|
||||||
|
TypoCorrection Correction;
|
||||||
|
unsigned DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend
|
||||||
|
: diag::err_member_def_does_not_match;
|
||||||
|
|
||||||
|
NewFD->setInvalidDecl();
|
||||||
|
S.LookupQualifiedName(Prev, DC);
|
||||||
assert(!Prev.isAmbiguous() &&
|
assert(!Prev.isAmbiguous() &&
|
||||||
"Cannot have an ambiguity in previous-declaration lookup");
|
"Cannot have an ambiguity in previous-declaration lookup");
|
||||||
for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
|
if (!Prev.empty()) {
|
||||||
Func != FuncEnd; ++Func) {
|
for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
|
||||||
FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func);
|
Func != FuncEnd; ++Func) {
|
||||||
if (FD && isNearlyMatchingFunction(S.Context, FD, NewFD,
|
FunctionDecl *FD = dyn_cast<FunctionDecl>(*Func);
|
||||||
MismatchedParams)) {
|
if (FD && isNearlyMatchingFunction(S.Context, FD, NewFD,
|
||||||
if (MismatchedParams.size() > 0) {
|
MismatchedParams)) {
|
||||||
unsigned Idx = MismatchedParams.front();
|
// Add 1 to the index so that 0 can mean the mismatch didn't
|
||||||
ParmVarDecl *FDParam = FD->getParamDecl(Idx);
|
// involve a parameter
|
||||||
S.Diag(FDParam->getTypeSpecStartLoc(),
|
unsigned ParamNum =
|
||||||
diag::note_member_def_close_param_match)
|
MismatchedParams.empty() ? 0 : MismatchedParams.front() + 1;
|
||||||
<< Idx+1 << FDParam->getType() << NewFD->getParamDecl(Idx)->getType();
|
NearMatches.push_back(std::make_pair(FD, ParamNum));
|
||||||
} else
|
}
|
||||||
S.Diag(FD->getLocation(), diag::note_member_def_close_match);
|
|
||||||
}
|
}
|
||||||
|
// If the qualified name lookup yielded nothing, try typo correction
|
||||||
|
} else if ((Correction = S.CorrectTypo(Prev.getLookupNameInfo(),
|
||||||
|
Prev.getLookupKind(), 0, 0, DC))) {
|
||||||
|
DiagMsg = isFriendDecl ? diag::err_no_matching_local_friend_suggest
|
||||||
|
: diag::err_member_def_does_not_match_suggest;
|
||||||
|
for (TypoCorrection::decl_iterator CDecl = Correction.begin(),
|
||||||
|
CDeclEnd = Correction.end();
|
||||||
|
CDecl != CDeclEnd; ++CDecl) {
|
||||||
|
FunctionDecl *FD = dyn_cast<FunctionDecl>(*CDecl);
|
||||||
|
if (FD && isNearlyMatchingFunction(S.Context, FD, NewFD,
|
||||||
|
MismatchedParams)) {
|
||||||
|
// Add 1 to the index so that 0 can mean the mismatch didn't
|
||||||
|
// involve a parameter
|
||||||
|
unsigned ParamNum =
|
||||||
|
MismatchedParams.empty() ? 0 : MismatchedParams.front() + 1;
|
||||||
|
NearMatches.push_back(std::make_pair(FD, ParamNum));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Correction)
|
||||||
|
S.Diag(NewFD->getLocation(), DiagMsg)
|
||||||
|
<< Name << DC << Correction.getQuoted(S.getLangOptions())
|
||||||
|
<< FixItHint::CreateReplacement(
|
||||||
|
NewFD->getLocation(), Correction.getAsString(S.getLangOptions()));
|
||||||
|
else
|
||||||
|
S.Diag(NewFD->getLocation(), DiagMsg) << Name << DC << NewFD->getLocation();
|
||||||
|
|
||||||
|
for (llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1>::iterator
|
||||||
|
NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end();
|
||||||
|
NearMatch != NearMatchEnd; ++NearMatch) {
|
||||||
|
FunctionDecl *FD = NearMatch->first;
|
||||||
|
|
||||||
|
if (unsigned Idx = NearMatch->second) {
|
||||||
|
ParmVarDecl *FDParam = FD->getParamDecl(Idx-1);
|
||||||
|
S.Diag(FDParam->getTypeSpecStartLoc(),
|
||||||
|
diag::note_member_def_close_param_match)
|
||||||
|
<< Idx << FDParam->getType() << NewFD->getParamDecl(Idx-1)->getType();
|
||||||
|
} else if (Correction) {
|
||||||
|
S.Diag(FD->getLocation(), diag::note_previous_decl)
|
||||||
|
<< Correction.getQuoted(S.getLangOptions());
|
||||||
|
} else
|
||||||
|
S.Diag(FD->getLocation(), diag::note_member_def_close_match);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4939,19 +4990,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
// Complain about this problem, and attempt to suggest close
|
// Complain about this problem, and attempt to suggest close
|
||||||
// matches (e.g., those that differ only in cv-qualifiers and
|
// matches (e.g., those that differ only in cv-qualifiers and
|
||||||
// whether the parameter types are references).
|
// whether the parameter types are references).
|
||||||
Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
|
|
||||||
<< Name << DC << D.getCXXScopeSpec().getRange();
|
|
||||||
NewFD->setInvalidDecl();
|
|
||||||
|
|
||||||
DiagnoseInvalidRedeclaration(*this, NewFD);
|
DiagnoseInvalidRedeclaration(*this, NewFD, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unqualified local friend declarations are required to resolve
|
// Unqualified local friend declarations are required to resolve
|
||||||
// to something.
|
// to something.
|
||||||
} else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) {
|
} else if (isFriend && cast<CXXRecordDecl>(CurContext)->isLocalClass()) {
|
||||||
Diag(D.getIdentifierLoc(), diag::err_no_matching_local_friend);
|
DiagnoseInvalidRedeclaration(*this, NewFD, true);
|
||||||
NewFD->setInvalidDecl();
|
|
||||||
DiagnoseInvalidRedeclaration(*this, NewFD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
|
} else if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
|
||||||
|
|
|
@ -24,3 +24,29 @@ namespace N {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
void typocorrection(); // expected-note {{'typocorrection' declared here}}
|
||||||
|
};
|
||||||
|
|
||||||
|
void A::Notypocorrection() { // expected-error {{out-of-line definition of 'Notypocorrection' does not match any declaration in 'A'; did you mean 'typocorrection'}}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace test0 {
|
||||||
|
void dummy() {
|
||||||
|
void Bar(); // expected-note {{'Bar' declared here}}
|
||||||
|
class A {
|
||||||
|
friend void bar(); // expected-error {{no matching function 'bar' found in local scope; did you mean 'Bar'}}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class B {
|
||||||
|
void typocorrection(const int); // expected-note {{type of 1st parameter of member declaration does not match definition}}
|
||||||
|
void typocorrection(double);
|
||||||
|
};
|
||||||
|
|
||||||
|
void B::Notypocorrection(int) { // expected-error {{out-of-line definition of 'Notypocorrection' does not match any declaration in 'B'; did you mean 'typocorrection'}}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue