zero9178 created this revision. zero9178 added reviewers: Quuxplusone, aaron.ballman, rsmith. zero9178 requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
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 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D116775 Files: clang/lib/Sema/SemaLookup.cpp clang/test/SemaCXX/typo-correction.cpp Index: clang/test/SemaCXX/typo-correction.cpp =================================================================== --- clang/test/SemaCXX/typo-correction.cpp +++ clang/test/SemaCXX/typo-correction.cpp @@ -757,3 +757,17 @@ 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; +} +void function() { + int x = ::Take(); // expected-error{{no member named 'Take' in the global namespace; did you mean 'Views::Take'?}} +} +} Index: clang/lib/Sema/SemaLookup.cpp =================================================================== --- clang/lib/Sema/SemaLookup.cpp +++ clang/lib/Sema/SemaLookup.cpp @@ -4310,15 +4310,38 @@ 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; + if (RI->getCorrectionDecl() != NewND) + continue; + + // The Correction refers to a decl already in the list. No insertion is + // necessary and all further cases will return. + + auto IsDeprecated = [](Decl *decl) { + while (decl) { + if (decl->isDeprecated()) + return true; + decl = llvm::dyn_cast_or_null<NamespaceDecl>(decl->getDeclContext()); + } + return false; + }; + + // If the Correction in the result list is deprecated and the new one + // isn't always replace it with the new Correction. + // Additionally, don't allow a new deprecated Correction to overwrite + // an old not-deprecated one. + auto newIsDeprecated = IsDeprecated(Correction.getFoundDecl()); + auto oldIsDeprecated = IsDeprecated(RI->getFoundDecl()); + if (oldIsDeprecated && !newIsDeprecated) { + *RI = Correction; return; } + if (newIsDeprecated && !oldIsDeprecated) + return; + + // Otherwise, simply sort them alphabetically. + if (CorrectionStr < RI->getAsString(SemaRef.getLangOpts())) + *RI = Correction; + return; } } if (CList.empty() || Correction.isResolved())
Index: clang/test/SemaCXX/typo-correction.cpp =================================================================== --- clang/test/SemaCXX/typo-correction.cpp +++ clang/test/SemaCXX/typo-correction.cpp @@ -757,3 +757,17 @@ 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; +} +void function() { + int x = ::Take(); // expected-error{{no member named 'Take' in the global namespace; did you mean 'Views::Take'?}} +} +} Index: clang/lib/Sema/SemaLookup.cpp =================================================================== --- clang/lib/Sema/SemaLookup.cpp +++ clang/lib/Sema/SemaLookup.cpp @@ -4310,15 +4310,38 @@ 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; + if (RI->getCorrectionDecl() != NewND) + continue; + + // The Correction refers to a decl already in the list. No insertion is + // necessary and all further cases will return. + + auto IsDeprecated = [](Decl *decl) { + while (decl) { + if (decl->isDeprecated()) + return true; + decl = llvm::dyn_cast_or_null<NamespaceDecl>(decl->getDeclContext()); + } + return false; + }; + + // If the Correction in the result list is deprecated and the new one + // isn't always replace it with the new Correction. + // Additionally, don't allow a new deprecated Correction to overwrite + // an old not-deprecated one. + auto newIsDeprecated = IsDeprecated(Correction.getFoundDecl()); + auto oldIsDeprecated = IsDeprecated(RI->getFoundDecl()); + if (oldIsDeprecated && !newIsDeprecated) { + *RI = Correction; return; } + if (newIsDeprecated && !oldIsDeprecated) + return; + + // Otherwise, simply sort them alphabetically. + if (CorrectionStr < RI->getAsString(SemaRef.getLangOpts())) + *RI = Correction; + return; } } if (CList.empty() || Correction.isResolved())
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits