From 3fa653bcafeca7da8bd28b247e19be0b52e5605e Mon Sep 17 00:00:00 2001 From: ykiko Date: Sun, 19 Apr 2026 13:42:32 +0800 Subject: [PATCH] feat(completion): mark deprecated symbols with strikethrough (#414) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 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) ## 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. Co-authored-by: Claude Opus 4.6 --- src/feature/code_completion.cpp | 13 ++++++++-- tests/unit/feature/code_completion_tests.cpp | 27 ++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/feature/code_completion.cpp b/src/feature/code_completion.cpp index 29f3ff2e..b883d5ab 100644 --- a/src/feature/code_completion.cpp +++ b/src/feature/code_completion.cpp @@ -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; } } diff --git a/tests/unit/feature/code_completion_tests.cpp b/tests/unit/feature/code_completion_tests.cpp index 09de96fa..8f7f7474 100644 --- a/tests/unit/feature/code_completion_tests.cpp +++ b/tests/unit/feature/code_completion_tests.cpp @@ -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;