Commit 0dc3ffc5 authored by Simon Zünd's avatar Simon Zünd Committed by Commit Bot

[torque-ls] Move GlobalContext into LangServerData after compilation

The language server needs Torque compilation artifacts like
declarables for more advanced features. This CL moves the GlobalContext
into the LanguageServerData class when Torque compilation finishes, to
preserve all the compiler data.

Additionally, all declarables are split up by source id. This makes
providing all symbols of a file easier.

R=tebbi@chromium.org

Bug: v8:8880
Change-Id: I424d1ddc04fcd18934f76a736900bc5d08261c07
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1601132
Commit-Queue: Simon Zünd <szuend@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61462}
parent 51be14ba
......@@ -17,6 +17,8 @@ namespace torque {
class GlobalContext : public ContextualClass<GlobalContext> {
public:
GlobalContext(GlobalContext&&) V8_NOEXCEPT = default;
GlobalContext& operator=(GlobalContext&&) V8_NOEXCEPT = default;
explicit GlobalContext(Ast ast)
: verbose_(false),
collect_language_server_data_(false),
......@@ -90,6 +92,8 @@ class GlobalContext : public ContextualClass<GlobalContext> {
std::vector<std::unique_ptr<Declarable>> declarables_;
std::vector<std::string> cpp_includes_;
std::map<std::string, ClassType*> classes_;
friend class LanguageServerData;
};
template <class T>
......
......@@ -165,7 +165,7 @@ void SendCompilationDiagnostics(const TorqueCompilerResult& result,
} // namespace
void CompilationFinished(TorqueCompilerResult result, MessageWriter writer) {
LanguageServerData::Get() = result.language_server_data;
LanguageServerData::Get() = std::move(result.language_server_data);
SourceFileMap::Get() = result.source_file_map;
SendCompilationDiagnostics(result, writer);
......@@ -186,7 +186,7 @@ void RecompileTorque(MessageWriter writer) {
Logger::Log("[info] Finished compilation run ...\n");
CompilationFinished(result, writer);
CompilationFinished(std::move(result), writer);
}
void RecompileTorqueWithDiagnostics(MessageWriter writer) {
......
......@@ -4,6 +4,9 @@
#include "src/torque/server-data.h"
#include "src/torque/declarable.h"
#include "src/torque/implementation-visitor.h"
namespace v8 {
namespace internal {
namespace torque {
......@@ -30,6 +33,23 @@ base::Optional<SourcePosition> LanguageServerData::FindDefinition(
return base::nullopt;
}
void LanguageServerData::PrepareAllDeclarableSymbols() {
const std::vector<std::unique_ptr<Declarable>>& all_declarables =
global_context_->declarables_;
for (const auto& declarable : all_declarables) {
// Auto-generated macros to access class fields should not show up in
// search results.
if (declarable->IsMacro() &&
!Macro::cast(declarable.get())->is_user_defined()) {
continue;
}
SourceId source = declarable->Position().source;
symbols_map_[source].push_back(declarable.get());
}
}
} // namespace torque
} // namespace internal
} // namespace v8
......@@ -10,6 +10,8 @@
#include "src/base/macros.h"
#include "src/base/optional.h"
#include "src/torque/declarable.h"
#include "src/torque/global-context.h"
#include "src/torque/source-positions.h"
namespace v8 {
......@@ -22,6 +24,13 @@ using DefinitionMapping = std::pair<SourcePosition, SourcePosition>;
using Definitions = std::vector<DefinitionMapping>;
using DefinitionsMap = std::map<SourceId, Definitions>;
// Symbols are used to answer search queries (either workspace or document
// scope). For now, declarables are stored directly without converting them
// into a custom format. Symbols are grouped by sourceId to implement document
// scoped searches.
using Symbols = std::vector<Declarable*>;
using SymbolsMap = std::map<SourceId, Symbols>;
// This contextual class holds all the necessary data to answer incoming
// LSP requests. It is reset for each compilation step and all information
// is calculated eagerly during compilation.
......@@ -35,8 +44,23 @@ class LanguageServerData : public ContextualClass<LanguageServerData> {
V8_EXPORT_PRIVATE static base::Optional<SourcePosition> FindDefinition(
SourceId source, LineAndColumn pos);
static void SetGlobalContext(GlobalContext global_context) {
Get().global_context_ =
base::make_unique<GlobalContext>(std::move(global_context));
Get().PrepareAllDeclarableSymbols();
}
static const Symbols& SymbolsForSourceId(SourceId id) {
return Get().symbols_map_[id];
}
private:
// Splits all declarables up by SourceId and filters out auto-generated ones.
void PrepareAllDeclarableSymbols();
DefinitionsMap definitions_map_;
SymbolsMap symbols_map_;
std::unique_ptr<GlobalContext> global_context_;
};
} // namespace torque
......
......@@ -95,20 +95,10 @@ void CompileCurrentAst(TorqueCompilerOptions options) {
implementation_visitor.GenerateImplementation(output_directory, n);
}
}
}
TorqueCompilerResult CollectResultFromContextuals() {
TorqueCompilerResult result;
result.source_file_map = SourceFileMap::Get();
result.language_server_data = LanguageServerData::Get();
result.lint_errors = LintErrors::Get();
return result;
}
TorqueCompilerResult ResultFromError(TorqueError& error) {
TorqueCompilerResult result = CollectResultFromContextuals();
result.error = error;
return result;
if (GlobalContext::collect_language_server_data()) {
LanguageServerData::SetGlobalContext(std::move(GlobalContext::Get()));
}
}
} // namespace
......@@ -121,14 +111,19 @@ TorqueCompilerResult CompileTorque(const std::string& source,
LintErrors::Scope lint_errors_scope;
LanguageServerData::Scope server_data_scope;
TorqueCompilerResult result;
try {
ParseTorque(source);
CompileCurrentAst(options);
} catch (TorqueError& error) {
return ResultFromError(error);
result.error = error;
}
return CollectResultFromContextuals();
result.source_file_map = SourceFileMap::Get();
result.language_server_data = std::move(LanguageServerData::Get());
result.lint_errors = LintErrors::Get();
return result;
}
TorqueCompilerResult CompileTorque(std::vector<std::string> files,
......@@ -139,13 +134,19 @@ TorqueCompilerResult CompileTorque(std::vector<std::string> files,
LintErrors::Scope lint_errors_scope;
LanguageServerData::Scope server_data_scope;
TorqueCompilerResult result;
try {
for (const auto& path : files) ReadAndParseTorqueFile(path);
CompileCurrentAst(options);
} catch (TorqueError& error) {
return ResultFromError(error);
result.error = error;
}
return CollectResultFromContextuals();
result.source_file_map = SourceFileMap::Get();
result.language_server_data = std::move(LanguageServerData::Get());
result.lint_errors = LintErrors::Get();
return result;
}
} // namespace torque
......
......@@ -121,7 +121,7 @@ TEST(LanguageServerMessage, CompilationErrorSendsDiagnostics) {
result.error = TorqueError("compilation failed somehow");
result.source_file_map = SourceFileMap::Get();
CompilationFinished(result, [](JsonValue& raw_response) {
CompilationFinished(std::move(result), [](JsonValue& raw_response) {
PublishDiagnosticsNotification notification(raw_response);
EXPECT_EQ(notification.method(), "textDocument/publishDiagnostics");
......@@ -150,7 +150,7 @@ TEST(LanguageServerMessage, LintErrorSendsDiagnostics) {
result.lint_errors.push_back({"lint error 2", pos2});
result.source_file_map = SourceFileMap::Get();
CompilationFinished(result, [](JsonValue& raw_response) {
CompilationFinished(std::move(result), [](JsonValue& raw_response) {
PublishDiagnosticsNotification notification(raw_response);
EXPECT_EQ(notification.method(), "textDocument/publishDiagnostics");
......@@ -175,17 +175,19 @@ TEST(LanguageServerMessage, CleanCompileSendsNoDiagnostics) {
TorqueCompilerResult result;
result.source_file_map = SourceFileMap::Get();
CompilationFinished(result, [](JsonValue& raw_response) {
CompilationFinished(std::move(result), [](JsonValue& raw_response) {
FAIL() << "Sending unexpected response!";
});
}
TEST(LanguageServerMessage, NoSymbolsSendsEmptyResponse) {
LanguageServerData::Scope server_data_scope;
SourceFileMap::Scope sourc_file_map_scope;
DocumentSymbolRequest request;
request.set_id(42);
request.set_method("textDocument/documentSymbol");
request.params().textDocument().set_uri("test.tq");
HandleMessage(request.GetJsonValue(), [](JsonValue& raw_response) {
DocumentSymbolResponse response(raw_response);
......
......@@ -23,9 +23,9 @@ struct TestCompiler {
options.collect_language_server_data = true;
options.force_assert_statements = true;
const TorqueCompilerResult result = CompileTorque(source, options);
TorqueCompilerResult result = CompileTorque(source, options);
SourceFileMap::Get() = result.source_file_map;
LanguageServerData::Get() = result.language_server_data;
LanguageServerData::Get() = std::move(result.language_server_data);
}
};
......@@ -199,6 +199,27 @@ TEST(LanguageServer, GotoLabelDefinitionGotoInOtherwise) {
EXPECT_EQ(*maybe_position, (SourcePosition{id, {7, 8}, {7, 15}}));
}
TEST(LanguageServer, SymbolsArePopulated) {
// Small test to ensure that the GlobalContext is correctly set in
// the LanguageServerData class and declarables are sorted into the
// SymbolsMap.
const std::string source = R"(
type void;
type never;
macro Foo(): never labels Fail {
goto Fail;
}
)";
TestCompiler compiler;
compiler.Compile(source);
const SourceId id = SourceFileMap::GetSourceId("<torque>");
const auto& symbols = LanguageServerData::SymbolsForSourceId(id);
ASSERT_FALSE(symbols.empty());
}
} // namespace torque
} // namespace internal
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment