=?utf-8?b?5YWo5Y2T?= <[email protected]>, =?utf-8?b?5YWo5Y2T?= <[email protected]> Message-ID: In-Reply-To: <llvm.org/llvm/llvm-project/pull/[email protected]>
https://github.com/quanzhuo updated https://github.com/llvm/llvm-project/pull/163926 >From 4239775554b399c9db5e86a83fd79476734a0e85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=A8=E5=8D=93?= <[email protected]> Date: Fri, 17 Oct 2025 16:24:39 +0800 Subject: [PATCH 1/3] Improve attribute range handling for attributed function types in selection This fix https://github.com/clangd/clangd/issues/2488 --- clang-tools-extra/clangd/Selection.cpp | 12 ++++++++++++ .../clangd/unittests/SelectionTests.cpp | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp index 06165dfbbcdd2..faa00d20497fa 100644 --- a/clang-tools-extra/clangd/Selection.cpp +++ b/clang-tools-extra/clangd/Selection.cpp @@ -958,6 +958,18 @@ class SelectionVisitor : public RecursiveASTVisitor<SelectionVisitor> { claimRange(SourceRange(FTL.getLParenLoc(), FTL.getEndLoc()), Result); return; } + if (auto ATL = TL->getAs<AttributedTypeLoc>()) { + // For attributed function types like `int foo() [[attr]]`, the + // AttributedTypeLoc's range includes the function name. We want to + // allow the function name to be associated with the FunctionDecl + // rather than the AttributedTypeLoc, so we only claim the attribute + // range itself. + if (ATL.getModifiedLoc().getAs<FunctionTypeLoc>()) { + // Only claim the attribute's source range, not the whole type. + claimRange(ATL.getLocalSourceRange(), Result); + return; + } + } } claimRange(getSourceRange(N), Result); } diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp index 3df19d8fc174d..103c00ebd5696 100644 --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -311,6 +311,15 @@ TEST(SelectionTest, CommonAncestor) { {"[[void foo^()]];", "FunctionProtoTypeLoc"}, {"[[^void foo^()]];", "FunctionDecl"}, {"[[void ^foo()]];", "FunctionDecl"}, + // Tricky case: with function attributes, the AttributedTypeLoc's range + // includes the function name, but we want the name to be associated with + // the FunctionDecl. + {"struct X { [[void ^foo() [[clang::lifetimebound]]]]; };", + "FunctionDecl"}, + {"struct X { [[void ^foo() const [[clang::lifetimebound]]]]; };", + "FunctionDecl"}, + {"struct X { [[const int* ^Get() const [[clang::lifetimebound]]]]; };", + "FunctionDecl"}, // Tricky case: two VarDecls share a specifier. {"[[int ^a]], b;", "VarDecl"}, {"[[int a, ^b]];", "VarDecl"}, >From d23f381ab3d3b82ab1c47a45cd85604c3eac62b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=A8=E5=8D=93?= <[email protected]> Date: Sat, 1 Nov 2025 14:59:33 +0800 Subject: [PATCH 2/3] Add test for AttributedTypeLoc --- .../clangd/unittests/SelectionTests.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp index 103c00ebd5696..6c978a401fddb 100644 --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -313,13 +313,13 @@ TEST(SelectionTest, CommonAncestor) { {"[[void ^foo()]];", "FunctionDecl"}, // Tricky case: with function attributes, the AttributedTypeLoc's range // includes the function name, but we want the name to be associated with - // the FunctionDecl. - {"struct X { [[void ^foo() [[clang::lifetimebound]]]]; };", - "FunctionDecl"}, - {"struct X { [[void ^foo() const [[clang::lifetimebound]]]]; };", - "FunctionDecl"}, - {"struct X { [[const int* ^Get() const [[clang::lifetimebound]]]]; };", - "FunctionDecl"}, + // the CXXMethodDecl. + {"struct X { [[const int* ^Get() const <:[clang::lifetimebound]:> " + "{return nullptr;}]]; };", + "CXXMethodDecl"}, + {"struct X { const [[int* Foo() const <:[clang::life^timebound]:>]] " + "{return nullptr;}; };", + "AttributedTypeLoc"}, // Tricky case: two VarDecls share a specifier. {"[[int ^a]], b;", "VarDecl"}, {"[[int a, ^b]];", "VarDecl"}, >From 342c87ffd106f2432200844fab2f01e268393184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=A8=E5=8D=93?= <[email protected]> Date: Sun, 2 Nov 2025 19:46:09 +0800 Subject: [PATCH 3/3] Update test for AttributedTypeLoc --- clang-tools-extra/clangd/unittests/SelectionTests.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp index 6c978a401fddb..63c0403ab2e70 100644 --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -317,7 +317,11 @@ TEST(SelectionTest, CommonAncestor) { {"struct X { [[const int* ^Get() const <:[clang::lifetimebound]:> " "{return nullptr;}]]; };", "CXXMethodDecl"}, - {"struct X { const [[int* Foo() const <:[clang::life^timebound]:>]] " + // When the cursor is on the attribute itself, we should select the + // AttributedTypeLoc. Note: Due to a bug or deliberate quirk in the AST + // modeling of AttributedTypeLoc, its range ends at the attribute name + // token, not including the closing brackets ":>:>". + {"struct X { const [[int* Foo() const <:<:clang::life^timebound]]:>:> " "{return nullptr;}; };", "AttributedTypeLoc"}, // Tricky case: two VarDecls share a specifier. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
