[clang] 6479f03 - [clang][#47272] Avoid suggesting deprecated version of a declaration over another in typo correction

Markus Böck via cfe-commits cfe-commits at lists.llvm.org
Tue Jan 11 13:58:20 PST 2022


Author: Markus Böck
Date: 2022-01-11T22:58:10+01:00
New Revision: 6479f03daec1786d1e45f9148bd9298caafba9d2

URL: https://github.com/llvm/llvm-project/commit/6479f03daec1786d1e45f9148bd9298caafba9d2
DIFF: https://github.com/llvm/llvm-project/commit/6479f03daec1786d1e45f9148bd9298caafba9d2.diff

LOG: [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

Added: 
    

Modified: 
    clang/lib/Sema/SemaLookup.cpp
    clang/test/SemaCXX/typo-correction.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 635e93ba84602..c905a10990d21 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -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())

diff  --git a/clang/test/SemaCXX/typo-correction.cpp b/clang/test/SemaCXX/typo-correction.cpp
index 8b13e43661eeb..7eca5d80770da 100644
--- a/clang/test/SemaCXX/typo-correction.cpp
+++ b/clang/test/SemaCXX/typo-correction.cpp
@@ -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'?}}
+}
+}
+
+


        


More information about the cfe-commits mailing list