[clangd] Handle lambda scopes inside Node::getDeclContext() (#76329)

We used to consider the `DeclContext` for selection nodes inside a
lambda as the enclosing scope of the lambda expression, rather than the
lambda itself.

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 method `operator()` of the lambda is closer.

Incidentally, this fixes a glitch in add-using-declaration tweaks.
(Thanks @HighCommander4 for the test case.)
This commit is contained in:
Younan Zhang 2024-01-11 16:59:18 +08:00 committed by GitHub
parent d7642b2200
commit 9ef2ac3ad1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 0 deletions

View File

@ -1113,6 +1113,9 @@ const DeclContext &SelectionTree::Node::getDeclContext() const {
return *DC;
return *Current->getLexicalDeclContext();
}
if (const auto *LE = CurrentNode->ASTNode.get<LambdaExpr>())
if (CurrentNode != this)
return *LE->getCallOperator();
}
llvm_unreachable("A tree must always be rooted at TranslationUnitDecl.");
}

View File

@ -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_TRUE(ST.commonAncestor()->getDeclContext().isFunctionOrMethod());
}
} // namespace
} // namespace clangd
} // namespace clang

View File

@ -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"