[clang] [clang-tools-extra] [clangd] Respect ArgumentLists for struct templates (PR #212094)
Nathan Ridge via cfe-commits
cfe-commits at lists.llvm.org
Sat Jul 25 23:47:34 PDT 2026
https://github.com/HighCommander4 created https://github.com/llvm/llvm-project/pull/212094
Also fix a bug in index::getSymbolKind where the returned symbol kind would be Class for a struct template.
Fixes https://github.com/clangd/clangd/issues/2616
>From 89e5445d1d572213a3f36bb7bda3362325a436b6 Mon Sep 17 00:00:00 2001
From: Nathan Ridge <zeratul976 at hotmail.com>
Date: Sun, 26 Jul 2026 02:44:54 -0400
Subject: [PATCH] [clangd] Respect ArgumentLists for struct templates
Also fix a bug in index::getSymbolKind where the returned symbol
kind would be Class for a struct template.
Fixes https://github.com/clangd/clangd/issues/2616
---
clang-tools-extra/clangd/CodeComplete.cpp | 1 +
.../clangd/unittests/CodeCompleteTests.cpp | 30 ++++++++++++++++++-
clang/lib/Index/IndexSymbol.cpp | 8 +++--
3 files changed, 36 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp
index 5f70dfe0dfd71..80091d3a48b33 100644
--- a/clang-tools-extra/clangd/CodeComplete.cpp
+++ b/clang-tools-extra/clangd/CodeComplete.cpp
@@ -643,6 +643,7 @@ struct CodeCompletionBuilder {
// 'CompletionItemKind::Interface' matches template type aliases.
if (Completion.Kind == CompletionItemKind::Interface ||
Completion.Kind == CompletionItemKind::Class ||
+ Completion.Kind == CompletionItemKind::Struct ||
Completion.Kind == CompletionItemKind::Variable) {
if (Snippet->front() != '<')
return *Snippet; // Not an arg snippet?
diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 5fad022cfe57b..4c1cab7b11e60 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -841,7 +841,7 @@ TEST(CompletionTest, Kinds) {
EXPECT_THAT(
Results.Completions,
UnorderedElementsAre(
- AllOf(named("complete_class"), kind(CompletionItemKind::Class)),
+ AllOf(named("complete_class"), kind(CompletionItemKind::Struct)),
AllOf(named("complete_function"), kind(CompletionItemKind::Function)),
AllOf(named("complete_type_alias"),
kind(CompletionItemKind::Interface)),
@@ -2996,6 +2996,8 @@ TEST(CompletionTest, ArgumentListsPolicy) {
template <class T>
class foo_class{};
template <class T>
+ struct foo_struct{};
+ template <class T>
using foo_alias = T**;
template <class T>
T foo_var = T{};
@@ -3004,8 +3006,34 @@ TEST(CompletionTest, ArgumentListsPolicy) {
EXPECT_THAT(
Results.Completions,
UnorderedElementsAre(AllOf(named("foo_class"), snippetSuffix("<$0>")),
+ AllOf(named("foo_struct"), snippetSuffix("<$0>")),
+ AllOf(named("foo_alias"), snippetSuffix("<$0>")),
+ AllOf(named("foo_var"), snippetSuffix("<$0>"))));
+ }
+ {
+ const char *Header = R"cpp(
+ template <class T>
+ class foo_class{};
+ template <class T>
+ struct foo_struct{};
+ template <class T>
+ using foo_alias = T**;
+ template <class T>
+ T foo_var = T{};
+ )cpp";
+ auto Index = TestTU::withHeaderCode(Header).index();
+ Opts.Index = Index.get();
+ auto Results = completions(
+ R"cpp(
+ void f() { foo_^ })cpp",
+ {}, Opts);
+ EXPECT_THAT(
+ Results.Completions,
+ UnorderedElementsAre(AllOf(named("foo_class"), snippetSuffix("<$0>")),
+ AllOf(named("foo_struct"), snippetSuffix("<$0>")),
AllOf(named("foo_alias"), snippetSuffix("<$0>")),
AllOf(named("foo_var"), snippetSuffix("<$0>"))));
+ Opts.Index = nullptr;
}
{
auto Results = completions(
diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp
index 9b7fee421bdfe..5131b321dedb2 100644
--- a/clang/lib/Index/IndexSymbol.cpp
+++ b/clang/lib/Index/IndexSymbol.cpp
@@ -302,11 +302,15 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
Info.Lang = SymbolLanguage::CXX;
break;
}
- case Decl::ClassTemplate:
- Info.Kind = SymbolKind::Class;
+ case Decl::ClassTemplate: {
+ const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(D);
+ Info.Kind = CTD->getTemplatedDecl()->getTagKind() == TagTypeKind::Struct
+ ? SymbolKind::Struct
+ : SymbolKind::Class;
Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
Info.Lang = SymbolLanguage::CXX;
break;
+ }
case Decl::FunctionTemplate:
Info.Kind = SymbolKind::Function;
Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
More information about the cfe-commits
mailing list