[clang-tools-extra] [clangd] Handle lambda scopes inside Node::getDeclContext() (PR #76329)

Younan Zhang via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 10 21:57:30 PST 2024


https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/76329

>From c894b9375ebbd1ab58c33a22297bebcd5394a1af Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sun, 24 Dec 2023 18:08:30 +0800
Subject: [PATCH 1/3] [clangd] Handle lambda scopes inside
 Node::getDeclContext()

We used to consider the DeclContext for selection nodes inside
a lambda as the scope of the lambda expression locates in.

For example,

```cpp
void foo();
auto lambda = [] {
  return ^foo();
};
```

where N is the selection node for the expression `foo()`,
`N.getDeclContext()` returns the TranslationUnitDecl previously,
which IMO is wrong, since the RecordDecl of the lambda is closer.
---
 clang-tools-extra/clangd/Selection.cpp              |  3 +++
 .../clangd/unittests/SelectionTests.cpp             | 13 +++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp
index 8c6d5750ecefdba..a7413485b04ac35 100644
--- a/clang-tools-extra/clangd/Selection.cpp
+++ b/clang-tools-extra/clangd/Selection.cpp
@@ -1113,6 +1113,9 @@ const DeclContext &SelectionTree::Node::getDeclContext() const {
           return *DC;
       return *Current->getLexicalDeclContext();
     }
+    if (auto *LE = CurrentNode->ASTNode.get<LambdaExpr>())
+      if (CurrentNode != this)
+        return *LE->getLambdaClass();
   }
   llvm_unreachable("A tree must always be rooted at TranslationUnitDecl.");
 }
diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp
index 4c019a1524f3c39..cdb50dfc1c3095c 100644
--- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp
@@ -880,6 +880,19 @@ TEST(SelectionTest, DeclContextIsLexical) {
   }
 }
 
+TEST(SelectionTest, DeclContextLambda) {
+  llvm::Annotations Test(R"cpp(
+    void foo();
+    auto lambda = [] {
+      return $1^foo();
+    };
+  )cpp");
+  auto AST = TestTU::withCode(Test.code()).build();
+  auto ST = SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),
+                                       Test.point("1"), Test.point("1"));
+  EXPECT_FALSE(ST.commonAncestor()->getDeclContext().isTranslationUnit());
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang

>From b07c191eee31c7d2f605a177459c216357a35b9a Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sun, 24 Dec 2023 23:50:10 +0800
Subject: [PATCH 2/3] DC should be operator()

---
 clang-tools-extra/clangd/Selection.cpp                | 4 ++--
 clang-tools-extra/clangd/unittests/SelectionTests.cpp | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp
index a7413485b04ac35..277cb8769a1b125 100644
--- a/clang-tools-extra/clangd/Selection.cpp
+++ b/clang-tools-extra/clangd/Selection.cpp
@@ -1113,9 +1113,9 @@ const DeclContext &SelectionTree::Node::getDeclContext() const {
           return *DC;
       return *Current->getLexicalDeclContext();
     }
-    if (auto *LE = CurrentNode->ASTNode.get<LambdaExpr>())
+    if (const auto *LE = CurrentNode->ASTNode.get<LambdaExpr>())
       if (CurrentNode != this)
-        return *LE->getLambdaClass();
+        return *LE->getCallOperator();
   }
   llvm_unreachable("A tree must always be rooted at TranslationUnitDecl.");
 }
diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp
index cdb50dfc1c3095c..754e8c287c51486 100644
--- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp
@@ -890,7 +890,7 @@ TEST(SelectionTest, DeclContextLambda) {
   auto AST = TestTU::withCode(Test.code()).build();
   auto ST = SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),
                                        Test.point("1"), Test.point("1"));
-  EXPECT_FALSE(ST.commonAncestor()->getDeclContext().isTranslationUnit());
+  EXPECT_TRUE(ST.commonAncestor()->getDeclContext().isFunctionOrMethod());
 }
 
 } // namespace

>From e289f7f8aa3a7b82976fa3df98e9fa08c410861c Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Thu, 11 Jan 2024 13:44:57 +0800
Subject: [PATCH 3/3] Add a case for AddUsingTweaks

---
 .../clangd/unittests/tweaks/AddUsingTests.cpp | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/clang-tools-extra/clangd/unittests/tweaks/AddUsingTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/AddUsingTests.cpp
index 1fd2487378d7055..c2dd8e1bb8eefaa 100644
--- a/clang-tools-extra/clangd/unittests/tweaks/AddUsingTests.cpp
+++ b/clang-tools-extra/clangd/unittests/tweaks/AddUsingTests.cpp
@@ -309,6 +309,29 @@ namespace foo { void fun(); }
 void foo::fun() {
   ff();
 })cpp"},
+      // Inside a lambda.
+      {
+          R"cpp(
+namespace NS {
+void unrelated();
+void foo();
+}
+
+auto L = [] {
+  using NS::unrelated;
+  NS::f^oo();
+};)cpp",
+          R"cpp(
+namespace NS {
+void unrelated();
+void foo();
+}
+
+auto L = [] {
+  using NS::foo;using NS::unrelated;
+  foo();
+};)cpp",
+      },
       // If all other using are fully qualified, add ::
       {R"cpp(
 #include "test.hpp"



More information about the cfe-commits mailing list