From a4cf80a89007bdcce2edf8024785f80a071320db Mon Sep 17 00:00:00 2001 From: Myriad-Dreamin Date: Sat, 6 Sep 2025 22:36:54 +0000 Subject: [PATCH] Add initial implementation of definition feature --- include/Feature/Definition.h | 107 ++++++++++++++++++++++++++++++ src/Feature/Definition.cpp | 2 + tests/unit/Feature/Definition.cpp | 96 +++++++++++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 include/Feature/Definition.h create mode 100644 src/Feature/Definition.cpp create mode 100644 tests/unit/Feature/Definition.cpp diff --git a/include/Feature/Definition.h b/include/Feature/Definition.h new file mode 100644 index 00000000..4af44125 --- /dev/null +++ b/include/Feature/Definition.h @@ -0,0 +1,107 @@ +#pragma once + +#include +#include + +#include "AST/SourceCode.h" +#include "llvm/ADT/StringRef.h" + +namespace clice { + +struct CompilationParams; + +namespace config { + +struct DefinitionOption { + /// Insert placeholder for keywords? function call parameters? template arguments? + bool enable_keyword_snippet = false; + + /// Also apply for lambda ... + bool enable_function_arguments_snippet = false; + bool enable_template_arguments_snippet = false; + + bool insert_paren_in_function_call = false; + /// TODO: Add more detailed option, see + /// https://github.com/llvm/llvm-project/issues/63565 + + bool bundle_overloads = true; + + /// The limits of code completion, 0 is non limit. + std::uint32_t limit = 0; +}; + +}; // namespace config + +namespace feature { + +enum class CompletionItemKind { + None = 0, + Text, + Method, + Function, + Constructor, + Field, + Variable, + Class, + Interface, + Module, + Property, + Unit, + Value, + Enum, + Keyword, + Snippet, + Color, + File, + Reference, + Folder, + EnumMember, + Constant, + Struct, + Event, + Operator, + TypeParameter +}; + +/// Represents a single code completion item to be presented to the user. +struct CompletionItem { + /// The primary label displayed in the completion list. + std::string label; + + /// Additional details, like a function signature, shown next to the label. + std::string detail; + + /// A short description of the item, typically its type or namespace. + std::string description; + + /// Full documentation for the item, shown on selection or hover. + std::string document; + + /// The kind of item (function, class, etc.), used for an icon. + CompletionItemKind kind; + + /// A score for ranking this item against others. Higher is better. + float score; + + /// Whether this item is deprecated (often rendered with a strikethrough). + bool deprecated; + + /// The text edit to be applied when this item is accepted. + struct Edit { + /// The new text to insert, which may be a snippet. + std::string text; + + /// The source range to be replaced by the new text. + LocalSourceRange range; + } edit; +}; + +using CodeCompletionResult = std::vector; + +std::vector definition(CompilationParams& params, + const config::DefinitionOption& option); + +} // namespace feature + +} // namespace clice + diff --git a/src/Feature/Definition.cpp b/src/Feature/Definition.cpp new file mode 100644 index 00000000..43e583e8 --- /dev/null +++ b/src/Feature/Definition.cpp @@ -0,0 +1,2 @@ + +namespace clice::feature {} diff --git a/tests/unit/Feature/Definition.cpp b/tests/unit/Feature/Definition.cpp new file mode 100644 index 00000000..5cac1845 --- /dev/null +++ b/tests/unit/Feature/Definition.cpp @@ -0,0 +1,96 @@ +#include "Test/Tester.h" +#include "Feature/Definition.h" + +namespace clice::testing { + +namespace { + +suite<"Definition"> goto_definition = [] { + std::vector items; + + auto definition = [&](llvm::StringRef code) { + CompilationParams params; + auto annotation = AnnotatedSource::from(code); + params.arguments = {"clang++", "-std=c++20", "main.cpp"}; + params.completion = {"main.cpp", annotation.offsets["pos"]}; + params.add_remapped_file("main.cpp", annotation.content); + + config::DefinitionOption options = {}; + items = feature::definition(params, options); + }; + + using enum feature::CompletionItemKind; + + test("Score") = [&] { + definition(R"cpp( +int foooo(int x); +int x = fo$(pos) +)cpp"); + expect(that % items.size() == 1); + expect(items.front().label == "foooo"); + expect(items.front().kind == Function); + }; + + test("Snippet") = [&] { + definition(R"cpp( +int x = tru$(pos) +)cpp"); + }; + + test("Overload") = [&] { + definition(R"cpp( +int foooo(int x); +int foooo(int x, int y); +int x = fooo$(pos) +)cpp"); + }; + + test("Unqualified") = [&] { + definition(R"cpp( +namespace A { + void fooooo(); +} + +void bar() { + fo$(pos) +} +)cpp"); + + /// EXPECT: "A::fooooo" + /// To implement this we need to search code completion result from index + /// or traverse AST to collect interesting names. + }; + + test("Functor") = [&] { + definition(R"cpp( + struct X { + void operator() () {} + }; + +void bar() { + X foo; + fo$(pos); +} +)cpp"); + + /// TODO: + /// complete lambda as it is a variable. + }; + + test("Lambda") = [&] { + definition(R"cpp( +void bar() { + auto foo = [](int x){ }; + fo$(pos); +} +)cpp"); + + /// TODO: + /// complete lambda as it is a function. + }; +}; + +} // namespace + +} // namespace clice::testing +