feat(completion): mark deprecated symbols with strikethrough (#414)

## Summary
- Check `CXAvailability_Deprecated` on `CodeCompletionResult` and set
`CompletionItemTag::Deprecated`
- Editors render deprecated completions with a strikethrough on the
label

## Test plan
- [x] `DeprecatedTag` — `[[deprecated]]` function gets the tag
- [x] `NotDeprecated` — normal function has no Deprecated tag
- [x] All 491 unit tests pass
- [x] `pixi run format` clean

Stacked on #411.

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

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

* **New Features**
* Code completion now marks deprecated declarations with a deprecated
tag so users can see deprecated items in completion lists.

* **Tests**
* Added unit tests ensuring deprecated declarations produce completion
items with the deprecated tag and non-deprecated items do not.
<!-- 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-19 13:42:32 +08:00
committed by GitHub
parent 592b37417e
commit 3fa653bcaf
2 changed files with 38 additions and 2 deletions

View File

@@ -296,7 +296,8 @@ public:
llvm::StringRef overload_key,
llvm::StringRef signature = {},
llvm::StringRef return_type = {},
bool is_snippet = false) {
bool is_snippet = false,
bool is_deprecated = false) {
if(label.empty()) {
return;
}
@@ -327,6 +328,9 @@ public:
}
item.label_details = std::move(details);
}
if(is_deprecated) {
item.tags = std::vector{protocol::CompletionItemTag::Deprecated};
}
overloads.push_back({
.item = std::move(item),
.score = *score,
@@ -355,6 +359,9 @@ public:
}
item.label_details = std::move(details);
}
if(is_deprecated) {
item.tags = std::vector{protocol::CompletionItemTag::Deprecated};
}
collected.push_back(std::move(item));
};
@@ -431,13 +438,15 @@ public:
bool has_snippet = !snippet.empty();
auto insert = has_snippet ? llvm::StringRef(snippet) : llvm::StringRef(label);
bool deprecated = candidate.Availability == CXAvailability_Deprecated;
try_add(label,
kind,
insert,
qualified_name.str(),
signature,
return_type,
has_snippet);
has_snippet,
deprecated);
break;
}
}

View File

@@ -233,6 +233,33 @@ void bar() {
}
}
TEST_CASE(DeprecatedTag) {
code_complete(R"cpp(
[[deprecated]] int foooo(int x);
int z = fo$(pos)
)cpp");
auto it = find_item("foooo");
ASSERT_TRUE(it != items.end());
ASSERT_TRUE(it->tags.has_value());
auto& tags = *it->tags;
ASSERT_TRUE(std::ranges::find(tags, protocol::CompletionItemTag::Deprecated) != tags.end());
}
TEST_CASE(NotDeprecated) {
code_complete(R"cpp(
int foooo(int x);
int z = fo$(pos)
)cpp");
auto it = find_item("foooo");
ASSERT_TRUE(it != items.end());
// Non-deprecated should have no Deprecated tag.
ASSERT_TRUE(!it->tags.has_value() ||
std::ranges::find(*it->tags, protocol::CompletionItemTag::Deprecated) ==
it->tags->end());
}
TEST_CASE(NoBundleOverloads) {
feature::CodeCompletionOptions opts;
opts.bundle_overloads = false;