fix(completion): use class name for constructor/deduction guide labels (#416)

## Summary
Fixes a bug where constructors and deduction guides had labels like
`vector<_Tp, _Alloc>` instead of just `vector`, causing:
1. Label deduplication to fail (class `vector` != constructor
`vector<_Tp, _Alloc>`)
2. Selecting the completion to insert invalid text `vector<_Tp, _Alloc>`

Now uses `getParent()->getName()` for constructors and
`getDeducedTemplate()->getName()` for deduction guides.

## Test plan
- [x] All 494 unit tests pass (existing `DeduplicateByLabel` test covers
this)
- [x] `pixi run format` clean

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Constructor and deduction-guide completions now show the parent type
name without template parameters, improving readability and preventing
duplicate entries.

* **Tests**
* Added a unit test verifying completion items for these entries use the
parent type name (no template-parameterized labels) and insertion text
starts with that name.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ykiko
2026-04-09 19:15:38 +08:00
committed by GitHub
parent 342d82a7aa
commit e554660c06
2 changed files with 54 additions and 1 deletions

View File

@@ -192,6 +192,47 @@ void bar() {
ASSERT_EQ(*it->kind, protocol::CompletionItemKind::Class);
}
TEST_CASE(ConstructorLabelNoTemplateArgs) {
// Constructors of class templates should use plain class name as label,
// not "Foo<T>" or "Foo<_Tp, _Alloc>". This ensures dedup works and
// insertion text is correct.
feature::CodeCompletionOptions opts;
opts.bundle_overloads = false;
code_complete(R"cpp(
template <typename T, typename U>
struct Bazzz {
Bazzz() {}
Bazzz(T x) {}
Bazzz(T x, U y) {}
};
template <typename T>
Bazzz(T) -> Bazzz<T, int>;
void bar() {
Ba$(pos)
}
)cpp",
opts);
// Non-bundled mode should produce multiple "Bazzz" items (class + constructors + guide).
auto count = std::ranges::count_if(items, [](const protocol::CompletionItem& item) {
return item.label == "Bazzz";
});
ASSERT_TRUE(count > 1);
// Every item's label must be plain "Bazzz", never "Bazzz<T, U>".
// And the insertion text must also be "Bazzz" (not the templated form).
for(auto& item: items) {
if(item.label.find("Bazzz") != std::string::npos) {
ASSERT_EQ(item.label, "Bazzz");
auto& edit = std::get<protocol::TextEdit>(*item.text_edit);
ASSERT_TRUE(edit.new_text.starts_with("Bazzz"));
ASSERT_TRUE(edit.new_text.find("<") == std::string::npos);
}
}
}
TEST_CASE(NoBundleOverloads) {
feature::CodeCompletionOptions opts;
opts.bundle_overloads = false;