Skip to content

Instantly share code, notes, and snippets.

@christianparpart
Created November 29, 2021 11:48
Show Gist options
  • Save christianparpart/e300b2c67353811fe1141f641633213c to your computer and use it in GitHub Desktop.
Save christianparpart/e300b2c67353811fe1141f641633213c to your computer and use it in GitHub Desktop.
Patch for reviving LSP TCP listener.
commit 6cccca59014f49c52faaf19f8f2e9f102f519884
Author: Christian Parpart <[email protected]>
Date: Mon Nov 29 12:46:52 2021 +0100
Revert "Drop LSP TCP listener."
This reverts commit 5b61209d11fe046dfc57e4c74762c3da9dfc0e3d.
diff --git a/solc/CMakeLists.txt b/solc/CMakeLists.txt
index 3e3594766..51b77d29b 100644
--- a/solc/CMakeLists.txt
+++ b/solc/CMakeLists.txt
@@ -5,6 +5,19 @@ set(libsolcli_sources
set(libsolcli_libs solidity Boost::boost Boost::program_options)
+if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
+ # Since we do not want to depend on networking code on production binaries,
+ # this feature is only available when creating a debug build.
+ # the LSP's TCP listener is exclusively used more convenient debugging.
+ option(SOLC_LSP_TCP "Solidity LSP: Enables TCP listener support (should only be eanbled for debugging purposes)." OFF)
+ if(SOLC_LSP_TCP)
+ set(libsolcli_defines SOLC_LSP_TCP=1)
+ list(APPEND libsolcli_sources LSPTCPTransport.cpp LSPTCPTransport.h)
+ find_package(Threads REQUIRED)
+ list(APPEND libsolcli_libs Threads::Threads)
+ endif()
+endif()
+
add_library(solcli ${libsolcli_sources})
target_compile_definitions(solcli PUBLIC ${libsolcli_defines})
target_link_libraries(solcli PUBLIC ${libsolcli_libs})
diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp
index ba1140f98..1bfa60f95 100644
--- a/solc/CommandLineInterface.cpp
+++ b/solc/CommandLineInterface.cpp
@@ -25,6 +25,10 @@
#include "license.h"
+#if defined(SOLC_LSP_TCP)
+#include <solc/LSPTCPTransport.h>
+#endif
+
#include "solidity/BuildInfo.h"
#include <libsolidity/interface/Version.h>
@@ -902,6 +906,15 @@ void CommandLineInterface::handleAst()
void CommandLineInterface::serveLSP()
{
+#if defined(SOLC_LSP_TCP)
+ if (m_options.lsp.port.has_value())
+ {
+ lsp::LSPTCPTransport transport(m_options.lsp.port.value());
+ lsp::LanguageServer{transport}.run();
+ return;
+ }
+#endif
+
lsp::JSONTransport transport;
lsp::LanguageServer{transport}.run();
}
diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp
index 73f6a1e3a..caa1fdfbd 100644
--- a/solc/CommandLineParser.cpp
+++ b/solc/CommandLineParser.cpp
@@ -1261,6 +1261,19 @@ bool CommandLineParser::processArgs()
}
}
+#if defined(SOLC_LSP_TCP)
+ if (m_args.count("lsp-port"))
+ {
+ unsigned const port = m_args.at("lsp-port").as<unsigned>();
+ if (port > 0xFFFF)
+ {
+ serr() << "LSP port number not in valid port range " << port << '.' << endl;
+ return false;
+ }
+ m_options.lsp.port = port;
+ }
+#endif
+
if (m_args.count(g_strModelCheckerContracts))
{
string contractsStr = m_args[g_strModelCheckerContracts].as<string>();
diff --git a/solc/CommandLineParser.h b/solc/CommandLineParser.h
index d4909a109..4bf0be764 100644
--- a/solc/CommandLineParser.h
+++ b/solc/CommandLineParser.h
@@ -227,6 +227,13 @@ struct CommandLineOptions
std::optional<std::string> yulSteps;
} optimizer;
+#if defined(SOLC_LSP_TCP)
+ struct
+ {
+ std::optional<unsigned short> port;
+ } lsp;
+#endif
+
struct
{
bool initialize = false;
diff --git a/solc/LSPTCPTransport.cpp b/solc/LSPTCPTransport.cpp
new file mode 100644
index 000000000..9c765fa0c
--- /dev/null
+++ b/solc/LSPTCPTransport.cpp
@@ -0,0 +1,96 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+// SPDX-License-Identifier: GPL-3.0
+#include <solc/LSPTCPTransport.h>
+
+#include <libsolutil/JSON.h>
+#include <fmt/format.h>
+
+#include <optional>
+#include <string>
+#include <iostream>
+
+namespace solidity::lsp
+{
+
+using std::nullopt;
+using std::optional;
+using std::string_view;
+
+using namespace std::string_literals;
+
+LSPTCPTransport::LSPTCPTransport(unsigned short _port, std::string const& _address):
+ m_io_service(),
+ m_endpoint(boost::asio::ip::make_address(_address), _port),
+ m_acceptor(m_io_service),
+ m_stream(),
+ m_jsonTransport()
+{
+ m_acceptor.open(m_endpoint.protocol());
+ m_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+ m_acceptor.bind(m_endpoint);
+ m_acceptor.listen();
+}
+
+bool LSPTCPTransport::closed() const noexcept
+{
+ return !m_acceptor.is_open();
+}
+
+optional<Json::Value> LSPTCPTransport::receive()
+{
+ auto const clientClosed = [&]() { return !m_stream || !m_stream.value().good() || m_stream.value().eof(); };
+
+ if (clientClosed())
+ {
+ m_stream.emplace(m_acceptor.accept());
+ if (clientClosed())
+ return nullopt;
+
+ m_jsonTransport.emplace(m_stream.value(), m_stream.value());
+ }
+
+ if (auto value = m_jsonTransport.value().receive(); value.has_value())
+ return value;
+
+ if (clientClosed())
+ {
+ m_jsonTransport.reset();
+ m_stream.reset();
+ }
+ return nullopt;
+}
+
+void LSPTCPTransport::notify(std::string _method, Json::Value _params)
+{
+ if (m_jsonTransport.has_value())
+ m_jsonTransport.value().notify(move(_method), _params);
+}
+
+void LSPTCPTransport::reply(MessageID _id, Json::Value _result)
+{
+ if (m_jsonTransport.has_value())
+ m_jsonTransport.value().reply(_id, _result);
+}
+
+void LSPTCPTransport::error(MessageID _id, ErrorCode _code, std::string _message)
+{
+ if (m_jsonTransport.has_value())
+ m_jsonTransport.value().error(_id, _code, move(_message));
+}
+
+}
diff --git a/solc/LSPTCPTransport.h b/solc/LSPTCPTransport.h
new file mode 100644
index 000000000..485849906
--- /dev/null
+++ b/solc/LSPTCPTransport.h
@@ -0,0 +1,46 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+// SPDX-License-Identifier: GPL-3.0
+#pragma once
+
+#include <libsolidity/lsp/Transport.h>
+
+#include <boost/asio.hpp>
+#include <optional>
+
+namespace solidity::lsp
+{
+
+class LSPTCPTransport: public lsp::Transport {
+public:
+ explicit LSPTCPTransport(unsigned short _port, std::string const& _address = "127.0.0.1");
+
+ bool closed() const noexcept override;
+ std::optional<Json::Value> receive() override;
+ void notify(std::string _method, Json::Value _params) override;
+ void reply(lsp::MessageID _id, Json::Value _result) override;
+ void error(lsp::MessageID _id, lsp::ErrorCode _code, std::string _message) override;
+
+private:
+ boost::asio::io_service m_io_service;
+ boost::asio::ip::tcp::endpoint m_endpoint;
+ boost::asio::ip::tcp::acceptor m_acceptor;
+ std::optional<boost::asio::ip::tcp::iostream> m_stream;
+ std::optional<lsp::JSONTransport> m_jsonTransport;
+};
+
+} // end namespace
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment