forked from OSchip/llvm-project
[clang][#47272] Avoid suggesting deprecated version of a declaration over another in typo correction
Prior to this patch, clang might suggest a deprecated name of a declaration over another name as the only mechanism for resolving two typo corrections referring to the same underlying declaration has previously been an alphabetical sort. This patch adjusts this resolve by also taking into account whether one of two declarations are deprecated. If the new one is deprecated it may not replace a previous correction with a non-deprecated correction and a previous deprecated correction always gets replaced by a non-deprecated new correction. Fixes https://github.com/llvm/llvm-project/issues/47272 Differential Revision: https://reviews.llvm.org/D116775
This commit is contained in:
parent
85e6e748d4
commit
6479f03dae
|
@ -4307,18 +4307,35 @@ void TypoCorrectionConsumer::addCorrection(TypoCorrection Correction) {
|
|||
if (!CList.empty() && !CList.back().isResolved())
|
||||
CList.pop_back();
|
||||
if (NamedDecl *NewND = Correction.getCorrectionDecl()) {
|
||||
std::string CorrectionStr = Correction.getAsString(SemaRef.getLangOpts());
|
||||
for (TypoResultList::iterator RI = CList.begin(), RIEnd = CList.end();
|
||||
RI != RIEnd; ++RI) {
|
||||
// If the Correction refers to a decl already in the result list,
|
||||
// replace the existing result if the string representation of Correction
|
||||
// comes before the current result alphabetically, then stop as there is
|
||||
// nothing more to be done to add Correction to the candidate set.
|
||||
if (RI->getCorrectionDecl() == NewND) {
|
||||
if (CorrectionStr < RI->getAsString(SemaRef.getLangOpts()))
|
||||
*RI = Correction;
|
||||
return;
|
||||
}
|
||||
auto RI = llvm::find_if(CList, [NewND](const TypoCorrection &TypoCorr) {
|
||||
return TypoCorr.getCorrectionDecl() == NewND;
|
||||
});
|
||||
if (RI != CList.end()) {
|
||||
// The Correction refers to a decl already in the list. No insertion is
|
||||
// necessary and all further cases will return.
|
||||
|
||||
auto IsDeprecated = [](Decl *D) {
|
||||
while (D) {
|
||||
if (D->isDeprecated())
|
||||
return true;
|
||||
D = llvm::dyn_cast_or_null<NamespaceDecl>(D->getDeclContext());
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Prefer non deprecated Corrections over deprecated and only then
|
||||
// sort using an alphabetical order.
|
||||
std::pair<bool, std::string> NewKey = {
|
||||
IsDeprecated(Correction.getFoundDecl()),
|
||||
Correction.getAsString(SemaRef.getLangOpts())};
|
||||
|
||||
std::pair<bool, std::string> PrevKey = {
|
||||
IsDeprecated(RI->getFoundDecl()),
|
||||
RI->getAsString(SemaRef.getLangOpts())};
|
||||
|
||||
if (NewKey < PrevKey)
|
||||
*RI = Correction;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (CList.empty() || Correction.isResolved())
|
||||
|
|
|
@ -757,3 +757,34 @@ namespace PR46487 {
|
|||
b = g_volatile_uchar // expected-error {{did you mean 'g_volatile_char'}}
|
||||
};
|
||||
}
|
||||
|
||||
namespace PR47272
|
||||
{
|
||||
|
||||
namespace Views {
|
||||
int Take(); // expected-note{{'Views::Take' declared here}}
|
||||
}
|
||||
|
||||
namespace [[deprecated("use Views instead")]] View {
|
||||
using Views::Take;
|
||||
}
|
||||
|
||||
namespace [[deprecated]] A { // expected-note{{'A' has been explicitly marked deprecated here}}
|
||||
int pr47272;
|
||||
}
|
||||
|
||||
namespace B {
|
||||
using A::pr47272; // expected-note{{'B::pr47272' declared here}} expected-warning{{'A' is deprecated}}
|
||||
}
|
||||
|
||||
namespace [[deprecated]] C {
|
||||
using A::pr47272;
|
||||
}
|
||||
|
||||
void function() {
|
||||
int x = ::Take(); // expected-error{{no member named 'Take' in the global namespace; did you mean 'Views::Take'?}}
|
||||
int y = ::pr47272; // expected-error{{no member named 'pr47272' in the global namespace; did you mean 'B::pr47272'?}}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue