[clang-tools-extra] Improve attribute range handling for attributed function types in sel… (PR #163926)
Quan Zhuo via cfe-commits
cfe-commits at lists.llvm.org
Sun Nov 2 03:46:46 PST 2025
=?utf-8?b?5YWo5Y2T?= <quanzhuo at kylinos.cn>,
=?utf-8?b?5YWo5Y2T?= <quanzhuo at kylinos.cn>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/163926 at github.com>
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?= <quanzhuo at kylinos.cn>
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?= <quanzhuo at kylinos.cn>
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?= <quanzhuo at kylinos.cn>
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.
More information about the cfe-commits
mailing list