Author: Quan Zhuo Date: 2025-11-02T17:21:03-05:00 New Revision: c1d1a40796426af668dac2cac1e6e89cc1082113
URL: https://github.com/llvm/llvm-project/commit/c1d1a40796426af668dac2cac1e6e89cc1082113 DIFF: https://github.com/llvm/llvm-project/commit/c1d1a40796426af668dac2cac1e6e89cc1082113.diff LOG: [clangd] Handle AttributedTypeLoc in SelectionTree (#163926) This ensures a method name continues to target the method's declaration even if the method's type uses an attribute. Before this change, the AttributedTypeLoc would claim the method name. Fixes https://github.com/clangd/clangd/issues/2488 Added: Modified: clang-tools-extra/clangd/Selection.cpp clang-tools-extra/clangd/unittests/SelectionTests.cpp Removed: ################################################################################ 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..63c0403ab2e70 100644 --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -311,6 +311,19 @@ 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 CXXMethodDecl. + {"struct X { [[const int* ^Get() const <:[clang::lifetimebound]:> " + "{return nullptr;}]]; };", + "CXXMethodDecl"}, + // 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. {"[[int ^a]], b;", "VarDecl"}, {"[[int a, ^b]];", "VarDecl"}, _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
