summaryrefslogtreecommitdiff
path: root/Userland/DevTools/HackStudio/LanguageServers
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/DevTools/HackStudio/LanguageServers')
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/CMakeLists.txt3
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/CodeComprehensionEngine.cpp42
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/CodeComprehensionEngine.h55
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/ConnectionFromClient.cpp20
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/ConnectionFromClient.h10
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/CMakeLists.txt4
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/ConnectionFromClient.h8
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp1011
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.h204
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests.cpp181
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests.h9
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_includes.cpp5
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_local_args.cpp4
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_local_vars.cpp5
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_type.cpp7
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/find_variable_declaration.cpp4
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/parameters_hint1.cpp8
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/sample_header.h3
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Cpp/main.cpp19
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/FileDB.cpp28
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/FileDB.h16
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/LanguageClient.ipc10
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/LanguageServer.ipc6
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Shell/CMakeLists.txt3
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Shell/ConnectionFromClient.h8
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Shell/ShellComprehensionEngine.cpp236
-rw-r--r--Userland/DevTools/HackStudio/LanguageServers/Shell/ShellComprehensionEngine.h58
27 files changed, 55 insertions, 1912 deletions
diff --git a/Userland/DevTools/HackStudio/LanguageServers/CMakeLists.txt b/Userland/DevTools/HackStudio/LanguageServers/CMakeLists.txt
index 357146c2fe..a8c61a0a21 100644
--- a/Userland/DevTools/HackStudio/LanguageServers/CMakeLists.txt
+++ b/Userland/DevTools/HackStudio/LanguageServers/CMakeLists.txt
@@ -2,7 +2,6 @@ compile_ipc(LanguageServer.ipc LanguageServerEndpoint.h)
compile_ipc(LanguageClient.ipc LanguageClientEndpoint.h)
set(SOURCES
- CodeComprehensionEngine.cpp
ConnectionFromClient.cpp
FileDB.cpp)
set(GENERATED_SOURCES
@@ -10,7 +9,7 @@ set(GENERATED_SOURCES
LanguageServerEndpoint.h)
serenity_lib(LibLanguageServer language_server)
-target_link_libraries(LibLanguageServer LibC)
+target_link_libraries(LibLanguageServer LibCodeComprehension LibC)
add_subdirectory(Cpp)
add_subdirectory(Shell)
diff --git a/Userland/DevTools/HackStudio/LanguageServers/CodeComprehensionEngine.cpp b/Userland/DevTools/HackStudio/LanguageServers/CodeComprehensionEngine.cpp
deleted file mode 100644
index 381a918b59..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/CodeComprehensionEngine.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
- * Copyright (c) 2022, the SerenityOS developers.
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#include "CodeComprehensionEngine.h"
-
-namespace LanguageServers {
-
-CodeComprehensionEngine::CodeComprehensionEngine(FileDB const& filedb, bool should_store_all_declarations)
- : m_filedb(filedb)
- , m_store_all_declarations(should_store_all_declarations)
-{
-}
-
-void CodeComprehensionEngine::set_declarations_of_document(String const& filename, Vector<GUI::AutocompleteProvider::Declaration>&& declarations)
-{
- // Callback may not be configured if we're running tests
- if (!set_declarations_of_document_callback)
- return;
-
- // Optimization - Only notify callback if declarations have changed
- if (auto previous_declarations = m_all_declarations.find(filename); previous_declarations != m_all_declarations.end()) {
- if (previous_declarations->value == declarations)
- return;
- }
- if (m_store_all_declarations)
- m_all_declarations.set(filename, declarations);
- set_declarations_of_document_callback(filename, move(declarations));
-}
-
-void CodeComprehensionEngine::set_todo_entries_of_document(String const& filename, Vector<Cpp::Parser::TodoEntry>&& todo_entries)
-{
- // Callback may not be configured if we're running tests
- if (!set_todo_entries_of_document_callback)
- return;
- set_todo_entries_of_document_callback(filename, move(todo_entries));
-}
-
-}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/CodeComprehensionEngine.h b/Userland/DevTools/HackStudio/LanguageServers/CodeComprehensionEngine.h
deleted file mode 100644
index ddca934520..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/CodeComprehensionEngine.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
- * Copyright (c) 2022, the SerenityOS developers.
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#pragma once
-
-#include "../AutoCompleteResponse.h"
-#include "FileDB.h"
-#include <LibGUI/AutocompleteProvider.h>
-#include <LibGUI/TextPosition.h>
-
-namespace LanguageServers {
-
-class ConnectionFromClient;
-
-class CodeComprehensionEngine {
-public:
- CodeComprehensionEngine(FileDB const& filedb, bool store_all_declarations = false);
- virtual ~CodeComprehensionEngine() = default;
-
- virtual Vector<GUI::AutocompleteProvider::Entry> get_suggestions(String const& file, const GUI::TextPosition& autocomplete_position) = 0;
-
- // TODO: In the future we can pass the range that was edited and only re-parse what we have to.
- virtual void on_edit([[maybe_unused]] String const& file) {};
- virtual void file_opened([[maybe_unused]] String const& file) {};
-
- virtual Optional<GUI::AutocompleteProvider::ProjectLocation> find_declaration_of(String const&, const GUI::TextPosition&) { return {}; }
-
- struct FunctionParamsHint {
- Vector<String> params;
- size_t current_index { 0 };
- };
- virtual Optional<FunctionParamsHint> get_function_params_hint(String const&, const GUI::TextPosition&) { return {}; }
-
- virtual Vector<GUI::AutocompleteProvider::TokenInfo> get_tokens_info(String const&) { return {}; }
-
-public:
- Function<void(String const&, Vector<GUI::AutocompleteProvider::Declaration>&&)> set_declarations_of_document_callback;
- Function<void(String const&, Vector<Cpp::Parser::TodoEntry>&&)> set_todo_entries_of_document_callback;
-
-protected:
- FileDB const& filedb() const { return m_filedb; }
- void set_declarations_of_document(String const&, Vector<GUI::AutocompleteProvider::Declaration>&&);
- void set_todo_entries_of_document(String const&, Vector<Cpp::Parser::TodoEntry>&&);
- HashMap<String, Vector<GUI::AutocompleteProvider::Declaration>> const& all_declarations() const { return m_all_declarations; }
-
-private:
- HashMap<String, Vector<GUI::AutocompleteProvider::Declaration>> m_all_declarations;
- FileDB const& m_filedb;
- bool m_store_all_declarations { false };
-};
-}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/ConnectionFromClient.cpp b/Userland/DevTools/HackStudio/LanguageServers/ConnectionFromClient.cpp
index d1f29a4199..7bf24c7cc9 100644
--- a/Userland/DevTools/HackStudio/LanguageServers/ConnectionFromClient.cpp
+++ b/Userland/DevTools/HackStudio/LanguageServers/ConnectionFromClient.cpp
@@ -66,25 +66,25 @@ void ConnectionFromClient::file_edit_remove_text(String const& filename, i32 sta
m_autocomplete_engine->on_edit(filename);
}
-void ConnectionFromClient::auto_complete_suggestions(GUI::AutocompleteProvider::ProjectLocation const& location)
+void ConnectionFromClient::auto_complete_suggestions(CodeComprehension::ProjectLocation const& location)
{
dbgln_if(LANGUAGE_SERVER_DEBUG, "AutoCompleteSuggestions for: {} {}:{}", location.file, location.line, location.column);
- auto document = m_filedb.get(location.file);
+ auto document = m_filedb.get_document(location.file);
if (!document) {
dbgln("file {} has not been opened", location.file);
return;
}
GUI::TextPosition autocomplete_position = { (size_t)location.line, (size_t)max(location.column, location.column - 1) };
- Vector<GUI::AutocompleteProvider::Entry> suggestions = m_autocomplete_engine->get_suggestions(location.file, autocomplete_position);
+ Vector<CodeComprehension::AutocompleteResultEntry> suggestions = m_autocomplete_engine->get_suggestions(location.file, autocomplete_position);
async_auto_complete_suggestions(move(suggestions));
}
void ConnectionFromClient::set_file_content(String const& filename, String const& content)
{
dbgln_if(LANGUAGE_SERVER_DEBUG, "SetFileContent: {}", filename);
- auto document = m_filedb.get(filename);
+ auto document = m_filedb.get_document(filename);
if (!document) {
m_filedb.add(filename, content);
VERIFY(m_filedb.is_open(filename));
@@ -95,10 +95,10 @@ void ConnectionFromClient::set_file_content(String const& filename, String const
m_autocomplete_engine->on_edit(filename);
}
-void ConnectionFromClient::find_declaration(GUI::AutocompleteProvider::ProjectLocation const& location)
+void ConnectionFromClient::find_declaration(CodeComprehension::ProjectLocation const& location)
{
dbgln_if(LANGUAGE_SERVER_DEBUG, "FindDeclaration: {} {}:{}", location.file, location.line, location.column);
- auto document = m_filedb.get(location.file);
+ auto document = m_filedb.get_document(location.file);
if (!document) {
dbgln("file {} has not been opened", location.file);
return;
@@ -112,13 +112,13 @@ void ConnectionFromClient::find_declaration(GUI::AutocompleteProvider::ProjectLo
}
dbgln_if(LANGUAGE_SERVER_DEBUG, "declaration location: {} {}:{}", decl_location.value().file, decl_location.value().line, decl_location.value().column);
- async_declaration_location(GUI::AutocompleteProvider::ProjectLocation { decl_location.value().file, decl_location.value().line, decl_location.value().column });
+ async_declaration_location(CodeComprehension::ProjectLocation { decl_location.value().file, decl_location.value().line, decl_location.value().column });
}
-void ConnectionFromClient::get_parameters_hint(GUI::AutocompleteProvider::ProjectLocation const& location)
+void ConnectionFromClient::get_parameters_hint(CodeComprehension::ProjectLocation const& location)
{
dbgln_if(LANGUAGE_SERVER_DEBUG, "GetParametersHint: {} {}:{}", location.file, location.line, location.column);
- auto document = m_filedb.get(location.file);
+ auto document = m_filedb.get_document(location.file);
if (!document) {
dbgln("file {} has not been opened", location.file);
return;
@@ -143,7 +143,7 @@ void ConnectionFromClient::get_parameters_hint(GUI::AutocompleteProvider::Projec
void ConnectionFromClient::get_tokens_info(String const& filename)
{
dbgln_if(LANGUAGE_SERVER_DEBUG, "GetTokenInfo: {}", filename);
- auto document = m_filedb.get(filename);
+ auto document = m_filedb.get_document(filename);
if (!document) {
dbgln("file {} has not been opened", filename);
return;
diff --git a/Userland/DevTools/HackStudio/LanguageServers/ConnectionFromClient.h b/Userland/DevTools/HackStudio/LanguageServers/ConnectionFromClient.h
index 6e909ff185..87563eba11 100644
--- a/Userland/DevTools/HackStudio/LanguageServers/ConnectionFromClient.h
+++ b/Userland/DevTools/HackStudio/LanguageServers/ConnectionFromClient.h
@@ -8,10 +8,10 @@
#pragma once
#include "../AutoCompleteResponse.h"
-#include "CodeComprehensionEngine.h"
#include "FileDB.h"
#include <AK/HashMap.h>
#include <AK/LexicalPath.h>
+#include <LibCodeComprehension/CodeComprehensionEngine.h>
#include <LibIPC/ConnectionFromClient.h>
#include <Userland/DevTools/HackStudio/LanguageServers/LanguageClientEndpoint.h>
@@ -32,13 +32,13 @@ protected:
virtual void file_edit_insert_text(String const&, String const&, i32, i32) override;
virtual void file_edit_remove_text(String const&, i32, i32, i32, i32) override;
virtual void set_file_content(String const&, String const&) override;
- virtual void auto_complete_suggestions(GUI::AutocompleteProvider::ProjectLocation const&) override;
- virtual void find_declaration(GUI::AutocompleteProvider::ProjectLocation const&) override;
- virtual void get_parameters_hint(GUI::AutocompleteProvider::ProjectLocation const&) override;
+ virtual void auto_complete_suggestions(CodeComprehension::ProjectLocation const&) override;
+ virtual void find_declaration(CodeComprehension::ProjectLocation const&) override;
+ virtual void get_parameters_hint(CodeComprehension::ProjectLocation const&) override;
virtual void get_tokens_info(String const&) override;
FileDB m_filedb;
- OwnPtr<CodeComprehensionEngine> m_autocomplete_engine;
+ OwnPtr<CodeComprehension::CodeComprehensionEngine> m_autocomplete_engine;
};
}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CMakeLists.txt b/Userland/DevTools/HackStudio/LanguageServers/Cpp/CMakeLists.txt
index 3ea2679652..4989bc42c1 100644
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CMakeLists.txt
+++ b/Userland/DevTools/HackStudio/LanguageServers/Cpp/CMakeLists.txt
@@ -4,8 +4,6 @@ serenity_component(
)
set(SOURCES
- CppComprehensionEngine.cpp
- Tests.cpp
main.cpp
)
@@ -17,4 +15,4 @@ serenity_bin(CppLanguageServer)
# We link with LibGUI because we use GUI::TextDocument to update
# the content of files according to the edit actions we receive over IPC.
-target_link_libraries(CppLanguageServer LibIPC LibCpp LibGUI LibLanguageServer LibMain)
+target_link_libraries(CppLanguageServer LibIPC LibCpp LibGUI LibLanguageServer LibCppComprehension LibMain)
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/ConnectionFromClient.h b/Userland/DevTools/HackStudio/LanguageServers/Cpp/ConnectionFromClient.h
index ff5744c369..13ab563474 100644
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/ConnectionFromClient.h
+++ b/Userland/DevTools/HackStudio/LanguageServers/Cpp/ConnectionFromClient.h
@@ -6,8 +6,8 @@
#pragma once
-#include "CppComprehensionEngine.h"
#include <DevTools/HackStudio/LanguageServers/ConnectionFromClient.h>
+#include <LibCodeComprehension/Cpp/CppComprehensionEngine.h>
namespace LanguageServers::Cpp {
@@ -18,11 +18,11 @@ private:
ConnectionFromClient(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: LanguageServers::ConnectionFromClient(move(socket))
{
- m_autocomplete_engine = make<CppComprehensionEngine>(m_filedb);
- m_autocomplete_engine->set_declarations_of_document_callback = [this](String const& filename, Vector<GUI::AutocompleteProvider::Declaration>&& declarations) {
+ m_autocomplete_engine = adopt_own(*new CodeComprehension::Cpp::CppComprehensionEngine(m_filedb));
+ m_autocomplete_engine->set_declarations_of_document_callback = [this](String const& filename, Vector<CodeComprehension::Declaration>&& declarations) {
async_declarations_in_document(filename, move(declarations));
};
- m_autocomplete_engine->set_todo_entries_of_document_callback = [this](String const& filename, Vector<Cpp::Parser::TodoEntry>&& todo_entries) {
+ m_autocomplete_engine->set_todo_entries_of_document_callback = [this](String const& filename, Vector<CodeComprehension::TodoEntry>&& todo_entries) {
async_todo_entries_in_document(filename, move(todo_entries));
};
}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp
deleted file mode 100644
index 4abfdc7861..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp
+++ /dev/null
@@ -1,1011 +0,0 @@
-/*
- * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#include "CppComprehensionEngine.h"
-#include <AK/Assertions.h>
-#include <AK/HashTable.h>
-#include <AK/OwnPtr.h>
-#include <AK/ScopeGuard.h>
-#include <LibCore/DirIterator.h>
-#include <LibCore/File.h>
-#include <LibCpp/AST.h>
-#include <LibCpp/Lexer.h>
-#include <LibCpp/Parser.h>
-#include <LibCpp/Preprocessor.h>
-#include <LibRegex/Regex.h>
-#include <Userland/DevTools/HackStudio/LanguageServers/ConnectionFromClient.h>
-
-namespace LanguageServers::Cpp {
-
-CppComprehensionEngine::CppComprehensionEngine(FileDB const& filedb)
- : CodeComprehensionEngine(filedb, true)
-{
-}
-
-CppComprehensionEngine::DocumentData const* CppComprehensionEngine::get_or_create_document_data(String const& file)
-{
- auto absolute_path = filedb().to_absolute_path(file);
- if (!m_documents.contains(absolute_path)) {
- set_document_data(absolute_path, create_document_data_for(absolute_path));
- }
- return get_document_data(absolute_path);
-}
-
-CppComprehensionEngine::DocumentData const* CppComprehensionEngine::get_document_data(String const& file) const
-{
- auto absolute_path = filedb().to_absolute_path(file);
- auto document_data = m_documents.get(absolute_path);
- if (!document_data.has_value())
- return nullptr;
- return document_data.value();
-}
-
-OwnPtr<CppComprehensionEngine::DocumentData> CppComprehensionEngine::create_document_data_for(String const& file)
-{
- if (m_unfinished_documents.contains(file)) {
- return {};
- }
- m_unfinished_documents.set(file);
- ScopeGuard mark_finished([&file, this]() { m_unfinished_documents.remove(file); });
- auto document = filedb().get_or_create_from_filesystem(file);
- if (!document)
- return {};
- return create_document_data(document->text(), file);
-}
-
-void CppComprehensionEngine::set_document_data(String const& file, OwnPtr<DocumentData>&& data)
-{
- m_documents.set(filedb().to_absolute_path(file), move(data));
-}
-
-Vector<GUI::AutocompleteProvider::Entry> CppComprehensionEngine::get_suggestions(String const& file, const GUI::TextPosition& autocomplete_position)
-{
- Cpp::Position position { autocomplete_position.line(), autocomplete_position.column() > 0 ? autocomplete_position.column() - 1 : 0 };
-
- dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "CppComprehensionEngine position {}:{}", position.line, position.column);
-
- auto const* document_ptr = get_or_create_document_data(file);
- if (!document_ptr)
- return {};
-
- auto const& document = *document_ptr;
- auto containing_token = document.parser().token_at(position);
-
- if (containing_token.has_value() && containing_token->type() == Token::Type::IncludePath) {
- auto results = try_autocomplete_include(document, containing_token.value(), position);
- if (results.has_value())
- return results.value();
- }
-
- auto node = document.parser().node_at(position);
- if (!node) {
- dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "no node at position {}:{}", position.line, position.column);
- return {};
- }
-
- if (node->parent() && node->parent()->parent())
- dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "node: {}, parent: {}, grandparent: {}", node->class_name(), node->parent()->class_name(), node->parent()->parent()->class_name());
-
- if (!node->parent())
- return {};
-
- auto results = try_autocomplete_property(document, *node, containing_token);
- if (results.has_value())
- return results.value();
-
- results = try_autocomplete_name(document, *node, containing_token);
- if (results.has_value())
- return results.value();
- return {};
-}
-
-Optional<Vector<GUI::AutocompleteProvider::Entry>> CppComprehensionEngine::try_autocomplete_name(DocumentData const& document, ASTNode const& node, Optional<Token> containing_token) const
-{
- auto partial_text = String::empty();
- if (containing_token.has_value() && containing_token.value().type() != Token::Type::ColonColon) {
- partial_text = containing_token.value().text();
- }
- return autocomplete_name(document, node, partial_text);
-}
-
-Optional<Vector<GUI::AutocompleteProvider::Entry>> CppComprehensionEngine::try_autocomplete_property(DocumentData const& document, ASTNode const& node, Optional<Token> containing_token) const
-{
- if (!containing_token.has_value())
- return {};
-
- if (!node.parent()->is_member_expression())
- return {};
-
- auto const& parent = static_cast<MemberExpression const&>(*node.parent());
-
- auto partial_text = String::empty();
- if (containing_token.value().type() != Token::Type::Dot) {
- if (&node != parent.property())
- return {};
- partial_text = containing_token.value().text();
- }
-
- return autocomplete_property(document, parent, partial_text);
-}
-
-Vector<GUI::AutocompleteProvider::Entry> CppComprehensionEngine::autocomplete_name(DocumentData const& document, ASTNode const& node, String const& partial_text) const
-{
- auto reference_scope = scope_of_reference_to_symbol(node);
- auto current_scope = scope_of_node(node);
-
- auto symbol_matches = [&](Symbol const& symbol) {
- if (!is_symbol_available(symbol, current_scope, reference_scope)) {
- return false;
- }
-
- if (!symbol.name.name.starts_with(partial_text))
- return false;
-
- if (symbol.is_local) {
- // If this symbol was declared below us in a function, it's not available to us.
- bool is_unavailable = symbol.is_local && symbol.declaration->start().line > node.start().line;
- if (is_unavailable)
- return false;
- }
-
- return true;
- };
-
- Vector<Symbol> matches;
-
- for_each_available_symbol(document, [&](Symbol const& symbol) {
- if (symbol_matches(symbol)) {
- matches.append(symbol);
- }
- return IterationDecision::Continue;
- });
-
- Vector<GUI::AutocompleteProvider::Entry> suggestions;
- for (auto& symbol : matches) {
- suggestions.append({ symbol.name.name, partial_text.length() });
- }
-
- if (reference_scope.is_empty()) {
- for (auto& preprocessor_name : document.preprocessor().definitions().keys()) {
- if (preprocessor_name.starts_with(partial_text)) {
- suggestions.append({ preprocessor_name, partial_text.length() });
- }
- }
- }
-
- return suggestions;
-}
-
-Vector<StringView> CppComprehensionEngine::scope_of_reference_to_symbol(ASTNode const& node) const
-{
- Name const* name = nullptr;
- if (node.is_name()) {
- // FIXME It looks like this code path is never taken
- name = reinterpret_cast<Name const*>(&node);
- } else if (node.is_identifier()) {
- auto* parent = node.parent();
- if (!(parent && parent->is_name()))
- return {};
- name = reinterpret_cast<Name const*>(parent);
- } else {
- return {};
- }
-
- VERIFY(name->is_name());
-
- Vector<StringView> scope_parts;
- for (auto& scope_part : name->scope()) {
- // If the target node is part of a scope reference, we want to end the scope chain before it.
- if (&scope_part == &node)
- break;
- scope_parts.append(scope_part.name());
- }
- return scope_parts;
-}
-
-Vector<GUI::AutocompleteProvider::Entry> CppComprehensionEngine::autocomplete_property(DocumentData const& document, MemberExpression const& parent, const String partial_text) const
-{
- VERIFY(parent.object());
- auto type = type_of(document, *parent.object());
- if (type.is_null()) {
- dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "Could not infer type of object");
- return {};
- }
-
- Vector<GUI::AutocompleteProvider::Entry> suggestions;
- for (auto& prop : properties_of_type(document, type)) {
- if (prop.name.name.starts_with(partial_text)) {
- suggestions.append({ prop.name.name, partial_text.length() });
- }
- }
- return suggestions;
-}
-
-bool CppComprehensionEngine::is_property(ASTNode const& node) const
-{
- if (!node.parent()->is_member_expression())
- return false;
-
- auto& parent = verify_cast<MemberExpression>(*node.parent());
- return parent.property() == &node;
-}
-
-String CppComprehensionEngine::type_of_property(DocumentData const& document, Identifier const& identifier) const
-{
- auto& parent = verify_cast<MemberExpression>(*identifier.parent());
- VERIFY(parent.object());
- auto properties = properties_of_type(document, type_of(document, *parent.object()));
- for (auto& prop : properties) {
- if (prop.name.name != identifier.name())
- continue;
- Type const* type { nullptr };
- if (prop.declaration->is_variable_declaration()) {
- type = verify_cast<VariableDeclaration>(*prop.declaration).type();
- }
- if (!type)
- continue;
- if (!type->is_named_type())
- continue;
-
- VERIFY(verify_cast<NamedType>(*type).name());
- if (verify_cast<NamedType>(*type).name())
- return verify_cast<NamedType>(*type).name()->full_name();
- return String::empty();
- }
- return {};
-}
-
-String CppComprehensionEngine::type_of_variable(Identifier const& identifier) const
-{
- ASTNode const* current = &identifier;
- while (current) {
- for (auto& decl : current->declarations()) {
- if (decl.is_variable_or_parameter_declaration()) {
- auto& var_or_param = verify_cast<VariableOrParameterDeclaration>(decl);
- if (var_or_param.full_name() == identifier.name() && var_or_param.type()->is_named_type()) {
- VERIFY(verify_cast<NamedType>(*var_or_param.type()).name());
- if (verify_cast<NamedType>(*var_or_param.type()).name())
- return verify_cast<NamedType>(*var_or_param.type()).name()->full_name();
- return String::empty();
- }
- }
- }
- current = current->parent();
- }
- return {};
-}
-
-String CppComprehensionEngine::type_of(DocumentData const& document, Expression const& expression) const
-{
- if (expression.is_member_expression()) {
- auto& member_expression = verify_cast<MemberExpression>(expression);
- VERIFY(member_expression.property());
- if (member_expression.property()->is_identifier())
- return type_of_property(document, static_cast<Identifier const&>(*member_expression.property()));
- return {};
- }
-
- Identifier const* identifier { nullptr };
- if (expression.is_name()) {
- identifier = static_cast<Name const&>(expression).name();
- } else if (expression.is_identifier()) {
- identifier = &static_cast<Identifier const&>(expression);
- } else {
- dbgln("expected identifier or name, got: {}", expression.class_name());
- VERIFY_NOT_REACHED(); // TODO
- }
- VERIFY(identifier);
- if (is_property(*identifier))
- return type_of_property(document, *identifier);
-
- return type_of_variable(*identifier);
-}
-
-Vector<CppComprehensionEngine::Symbol> CppComprehensionEngine::properties_of_type(DocumentData const& document, String const& type) const
-{
- auto type_symbol = SymbolName::create(type);
- auto decl = find_declaration_of(document, type_symbol);
- if (!decl) {
- dbgln("Couldn't find declaration of type: {}", type);
- return {};
- }
-
- if (!decl->is_struct_or_class()) {
- dbgln("Expected declaration of type: {} to be struct or class", type);
- return {};
- }
-
- auto& struct_or_class = verify_cast<StructOrClassDeclaration>(*decl);
- VERIFY(struct_or_class.full_name() == type_symbol.name);
-
- Vector<Symbol> properties;
- for (auto& member : struct_or_class.members()) {
- Vector<StringView> scope(type_symbol.scope);
- scope.append(type_symbol.name);
- // FIXME: We don't have to create the Symbol here, it should already exist in the 'm_symbol' table of some DocumentData we already parsed.
- properties.append(Symbol::create(member.full_name(), scope, member, Symbol::IsLocal::No));
- }
- return properties;
-}
-
-CppComprehensionEngine::Symbol CppComprehensionEngine::Symbol::create(StringView name, Vector<StringView> const& scope, NonnullRefPtr<Declaration> declaration, IsLocal is_local)
-{
- return { { name, scope }, move(declaration), is_local == IsLocal::Yes };
-}
-
-Vector<CppComprehensionEngine::Symbol> CppComprehensionEngine::get_child_symbols(ASTNode const& node) const
-{
- return get_child_symbols(node, {}, Symbol::IsLocal::No);
-}
-
-Vector<CppComprehensionEngine::Symbol> CppComprehensionEngine::get_child_symbols(ASTNode const& node, Vector<StringView> const& scope, Symbol::IsLocal is_local) const
-{
- Vector<Symbol> symbols;
-
- for (auto& decl : node.declarations()) {
- symbols.append(Symbol::create(decl.full_name(), scope, decl, is_local));
-
- bool should_recurse = decl.is_namespace() || decl.is_struct_or_class() || decl.is_function();
- bool are_child_symbols_local = decl.is_function();
-
- if (!should_recurse)
- continue;
-
- auto new_scope = scope;
- new_scope.append(decl.full_name());
- symbols.extend(get_child_symbols(decl, new_scope, are_child_symbols_local ? Symbol::IsLocal::Yes : is_local));
- }
-
- return symbols;
-}
-
-String CppComprehensionEngine::document_path_from_include_path(StringView include_path) const
-{
- static Regex<PosixExtended> library_include("<(.+)>");
- static Regex<PosixExtended> user_defined_include("\"(.+)\"");
-
- auto document_path_for_library_include = [&](StringView include_path) -> String {
- RegexResult result;
- if (!library_include.search(include_path, result))
- return {};
-
- auto path = result.capture_group_matches.at(0).at(0).view.string_view();
- return String::formatted("/usr/include/{}", path);
- };
-
- auto document_path_for_user_defined_include = [&](StringView include_path) -> String {
- RegexResult result;
- if (!user_defined_include.search(include_path, result))
- return {};
-
- return result.capture_group_matches.at(0).at(0).view.string_view();
- };
-
- auto result = document_path_for_library_include(include_path);
- if (result.is_null())
- result = document_path_for_user_defined_include(include_path);
-
- return result;
-}
-
-void CppComprehensionEngine::on_edit(String const& file)
-{
- set_document_data(file, create_document_data_for(file));
-}
-
-void CppComprehensionEngine::file_opened([[maybe_unused]] String const& file)
-{
- get_or_create_document_data(file);
-}
-
-Optional<GUI::AutocompleteProvider::ProjectLocation> CppComprehensionEngine::find_declaration_of(String const& filename, const GUI::TextPosition& identifier_position)
-{
- auto const* document_ptr = get_or_create_document_data(filename);
- if (!document_ptr)
- return {};
-
- auto const& document = *document_ptr;
- auto decl = find_declaration_of(document, identifier_position);
- if (decl) {
- return GUI::AutocompleteProvider::ProjectLocation { decl->filename(), decl->start().line, decl->start().column };
- }
-
- return find_preprocessor_definition(document, identifier_position);
-}
-
-RefPtr<Declaration> CppComprehensionEngine::find_declaration_of(DocumentData const& document, const GUI::TextPosition& identifier_position)
-{
- auto node = document.parser().node_at(Cpp::Position { identifier_position.line(), identifier_position.column() });
- if (!node) {
- dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "no node at position {}:{}", identifier_position.line(), identifier_position.column());
- return {};
- }
- return find_declaration_of(document, *node);
-}
-
-Optional<GUI::AutocompleteProvider::ProjectLocation> CppComprehensionEngine::find_preprocessor_definition(DocumentData const& document, const GUI::TextPosition& text_position)
-{
- Position cpp_position { text_position.line(), text_position.column() };
- auto substitution = find_preprocessor_substitution(document, cpp_position);
- if (!substitution.has_value())
- return {};
- return GUI::AutocompleteProvider::ProjectLocation { substitution->defined_value.filename, substitution->defined_value.line, substitution->defined_value.column };
-}
-
-Optional<Cpp::Preprocessor::Substitution> CppComprehensionEngine::find_preprocessor_substitution(DocumentData const& document, Cpp::Position const& cpp_position)
-{
- // Search for a replaced preprocessor token that intersects with text_position
- for (auto& substitution : document.preprocessor().substitutions()) {
- if (substitution.original_tokens.first().start() > cpp_position)
- continue;
- if (substitution.original_tokens.first().end() < cpp_position)
- continue;
- return substitution;
- }
- return {};
-}
-
-struct TargetDeclaration {
- enum Type {
- Variable,
- Type,
- Function,
- Property,
- Scope
- } type;
- String name;
-};
-
-static Optional<TargetDeclaration> get_target_declaration(ASTNode const& node, String name);
-static Optional<TargetDeclaration> get_target_declaration(ASTNode const& node)
-{
- if (node.is_identifier()) {
- return get_target_declaration(node, static_cast<Identifier const&>(node).name());
- }
-
- if (node.is_declaration()) {
- return get_target_declaration(node, verify_cast<Declaration>(node).full_name());
- }
-
- if (node.is_type() && node.parent() && node.parent()->is_declaration()) {
- return get_target_declaration(*node.parent(), verify_cast<Declaration>(node.parent())->full_name());
- }
-
- dbgln("get_target_declaration: Invalid argument node of type: {}", node.class_name());
- return {};
-}
-
-static Optional<TargetDeclaration> get_target_declaration(ASTNode const& node, String name)
-{
- if (node.parent() && node.parent()->is_name()) {
- auto& name_node = *verify_cast<Name>(node.parent());
- if (&node != name_node.name()) {
- // Node is part of scope reference chain
- return TargetDeclaration { TargetDeclaration::Type::Scope, name };
- }
- if (name_node.parent() && name_node.parent()->is_declaration()) {
- auto declaration = verify_cast<Declaration>(name_node.parent());
- if (declaration->is_struct_or_class() || declaration->is_enum()) {
- return TargetDeclaration { TargetDeclaration::Type::Type, name };
- }
- if (declaration->is_function()) {
- return TargetDeclaration { TargetDeclaration::Type::Function, name };
- }
- }
- }
-
- if ((node.parent() && node.parent()->is_function_call()) || (node.parent()->is_name() && node.parent()->parent() && node.parent()->parent()->is_function_call())) {
- return TargetDeclaration { TargetDeclaration::Type::Function, name };
- }
-
- if ((node.parent() && node.parent()->is_type()) || (node.parent()->is_name() && node.parent()->parent() && node.parent()->parent()->is_type()))
- return TargetDeclaration { TargetDeclaration::Type::Type, name };
-
- if ((node.parent() && node.parent()->is_member_expression()))
- return TargetDeclaration { TargetDeclaration::Type::Property, name };
-
- return TargetDeclaration { TargetDeclaration::Type::Variable, name };
-}
-RefPtr<Declaration> CppComprehensionEngine::find_declaration_of(DocumentData const& document_data, ASTNode const& node) const
-{
- dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "find_declaration_of: {} ({})", document_data.parser().text_of_node(node), node.class_name());
-
- auto target_decl = get_target_declaration(node);
- if (!target_decl.has_value())
- return {};
-
- auto reference_scope = scope_of_reference_to_symbol(node);
- auto current_scope = scope_of_node(node);
-
- auto symbol_matches = [&](Symbol const& symbol) {
- bool match_function = target_decl.value().type == TargetDeclaration::Function && symbol.declaration->is_function();
- bool match_variable = target_decl.value().type == TargetDeclaration::Variable && symbol.declaration->is_variable_declaration();
- bool match_type = target_decl.value().type == TargetDeclaration::Type && (symbol.declaration->is_struct_or_class() || symbol.declaration->is_enum());
- bool match_property = target_decl.value().type == TargetDeclaration::Property && symbol.declaration->parent()->is_declaration() && verify_cast<Declaration>(symbol.declaration->parent())->is_struct_or_class();
- bool match_parameter = target_decl.value().type == TargetDeclaration::Variable && symbol.declaration->is_parameter();
- bool match_scope = target_decl.value().type == TargetDeclaration::Scope && (symbol.declaration->is_namespace() || symbol.declaration->is_struct_or_class());
-
- if (match_property) {
- // FIXME: This is not really correct, we also need to check that the type of the struct/class matches (not just the property name)
- if (symbol.name.name == target_decl.value().name) {
- return true;
- }
- }
-
- if (!is_symbol_available(symbol, current_scope, reference_scope)) {
- return false;
- }
-
- if (match_function || match_type || match_scope) {
- if (symbol.name.name == target_decl->name)
- return true;
- }
-
- if (match_variable || match_parameter) {
- // If this symbol was declared below us in a function, it's not available to us.
- bool is_unavailable = symbol.is_local && symbol.declaration->start().line > node.start().line;
-
- if (!is_unavailable && (symbol.name.name == target_decl->name)) {
- return true;
- }
- }
-
- return false;
- };
-
- Optional<Symbol> match;
-
- for_each_available_symbol(document_data, [&](Symbol const& symbol) {
- if (symbol_matches(symbol)) {
- match = symbol;
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
-
- if (!match.has_value())
- return {};
-
- return match->declaration;
-}
-
-void CppComprehensionEngine::update_declared_symbols(DocumentData& document)
-{
- for (auto& symbol : get_child_symbols(*document.parser().root_node())) {
- document.m_symbols.set(symbol.name, move(symbol));
- }
-
- Vector<GUI::AutocompleteProvider::Declaration> declarations;
- for (auto& symbol_entry : document.m_symbols) {
- auto& symbol = symbol_entry.value;
- declarations.append({ symbol.name.name, { document.filename(), symbol.declaration->start().line, symbol.declaration->start().column }, type_of_declaration(symbol.declaration), symbol.name.scope_as_string() });
- }
-
- for (auto& definition : document.preprocessor().definitions()) {
- declarations.append({ definition.key, { document.filename(), definition.value.line, definition.value.column }, GUI::AutocompleteProvider::DeclarationType::PreprocessorDefinition, {} });
- }
- set_declarations_of_document(document.filename(), move(declarations));
-}
-
-void CppComprehensionEngine::update_todo_entries(DocumentData& document)
-{
- set_todo_entries_of_document(document.filename(), document.parser().get_todo_entries());
-}
-
-GUI::AutocompleteProvider::DeclarationType CppComprehensionEngine::type_of_declaration(Declaration const& decl)
-{
- if (decl.is_struct())
- return GUI::AutocompleteProvider::DeclarationType::Struct;
- if (decl.is_class())
- return GUI::AutocompleteProvider::DeclarationType::Class;
- if (decl.is_function())
- return GUI::AutocompleteProvider::DeclarationType::Function;
- if (decl.is_variable_declaration())
- return GUI::AutocompleteProvider::DeclarationType::Variable;
- if (decl.is_namespace())
- return GUI::AutocompleteProvider::DeclarationType::Namespace;
- if (decl.is_member())
- return GUI::AutocompleteProvider::DeclarationType::Member;
- return GUI::AutocompleteProvider::DeclarationType::Variable;
-}
-
-OwnPtr<CppComprehensionEngine::DocumentData> CppComprehensionEngine::create_document_data(String&& text, String const& filename)
-{
- auto document_data = make<DocumentData>();
- document_data->m_filename = filename;
- document_data->m_text = move(text);
- document_data->m_preprocessor = make<Preprocessor>(document_data->m_filename, document_data->text());
- document_data->preprocessor().set_ignore_unsupported_keywords(true);
- document_data->preprocessor().set_ignore_invalid_statements(true);
- document_data->preprocessor().set_keep_include_statements(true);
-
- document_data->preprocessor().definitions_in_header_callback = [this](StringView include_path) -> Preprocessor::Definitions {
- auto included_document = get_or_create_document_data(document_path_from_include_path(include_path));
- if (!included_document)
- return {};
-
- return included_document->preprocessor().definitions();
- };
-
- auto tokens = document_data->preprocessor().process_and_lex();
-
- for (auto include_path : document_data->preprocessor().included_paths()) {
- auto include_fullpath = document_path_from_include_path(include_path);
- auto included_document = get_or_create_document_data(include_fullpath);
- if (!included_document)
- continue;
-
- document_data->m_available_headers.set(include_fullpath);
-
- for (auto& header : included_document->m_available_headers)
- document_data->m_available_headers.set(header);
- }
-
- document_data->m_parser = make<Parser>(move(tokens), filename);
-
- auto root = document_data->parser().parse();
-
- if constexpr (CPP_LANGUAGE_SERVER_DEBUG)
- root->dump();
-
- update_declared_symbols(*document_data);
- update_todo_entries(*document_data);
-
- return document_data;
-}
-
-Vector<StringView> CppComprehensionEngine::scope_of_node(ASTNode const& node) const
-{
-
- auto parent = node.parent();
- if (!parent)
- return {};
-
- auto parent_scope = scope_of_node(*parent);
-
- if (!parent->is_declaration())
- return parent_scope;
-
- auto& parent_decl = static_cast<Declaration&>(*parent);
-
- StringView containing_scope;
- if (parent_decl.is_namespace())
- containing_scope = static_cast<NamespaceDeclaration&>(parent_decl).full_name();
- if (parent_decl.is_struct_or_class())
- containing_scope = static_cast<StructOrClassDeclaration&>(parent_decl).full_name();
- if (parent_decl.is_function())
- containing_scope = static_cast<FunctionDeclaration&>(parent_decl).full_name();
-
- parent_scope.append(containing_scope);
- return parent_scope;
-}
-
-Optional<Vector<GUI::AutocompleteProvider::Entry>> CppComprehensionEngine::try_autocomplete_include(DocumentData const&, Token include_path_token, Cpp::Position const& cursor_position) const
-{
- VERIFY(include_path_token.type() == Token::Type::IncludePath);
- auto partial_include = include_path_token.text().trim_whitespace();
-
- enum IncludeType {
- Project,
- System,
- } include_type { Project };
-
- String include_root;
- bool already_has_suffix = false;
- if (partial_include.starts_with("<")) {
- include_root = "/usr/include/";
- include_type = System;
- if (partial_include.ends_with(">")) {
- already_has_suffix = true;
- partial_include = partial_include.substring_view(0, partial_include.length() - 1).trim_whitespace();
- }
- } else if (partial_include.starts_with("\"")) {
- include_root = filedb().project_root();
- if (partial_include.length() > 1 && partial_include.ends_with("\"")) {
- already_has_suffix = true;
- partial_include = partial_include.substring_view(0, partial_include.length() - 1).trim_whitespace();
- }
- } else
- return {};
-
- // The cursor is past the end of the <> or "", and so should not trigger autocomplete.
- if (already_has_suffix && include_path_token.end() <= cursor_position)
- return {};
-
- auto last_slash = partial_include.find_last('/');
- auto include_dir = String::empty();
- auto partial_basename = partial_include.substring_view((last_slash.has_value() ? last_slash.value() : 0) + 1);
- if (last_slash.has_value()) {
- include_dir = partial_include.substring_view(1, last_slash.value());
- }
-
- auto full_dir = LexicalPath::join(include_root, include_dir).string();
- dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "searching path: {}, partial_basename: {}", full_dir, partial_basename);
-
- Core::DirIterator it(full_dir, Core::DirIterator::Flags::SkipDots);
- Vector<GUI::AutocompleteProvider::Entry> options;
-
- auto prefix = include_type == System ? "<" : "\"";
- auto suffix = include_type == System ? ">" : "\"";
- while (it.has_next()) {
- auto path = it.next_path();
-
- if (!path.starts_with(partial_basename))
- continue;
-
- if (Core::File::is_directory(LexicalPath::join(full_dir, path).string())) {
- // FIXME: Don't dismiss the autocomplete when filling these suggestions.
- auto completion = String::formatted("{}{}{}/", prefix, include_dir, path);
- options.empend(completion, include_dir.length() + partial_basename.length() + 1, GUI::AutocompleteProvider::Language::Cpp, path, GUI::AutocompleteProvider::Entry::HideAutocompleteAfterApplying::No);
- } else if (path.ends_with(".h")) {
- // FIXME: Place the cursor after the trailing > or ", even if it was
- // already typed.
- auto completion = String::formatted("{}{}{}{}", prefix, include_dir, path, already_has_suffix ? "" : suffix);
- options.empend(completion, include_dir.length() + partial_basename.length() + 1, GUI::AutocompleteProvider::Language::Cpp, path);
- }
- }
-
- return options;
-}
-
-RefPtr<Declaration> CppComprehensionEngine::find_declaration_of(CppComprehensionEngine::DocumentData const& document, CppComprehensionEngine::SymbolName const& target_symbol_name) const
-{
- RefPtr<Declaration> target_declaration;
- for_each_available_symbol(document, [&](Symbol const& symbol) {
- if (symbol.name == target_symbol_name) {
- target_declaration = symbol.declaration;
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
- return target_declaration;
-}
-
-String CppComprehensionEngine::SymbolName::scope_as_string() const
-{
- if (scope.is_empty())
- return String::empty();
-
- StringBuilder builder;
- for (size_t i = 0; i < scope.size() - 1; ++i) {
- builder.appendff("{}::", scope[i]);
- }
- builder.append(scope.last());
- return builder.to_string();
-}
-
-CppComprehensionEngine::SymbolName CppComprehensionEngine::SymbolName::create(StringView name, Vector<StringView>&& scope)
-{
- return { name, move(scope) };
-}
-
-CppComprehensionEngine::SymbolName CppComprehensionEngine::SymbolName::create(StringView qualified_name)
-{
- auto parts = qualified_name.split_view("::");
- VERIFY(!parts.is_empty());
- auto name = parts.take_last();
- return SymbolName::create(name, move(parts));
-}
-
-String CppComprehensionEngine::SymbolName::to_string() const
-{
- if (scope.is_empty())
- return name;
- return String::formatted("{}::{}", scope_as_string(), name);
-}
-
-bool CppComprehensionEngine::is_symbol_available(Symbol const& symbol, Vector<StringView> const& current_scope, Vector<StringView> const& reference_scope)
-{
-
- if (!reference_scope.is_empty()) {
- return reference_scope == symbol.name.scope;
- }
-
- // FIXME: Take "using namespace ..." into consideration
-
- // Check if current_scope starts with symbol's scope
- if (symbol.name.scope.size() > current_scope.size())
- return false;
-
- for (size_t i = 0; i < symbol.name.scope.size(); ++i) {
- if (current_scope[i] != symbol.name.scope[i])
- return false;
- }
-
- return true;
-}
-
-Optional<CodeComprehensionEngine::FunctionParamsHint> CppComprehensionEngine::get_function_params_hint(String const& filename, const GUI::TextPosition& identifier_position)
-{
- auto const* document_ptr = get_or_create_document_data(filename);
- if (!document_ptr)
- return {};
-
- auto const& document = *document_ptr;
- Cpp::Position cpp_position { identifier_position.line(), identifier_position.column() };
- auto node = document.parser().node_at(cpp_position);
- if (!node) {
- dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "no node at position {}:{}", identifier_position.line(), identifier_position.column());
- return {};
- }
-
- dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "node type: {}", node->class_name());
-
- FunctionCall* call_node { nullptr };
-
- if (node->is_function_call()) {
- call_node = verify_cast<FunctionCall>(node.ptr());
-
- auto token = document.parser().token_at(cpp_position);
-
- // If we're in a function call with 0 arguments
- if (token.has_value() && (token->type() == Token::Type::LeftParen || token->type() == Token::Type::RightParen)) {
- return get_function_params_hint(document, *call_node, call_node->arguments().is_empty() ? 0 : call_node->arguments().size() - 1);
- }
- }
-
- // Walk upwards in the AST to find a FunctionCall node
- while (!call_node && node) {
- auto parent_is_call = node->parent() && node->parent()->is_function_call();
- if (parent_is_call) {
- call_node = verify_cast<FunctionCall>(node->parent());
- break;
- }
- node = node->parent();
- }
-
- if (!call_node) {
- dbgln("did not find function call");
- return {};
- }
-
- Optional<size_t> invoked_arg_index;
- for (size_t arg_index = 0; arg_index < call_node->arguments().size(); ++arg_index) {
- if (&call_node->arguments()[arg_index] == node.ptr()) {
- invoked_arg_index = arg_index;
- break;
- }
- }
- if (!invoked_arg_index.has_value()) {
- dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "could not find argument index, defaulting to the last argument");
- invoked_arg_index = call_node->arguments().is_empty() ? 0 : call_node->arguments().size() - 1;
- }
-
- dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "arg index: {}", invoked_arg_index.value());
- return get_function_params_hint(document, *call_node, invoked_arg_index.value());
-}
-
-Optional<CppComprehensionEngine::FunctionParamsHint> CppComprehensionEngine::get_function_params_hint(
- DocumentData const& document,
- FunctionCall& call_node,
- size_t argument_index)
-{
- Identifier const* callee = nullptr;
- VERIFY(call_node.callee());
- if (call_node.callee()->is_identifier()) {
- callee = verify_cast<Identifier>(call_node.callee());
- } else if (call_node.callee()->is_name()) {
- callee = verify_cast<Name>(*call_node.callee()).name();
- } else if (call_node.callee()->is_member_expression()) {
- auto& member_exp = verify_cast<MemberExpression>(*call_node.callee());
- VERIFY(member_exp.property());
- if (member_exp.property()->is_identifier()) {
- callee = verify_cast<Identifier>(member_exp.property());
- }
- }
-
- if (!callee) {
- dbgln("unexpected node type for function call: {}", call_node.callee()->class_name());
- return {};
- }
- VERIFY(callee);
-
- auto decl = find_declaration_of(document, *callee);
- if (!decl) {
- dbgln("func decl not found");
- return {};
- }
- if (!decl->is_function()) {
- dbgln("declaration is not a function");
- return {};
- }
-
- auto& func_decl = verify_cast<FunctionDeclaration>(*decl);
- auto document_of_declaration = get_document_data(func_decl.filename());
-
- FunctionParamsHint hint {};
- hint.current_index = argument_index;
- for (auto& arg : func_decl.parameters()) {
- Vector<StringView> tokens_text;
- for (auto token : document_of_declaration->parser().tokens_in_range(arg.start(), arg.end())) {
- tokens_text.append(token.text());
- }
- hint.params.append(String::join(" ", tokens_text));
- }
-
- return hint;
-}
-
-Vector<GUI::AutocompleteProvider::TokenInfo> CppComprehensionEngine::get_tokens_info(String const& filename)
-{
- dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "CppComprehensionEngine::get_tokens_info: {}", filename);
-
- auto const* document_ptr = get_or_create_document_data(filename);
- if (!document_ptr)
- return {};
-
- auto const& document = *document_ptr;
-
- Vector<GUI::AutocompleteProvider::TokenInfo> tokens_info;
- size_t i = 0;
- for (auto const& token : document.preprocessor().unprocessed_tokens()) {
-
- tokens_info.append({ get_token_semantic_type(document, token),
- token.start().line, token.start().column, token.end().line, token.end().column });
- ++i;
- dbgln_if(CPP_LANGUAGE_SERVER_DEBUG, "{}: {}", token.text(), GUI::AutocompleteProvider::TokenInfo::type_to_string(tokens_info.last().type));
- }
- return tokens_info;
-}
-
-GUI::AutocompleteProvider::TokenInfo::SemanticType CppComprehensionEngine::get_token_semantic_type(DocumentData const& document, Token const& token)
-{
- using GUI::AutocompleteProvider;
- switch (token.type()) {
- case Cpp::Token::Type::Identifier:
- return get_semantic_type_for_identifier(document, token.start());
- case Cpp::Token::Type::Keyword:
- return AutocompleteProvider::TokenInfo::SemanticType::Keyword;
- case Cpp::Token::Type::KnownType:
- return AutocompleteProvider::TokenInfo::SemanticType::Type;
- case Cpp::Token::Type::DoubleQuotedString:
- case Cpp::Token::Type::SingleQuotedString:
- case Cpp::Token::Type::RawString:
- return AutocompleteProvider::TokenInfo::SemanticType::String;
- case Cpp::Token::Type::Integer:
- case Cpp::Token::Type::Float:
- return AutocompleteProvider::TokenInfo::SemanticType::Number;
- case Cpp::Token::Type::IncludePath:
- return AutocompleteProvider::TokenInfo::SemanticType::IncludePath;
- case Cpp::Token::Type::EscapeSequence:
- return AutocompleteProvider::TokenInfo::SemanticType::Keyword;
- case Cpp::Token::Type::PreprocessorStatement:
- case Cpp::Token::Type::IncludeStatement:
- return AutocompleteProvider::TokenInfo::SemanticType::PreprocessorStatement;
- case Cpp::Token::Type::Comment:
- return AutocompleteProvider::TokenInfo::SemanticType::Comment;
- default:
- return AutocompleteProvider::TokenInfo::SemanticType::Unknown;
- }
-}
-
-GUI::AutocompleteProvider::TokenInfo::SemanticType CppComprehensionEngine::get_semantic_type_for_identifier(DocumentData const& document, Position position)
-{
- if (find_preprocessor_substitution(document, position).has_value())
- return GUI::AutocompleteProvider::TokenInfo::SemanticType::PreprocessorMacro;
-
- auto decl = find_declaration_of(document, GUI::TextPosition { position.line, position.column });
- if (!decl)
- return GUI::AutocompleteProvider::TokenInfo::SemanticType::Identifier;
-
- if (decl->is_function())
- return GUI::AutocompleteProvider::TokenInfo::SemanticType::Function;
- if (decl->is_parameter())
- return GUI::AutocompleteProvider::TokenInfo::SemanticType::Parameter;
- if (decl->is_variable_declaration()) {
- if (decl->is_member())
- return GUI::AutocompleteProvider::TokenInfo::SemanticType::Member;
- return GUI::AutocompleteProvider::TokenInfo::SemanticType::Variable;
- }
- if (decl->is_struct_or_class() || decl->is_enum())
- return GUI::AutocompleteProvider::TokenInfo::SemanticType::CustomType;
- if (decl->is_namespace())
- return GUI::AutocompleteProvider::TokenInfo::SemanticType::Namespace;
-
- return GUI::AutocompleteProvider::TokenInfo::SemanticType::Identifier;
-}
-
-}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.h b/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.h
deleted file mode 100644
index 0473480d1d..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.h
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#pragma once
-
-#include <AK/Function.h>
-#include <AK/String.h>
-#include <AK/Vector.h>
-#include <DevTools/HackStudio/AutoCompleteResponse.h>
-#include <DevTools/HackStudio/LanguageServers/CodeComprehensionEngine.h>
-#include <DevTools/HackStudio/LanguageServers/FileDB.h>
-#include <LibCpp/AST.h>
-#include <LibCpp/Parser.h>
-#include <LibCpp/Preprocessor.h>
-#include <LibGUI/TextPosition.h>
-
-namespace LanguageServers::Cpp {
-
-using namespace ::Cpp;
-
-class CppComprehensionEngine : public CodeComprehensionEngine {
-public:
- CppComprehensionEngine(FileDB const& filedb);
-
- virtual Vector<GUI::AutocompleteProvider::Entry> get_suggestions(String const& file, const GUI::TextPosition& autocomplete_position) override;
- virtual void on_edit(String const& file) override;
- virtual void file_opened([[maybe_unused]] String const& file) override;
- virtual Optional<GUI::AutocompleteProvider::ProjectLocation> find_declaration_of(String const& filename, const GUI::TextPosition& identifier_position) override;
- virtual Optional<FunctionParamsHint> get_function_params_hint(String const&, const GUI::TextPosition&) override;
- virtual Vector<GUI::AutocompleteProvider::TokenInfo> get_tokens_info(String const& filename) override;
-
-private:
- struct SymbolName {
- StringView name;
- Vector<StringView> scope;
-
- static SymbolName create(StringView, Vector<StringView>&&);
- static SymbolName create(StringView);
- String scope_as_string() const;
- String to_string() const;
-
- bool operator==(SymbolName const&) const = default;
- };
-
- struct Symbol {
- SymbolName name;
- NonnullRefPtr<Declaration> declaration;
-
- // Local symbols are symbols that should not appear in a global symbol search.
- // For example, a variable that is declared inside a function will have is_local = true.
- bool is_local { false };
-
- enum class IsLocal {
- No,
- Yes
- };
- static Symbol create(StringView name, Vector<StringView> const& scope, NonnullRefPtr<Declaration>, IsLocal is_local);
- };
-
- friend Traits<SymbolName>;
-
- struct DocumentData {
- String const& filename() const { return m_filename; }
- String const& text() const { return m_text; }
- Preprocessor const& preprocessor() const
- {
- VERIFY(m_preprocessor);
- return *m_preprocessor;
- }
- Preprocessor& preprocessor()
- {
- VERIFY(m_preprocessor);
- return *m_preprocessor;
- }
- Parser const& parser() const
- {
- VERIFY(m_parser);
- return *m_parser;
- }
- Parser& parser()
- {
- VERIFY(m_parser);
- return *m_parser;
- }
-
- String m_filename;
- String m_text;
- OwnPtr<Preprocessor> m_preprocessor;
- OwnPtr<Parser> m_parser;
-
- HashMap<SymbolName, Symbol> m_symbols;
- HashTable<String> m_available_headers;
- };
-
- Vector<GUI::AutocompleteProvider::Entry> autocomplete_property(DocumentData const&, MemberExpression const&, const String partial_text) const;
- Vector<GUI::AutocompleteProvider::Entry> autocomplete_name(DocumentData const&, ASTNode const&, String const& partial_text) const;
- String type_of(DocumentData const&, Expression const&) const;
- String type_of_property(DocumentData const&, Identifier const&) const;
- String type_of_variable(Identifier const&) const;
- bool is_property(ASTNode const&) const;
- RefPtr<Declaration> find_declaration_of(DocumentData const&, ASTNode const&) const;
- RefPtr<Declaration> find_declaration_of(DocumentData const&, SymbolName const&) const;
- RefPtr<Declaration> find_declaration_of(DocumentData const&, const GUI::TextPosition& identifier_position);
-
- enum class RecurseIntoScopes {
- No,
- Yes
- };
-
- Vector<Symbol> properties_of_type(DocumentData const& document, String const& type) const;
- Vector<Symbol> get_child_symbols(ASTNode const&) const;
- Vector<Symbol> get_child_symbols(ASTNode const&, Vector<StringView> const& scope, Symbol::IsLocal) const;
-
- DocumentData const* get_document_data(String const& file) const;
- DocumentData const* get_or_create_document_data(String const& file);
- void set_document_data(String const& file, OwnPtr<DocumentData>&& data);
-
- OwnPtr<DocumentData> create_document_data_for(String const& file);
- String document_path_from_include_path(StringView include_path) const;
- void update_declared_symbols(DocumentData&);
- void update_todo_entries(DocumentData&);
- GUI::AutocompleteProvider::DeclarationType type_of_declaration(Declaration const&);
- Vector<StringView> scope_of_node(ASTNode const&) const;
- Vector<StringView> scope_of_reference_to_symbol(ASTNode const&) const;
-
- Optional<GUI::AutocompleteProvider::ProjectLocation> find_preprocessor_definition(DocumentData const&, const GUI::TextPosition&);
- Optional<Cpp::Preprocessor::Substitution> find_preprocessor_substitution(DocumentData const&, Cpp::Position const&);
-
- OwnPtr<DocumentData> create_document_data(String&& text, String const& filename);
- Optional<Vector<GUI::AutocompleteProvider::Entry>> try_autocomplete_property(DocumentData const&, ASTNode const&, Optional<Token> containing_token) const;
- Optional<Vector<GUI::AutocompleteProvider::Entry>> try_autocomplete_name(DocumentData const&, ASTNode const&, Optional<Token> containing_token) const;
- Optional<Vector<GUI::AutocompleteProvider::Entry>> try_autocomplete_include(DocumentData const&, Token include_path_token, Cpp::Position const& cursor_position) const;
- static bool is_symbol_available(Symbol const&, Vector<StringView> const& current_scope, Vector<StringView> const& reference_scope);
- Optional<FunctionParamsHint> get_function_params_hint(DocumentData const&, FunctionCall&, size_t argument_index);
-
- template<typename Func>
- void for_each_available_symbol(DocumentData const&, Func) const;
-
- template<typename Func>
- void for_each_included_document_recursive(DocumentData const&, Func) const;
-
- GUI::AutocompleteProvider::TokenInfo::SemanticType get_token_semantic_type(DocumentData const&, Token const&);
- GUI::AutocompleteProvider::TokenInfo::SemanticType get_semantic_type_for_identifier(DocumentData const&, Position);
-
- HashMap<String, OwnPtr<DocumentData>> m_documents;
-
- // A document's path will be in this set if we're currently processing it.
- // A document is added to this set when we start processing it (e.g because it was #included) and removed when we're done.
- // We use this to prevent circular #includes from looping indefinitely.
- HashTable<String> m_unfinished_documents;
-};
-
-template<typename Func>
-void CppComprehensionEngine::for_each_available_symbol(DocumentData const& document, Func func) const
-{
- for (auto& item : document.m_symbols) {
- auto decision = func(item.value);
- if (decision == IterationDecision::Break)
- return;
- }
-
- for_each_included_document_recursive(document, [&](DocumentData const& document) {
- for (auto& item : document.m_symbols) {
- auto decision = func(item.value);
- if (decision == IterationDecision::Break)
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
-}
-
-template<typename Func>
-void CppComprehensionEngine::for_each_included_document_recursive(DocumentData const& document, Func func) const
-{
- for (auto& included_path : document.m_available_headers) {
- auto* included_document = get_document_data(included_path);
- if (!included_document)
- continue;
- auto decision = func(*included_document);
- if (decision == IterationDecision::Break)
- continue;
- }
-}
-}
-
-namespace AK {
-
-template<>
-struct Traits<LanguageServers::Cpp::CppComprehensionEngine::SymbolName> : public GenericTraits<LanguageServers::Cpp::CppComprehensionEngine::SymbolName> {
- static unsigned hash(LanguageServers::Cpp::CppComprehensionEngine::SymbolName const& key)
- {
- unsigned hash = 0;
- hash = pair_int_hash(hash, string_hash(key.name.characters_without_null_termination(), key.name.length()));
- for (auto& scope_part : key.scope) {
- hash = pair_int_hash(hash, string_hash(scope_part.characters_without_null_termination(), scope_part.length()));
- }
- return hash;
- }
-};
-
-}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests.cpp
deleted file mode 100644
index 14dbd87944..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#include "Tests.h"
-#include "../FileDB.h"
-#include "CppComprehensionEngine.h"
-#include <AK/LexicalPath.h>
-#include <LibCore/File.h>
-
-using namespace LanguageServers;
-using namespace LanguageServers::Cpp;
-
-static bool s_some_test_failed = false;
-
-#define I_TEST(name) \
- { \
- printf("Testing " #name "... "); \
- fflush(stdout); \
- }
-
-#define PASS \
- do { \
- printf("PASS\n"); \
- fflush(stdout); \
- return; \
- } while (0)
-
-#define FAIL(reason) \
- do { \
- printf("FAIL: " #reason "\n"); \
- s_some_test_failed = true; \
- return; \
- } while (0)
-
-constexpr char TESTS_ROOT_DIR[] = "/home/anon/Tests/cpp-tests/comprehension";
-
-static void test_complete_local_args();
-static void test_complete_local_vars();
-static void test_complete_type();
-static void test_find_variable_definition();
-static void test_complete_includes();
-static void test_parameters_hint();
-
-int run_tests()
-{
- test_complete_local_args();
- test_complete_local_vars();
- test_complete_type();
- test_find_variable_definition();
- test_complete_includes();
- test_parameters_hint();
- return s_some_test_failed ? 1 : 0;
-}
-
-static void add_file(FileDB& filedb, String const& name)
-{
- auto file = Core::File::open(LexicalPath::join(TESTS_ROOT_DIR, name).string(), Core::OpenMode::ReadOnly);
- VERIFY(!file.is_error());
- filedb.add(name, file.value()->fd());
-}
-
-void test_complete_local_args()
-{
- I_TEST(Complete Local Args)
- FileDB filedb;
- add_file(filedb, "complete_local_args.cpp");
- CppComprehensionEngine engine(filedb);
- auto suggestions = engine.get_suggestions("complete_local_args.cpp", { 2, 6 });
- if (suggestions.size() != 2)
- FAIL(bad size);
-
- if (suggestions[0].completion == "argc" && suggestions[1].completion == "argv")
- PASS;
-
- FAIL("wrong results");
-}
-
-void test_complete_local_vars()
-{
- I_TEST(Complete Local Vars)
- FileDB filedb;
- add_file(filedb, "complete_local_vars.cpp");
- CppComprehensionEngine autocomplete(filedb);
- auto suggestions = autocomplete.get_suggestions("complete_local_vars.cpp", { 3, 7 });
- if (suggestions.size() != 1)
- FAIL(bad size);
-
- if (suggestions[0].completion == "myvar1")
- PASS;
-
- FAIL("wrong results");
-}
-
-void test_complete_type()
-{
- I_TEST(Complete Type)
- FileDB filedb;
- add_file(filedb, "complete_type.cpp");
- CppComprehensionEngine autocomplete(filedb);
- auto suggestions = autocomplete.get_suggestions("complete_type.cpp", { 5, 7 });
- if (suggestions.size() != 1)
- FAIL(bad size);
-
- if (suggestions[0].completion == "MyStruct")
- PASS;
-
- FAIL("wrong results");
-}
-
-void test_find_variable_definition()
-{
- I_TEST(Find Variable Declaration)
- FileDB filedb;
- add_file(filedb, "find_variable_declaration.cpp");
- CppComprehensionEngine engine(filedb);
- auto position = engine.find_declaration_of("find_variable_declaration.cpp", { 2, 5 });
- if (!position.has_value())
- FAIL("declaration not found");
-
- if (position.value().file == "find_variable_declaration.cpp" && position.value().line == 0 && position.value().column >= 19)
- PASS;
- FAIL("wrong declaration location");
-}
-
-void test_complete_includes()
-{
- I_TEST(Complete Type)
- FileDB filedb;
- filedb.set_project_root(TESTS_ROOT_DIR);
- add_file(filedb, "complete_includes.cpp");
- add_file(filedb, "sample_header.h");
- CppComprehensionEngine autocomplete(filedb);
-
- auto suggestions = autocomplete.get_suggestions("complete_includes.cpp", { 0, 22 });
- if (suggestions.size() != 1)
- FAIL(project include - bad size);
-
- if (suggestions[0].completion != "\"sample_header.h\"")
- FAIL("project include - wrong results");
-
- suggestions = autocomplete.get_suggestions("complete_includes.cpp", { 1, 18 });
- if (suggestions.size() != 1)
- FAIL(global include - bad size);
-
- if (suggestions[0].completion != "<sys/cdefs.h>")
- FAIL("global include - wrong results");
-
- PASS;
-}
-
-void test_parameters_hint()
-{
- I_TEST(Function Parameters hint)
- FileDB filedb;
- filedb.set_project_root(TESTS_ROOT_DIR);
- add_file(filedb, "parameters_hint1.cpp");
- CppComprehensionEngine engine(filedb);
-
- auto result = engine.get_function_params_hint("parameters_hint1.cpp", { 4, 9 });
- if (!result.has_value())
- FAIL("failed to get parameters hint (1)");
- if (result->params != Vector<String> { "int x", "char y" } || result->current_index != 0)
- FAIL("bad result (1)");
-
- result = engine.get_function_params_hint("parameters_hint1.cpp", { 5, 15 });
- if (!result.has_value())
- FAIL("failed to get parameters hint (2)");
- if (result->params != Vector<String> { "int x", "char y" } || result->current_index != 1)
- FAIL("bad result (2)");
-
- result = engine.get_function_params_hint("parameters_hint1.cpp", { 6, 8 });
- if (!result.has_value())
- FAIL("failed to get parameters hint (3)");
- if (result->params != Vector<String> { "int x", "char y" } || result->current_index != 0)
- FAIL("bad result (3)");
-
- PASS;
-}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests.h b/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests.h
deleted file mode 100644
index 0c98313e9a..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#pragma once
-
-int run_tests();
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_includes.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_includes.cpp
deleted file mode 100644
index 3eb239f29f..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_includes.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "sample_heade
-#include <sys/cdef
-
-void foo() {}
-
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_local_args.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_local_args.cpp
deleted file mode 100644
index 893bed6c54..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_local_args.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-int main(int argc, char** argv)
-{
- ar
-}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_local_vars.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_local_vars.cpp
deleted file mode 100644
index 02f53b5631..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_local_vars.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-int main(int argc, char** argv)
-{
- int myvar1 = 3;
- myv
-}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_type.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_type.cpp
deleted file mode 100644
index a552ad8cbf..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/complete_type.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-struct MyStruct {
- int x;
-};
-void foo()
-{
- MyS
-}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/find_variable_declaration.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/find_variable_declaration.cpp
deleted file mode 100644
index 22f20d2f34..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/find_variable_declaration.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-int main(int argc, char** argv)
-{
- argv = nullptr;
-}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/parameters_hint1.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/parameters_hint1.cpp
deleted file mode 100644
index 43fc7c5e32..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/parameters_hint1.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-void foo(int x, char y);
-
-void bar()
-{
- foo();
- foo(123, 'b');
- foo(
-}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/sample_header.h b/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/sample_header.h
deleted file mode 100644
index ab2154484e..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/Tests/sample_header.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-int bar();
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/main.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/main.cpp
index 4978a22eb9..b8511d0117 100644
--- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/main.cpp
+++ b/Userland/DevTools/HackStudio/LanguageServers/Cpp/main.cpp
@@ -5,7 +5,6 @@
*/
#include "ConnectionFromClient.h"
-#include "Tests.h"
#include <LibCore/ArgsParser.h>
#include <LibCore/EventLoop.h>
#include <LibCore/LocalServer.h>
@@ -13,23 +12,7 @@
#include <LibIPC/SingleServer.h>
#include <LibMain/Main.h>
-static ErrorOr<int> mode_server();
-
-ErrorOr<int> serenity_main(Main::Arguments arguments)
-{
- bool tests = false;
-
- Core::ArgsParser parser;
- parser.add_option(tests, "Run tests", "tests", 't');
- parser.parse(arguments);
-
- if (tests)
- return run_tests();
-
- return mode_server();
-}
-
-ErrorOr<int> mode_server()
+ErrorOr<int> serenity_main(Main::Arguments)
{
Core::EventLoop event_loop;
TRY(Core::System::pledge("stdio unix recvfd rpath"));
diff --git a/Userland/DevTools/HackStudio/LanguageServers/FileDB.cpp b/Userland/DevTools/HackStudio/LanguageServers/FileDB.cpp
index a45882afbe..f704407368 100644
--- a/Userland/DevTools/HackStudio/LanguageServers/FileDB.cpp
+++ b/Userland/DevTools/HackStudio/LanguageServers/FileDB.cpp
@@ -12,7 +12,7 @@
namespace LanguageServers {
-RefPtr<const GUI::TextDocument> FileDB::get(String const& filename) const
+RefPtr<const GUI::TextDocument> FileDB::get_document(String const& filename) const
{
auto absolute_path = to_absolute_path(filename);
auto document_optional = m_open_files.get(absolute_path);
@@ -22,29 +22,25 @@ RefPtr<const GUI::TextDocument> FileDB::get(String const& filename) const
return *document_optional.value();
}
-RefPtr<GUI::TextDocument> FileDB::get(String const& filename)
+RefPtr<GUI::TextDocument> FileDB::get_document(String const& filename)
{
- auto document = reinterpret_cast<FileDB const*>(this)->get(filename);
+ auto document = reinterpret_cast<FileDB const*>(this)->get_document(filename);
if (document.is_null())
return nullptr;
return adopt_ref(*const_cast<GUI::TextDocument*>(document.leak_ref()));
}
-RefPtr<const GUI::TextDocument> FileDB::get_or_create_from_filesystem(String const& filename) const
+Optional<String> FileDB::get_or_read_from_filesystem(StringView filename) const
{
auto absolute_path = to_absolute_path(filename);
- auto document = get(absolute_path);
+ auto document = get_document(absolute_path);
if (document)
- return document;
- return create_from_filesystem(absolute_path);
-}
+ return document->text();
-RefPtr<GUI::TextDocument> FileDB::get_or_create_from_filesystem(String const& filename)
-{
- auto document = reinterpret_cast<FileDB const*>(this)->get_or_create_from_filesystem(filename);
- if (document.is_null())
- return nullptr;
- return adopt_ref(*const_cast<GUI::TextDocument*>(document.leak_ref()));
+ document = create_from_filesystem(absolute_path);
+ if (document)
+ return document->text();
+ return {};
}
bool FileDB::is_open(String const& filename) const
@@ -123,7 +119,7 @@ RefPtr<GUI::TextDocument> FileDB::create_from_file(Core::File& file) const
void FileDB::on_file_edit_insert_text(String const& filename, String const& inserted_text, size_t start_line, size_t start_column)
{
VERIFY(is_open(filename));
- auto document = get(filename);
+ auto document = get_document(filename);
VERIFY(document);
GUI::TextPosition start_position { start_line, start_column };
document->insert_at(start_position, inserted_text, &s_default_document_client);
@@ -136,7 +132,7 @@ void FileDB::on_file_edit_remove_text(String const& filename, size_t start_line,
// TODO: If file is not open - need to get its contents
// Otherwise- somehow verify that respawned language server is synced with all file contents
VERIFY(is_open(filename));
- auto document = get(filename);
+ auto document = get_document(filename);
VERIFY(document);
GUI::TextPosition start_position { start_line, start_column };
GUI::TextRange range {
diff --git a/Userland/DevTools/HackStudio/LanguageServers/FileDB.h b/Userland/DevTools/HackStudio/LanguageServers/FileDB.h
index c8d64b2182..b25bd0b7b5 100644
--- a/Userland/DevTools/HackStudio/LanguageServers/FileDB.h
+++ b/Userland/DevTools/HackStudio/LanguageServers/FileDB.h
@@ -9,22 +9,22 @@
#include <AK/HashMap.h>
#include <AK/NonnullRefPtr.h>
#include <AK/String.h>
+#include <LibCodeComprehension/FileDB.h>
#include <LibGUI/TextDocument.h>
namespace LanguageServers {
-class FileDB final {
+class FileDB final : public CodeComprehension::FileDB {
public:
- RefPtr<const GUI::TextDocument> get(String const& filename) const;
- RefPtr<GUI::TextDocument> get(String const& filename);
- RefPtr<const GUI::TextDocument> get_or_create_from_filesystem(String const& filename) const;
- RefPtr<GUI::TextDocument> get_or_create_from_filesystem(String const& filename);
+ FileDB() = default;
+ virtual Optional<String> get_or_read_from_filesystem(StringView filename) const override;
+
+ RefPtr<const GUI::TextDocument> get_document(String const& filename) const;
+ RefPtr<GUI::TextDocument> get_document(String const& filename);
+
bool add(String const& filename, int fd);
bool add(String const& filename, String const& content);
- void set_project_root(String const& root_path) { m_project_root = root_path; }
- String const& project_root() const { return m_project_root; }
-
void on_file_edit_insert_text(String const& filename, String const& inserted_text, size_t start_line, size_t start_column);
void on_file_edit_remove_text(String const& filename, size_t start_line, size_t start_column, size_t end_line, size_t end_column);
String to_absolute_path(String const& filename) const;
diff --git a/Userland/DevTools/HackStudio/LanguageServers/LanguageClient.ipc b/Userland/DevTools/HackStudio/LanguageServers/LanguageClient.ipc
index 97d72ee0b3..e4088ad3c4 100644
--- a/Userland/DevTools/HackStudio/LanguageServers/LanguageClient.ipc
+++ b/Userland/DevTools/HackStudio/LanguageServers/LanguageClient.ipc
@@ -1,9 +1,9 @@
endpoint LanguageClient
{
- auto_complete_suggestions(Vector<GUI::AutocompleteProvider::Entry> suggestions) =|
- declaration_location(GUI::AutocompleteProvider::ProjectLocation location) =|
- declarations_in_document(String filename, Vector<GUI::AutocompleteProvider::Declaration> declarations) =|
- todo_entries_in_document(String filename, Vector<Cpp::Parser::TodoEntry> todo_entries) =|
+ auto_complete_suggestions(Vector<CodeComprehension::AutocompleteResultEntry> suggestions) =|
+ declaration_location(CodeComprehension::ProjectLocation location) =|
+ declarations_in_document(String filename, Vector<CodeComprehension::Declaration> declarations) =|
+ todo_entries_in_document(String filename, Vector<CodeComprehension::TodoEntry> todo_entries) =|
parameters_hint_result(Vector<String> params, int current_index) =|
- tokens_info_result(Vector<GUI::AutocompleteProvider::TokenInfo> tokens_info) =|
+ tokens_info_result(Vector<CodeComprehension::TokenInfo> tokens_info) =|
}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/LanguageServer.ipc b/Userland/DevTools/HackStudio/LanguageServers/LanguageServer.ipc
index 7cdcd4e635..1f97dbc97d 100644
--- a/Userland/DevTools/HackStudio/LanguageServers/LanguageServer.ipc
+++ b/Userland/DevTools/HackStudio/LanguageServers/LanguageServer.ipc
@@ -7,9 +7,9 @@ endpoint LanguageServer
file_edit_remove_text(String filename, i32 start_line, i32 start_column, i32 end_line, i32 end_column) =|
set_file_content(String filename, String content) =|
- auto_complete_suggestions(GUI::AutocompleteProvider::ProjectLocation location) =|
- find_declaration(GUI::AutocompleteProvider::ProjectLocation location) =|
- get_parameters_hint(GUI::AutocompleteProvider::ProjectLocation location) =|
+ auto_complete_suggestions(CodeComprehension::ProjectLocation location) =|
+ find_declaration(CodeComprehension::ProjectLocation location) =|
+ get_parameters_hint(CodeComprehension::ProjectLocation location) =|
get_tokens_info(String filename) =|
}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Shell/CMakeLists.txt b/Userland/DevTools/HackStudio/LanguageServers/Shell/CMakeLists.txt
index 246f7e42d4..3fac0d165e 100644
--- a/Userland/DevTools/HackStudio/LanguageServers/Shell/CMakeLists.txt
+++ b/Userland/DevTools/HackStudio/LanguageServers/Shell/CMakeLists.txt
@@ -4,7 +4,6 @@ serenity_component(
)
set(SOURCES
- ShellComprehensionEngine.cpp
main.cpp
)
@@ -16,4 +15,4 @@ serenity_bin(ShellLanguageServer)
# We link with LibGUI because we use GUI::TextDocument to update
# the content of files according to the edit actions we receive over IPC.
-target_link_libraries(ShellLanguageServer LibIPC LibShell LibGUI LibLanguageServer LibMain)
+target_link_libraries(ShellLanguageServer LibIPC LibShell LibGUI LibLanguageServer LibShellComprehension LibMain)
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Shell/ConnectionFromClient.h b/Userland/DevTools/HackStudio/LanguageServers/Shell/ConnectionFromClient.h
index 7e5ab2682d..58864ddd97 100644
--- a/Userland/DevTools/HackStudio/LanguageServers/Shell/ConnectionFromClient.h
+++ b/Userland/DevTools/HackStudio/LanguageServers/Shell/ConnectionFromClient.h
@@ -6,8 +6,8 @@
#pragma once
-#include "ShellComprehensionEngine.h"
#include <DevTools/HackStudio/LanguageServers/ConnectionFromClient.h>
+#include <LibCodeComprehension/Shell/ShellComprehensionEngine.h>
#include <LibCpp/Parser.h>
namespace LanguageServers::Shell {
@@ -19,11 +19,11 @@ private:
ConnectionFromClient(NonnullOwnPtr<Core::Stream::LocalSocket> socket)
: LanguageServers::ConnectionFromClient(move(socket))
{
- m_autocomplete_engine = make<ShellComprehensionEngine>(m_filedb);
- m_autocomplete_engine->set_declarations_of_document_callback = [this](String const& filename, Vector<GUI::AutocompleteProvider::Declaration>&& declarations) {
+ m_autocomplete_engine = make<CodeComprehension::Shell::ShellComprehensionEngine>(m_filedb);
+ m_autocomplete_engine->set_declarations_of_document_callback = [this](String const& filename, Vector<CodeComprehension::Declaration>&& declarations) {
async_declarations_in_document(filename, move(declarations));
};
- m_autocomplete_engine->set_todo_entries_of_document_callback = [this](String const& filename, Vector<Cpp::Parser::TodoEntry>&& todo_entries) {
+ m_autocomplete_engine->set_todo_entries_of_document_callback = [this](String const& filename, Vector<CodeComprehension::TodoEntry>&& todo_entries) {
async_todo_entries_in_document(filename, move(todo_entries));
};
}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Shell/ShellComprehensionEngine.cpp b/Userland/DevTools/HackStudio/LanguageServers/Shell/ShellComprehensionEngine.cpp
deleted file mode 100644
index 090ceaaa3d..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/Shell/ShellComprehensionEngine.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#include "ShellComprehensionEngine.h"
-#include <AK/Assertions.h>
-#include <AK/HashTable.h>
-#include <LibRegex/Regex.h>
-#include <Userland/DevTools/HackStudio/LanguageServers/ConnectionFromClient.h>
-
-namespace LanguageServers::Shell {
-
-RefPtr<::Shell::Shell> ShellComprehensionEngine::s_shell {};
-
-ShellComprehensionEngine::ShellComprehensionEngine(FileDB const& filedb)
- : CodeComprehensionEngine(filedb, true)
-{
-}
-
-ShellComprehensionEngine::DocumentData const& ShellComprehensionEngine::get_or_create_document_data(String const& file)
-{
- auto absolute_path = filedb().to_absolute_path(file);
- if (!m_documents.contains(absolute_path)) {
- set_document_data(absolute_path, create_document_data_for(absolute_path));
- }
- return get_document_data(absolute_path);
-}
-
-ShellComprehensionEngine::DocumentData const& ShellComprehensionEngine::get_document_data(String const& file) const
-{
- auto absolute_path = filedb().to_absolute_path(file);
- auto document_data = m_documents.get(absolute_path);
- VERIFY(document_data.has_value());
- return *document_data.value();
-}
-
-OwnPtr<ShellComprehensionEngine::DocumentData> ShellComprehensionEngine::create_document_data_for(String const& file)
-{
- auto document = filedb().get(file);
- if (!document)
- return {};
- auto content = document->text();
- auto document_data = make<DocumentData>(document->text(), file);
- for (auto& path : document_data->sourced_paths())
- get_or_create_document_data(path);
-
- update_declared_symbols(*document_data);
- return document_data;
-}
-
-void ShellComprehensionEngine::set_document_data(String const& file, OwnPtr<DocumentData>&& data)
-{
- m_documents.set(filedb().to_absolute_path(file), move(data));
-}
-
-ShellComprehensionEngine::DocumentData::DocumentData(String&& _text, String _filename)
- : filename(move(_filename))
- , text(move(_text))
- , node(parse())
-{
-}
-
-Vector<String> const& ShellComprehensionEngine::DocumentData::sourced_paths() const
-{
- if (all_sourced_paths.has_value())
- return all_sourced_paths.value();
-
- struct : public ::Shell::AST::NodeVisitor {
- void visit(const ::Shell::AST::CastToCommand* node) override
- {
- auto& inner = node->inner();
- if (inner->is_list()) {
- if (auto* list = dynamic_cast<const ::Shell::AST::ListConcatenate*>(inner.ptr())) {
- auto& entries = list->list();
- if (entries.size() == 2 && entries.first()->is_bareword() && static_ptr_cast<::Shell::AST::BarewordLiteral>(entries.first())->text() == "source") {
- auto& filename = entries[1];
- if (filename->would_execute())
- return;
- auto name_list = const_cast<::Shell::AST::Node*>(filename.ptr())->run(nullptr)->resolve_as_list(nullptr);
- StringBuilder builder;
- builder.join(" ", name_list);
- sourced_files.set(builder.build());
- }
- }
- }
- ::Shell::AST::NodeVisitor::visit(node);
- }
-
- HashTable<String> sourced_files;
- } visitor;
-
- node->visit(visitor);
-
- Vector<String> sourced_paths;
- for (auto& entry : visitor.sourced_files)
- sourced_paths.append(move(entry));
-
- all_sourced_paths = move(sourced_paths);
- return all_sourced_paths.value();
-}
-
-NonnullRefPtr<::Shell::AST::Node> ShellComprehensionEngine::DocumentData::parse() const
-{
- ::Shell::Parser parser { text };
- if (auto node = parser.parse())
- return node.release_nonnull();
-
- return ::Shell::AST::make_ref_counted<::Shell::AST::SyntaxError>(::Shell::AST::Position {}, "Unable to parse file");
-}
-
-size_t ShellComprehensionEngine::resolve(ShellComprehensionEngine::DocumentData const& document, const GUI::TextPosition& position)
-{
- size_t offset = 0;
-
- if (position.line() > 0) {
- auto first = true;
- size_t line = 0;
- for (auto& line_view : document.text.split_limit('\n', position.line() + 1, true)) {
- if (line == position.line())
- break;
- if (first)
- first = false;
- else
- ++offset; // For the newline.
- offset += line_view.length();
- ++line;
- }
- }
-
- offset += position.column() + 1;
- return offset;
-}
-
-Vector<GUI::AutocompleteProvider::Entry> ShellComprehensionEngine::get_suggestions(String const& file, const GUI::TextPosition& position)
-{
- dbgln_if(SH_LANGUAGE_SERVER_DEBUG, "ShellComprehensionEngine position {}:{}", position.line(), position.column());
-
- auto const& document = get_or_create_document_data(file);
- size_t offset_in_file = resolve(document, position);
-
- ::Shell::AST::HitTestResult hit_test = document.node->hit_test_position(offset_in_file);
- if (!hit_test.matching_node) {
- dbgln_if(SH_LANGUAGE_SERVER_DEBUG, "no node at position {}:{}", position.line(), position.column());
- return {};
- }
-
- auto completions = const_cast<::Shell::AST::Node*>(document.node.ptr())->complete_for_editor(shell(), offset_in_file, hit_test);
- Vector<GUI::AutocompleteProvider::Entry> entries;
- for (auto& completion : completions)
- entries.append({ completion.text_string, completion.input_offset });
-
- return entries;
-}
-
-void ShellComprehensionEngine::on_edit(String const& file)
-{
- set_document_data(file, create_document_data_for(file));
-}
-
-void ShellComprehensionEngine::file_opened([[maybe_unused]] String const& file)
-{
- set_document_data(file, create_document_data_for(file));
-}
-
-Optional<GUI::AutocompleteProvider::ProjectLocation> ShellComprehensionEngine::find_declaration_of(String const& filename, const GUI::TextPosition& identifier_position)
-{
- dbgln_if(SH_LANGUAGE_SERVER_DEBUG, "find_declaration_of({}, {}:{})", filename, identifier_position.line(), identifier_position.column());
- auto const& document = get_or_create_document_data(filename);
- auto position = resolve(document, identifier_position);
- auto result = document.node->hit_test_position(position);
- if (!result.matching_node) {
- dbgln_if(SH_LANGUAGE_SERVER_DEBUG, "no node at position {}:{}", identifier_position.line(), identifier_position.column());
- return {};
- }
-
- if (!result.matching_node->is_bareword()) {
- dbgln_if(SH_LANGUAGE_SERVER_DEBUG, "no bareword at position {}:{}", identifier_position.line(), identifier_position.column());
- return {};
- }
-
- auto name = static_ptr_cast<::Shell::AST::BarewordLiteral>(result.matching_node)->text();
- auto& declarations = all_declarations();
- for (auto& entry : declarations) {
- for (auto& declaration : entry.value) {
- if (declaration.name == name)
- return declaration.position;
- }
- }
-
- return {};
-}
-
-void ShellComprehensionEngine::update_declared_symbols(DocumentData const& document)
-{
- struct Visitor : public ::Shell::AST::NodeVisitor {
- explicit Visitor(String const& filename)
- : filename(filename)
- {
- }
-
- void visit(const ::Shell::AST::VariableDeclarations* node) override
- {
- for (auto& entry : node->variables()) {
- auto literal = entry.name->leftmost_trivial_literal();
- if (!literal)
- continue;
-
- String name;
- if (literal->is_bareword())
- name = static_ptr_cast<::Shell::AST::BarewordLiteral>(literal)->text();
-
- if (!name.is_empty()) {
- dbgln("Found variable {}", name);
- declarations.append({ move(name), { filename, entry.name->position().start_line.line_number, entry.name->position().start_line.line_column }, GUI::AutocompleteProvider::DeclarationType::Variable, {} });
- }
- }
- ::Shell::AST::NodeVisitor::visit(node);
- }
-
- void visit(const ::Shell::AST::FunctionDeclaration* node) override
- {
- dbgln("Found function {}", node->name().name);
- declarations.append({ node->name().name, { filename, node->position().start_line.line_number, node->position().start_line.line_column }, GUI::AutocompleteProvider::DeclarationType::Function, {} });
- }
-
- String const& filename;
- Vector<GUI::AutocompleteProvider::Declaration> declarations;
- } visitor { document.filename };
-
- document.node->visit(visitor);
-
- set_declarations_of_document(document.filename, move(visitor.declarations));
-}
-}
diff --git a/Userland/DevTools/HackStudio/LanguageServers/Shell/ShellComprehensionEngine.h b/Userland/DevTools/HackStudio/LanguageServers/Shell/ShellComprehensionEngine.h
deleted file mode 100644
index 774a7be45a..0000000000
--- a/Userland/DevTools/HackStudio/LanguageServers/Shell/ShellComprehensionEngine.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2020, the SerenityOS developers.
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
-
-#pragma once
-
-#include <DevTools/HackStudio/LanguageServers/CodeComprehensionEngine.h>
-#include <Shell/Shell.h>
-
-namespace LanguageServers::Shell {
-
-class ShellComprehensionEngine : public CodeComprehensionEngine {
-public:
- ShellComprehensionEngine(FileDB const& filedb);
- virtual Vector<GUI::AutocompleteProvider::Entry> get_suggestions(String const& file, const GUI::TextPosition& position) override;
- virtual void on_edit(String const& file) override;
- virtual void file_opened([[maybe_unused]] String const& file) override;
- virtual Optional<GUI::AutocompleteProvider::ProjectLocation> find_declaration_of(String const& filename, const GUI::TextPosition& identifier_position) override;
-
-private:
- struct DocumentData {
- DocumentData(String&& text, String filename);
- String filename;
- String text;
- NonnullRefPtr<::Shell::AST::Node> node;
-
- Vector<String> const& sourced_paths() const;
-
- private:
- NonnullRefPtr<::Shell::AST::Node> parse() const;
-
- mutable Optional<Vector<String>> all_sourced_paths {};
- };
-
- DocumentData const& get_document_data(String const& file) const;
- DocumentData const& get_or_create_document_data(String const& file);
- void set_document_data(String const& file, OwnPtr<DocumentData>&& data);
-
- OwnPtr<DocumentData> create_document_data_for(String const& file);
- String document_path_from_include_path(StringView include_path) const;
- void update_declared_symbols(DocumentData const&);
-
- static size_t resolve(ShellComprehensionEngine::DocumentData const& document, const GUI::TextPosition& position);
-
- ::Shell::Shell& shell()
- {
- if (s_shell)
- return *s_shell;
- s_shell = ::Shell::Shell::construct();
- return *s_shell;
- }
-
- HashMap<String, OwnPtr<DocumentData>> m_documents;
- static RefPtr<::Shell::Shell> s_shell;
-};
-}