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

Reply via email to