[clangd] Fix action `RemoveUsingNamespace` for inline namespace
authorv1nh1shungry <v1nh1shungry@outlook.com>
Wed, 28 Dec 2022 12:34:41 +0000 (13:34 +0100)
committerTom Praschan <13141438+tom-anders@users.noreply.github.com>
Wed, 28 Dec 2022 12:34:43 +0000 (13:34 +0100)
Existing version ignores symbols declared in an inline namespace `ns`
when removing `using namespace ns`

Reviewed By: tom-anders

Differential Revision: https://reviews.llvm.org/D138028

clang-tools-extra/clangd/refactor/tweaks/RemoveUsingNamespace.cpp
clang-tools-extra/clangd/unittests/tweaks/RemoveUsingNamespaceTests.cpp

index f4228ae..ec02beb 100644 (file)
@@ -89,16 +89,15 @@ bool isTopLevelDecl(const SelectionTree::Node *Node) {
   return Node->Parent && Node->Parent->ASTNode.get<TranslationUnitDecl>();
 }
 
-// Returns the first visible context that contains this DeclContext.
-// For example: Returns ns1 for S1 and a.
-// namespace ns1 {
-// inline namespace ns2 { struct S1 {}; }
-// enum E { a, b, c, d };
-// }
-const DeclContext *visibleContext(const DeclContext *D) {
-  while (D->isInlineNamespace() || D->isTransparentContext())
+// Return true if `LHS` is declared in `RHS`
+bool isDeclaredIn(const NamedDecl *LHS, const DeclContext *RHS) {
+  const auto *D = LHS->getDeclContext();
+  while (D->isInlineNamespace() || D->isTransparentContext()) {
+    if (D->Equals(RHS))
+      return true;
     D = D->getParent();
-  return D;
+  }
+  return D->Equals(RHS);
 }
 
 bool RemoveUsingNamespace::prepare(const Selection &Inputs) {
@@ -152,8 +151,7 @@ Expected<Tweak::Effect> RemoveUsingNamespace::apply(const Selection &Inputs) {
             return; // This reference is already qualified.
 
           for (auto *T : Ref.Targets) {
-            if (!visibleContext(T->getDeclContext())
-                     ->Equals(TargetDirective->getNominatedNamespace()))
+            if (!isDeclaredIn(T, TargetDirective->getNominatedNamespace()))
               return;
             auto Kind = T->getDeclName().getNameKind();
             // Avoid adding qualifiers before operators, e.g.
index 03a46d9..b031153 100644 (file)
@@ -264,6 +264,17 @@ TEST_F(RemoveUsingNamespaceTest, All) {
       }
       
       int main() { 1.5_w; }
+    )cpp"},
+      {
+          R"cpp(
+      namespace a { inline namespace b { void foobar(); } }
+      using namespace a::[[b]];
+      int main() { foobar(); }
+    )cpp",
+          R"cpp(
+      namespace a { inline namespace b { void foobar(); } }
+      
+      int main() { a::b::foobar(); }
     )cpp"}};
   for (auto C : Cases)
     EXPECT_EQ(C.second, apply(C.first)) << C.first;