From 134b3adafae560889102292b323c1a09491db5ab Mon Sep 17 00:00:00 2001 From: Tamas Dunai Date: Sat, 14 Jan 2023 12:43:06 +0100 Subject: [PATCH 01/26] Add LSP support --- CMakeLists.txt | 2 +- .../cpp/service/include/service/cppservice.h | 2 +- service/CMakeLists.txt | 1 + service/lsp/CMakeLists.txt | 29 ++ service/lsp/include/lspservice/lsp_types.h | 274 +++++++++++++++++ service/lsp/include/lspservice/lspservice.h | 60 ++++ service/lsp/src/lsp_types.cpp | 190 ++++++++++++ service/lsp/src/lspservice.cpp | 282 ++++++++++++++++++ service/lsp/src/plugin.cpp | 29 ++ webserver/CMakeLists.txt | 20 +- webserver/include/webserver/lsphandler.h | 63 ++++ webserver/src/lsphandler.cpp | 245 +++++++++++++++ 12 files changed, 1193 insertions(+), 4 deletions(-) create mode 100644 service/lsp/CMakeLists.txt create mode 100644 service/lsp/include/lspservice/lsp_types.h create mode 100644 service/lsp/include/lspservice/lspservice.h create mode 100644 service/lsp/src/lsp_types.cpp create mode 100644 service/lsp/src/lspservice.cpp create mode 100644 service/lsp/src/plugin.cpp create mode 100644 webserver/include/webserver/lsphandler.h create mode 100644 webserver/src/lsphandler.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d4e81c7d0..c93f97a2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,10 +28,10 @@ set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH};${RUNENV_LD_LIBRARY_PATH}") add_subdirectory(logger) add_subdirectory(model) add_subdirectory(parser) +add_subdirectory(plugins) # must precede service add_subdirectory(scripts) add_subdirectory(service) add_subdirectory(util) -add_subdirectory(plugins) # must precede webgui add_subdirectory(webgui) add_subdirectory(webserver) diff --git a/plugins/cpp/service/include/service/cppservice.h b/plugins/cpp/service/include/service/cppservice.h index edfc3bbfc..7bcec09a4 100644 --- a/plugins/cpp/service/include/service/cppservice.h +++ b/plugins/cpp/service/include/service/cppservice.h @@ -131,7 +131,6 @@ class CppServiceHandler : virtual public LanguageServiceIf std::vector& return_, const core::FileRange& range_) override; -private: enum ReferenceType { DEFINITION, /*!< By this option the definition(s) of the AST node can be @@ -258,6 +257,7 @@ class CppServiceHandler : virtual public LanguageServiceIf of a module. */ }; +private: static bool compareByPosition( const model::CppAstNode& lhs, const model::CppAstNode& rhs); diff --git a/service/CMakeLists.txt b/service/CMakeLists.txt index 21b32b2ae..985f4f5b7 100644 --- a/service/CMakeLists.txt +++ b/service/CMakeLists.txt @@ -3,3 +3,4 @@ add_subdirectory(language) add_subdirectory(plugin) add_subdirectory(project) add_subdirectory(workspace) +add_subdirectory(lsp) diff --git a/service/lsp/CMakeLists.txt b/service/lsp/CMakeLists.txt new file mode 100644 index 000000000..d15f0f5a8 --- /dev/null +++ b/service/lsp/CMakeLists.txt @@ -0,0 +1,29 @@ +include_directories( + include + ${PROJECT_SOURCE_DIR}/util/include + ${PROJECT_SOURCE_DIR}/webserver/include + ${PROJECT_SOURCE_DIR}/model/include + ${PROJECT_BINARY_DIR}/service/language/gen-cpp + ${PROJECT_BINARY_DIR}/service/project/gen-cpp + ${PROJECT_SOURCE_DIR}/service/project/include + ${PROJECT_SOURCE_DIR}/plugins/cpp/service/include + ${PROJECT_SOURCE_DIR}/plugins/cpp/model/include + ${CMAKE_BINARY_DIR}/model/include + ${CMAKE_BINARY_DIR}/plugins/cpp/model/include) + +include_directories(SYSTEM + ${THRIFT_LIBTHRIFT_INCLUDE_DIRS}) + +add_library(lspservice SHARED + src/lspservice.cpp + src/lsp_types.cpp + src/plugin.cpp) + +target_link_libraries(lspservice + util + ${THRIFT_LIBTHRIFT_LIBRARIES}) + +add_dependencies(lspservice projectthrift) +add_dependencies(lspservice languagethrift) + +install(TARGETS lspservice DESTINATION ${INSTALL_SERVICE_DIR}) \ No newline at end of file diff --git a/service/lsp/include/lspservice/lsp_types.h b/service/lsp/include/lspservice/lsp_types.h new file mode 100644 index 000000000..792c3e5b6 --- /dev/null +++ b/service/lsp/include/lspservice/lsp_types.h @@ -0,0 +1,274 @@ +#ifndef CC_MODEL_LSP_TYPES_H +#define CC_MODEL_LSP_TYPES_H + +#include + +#include +#include + +namespace cc +{ +namespace service +{ +namespace lsp +{ + +namespace pt = boost::property_tree; + +typedef std::string DocumentUri; +typedef std::string Diagram; + +/** + * LSP error codes. + */ +enum class ErrorCode +{ + // Defined by JSON RPC + ParseError = -32700, + InvalidRequest = -32600, + MethodNotFound = -32601, + InvalidParams = -32602, + InternalError = -32603, + ServerErrorStart = -32099, + ServerErrorEnd = -32000, + ServerNotInitialized = -32002, + UnknownError = -32001, + + // Defined by the protocol + RequestCancelled = -32800 +}; + +/** + * Represents an abstract base class for readable LSP structures. + */ +struct Readable +{ + virtual void readNode(const pt::ptree& node) = 0; +}; + +/** + * Represents an abstract base class for writeable LSP structures. + */ +struct Writeable +{ + virtual void writeNode(pt::ptree& node) const = 0; + + inline pt::ptree createNode() const + { + pt::ptree node; + writeNode(node); + return node; + } +}; + +/** + * Represents an LSP response error message. + */ +struct ResponseError : public Writeable +{ + /** + * A number indicating the error type that occurred. + */ + ErrorCode code; + /** + * A string providing a short description of the error. + */ + std::string message; + + void writeNode(pt::ptree& node) const override; +}; + +/** + * Text documents are identified using a URI. + * + * On the protocol level, URIs are passed as strings. + */ +struct TextDocumentIdentifier : public Readable, public Writeable +{ + /** + * The text document's URI. + */ + DocumentUri uri; + + void readNode(const pt::ptree& node) override; + void writeNode(pt::ptree& node) const override; +}; + +/** + * Position in a text document expressed as zero-based line and zero-based character offset. + * + * A position is between two characters like an ‘insert’ cursor in a editor. + * Special values like for example -1 to denote the end of a line are not supported. + */ +struct Position : public Readable, public Writeable +{ + /** + * Line position in a document (zero-based). + */ + int line; + /** + * Character offset on a line in a document (zero-based). Assuming that the line is + * represented as a string, the `character` value represents the gap between the + * `character` and `character + 1`. + * + * If the character value is greater than the line length it defaults back to the + * line length. + */ + int character; + + void readNode(const pt::ptree& node) override; + void writeNode(pt::ptree& node) const override; +}; + +/** + * A range in a text document expressed as (zero-based) start and end positions. + * + * A range is comparable to a selection in an editor. Therefore the end position is exclusive. + * If you want to specify a range that contains a line including the line ending character(s) + * then use an end position denoting the start of the next line. + */ +struct Range : public Readable, public Writeable +{ + /** + * The range's start position. + */ + Position start; + /** + * The range's end position. + */ + Position end; + + void readNode(const pt::ptree& node) override; + void writeNode(pt::ptree& node) const override; +}; + +/** + * Represents a location inside a resource, such as a line inside a text file. + */ +struct Location : public Readable, public Writeable +{ + DocumentUri uri; + Range range; + + void readNode(const pt::ptree& node) override; + void writeNode(pt::ptree& node) const override; +}; + +/** + * A parameter literal used in requests to pass a text document and a position + * inside that document. + */ +struct TextDocumentPositionParams : public Readable, public Writeable +{ + TextDocumentIdentifier textDocument; + Position position; + + void readNode(const pt::ptree& node) override; + void writeNode(pt::ptree& node) const override; +}; + +/** + * Represents th context used in requests to retrieve the references. + */ +struct ReferenceContext : public Readable, public Writeable +{ + bool includeDeclaration; + + void readNode(const pt::ptree& node) override; + void writeNode(pt::ptree& node) const override; +}; + +/** + * A parameter literal used in requests to retrieve the references. + */ +struct ReferenceParams : public TextDocumentPositionParams +{ + ReferenceContext context; + + void readNode(const pt::ptree& node) override; + void writeNode(pt::ptree& node) const override; +}; + +/** + * A parameter literal used in requests to retrieve the type of diagrams + * available for a document and optionally a selected position inside it. + */ +struct DiagramTypeParams : public Readable, public Writeable +{ + TextDocumentIdentifier textDocument; + boost::optional position; + + void readNode(const pt::ptree& node) override; + void writeNode(pt::ptree& node) const override; +}; + +/** + * A parameter literal used in requests to retrieve the a specific diagram + * for a document and optionally a selected position inside it. + */ +struct DiagramParams : DiagramTypeParams +{ + std::string diagramType; + + void readNode(const pt::ptree& node) override; + void writeNode(pt::ptree& node) const override; +}; + +/** + * Represents a possible auto-complete or context menu item. + */ +struct CompletionItem : public Readable, public Writeable +{ + /** + * The label of this completion item. By default + * also the text that is inserted when selecting + * this completion. + */ + std::string label; + /** + * The kind of this completion item. Based of the kind + * an icon is chosen by the editor. + */ + boost::optional kind; + /** + * A human-readable string with additional information + * about this item, like type or symbol information. + */ + boost::optional detail; + /** + * A human-readable string that represents a doc-comment. + */ + boost::optional documentation; + /** + * A data entry field that is preserved on a completion item between + * a completion and a completion resolve request. + */ + boost::optional data; + + void readNode(const pt::ptree& node) override; + void writeNode(pt::ptree& node) const override; +}; + +/** + * Represents a list of completion items. + */ +struct CompletionList : public Writeable +{ + /** + * This list it not complete. Further typing should result in recomputing + * this list. + */ + bool isIncomplete; + /** + * The completion items. + */ + std::vector items; + + void writeNode(pt::ptree& node) const override; +}; + +} // lsp +} // service +} // cc + +#endif // CC_MODEL_LSP_TYPES_H \ No newline at end of file diff --git a/service/lsp/include/lspservice/lspservice.h b/service/lsp/include/lspservice/lspservice.h new file mode 100644 index 000000000..d017e0515 --- /dev/null +++ b/service/lsp/include/lspservice/lspservice.h @@ -0,0 +1,60 @@ +#ifndef CC_SERVICE_LSP_LSPSERVICE_H +#define CC_SERVICE_LSP_LSPSERVICE_H + +#include + +#include + +#include + +#include +#include + +#include + +namespace cc +{ +namespace service +{ +namespace lsp +{ + +class LspServiceHandler +{ +public: + LspServiceHandler( + std::shared_ptr db_, + std::shared_ptr datadir_, + const cc::webserver::ServerContext& context_); + + std::vector definition( + const TextDocumentPositionParams& params_); + + std::vector references( + const ReferenceParams& params_); + + CompletionList fileDiagramTypes( + const DiagramTypeParams& params_); + + CompletionList nodeDiagramTypes( + const DiagramTypeParams& params_); + + Diagram fileDiagram( + const DiagramParams& params_); + + Diagram nodeDiagram( + const DiagramParams& params_); + +private: + std::shared_ptr _db; + util::OdbTransaction _transaction; + + const cc::webserver::ServerContext& _context; + language::CppServiceHandler _cppService; +}; + +} // lsp +} // service +} // cc + +#endif // CC_SERVICE_LSP_LSPSERVICE_H \ No newline at end of file diff --git a/service/lsp/src/lsp_types.cpp b/service/lsp/src/lsp_types.cpp new file mode 100644 index 000000000..af1b7bd48 --- /dev/null +++ b/service/lsp/src/lsp_types.cpp @@ -0,0 +1,190 @@ +#include + +namespace cc +{ +namespace service +{ +namespace lsp +{ + +//--- ResponseError ---// + +void ResponseError::writeNode(pt::ptree& node) const +{ + node.put("code", static_cast(code)); + node.put("message", message); +} + +//--- TextDocumentIdentifier ---// + +void TextDocumentIdentifier::readNode(const pt::ptree& node) +{ + uri = node.get("uri"); +} + +void TextDocumentIdentifier::writeNode(pt::ptree& node) const +{ + node.put("uri", uri); +} + +//--- Position ---// + +void Position::readNode(const pt::ptree& node) +{ + line = node.get("line"); + character = node.get("character"); +} + +void Position::writeNode(pt::ptree& node) const +{ + node.put("line", line); + node.put("character", character); +} + +//--- Range ---// + +void Range::readNode(const pt::ptree& node) +{ + start.readNode(node.get_child("start")); + end.readNode(node.get_child("end")); +} + +void Range::writeNode(pt::ptree& node) const +{ + node.put_child("start", start.createNode()); + node.put_child("end", end.createNode()); +} + +//--- Location ---// + +void Location::readNode(const pt::ptree& node) +{ + uri = node.get("uri"); + range.readNode(node.get_child("range")); +} + +void Location::writeNode(pt::ptree& node) const +{ + node.put("uri", uri); + node.put_child("range", range.createNode()); +} + +//--- TextDocumentPositionParams ---// + +void TextDocumentPositionParams::readNode(const pt::ptree& node) +{ + textDocument.readNode(node.get_child("textDocument")); + position.readNode(node.get_child("position")); +} + +void TextDocumentPositionParams::writeNode(pt::ptree& node) const +{ + node.put_child("textDocument", textDocument.createNode()); + node.put_child("position", position.createNode()); +} + +//--- ReferenceContext ---// + +void ReferenceContext::readNode(const pt::ptree& node) +{ + includeDeclaration = node.get("includeDeclaration"); +} + +void ReferenceContext::writeNode(pt::ptree& node) const +{ + node.put("includeDeclaration", includeDeclaration); +} + +//--- ReferenceParams ---// + +void ReferenceParams::readNode(const pt::ptree& node) +{ + TextDocumentPositionParams::readNode(node); + context.readNode(node.get_child("context")); +} + +void ReferenceParams::writeNode(pt::ptree& node) const +{ + TextDocumentPositionParams::writeNode(node); + node.put_child("context", context.createNode()); +} + +//--- DiagramTypeParams ---// + +void DiagramTypeParams::readNode(const pt::ptree& node) +{ + textDocument.readNode(node.get_child("textDocument")); + + if (auto item = node.get_child_optional("position")) + { + position = Position(); + position->readNode(item.get()); + } +} + +void DiagramTypeParams::writeNode(pt::ptree& node) const +{ + node.put_child("textDocument", textDocument.createNode()); + if (position) + node.put_child("position", position->createNode()); +} + +//--- DiagramParams ---// + +void DiagramParams::readNode(const pt::ptree& node) +{ + DiagramTypeParams::readNode(node); + diagramType = node.get("diagramType"); +} + +void DiagramParams::writeNode(pt::ptree& node) const +{ + DiagramTypeParams::writeNode(node); + node.put("diagramType", diagramType); +} + +//--- CompletionItem ---// + +void CompletionItem::readNode(const pt::ptree& node) +{ + label = node.get("label"); + if (auto item = node.get_optional("kind")) + kind = item; + if (auto item = node.get_optional("detail")) + detail = item; + if (auto item = node.get_optional("documentation")) + documentation = item; + if (auto item = node.get_optional("data")) + data = item; +} + +void CompletionItem::writeNode(pt::ptree& node) const +{ + node.put("label", label); + if (kind) + node.put("kind", kind); + if (detail) + node.put("detail", detail); + if (documentation) + node.put("documentation", documentation); + if (data) + node.put("data", data); +} + +//--- CompletionList ---// + +void CompletionList::writeNode(pt::ptree& node) const +{ + node.put("isIncomplete", isIncomplete); + + pt::ptree itemsNode; + for (const CompletionItem& item : items) + { + itemsNode.push_back(std::make_pair("", item.createNode())); + } + node.put_child("items", itemsNode); +} + +} // lsp +} // service +} // cc diff --git a/service/lsp/src/lspservice.cpp b/service/lsp/src/lspservice.cpp new file mode 100644 index 000000000..fe922601e --- /dev/null +++ b/service/lsp/src/lspservice.cpp @@ -0,0 +1,282 @@ +#include +#include + +#include + +#include + +namespace cc +{ +namespace service +{ +namespace lsp +{ + +LspServiceHandler::LspServiceHandler( + std::shared_ptr db_, + std::shared_ptr datadir_, + const cc::webserver::ServerContext& context_) + : _db(db_), + _transaction(db_), + _context(context_), + _cppService(db_, datadir_, context_) +{ +} + +std::vector LspServiceHandler::definition( + const TextDocumentPositionParams& params_) +{ + language::AstNodeInfo astNodeInfo; + core::FilePosition cppPosition; + + model::FilePtr file = _transaction([&, this](){ + return _db->query_one( + odb::query::path == params_.textDocument.uri); + }); + + if (!file) + return std::vector(); + + cppPosition.file = std::to_string(file->id); + cppPosition.pos.line = params_.position.line; + cppPosition.pos.column = params_.position.character; + + _cppService.getAstNodeInfoByPosition(astNodeInfo, cppPosition); + + std::vector definitionInfo; + _cppService.getReferences(definitionInfo, astNodeInfo.id, language::CppServiceHandler::DEFINITION, {}); + + std::vector definitionLocations(definitionInfo.size()); + std::transform( + definitionInfo.begin(), definitionInfo.end(), + definitionLocations.begin(), + [&, this](const language::AstNodeInfo& definition) + { + std::string path = _transaction([&, this](){ + return _db->load(std::stoull(definition.range.file))->path; + }); + + Location location; + location.uri = path; + location.range.start.line = definition.range.range.startpos.line; + location.range.start.character = definition.range.range.startpos.column; + location.range.end.line = definition.range.range.endpos.line; + location.range.end.character = definition.range.range.endpos.column; + + return location; + }); + + return definitionLocations; +} + +std::vector LspServiceHandler::references( + const ReferenceParams& params_) +{ + language::AstNodeInfo astNodeInfo; + core::FilePosition cppPosition; + + model::FilePtr file = _transaction([&, this]() + { + return _db->query_one( + odb::query::path == params_.textDocument.uri); + }); + + if (!file) + return std::vector(); + + cppPosition.file = std::to_string(file->id); + cppPosition.pos.line = params_.position.line; + cppPosition.pos.column = params_.position.character; + + _cppService.getAstNodeInfoByPosition(astNodeInfo, cppPosition); + + //--- Usages ---// + std::vector usageInfo; + _cppService.getReferences(usageInfo, astNodeInfo.id, language::CppServiceHandler::USAGE, {}); + + std::vector usageLocations(usageInfo.size()); + std::transform( + usageInfo.begin(), usageInfo.end(), + usageLocations.begin(), + [&, this](const language::AstNodeInfo &usage) + { + std::string path = _transaction([&, this]() + { + return _db->load(std::stoull(usage.range.file))->path; + }); + + Location location; + location.uri = path; + location.range.start.line = usage.range.range.startpos.line; + location.range.start.character = usage.range.range.startpos.column; + location.range.end.line = usage.range.range.endpos.line; + location.range.end.character = usage.range.range.endpos.column; + + return location; + }); + + if (!params_.context.includeDeclaration) + { + return usageLocations; + } + + //--- Declarations ---// + std::vector declarationInfo; + _cppService.getReferences(declarationInfo, astNodeInfo.id, language::CppServiceHandler::DECLARATION, {}); + + std::vector declarationLocations(declarationInfo.size()); + std::transform( + declarationInfo.begin(), declarationInfo.end(), + declarationLocations.begin(), + [&, this](const language::AstNodeInfo &declaration) + { + std::string path = _transaction([&, this]() + { + return _db->load(std::stoull(declaration.range.file))->path; + }); + + Location location; + location.uri = path; + location.range.start.line = declaration.range.range.startpos.line; + location.range.start.character = declaration.range.range.startpos.column; + location.range.end.line = declaration.range.range.endpos.line; + location.range.end.character = declaration.range.range.endpos.column; + + return location; + }); + + usageLocations.insert(usageLocations.end(), + std::make_move_iterator(declarationLocations.begin()), + std::make_move_iterator(declarationLocations.end())); + return usageLocations; +} + +CompletionList LspServiceHandler::fileDiagramTypes( + const DiagramTypeParams& params_) +{ + model::FilePtr file = _transaction([&, this](){ + return _db->query_one( + odb::query::path == params_.textDocument.uri); + }); + + if (!file) + return CompletionList(); + + std::map result; + _cppService.getFileDiagramTypes(result, std::to_string(file->id)); + + std::vector diagramTypes(result.size()); + std::transform(result.begin(), result.end(), diagramTypes.begin(), + [](std::pair item) + { + CompletionItem ci; + ci.label = item.first; + ci.data = std::to_string(item.second); + return ci; + } + ); + + CompletionList list; + list.isIncomplete = false; + list.items = diagramTypes; + return list; +} + +CompletionList LspServiceHandler::nodeDiagramTypes( + const DiagramTypeParams& params_) +{ + language::AstNodeInfo astNodeInfo; + core::FilePosition cppPosition; + + model::FilePtr file = _transaction([&, this](){ + return _db->query_one( + odb::query::path == params_.textDocument.uri); + }); + + if (!file) + return CompletionList(); + + cppPosition.file = std::to_string(file->id); + cppPosition.pos.line = params_.position->line; + cppPosition.pos.column = params_.position->character; + _cppService.getAstNodeInfoByPosition(astNodeInfo, cppPosition); + + std::map result; + _cppService.getDiagramTypes(result, astNodeInfo.id); + + std::vector diagramTypes(result.size()); + std::transform(result.begin(), result.end(), diagramTypes.begin(), + [](std::pair item) + { + CompletionItem ci; + ci.label = item.first; + ci.data = std::to_string(item.second); + return ci; + } + ); + + CompletionList list; + list.isIncomplete = false; + list.items = diagramTypes; + return list; +} + +Diagram LspServiceHandler::fileDiagram( + const DiagramParams& params_) +{ + model::FilePtr file = _transaction([&, this](){ + return _db->query_one( + odb::query::path == params_.textDocument.uri); + }); + + if (!file) + return std::string(); + + std::map diagramTypes; + _cppService.getFileDiagramTypes(diagramTypes, std::to_string(file->id)); + + auto diagramTypeIt = diagramTypes.find(params_.diagramType); + if(diagramTypeIt == diagramTypes.end()) + return std::string(); + + Diagram diagram; + _cppService.getFileDiagram(diagram, std::to_string(file->id), diagramTypeIt->second); + return diagram; +} + +Diagram LspServiceHandler::nodeDiagram( + const DiagramParams& params_) +{ + language::AstNodeInfo astNodeInfo; + core::FilePosition cppPosition; + + model::FilePtr file = _transaction([&, this](){ + return _db->query_one( + odb::query::path == params_.textDocument.uri); + }); + + if (!file) + return std::string(); + + cppPosition.file = std::to_string(file->id); + cppPosition.pos.line = params_.position->line; + cppPosition.pos.column = params_.position->character; + + _cppService.getAstNodeInfoByPosition(astNodeInfo, cppPosition); + + std::map diagramTypes; + _cppService.getDiagramTypes(diagramTypes, astNodeInfo.id); + + auto diagramTypeIt = diagramTypes.find(params_.diagramType); + if(diagramTypeIt == diagramTypes.end()) + return std::string(); + + Diagram diagram; + _cppService.getDiagram(diagram, astNodeInfo.id, diagramTypeIt->second); + + return diagram; +} + +} // lsp +} // service +} // cc diff --git a/service/lsp/src/plugin.cpp b/service/lsp/src/plugin.cpp new file mode 100644 index 000000000..97be269df --- /dev/null +++ b/service/lsp/src/plugin.cpp @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" +extern "C" +{ + boost::program_options::options_description getOptions() + { + boost::program_options::options_description description("LSP Plugin"); + + return description; + } + + void registerPlugin( + const cc::webserver::ServerContext& context_, + cc::webserver::PluginHandler* pluginHandler_) + { + std::shared_ptr handler( + new cc::webserver::LspHandler(context_)); + + pluginHandler_->registerImplementation("LspService", handler); + } +} +#pragma clang diagnostic pop diff --git a/webserver/CMakeLists.txt b/webserver/CMakeLists.txt index 534f4a341..598ab471c 100644 --- a/webserver/CMakeLists.txt +++ b/webserver/CMakeLists.txt @@ -1,3 +1,6 @@ +include_directories(SYSTEM + ${THRIFT_LIBTHRIFT_INCLUDE_DIRS}) + add_subdirectory(authenticators) add_executable(CodeCompass_webserver @@ -6,7 +9,8 @@ add_executable(CodeCompass_webserver src/mainrequesthandler.cpp src/session.cpp src/sessionmanager.cpp - src/threadedmongoose.cpp) + src/threadedmongoose.cpp + src/lsphandler.cpp) set_target_properties(CodeCompass_webserver PROPERTIES ENABLE_EXPORTS 1) @@ -20,16 +24,28 @@ target_link_libraries(mongoose PRIVATE ssl) target_include_directories(CodeCompass_webserver PUBLIC include ${PROJECT_SOURCE_DIR}/model/include - ${PROJECT_SOURCE_DIR}/util/include) + ${PROJECT_SOURCE_DIR}/util/include + ${PROJECT_SOURCE_DIR}/service/lsp/include + ${PROJECT_BINARY_DIR}/service/language/gen-cpp + ${PROJECT_BINARY_DIR}/service/project/gen-cpp + ${PROJECT_SOURCE_DIR}/service/project/include + ${PROJECT_SOURCE_DIR}/plugins/cpp/service/include + ${PROJECT_SOURCE_DIR}/plugins/cpp/model/include) target_link_libraries(CodeCompass_webserver util + lspservice + cppservice mongoose ${Boost_LIBRARIES} ${ODB_LIBRARIES} + ${THRIFT_LIBTHRIFT_LIBRARIES} pthread dl) +add_dependencies(CodeCompass_webserver projectthrift) +add_dependencies(CodeCompass_webserver languagethrift) + install(TARGETS CodeCompass_webserver RUNTIME DESTINATION ${INSTALL_BIN_DIR} LIBRARY DESTINATION ${INSTALL_LIB_DIR}) diff --git a/webserver/include/webserver/lsphandler.h b/webserver/include/webserver/lsphandler.h new file mode 100644 index 000000000..ba7a23887 --- /dev/null +++ b/webserver/include/webserver/lsphandler.h @@ -0,0 +1,63 @@ +#ifndef CC_WEBSERVER_LSPHANDLER_H +#define CC_WEBSERVER_LSPHANDLER_H + +#include + +#include + +#include "requesthandler.h" + +namespace cc +{ +namespace webserver +{ + +class LspHandler : public RequestHandler +{ +public: + LspHandler(const ServerContext& ctx_); + + std::string key() const override + { + return "LspHandler"; + } + + int beginRequest(struct mg_connection *conn_) override; + +private: + /** + * Support methods of the Language Server Protocol. + */ + enum class LspMethod + { + Unknown = 0, + Definition, + References, + DiagramTypes, + Diagram + }; + + /** + * Maps a JSON RPC method (string) to inner representation (LspMethod). + * @param method The method as JSON RPC method string. + * @return The matching LspMethod value. + */ + static LspMethod parseMethod(const std::string& method); + + inline std::string getContent(mg_connection* conn_) + { + return std::string(conn_->content, conn_->content + conn_->content_len); + } + + /** + * A mapping from JSON RPC method (string) to inner representation (LspMethod). + */ + static std::unordered_map _methodMap; + + std::shared_ptr _service; +}; + +} // webserver +} // cc + +#endif diff --git a/webserver/src/lsphandler.cpp b/webserver/src/lsphandler.cpp new file mode 100644 index 000000000..244620aea --- /dev/null +++ b/webserver/src/lsphandler.cpp @@ -0,0 +1,245 @@ +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace cc +{ +namespace webserver +{ + +using namespace service::lsp; + +namespace fs = boost::filesystem; +namespace pt = boost::property_tree; + +std::unordered_map LspHandler::_methodMap = { + { "textDocument/definition", LspHandler::LspMethod::Definition }, + { "textDocument/references", LspHandler::LspMethod::References }, + { "diagram/diagramTypes", LspHandler::LspMethod::DiagramTypes }, + { "diagram/diagram", LspHandler::LspMethod::Diagram}, +}; + +LspHandler::LspHandler(const ServerContext& ctx_) +{ + for (fs::directory_iterator it(ctx_.options["workspace"].as()); + it != fs::directory_iterator(); + ++it) + { + std::string project = it->path().filename().native(); + + fs::path projectInfo = it->path(); + projectInfo += "/project_info.json"; + pt::ptree root; + pt::read_json(projectInfo.native(), root); + + std::string dbName = root.get("database", ""); + if (dbName.empty()) + dbName = project; + + // LOG(info)<(), + // "database", + // dbName); + + std::shared_ptr db = util::connectDatabase(dbName); + + if (!db) + { + LOG(error) + << "[LSP] Wrong connection string: '" << dbName << "'"; + + throw std::runtime_error("Wrong database!"); + } + + auto datadir = std::make_shared(fs::canonical(it->path()).native()); + _service = std::make_shared(db, datadir, ctx_); + } +} + +int LspHandler::beginRequest(struct mg_connection *conn_) +{ + pt::ptree responseTree; + responseTree.put("jsonrpc", "2.0"); + + try + { + std::string request = getContent(conn_); + LOG(debug) << "[LSP] Request content:\n" << request; + + pt::ptree requestTree; + std::stringstream requestStream(request); + pt::read_json(requestStream, requestTree); + + std::string requestId = requestTree.get("id"); + responseTree.put("id", requestId); + + std::string method = requestTree.get("method"); + pt::ptree& params = requestTree.get_child("params"); + + switch (parseMethod(method)) + { + case LspMethod::Definition: + { + TextDocumentPositionParams gotoDefParams; + gotoDefParams.readNode(params); + + std::vector gotoDefLocations = + _service->definition(gotoDefParams); + + if (gotoDefLocations.size() == 1) + { + responseTree.put_child("result", gotoDefLocations[0].createNode()); + } + else if (gotoDefLocations.size() > 1) + { + pt::ptree resultNode; + for (const Location &location : gotoDefLocations) + { + resultNode.push_back(std::make_pair("", location.createNode())); + } + responseTree.put_child("result", resultNode); + } + break; + } + case LspMethod::References: + { + ReferenceParams refParams; + refParams.readNode(params); + + std::vector refLocations = _service->references(refParams); + + pt::ptree resultNode; + for (const Location& location : refLocations) + { + resultNode.push_back(std::make_pair("", location.createNode())); + } + responseTree.put_child("result", resultNode); + break; + } + case LspMethod::DiagramTypes: + { + DiagramTypeParams diagramTypeParams; + diagramTypeParams.readNode(params); + + CompletionList diagramTypesResult; + if (!diagramTypeParams.position) + { + diagramTypesResult = _service->fileDiagramTypes(diagramTypeParams); + } + else + { + diagramTypesResult = _service->nodeDiagramTypes(diagramTypeParams); + } + + responseTree.put_child("result", diagramTypesResult.createNode()); + break; + } + case LspMethod::Diagram: + { + DiagramParams diagramParams; + diagramParams.readNode(params); + + Diagram diagramResult; + if (!diagramParams.position) + { + diagramResult = _service->fileDiagram(diagramParams); + } + else + { + diagramResult = _service->nodeDiagram(diagramParams); + } + + responseTree.put("result", diagramResult); + break; + } + default: + { + LOG(warning) << "[LSP] Unsupported method: '" << method << "'"; + + ResponseError error; + error.code = ErrorCode::MethodNotFound; + error.message = std::string("Unsupported method: ").append(method); + responseTree.put_child("error", error.createNode()); + } + } + } + catch (const pt::ptree_error& ex) + { + LOG(warning) << ex.what(); + + ResponseError error; + error.code = ErrorCode::ParseError; + error.message = std::string("JSON RPC parsing error: ").append(ex.what()); + responseTree.put_child("error", error.createNode()); + } + catch (const std::exception& ex) + { + LOG(warning) << ex.what(); + + ResponseError error; + error.code = ErrorCode::InternalError; + error.message = ex.what(); + responseTree.put_child("error", error.createNode()); + } + catch (...) + { + LOG(warning) << "Unknown exception has been caught"; + + ResponseError error; + error.code = ErrorCode::UnknownError; + responseTree.put_child("error", error.createNode()); + } + + try + { + std::stringstream responseStream; + pt::write_json(responseStream, responseTree); + std::string response = responseStream.str(); + LOG(debug) << "[LSP] Response content:\n" << response << std::endl; + + // Send HTTP reply to the client create headers + mg_send_header(conn_, "Content-Type", "application/json"); + mg_send_header( + conn_, "Content-Length", std::to_string(response.length()).c_str()); + + // Terminate headers + mg_write(conn_, "\r\n", 2); + + // Send content + mg_write(conn_, response.c_str(), response.length()); + } + catch (const std::exception& ex) + { + LOG(warning) << ex.what(); + } + catch (...) + { + LOG(warning) << "Unknown exception has been caught"; + } + + // Returning non-zero tells mongoose that our function has replied to + // the client, and mongoose should not send client any more data. + return MG_TRUE; +} + +LspHandler::LspMethod LspHandler::parseMethod(const std::string& method) +{ + auto it = _methodMap.find(method); + if (it != _methodMap.end()) + return it->second; + return LspMethod::Unknown; +} +} // webserver +} // cc From 16cc347251362020d86cb4ca89d907eae7271131 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Sun, 19 Feb 2023 21:52:25 +0100 Subject: [PATCH 02/26] Add position data to function call diagram as tooltip --- plugins/cpp/service/src/diagram.cpp | 22 ++++++++++++++++++++++ plugins/cpp/service/src/diagram.h | 13 +++++++++++++ 2 files changed, 35 insertions(+) diff --git a/plugins/cpp/service/src/diagram.cpp b/plugins/cpp/service/src/diagram.cpp index 4a241c1ef..85a63a187 100644 --- a/plugins/cpp/service/src/diagram.cpp +++ b/plugins/cpp/service/src/diagram.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -195,6 +197,7 @@ void Diagram::getFunctionCallDiagram( util::Graph::Node centerNode = addNode(graph_, nodes.front()); decorateNode(graph_, centerNode, centerNodeDecoration); + setNodeTooltip(graph_, centerNode, nodes.front()); visitedNodes[astNodeId_] = centerNode; //--- Callees ---// @@ -211,6 +214,7 @@ void Diagram::getFunctionCallDiagram( { calleeNode = addNode(graph_, node); decorateNode(graph_, calleeNode, calleeNodeDecoration); + setNodeTooltip(graph_, calleeNode, node); visitedNodes.insert(it, std::make_pair(node.id, calleeNode)); } else @@ -237,6 +241,7 @@ void Diagram::getFunctionCallDiagram( { callerNode = addNode(graph_, node); decorateNode(graph_, callerNode, callerNodeDecoration); + setNodeTooltip(graph_, callerNode, node); visitedNodes.insert(it, std::make_pair(node.id, callerNode)); } else @@ -506,6 +511,23 @@ void Diagram::decorateNode( graph_.setNodeAttribute(node_, attr.first, attr.second); } +void Diagram::setNodeTooltip( + util::Graph& graph_, + const util::Graph::Node& node_, + const AstNodeInfo& info_) +{ + std::stringstream ss; + ss<<_cppHandler._transaction([&, this](){ + return _cppHandler._db->load(std::stoull(info_.range.file))->path; + }) + <<';' + < Date: Sat, 25 Feb 2023 17:51:07 +0100 Subject: [PATCH 03/26] Add position data to all diagrams as tooltip --- plugins/cpp/service/src/diagram.cpp | 31 +++++++++---------------- plugins/cpp/service/src/diagram.h | 13 ----------- plugins/cpp/service/src/filediagram.cpp | 3 ++- 3 files changed, 13 insertions(+), 34 deletions(-) diff --git a/plugins/cpp/service/src/diagram.cpp b/plugins/cpp/service/src/diagram.cpp index 85a63a187..8f7f340b4 100644 --- a/plugins/cpp/service/src/diagram.cpp +++ b/plugins/cpp/service/src/diagram.cpp @@ -197,7 +197,6 @@ void Diagram::getFunctionCallDiagram( util::Graph::Node centerNode = addNode(graph_, nodes.front()); decorateNode(graph_, centerNode, centerNodeDecoration); - setNodeTooltip(graph_, centerNode, nodes.front()); visitedNodes[astNodeId_] = centerNode; //--- Callees ---// @@ -214,7 +213,6 @@ void Diagram::getFunctionCallDiagram( { calleeNode = addNode(graph_, node); decorateNode(graph_, calleeNode, calleeNodeDecoration); - setNodeTooltip(graph_, calleeNode, node); visitedNodes.insert(it, std::make_pair(node.id, calleeNode)); } else @@ -241,7 +239,6 @@ void Diagram::getFunctionCallDiagram( { callerNode = addNode(graph_, node); decorateNode(graph_, callerNode, callerNodeDecoration); - setNodeTooltip(graph_, callerNode, node); visitedNodes.insert(it, std::make_pair(node.id, callerNode)); } else @@ -430,6 +427,17 @@ util::Graph::Node Diagram::addNode( graph_.setNodeAttribute(node, "label", nodeInfo_.astNodeValue); + std::stringstream ss; + ss<<_cppHandler._transaction([&, this](){ + return _cppHandler._db->load(std::stoull(nodeInfo_.range.file))->path; + }) + <<';' + <load(std::stoull(info_.range.file))->path; - }) - <<';' - < Date: Sun, 12 Mar 2023 21:29:02 +0100 Subject: [PATCH 04/26] Add go to implementation to lsp --- service/lsp/include/lspservice/lspservice.h | 3 ++ service/lsp/src/lspservice.cpp | 46 +++++++++++++++++++++ webserver/include/webserver/lsphandler.h | 1 + webserver/src/lsphandler.cpp | 32 ++++++++++++-- 4 files changed, 78 insertions(+), 4 deletions(-) diff --git a/service/lsp/include/lspservice/lspservice.h b/service/lsp/include/lspservice/lspservice.h index d017e0515..7fbd2b0d5 100644 --- a/service/lsp/include/lspservice/lspservice.h +++ b/service/lsp/include/lspservice/lspservice.h @@ -33,6 +33,9 @@ class LspServiceHandler std::vector references( const ReferenceParams& params_); + std::vector implementation( + const TextDocumentPositionParams& params_); + CompletionList fileDiagramTypes( const DiagramTypeParams& params_); diff --git a/service/lsp/src/lspservice.cpp b/service/lsp/src/lspservice.cpp index fe922601e..548bcb29d 100644 --- a/service/lsp/src/lspservice.cpp +++ b/service/lsp/src/lspservice.cpp @@ -69,6 +69,52 @@ std::vector LspServiceHandler::definition( return definitionLocations; } +std::vector LspServiceHandler::implementation( + const TextDocumentPositionParams& params_) +{ + language::AstNodeInfo astNodeInfo; + core::FilePosition cppPosition; + + model::FilePtr file = _transaction([&, this](){ + return _db->query_one( + odb::query::path == params_.textDocument.uri); + }); + + if (!file) + return std::vector(); + + cppPosition.file = std::to_string(file->id); + cppPosition.pos.line = params_.position.line; + cppPosition.pos.column = params_.position.character; + + _cppService.getAstNodeInfoByPosition(astNodeInfo, cppPosition); + + std::vector implementationInfo; + _cppService.getReferences(implementationInfo, astNodeInfo.id, language::CppServiceHandler::INHERIT_BY, {}); + + std::vector implementationLocations(implementationInfo.size()); + std::transform( + implementationInfo.begin(), implementationInfo.end(), + implementationLocations.begin(), + [&, this](const language::AstNodeInfo& definition) + { + std::string path = _transaction([&, this](){ + return _db->load(std::stoull(definition.range.file))->path; + }); + + Location location; + location.uri = path; + location.range.start.line = definition.range.range.startpos.line; + location.range.start.character = definition.range.range.startpos.column; + location.range.end.line = definition.range.range.endpos.line; + location.range.end.character = definition.range.range.endpos.column; + + return location; + }); + + return implementationLocations; +} + std::vector LspServiceHandler::references( const ReferenceParams& params_) { diff --git a/webserver/include/webserver/lsphandler.h b/webserver/include/webserver/lsphandler.h index ba7a23887..4b8b9c966 100644 --- a/webserver/include/webserver/lsphandler.h +++ b/webserver/include/webserver/lsphandler.h @@ -32,6 +32,7 @@ class LspHandler : public RequestHandler { Unknown = 0, Definition, + Implementation, References, DiagramTypes, Diagram diff --git a/webserver/src/lsphandler.cpp b/webserver/src/lsphandler.cpp index 244620aea..3a4716993 100644 --- a/webserver/src/lsphandler.cpp +++ b/webserver/src/lsphandler.cpp @@ -23,10 +23,11 @@ namespace fs = boost::filesystem; namespace pt = boost::property_tree; std::unordered_map LspHandler::_methodMap = { - { "textDocument/definition", LspHandler::LspMethod::Definition }, - { "textDocument/references", LspHandler::LspMethod::References }, - { "diagram/diagramTypes", LspHandler::LspMethod::DiagramTypes }, - { "diagram/diagram", LspHandler::LspMethod::Diagram}, + { "textDocument/definition", LspHandler::LspMethod::Definition }, + { "textDocument/implementation", LspHandler::LspMethod::Implementation }, + { "textDocument/references", LspHandler::LspMethod::References }, + { "diagram/diagramTypes", LspHandler::LspMethod::DiagramTypes }, + { "diagram/diagram", LspHandler::LspMethod::Diagram}, }; LspHandler::LspHandler(const ServerContext& ctx_) @@ -113,6 +114,29 @@ int LspHandler::beginRequest(struct mg_connection *conn_) } break; } + case LspMethod::Implementation: + { + TextDocumentPositionParams implementationParams; + implementationParams.readNode(params); + + std::vector implementationLocations = + _service->implementation(implementationParams); + + if (implementationLocations.size() == 1) + { + responseTree.put_child("result", implementationLocations[0].createNode()); + } + else if (implementationLocations.size() > 1) + { + pt::ptree resultNode; + for (const Location &location : implementationLocations) + { + resultNode.push_back(std::make_pair("", location.createNode())); + } + responseTree.put_child("result", resultNode); + } + break; + } case LspMethod::References: { ReferenceParams refParams; From b5bb0c5404f843b1d3094115d097f71676572bcd Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Sun, 19 Mar 2023 02:17:20 +0100 Subject: [PATCH 05/26] Move the lsp from services to plugins --- CMakeLists.txt | 2 +- plugins/lsp/CMakeLists.txt | 11 + plugins/lsp/service/CMakeLists.txt | 59 ++++ .../service}/include/lspservice/lsp_types.h | 4 +- .../service}/include/lspservice/lspservice.h | 37 ++- plugins/lsp/service/lsp.thrift | 7 + .../lsp/service}/src/lsp_types.cpp | 0 .../lsp/service}/src/lspservice.cpp | 177 +++++++++++- .../lsp/service}/src/plugin.cpp | 11 +- service/CMakeLists.txt | 1 - service/lsp/CMakeLists.txt | 29 -- webserver/CMakeLists.txt | 3 +- webserver/include/webserver/lsphandler.h | 123 +++++--- webserver/include/webserver/pluginhelper.h | 90 +++++- webserver/include/webserver/thrifthandler.h | 3 +- webserver/src/lsphandler.cpp | 269 ------------------ 16 files changed, 478 insertions(+), 348 deletions(-) create mode 100644 plugins/lsp/CMakeLists.txt create mode 100644 plugins/lsp/service/CMakeLists.txt rename {service/lsp => plugins/lsp/service}/include/lspservice/lsp_types.h (98%) rename {service/lsp => plugins/lsp/service}/include/lspservice/lspservice.h (60%) create mode 100644 plugins/lsp/service/lsp.thrift rename {service/lsp => plugins/lsp/service}/src/lsp_types.cpp (100%) rename {service/lsp => plugins/lsp/service}/src/lspservice.cpp (65%) rename {service/lsp => plugins/lsp/service}/src/plugin.cpp (75%) delete mode 100644 service/lsp/CMakeLists.txt delete mode 100644 webserver/src/lsphandler.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c93f97a2a..d4e81c7d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,10 +28,10 @@ set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH};${RUNENV_LD_LIBRARY_PATH}") add_subdirectory(logger) add_subdirectory(model) add_subdirectory(parser) -add_subdirectory(plugins) # must precede service add_subdirectory(scripts) add_subdirectory(service) add_subdirectory(util) +add_subdirectory(plugins) # must precede webgui add_subdirectory(webgui) add_subdirectory(webserver) diff --git a/plugins/lsp/CMakeLists.txt b/plugins/lsp/CMakeLists.txt new file mode 100644 index 000000000..def947f71 --- /dev/null +++ b/plugins/lsp/CMakeLists.txt @@ -0,0 +1,11 @@ +# The C++ lsp plugin depends on the C++ plugin's components to be built. + +if ("${cpp_PLUGIN_DIR}" STREQUAL "") + # Use SEND_ERROR here so a build file is not generated at the end. + # CodeCompass might use a lot of plugins and produce a lengthy build, so + # a warning at configure time would easily be missed by the users. + message(SEND_ERROR + "C++ LSP plugin found without C++ plugin in the plugins directory.") +endif() + +add_subdirectory(service) diff --git a/plugins/lsp/service/CMakeLists.txt b/plugins/lsp/service/CMakeLists.txt new file mode 100644 index 000000000..a84b8a8f6 --- /dev/null +++ b/plugins/lsp/service/CMakeLists.txt @@ -0,0 +1,59 @@ +include_directories( + include + ${PROJECT_SOURCE_DIR}/model/include + ${PROJECT_BINARY_DIR}/service/language/gen-cpp + ${PROJECT_BINARY_DIR}/service/project/gen-cpp + ${PROJECT_SOURCE_DIR}/service/project/include + ${PROJECT_SOURCE_DIR}/plugins/cpp/service/include + ${PROJECT_SOURCE_DIR}/plugins/cpp/model/include + ${CMAKE_BINARY_DIR}/model/include + ${CMAKE_BINARY_DIR}/plugins/cpp/model/include + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp + ${PROJECT_SOURCE_DIR}/util/include + ${PROJECT_SOURCE_DIR}/webserver/include) + +include_directories(SYSTEM + ${THRIFT_LIBTHRIFT_INCLUDE_DIRS}) + +add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_constants.cpp + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_constants.h + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_types.cpp + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_types.h + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/LspService.cpp + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/LspService.h + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp + COMMAND + ${THRIFT_EXECUTABLE} --gen cpp + -o ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/lsp.thrift + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/lsp.thrift + COMMENT + "Generating Thrift for lsp.thrift") + +add_library(lspthrift STATIC + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_constants.cpp + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_types.cpp + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/LspService.cpp) + +target_compile_options(lspthrift PUBLIC -fPIC) + +include_directories(SYSTEM + ${THRIFT_LIBTHRIFT_INCLUDE_DIRS}) + +add_library(lspservice SHARED + src/lspservice.cpp + src/lsp_types.cpp + src/plugin.cpp) + +target_link_libraries(lspservice + util + lspthrift + ${THRIFT_LIBTHRIFT_LIBRARIES}) + +add_dependencies(lspservice projectthrift) +add_dependencies(lspservice languagethrift) + +install(TARGETS lspservice DESTINATION ${INSTALL_SERVICE_DIR}) \ No newline at end of file diff --git a/service/lsp/include/lspservice/lsp_types.h b/plugins/lsp/service/include/lspservice/lsp_types.h similarity index 98% rename from service/lsp/include/lspservice/lsp_types.h rename to plugins/lsp/service/include/lspservice/lsp_types.h index 792c3e5b6..9ed4b4e1a 100644 --- a/service/lsp/include/lspservice/lsp_types.h +++ b/plugins/lsp/service/include/lspservice/lsp_types.h @@ -145,7 +145,7 @@ struct Range : public Readable, public Writeable /** * Represents a location inside a resource, such as a line inside a text file. */ -struct Location : public Readable, public Writeable +struct Location final : public Readable, public Writeable { DocumentUri uri; Range range; @@ -217,7 +217,7 @@ struct DiagramParams : DiagramTypeParams /** * Represents a possible auto-complete or context menu item. */ -struct CompletionItem : public Readable, public Writeable +struct CompletionItem final : public Readable, public Writeable { /** * The label of this completion item. By default diff --git a/service/lsp/include/lspservice/lspservice.h b/plugins/lsp/service/include/lspservice/lspservice.h similarity index 60% rename from service/lsp/include/lspservice/lspservice.h rename to plugins/lsp/service/include/lspservice/lspservice.h index 7fbd2b0d5..b1e0bf2b1 100644 --- a/service/lsp/include/lspservice/lspservice.h +++ b/plugins/lsp/service/include/lspservice/lspservice.h @@ -1,15 +1,15 @@ #ifndef CC_SERVICE_LSP_LSPSERVICE_H #define CC_SERVICE_LSP_LSPSERVICE_H +#include #include #include - -#include - #include #include +#include "LspService.h" +#include #include namespace cc @@ -19,7 +19,7 @@ namespace service namespace lsp { -class LspServiceHandler +class LspServiceHandler : virtual public LspServiceIf { public: LspServiceHandler( @@ -27,6 +27,8 @@ class LspServiceHandler std::shared_ptr datadir_, const cc::webserver::ServerContext& context_); + virtual void getLspResponse(std::string& _return, const std::string& request) override; + std::vector definition( const TextDocumentPositionParams& params_); @@ -52,8 +54,33 @@ class LspServiceHandler std::shared_ptr _db; util::OdbTransaction _transaction; - const cc::webserver::ServerContext& _context; language::CppServiceHandler _cppService; + + + /** + * Support methods of the Language Server Protocol. + */ + enum class LspMethod + { + Unknown = 0, + Definition, + Implementation, + References, + DiagramTypes, + Diagram + }; + + /** + * Maps a JSON RPC method (string) to inner representation (LspMethod). + * @param method The method as JSON RPC method string. + * @return The matching LspMethod value. + */ + LspMethod parseMethod(const std::string& method); + + /** + * A mapping from JSON RPC method (string) to inner representation (LspMethod). + */ + static std::unordered_map _methodMap; }; } // lsp diff --git a/plugins/lsp/service/lsp.thrift b/plugins/lsp/service/lsp.thrift new file mode 100644 index 000000000..a38b8d5e1 --- /dev/null +++ b/plugins/lsp/service/lsp.thrift @@ -0,0 +1,7 @@ +namespace cpp cc.service.lsp +namespace java cc.service.lsp + +service LspService +{ + string getLspResponse(1: string request) +} \ No newline at end of file diff --git a/service/lsp/src/lsp_types.cpp b/plugins/lsp/service/src/lsp_types.cpp similarity index 100% rename from service/lsp/src/lsp_types.cpp rename to plugins/lsp/service/src/lsp_types.cpp diff --git a/service/lsp/src/lspservice.cpp b/plugins/lsp/service/src/lspservice.cpp similarity index 65% rename from service/lsp/src/lspservice.cpp rename to plugins/lsp/service/src/lspservice.cpp index 548bcb29d..7de708715 100644 --- a/service/lsp/src/lspservice.cpp +++ b/plugins/lsp/service/src/lspservice.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -12,17 +13,183 @@ namespace service namespace lsp { +std::unordered_map LspServiceHandler::_methodMap = { + { "textDocument/definition", LspServiceHandler::LspMethod::Definition }, + { "textDocument/implementation", LspServiceHandler::LspMethod::Implementation }, + { "textDocument/references", LspServiceHandler::LspMethod::References }, + { "diagram/diagramTypes", LspServiceHandler::LspMethod::DiagramTypes }, + { "diagram/diagram", LspServiceHandler::LspMethod::Diagram}, +}; + LspServiceHandler::LspServiceHandler( std::shared_ptr db_, std::shared_ptr datadir_, const cc::webserver::ServerContext& context_) : _db(db_), _transaction(db_), - _context(context_), _cppService(db_, datadir_, context_) { } +void LspServiceHandler::getLspResponse(std::string& _return, const std::string& request) +{ + pt::ptree responseTree; + responseTree.put("jsonrpc", "2.0"); + + try + { + pt::ptree requestTree; + std::stringstream requestStream(request); + pt::read_json(requestStream, requestTree); + + std::string requestId = requestTree.get("id"); + responseTree.put("id", requestId); + + std::string method = requestTree.get("method"); + pt::ptree& params = requestTree.get_child("params"); + + switch (parseMethod(method)) + { + case LspMethod::Definition: + { + TextDocumentPositionParams gotoDefParams; + gotoDefParams.readNode(params); + + std::vector gotoDefLocations = + definition(gotoDefParams); + + if (gotoDefLocations.size() == 1) + { + responseTree.put_child("result", gotoDefLocations[0].createNode()); + } + else if (gotoDefLocations.size() > 1) + { + pt::ptree resultNode; + for (const Location &location : gotoDefLocations) + { + resultNode.push_back(std::make_pair("", location.createNode())); + } + responseTree.put_child("result", resultNode); + } + break; + } + case LspMethod::Implementation: + { + TextDocumentPositionParams implementationParams; + implementationParams.readNode(params); + + std::vector implementationLocations = + implementation(implementationParams); + + if (implementationLocations.size() == 1) + { + responseTree.put_child("result", implementationLocations[0].createNode()); + } + else if (implementationLocations.size() > 1) + { + pt::ptree resultNode; + for (const Location &location : implementationLocations) + { + resultNode.push_back(std::make_pair("", location.createNode())); + } + responseTree.put_child("result", resultNode); + } + break; + } + case LspMethod::References: + { + ReferenceParams refParams; + refParams.readNode(params); + + std::vector refLocations = references(refParams); + + pt::ptree resultNode; + for (const Location& location : refLocations) + { + resultNode.push_back(std::make_pair("", location.createNode())); + } + responseTree.put_child("result", resultNode); + break; + } + case LspMethod::DiagramTypes: + { + DiagramTypeParams diagramTypeParams; + diagramTypeParams.readNode(params); + + CompletionList diagramTypesResult; + if (!diagramTypeParams.position) + { + diagramTypesResult = fileDiagramTypes(diagramTypeParams); + } + else + { + diagramTypesResult = nodeDiagramTypes(diagramTypeParams); + } + + responseTree.put_child("result", diagramTypesResult.createNode()); + break; + } + case LspMethod::Diagram: + { + DiagramParams diagramParams; + diagramParams.readNode(params); + + Diagram diagramResult; + if (!diagramParams.position) + { + diagramResult = fileDiagram(diagramParams); + } + else + { + diagramResult = nodeDiagram(diagramParams); + } + + responseTree.put("result", diagramResult); + break; + } + default: + { + LOG(warning) << "[LSP] Unsupported method: '" << method << "'"; + + ResponseError error; + error.code = ErrorCode::MethodNotFound; + error.message = std::string("Unsupported method: ").append(method); + responseTree.put_child("error", error.createNode()); + } + } + } + catch (const pt::ptree_error& ex) + { + LOG(warning) << ex.what(); + + ResponseError error; + error.code = ErrorCode::ParseError; + error.message = std::string("JSON RPC parsing error: ").append(ex.what()); + responseTree.put_child("error", error.createNode()); + } + catch (const std::exception& ex) + { + LOG(warning) << ex.what(); + + ResponseError error; + error.code = ErrorCode::InternalError; + error.message = ex.what(); + responseTree.put_child("error", error.createNode()); + } + catch (...) + { + LOG(warning) << "Unknown exception has been caught"; + + ResponseError error; + error.code = ErrorCode::UnknownError; + responseTree.put_child("error", error.createNode()); + } + + std::stringstream responseStream; + pt::write_json(responseStream, responseTree); + _return = responseStream.str(); +} + std::vector LspServiceHandler::definition( const TextDocumentPositionParams& params_) { @@ -323,6 +490,14 @@ Diagram LspServiceHandler::nodeDiagram( return diagram; } +LspServiceHandler::LspMethod LspServiceHandler::parseMethod(const std::string& method) +{ + auto it = _methodMap.find(method); + if (it != _methodMap.end()) + return it->second; + return LspMethod::Unknown; +} + } // lsp } // service } // cc diff --git a/service/lsp/src/plugin.cpp b/plugins/lsp/service/src/plugin.cpp similarity index 75% rename from service/lsp/src/plugin.cpp rename to plugins/lsp/service/src/plugin.cpp index 97be269df..f338d44cf 100644 --- a/service/lsp/src/plugin.cpp +++ b/plugins/lsp/service/src/plugin.cpp @@ -1,4 +1,6 @@ +#include "LspService.h" #include +#include #include #include #include @@ -20,10 +22,11 @@ extern "C" const cc::webserver::ServerContext& context_, cc::webserver::PluginHandler* pluginHandler_) { - std::shared_ptr handler( - new cc::webserver::LspHandler(context_)); - - pluginHandler_->registerImplementation("LspService", handler); + cc::webserver::registerLspPluginSimple( + context_, + pluginHandler_, + CODECOMPASS_LSP_SERVICE_FACTORY_WITH_CFG(Lsp, lsp), + "LspService"); } } #pragma clang diagnostic pop diff --git a/service/CMakeLists.txt b/service/CMakeLists.txt index 985f4f5b7..21b32b2ae 100644 --- a/service/CMakeLists.txt +++ b/service/CMakeLists.txt @@ -3,4 +3,3 @@ add_subdirectory(language) add_subdirectory(plugin) add_subdirectory(project) add_subdirectory(workspace) -add_subdirectory(lsp) diff --git a/service/lsp/CMakeLists.txt b/service/lsp/CMakeLists.txt deleted file mode 100644 index d15f0f5a8..000000000 --- a/service/lsp/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -include_directories( - include - ${PROJECT_SOURCE_DIR}/util/include - ${PROJECT_SOURCE_DIR}/webserver/include - ${PROJECT_SOURCE_DIR}/model/include - ${PROJECT_BINARY_DIR}/service/language/gen-cpp - ${PROJECT_BINARY_DIR}/service/project/gen-cpp - ${PROJECT_SOURCE_DIR}/service/project/include - ${PROJECT_SOURCE_DIR}/plugins/cpp/service/include - ${PROJECT_SOURCE_DIR}/plugins/cpp/model/include - ${CMAKE_BINARY_DIR}/model/include - ${CMAKE_BINARY_DIR}/plugins/cpp/model/include) - -include_directories(SYSTEM - ${THRIFT_LIBTHRIFT_INCLUDE_DIRS}) - -add_library(lspservice SHARED - src/lspservice.cpp - src/lsp_types.cpp - src/plugin.cpp) - -target_link_libraries(lspservice - util - ${THRIFT_LIBTHRIFT_LIBRARIES}) - -add_dependencies(lspservice projectthrift) -add_dependencies(lspservice languagethrift) - -install(TARGETS lspservice DESTINATION ${INSTALL_SERVICE_DIR}) \ No newline at end of file diff --git a/webserver/CMakeLists.txt b/webserver/CMakeLists.txt index 598ab471c..3eaae4857 100644 --- a/webserver/CMakeLists.txt +++ b/webserver/CMakeLists.txt @@ -9,8 +9,7 @@ add_executable(CodeCompass_webserver src/mainrequesthandler.cpp src/session.cpp src/sessionmanager.cpp - src/threadedmongoose.cpp - src/lsphandler.cpp) + src/threadedmongoose.cpp) set_target_properties(CodeCompass_webserver PROPERTIES ENABLE_EXPORTS 1) diff --git a/webserver/include/webserver/lsphandler.h b/webserver/include/webserver/lsphandler.h index 4b8b9c966..77f5e8c65 100644 --- a/webserver/include/webserver/lsphandler.h +++ b/webserver/include/webserver/lsphandler.h @@ -1,61 +1,120 @@ #ifndef CC_WEBSERVER_LSPHANDLER_H #define CC_WEBSERVER_LSPHANDLER_H +#include #include -#include +//#include +#include +#include -#include "requesthandler.h" +#include "webserver/thrifthandler.h" + +#include +#include namespace cc { namespace webserver { -class LspHandler : public RequestHandler +template +class LspHandler : public ThriftHandler { public: - LspHandler(const ServerContext& ctx_); - std::string key() const override { return "LspHandler"; } - int beginRequest(struct mg_connection *conn_) override; + template + LspHandler(Handler handler_) + : ThriftHandler(handler_) + { + } -private: - /** - * Support methods of the Language Server Protocol. - */ - enum class LspMethod + template + LspHandler(Handler *handler_) + : ThriftHandler(handler_) { - Unknown = 0, - Definition, - Implementation, - References, - DiagramTypes, - Diagram - }; - - /** - * Maps a JSON RPC method (string) to inner representation (LspMethod). - * @param method The method as JSON RPC method string. - * @return The matching LspMethod value. - */ - static LspMethod parseMethod(const std::string& method); + } - inline std::string getContent(mg_connection* conn_) +int beginRequest(struct mg_connection *conn_) override +{ + using namespace ::apache::thrift; + using namespace ::apache::thrift::transport; + using namespace ::apache::thrift::protocol; + + try { - return std::string(conn_->content, conn_->content + conn_->content_len); + std::string content = getContent(conn_); + LOG(debug) << "[LSP] Request content:\n" << content; + + // Place LSP message into thrift message + boost::replace_all(content, "\"", "\\\""); + std::string request = "[1,\"getLspResponse\",1,0,{\"1\":{\"str\":\"" + content + "\"}}]"; + + std::shared_ptr inputBuffer( + new TMemoryBuffer((std::uint8_t*)request.c_str(), request.length())); + + std::shared_ptr outputBuffer(new TMemoryBuffer(4096)); + + std::shared_ptr inputProtocol( + new TJSONProtocol(inputBuffer)); + std::shared_ptr outputProtocol( + new TJSONProtocol(outputBuffer)); + + typename LspHandler::CallContext ctx{conn_, nullptr}; + LspHandler::_processor.process(inputProtocol, outputProtocol, &ctx); + + TMemoryBuffer *mBuffer = dynamic_cast(outputBuffer.get()); + + std::string response = mBuffer->getBufferAsString(); + + // Get LSP response from thrift + std::regex rgx("\\[1,\"getLspResponse\",2,0,\\{\"0\":\\{\"str\":\"(.*)\"\\}\\}\\]"); + std::smatch match; + std::regex_search(response, match, rgx); + response = match[1]; + + // Remove whitespaces and escape characters + rgx = "\\s*|\\\\n|\\\\"; + response = std::regex_replace(response, rgx, ""); + + LOG(debug) << "[LSP] Response content:\n" << response << std::endl; + + // Send HTTP reply to the client create headers + mg_send_header(conn_, "Content-Type", "application/json"); + mg_send_header( + conn_, "Content-Length", std::to_string(response.length()).c_str()); + + // Terminate headers + mg_write(conn_, "\r\n", 2); + + // Send content + mg_write(conn_, response.c_str(), response.length()); + } + catch (const std::exception& ex) + { + LOG(warning) << ex.what(); } + catch (...) + { + LOG(warning) << "Unknown exception has been caught"; + } + + // Returning non-zero tells mongoose that our function has replied to + // the client, and mongoose should not send client any more data. + return MG_TRUE; +} - /** - * A mapping from JSON RPC method (string) to inner representation (LspMethod). - */ - static std::unordered_map _methodMap; - std::shared_ptr _service; + +private: + inline std::string getContent(mg_connection* conn_) + { + return std::string(conn_->content, conn_->content + conn_->content_len); + } }; } // webserver diff --git a/webserver/include/webserver/pluginhelper.h b/webserver/include/webserver/pluginhelper.h index 4096c45f5..8cb9e1232 100644 --- a/webserver/include/webserver/pluginhelper.h +++ b/webserver/include/webserver/pluginhelper.h @@ -16,7 +16,7 @@ #include #include "requesthandler.h" -#include "thrifthandler.h" +#include "lsphandler.h" namespace cc { @@ -105,6 +105,84 @@ inline void registerPluginSimple( "There are no parsed projects in the given workspace directory."); } +template +inline void registerLspPluginSimple( + const ServerContext& ctx_, + PluginHandler* pluginHandler_, + ServiceFactoryT serviceFactory_, + const std::string& serviceName_) +{ + namespace fs = boost::filesystem; + namespace pt = boost::property_tree; + + for (fs::directory_iterator it(ctx_.options["workspace"].as()); + it != fs::directory_iterator(); + ++it) + { + std::string project = it->path().filename().native(); + + fs::path projectInfo = it->path(); + if ( fs::is_regular_file( projectInfo) ) + continue; + + projectInfo += "/project_info.json"; + if (!fs::exists(projectInfo.native())) + { + LOG(error) + << "Skip project '" << project << "', because no project info file " + << "can be found at: " << projectInfo; + continue; + } + + pt::ptree root; + pt::read_json(projectInfo.native(), root); + + std::string connStr = root.get("database", ""); + if (connStr.empty()) { + LOG(error) + << "Skip project '" << project << "', because no database " + << "connection string can be found for it in the '" + << projectInfo << "' file!"; + continue; + } + + std::shared_ptr db = util::connectDatabase(connStr); + + if (!db) + { + LOG(error) + << "Wrong connection string: '" << connStr << "' " + << "for project: '" << project << "' " + << "for service: '" << serviceName_ << "'"; + + continue; + } + + try + { + // Create handler + std::shared_ptr servicePtr( + serviceFactory_( + db, + std::make_shared(fs::canonical(it->path()).native()), + ctx_)); + + // Register implementation + pluginHandler_->registerImplementation(serviceName_, servicePtr); + } + catch (const util::ServiceNotAvailException& ex) + { + LOG(warning) + << "Exception: " << ex.what() + << " in workspace " << project; + } + } + + if (pluginHandler_->getImplementationMap().empty()) + throw std::runtime_error( + "There are no parsed projects in the given workspace directory."); +} + #define CODECOMPASS_SERVICE_FACTORY_WITH_CFG(serviceName, nspace) \ [](std::shared_ptr& db_, \ std::shared_ptr datadir_, \ @@ -115,6 +193,16 @@ inline void registerPluginSimple( db_, datadir_, ctx_)); \ } +#define CODECOMPASS_LSP_SERVICE_FACTORY_WITH_CFG(serviceName, nspace) \ + [](std::shared_ptr& db_, \ + std::shared_ptr datadir_, \ + const cc::webserver::ServerContext& ctx_) { \ + return new cc::webserver::LspHandler< \ + cc::service::nspace::serviceName##ServiceProcessor>( \ + new cc::service::nspace::serviceName##ServiceHandler( \ + db_, datadir_, ctx_)); \ + } + #define CODECOMPASS_LANGUAGE_SERVICE_FACTORY_WITH_CFG(serviceName) \ [](std::shared_ptr& db_, \ std::shared_ptr datadir_, \ diff --git a/webserver/include/webserver/thrifthandler.h b/webserver/include/webserver/thrifthandler.h index 173e850db..32924cc10 100644 --- a/webserver/include/webserver/thrifthandler.h +++ b/webserver/include/webserver/thrifthandler.h @@ -12,6 +12,7 @@ #include #include "mongoose.h" +#include "webserver/requesthandler.h" namespace cc { @@ -136,7 +137,7 @@ class ThriftHandler : public RequestHandler return MG_TRUE; } -private: +protected: LoggingProcessor _processor; }; diff --git a/webserver/src/lsphandler.cpp b/webserver/src/lsphandler.cpp deleted file mode 100644 index 3a4716993..000000000 --- a/webserver/src/lsphandler.cpp +++ /dev/null @@ -1,269 +0,0 @@ -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include - -namespace cc -{ -namespace webserver -{ - -using namespace service::lsp; - -namespace fs = boost::filesystem; -namespace pt = boost::property_tree; - -std::unordered_map LspHandler::_methodMap = { - { "textDocument/definition", LspHandler::LspMethod::Definition }, - { "textDocument/implementation", LspHandler::LspMethod::Implementation }, - { "textDocument/references", LspHandler::LspMethod::References }, - { "diagram/diagramTypes", LspHandler::LspMethod::DiagramTypes }, - { "diagram/diagram", LspHandler::LspMethod::Diagram}, -}; - -LspHandler::LspHandler(const ServerContext& ctx_) -{ - for (fs::directory_iterator it(ctx_.options["workspace"].as()); - it != fs::directory_iterator(); - ++it) - { - std::string project = it->path().filename().native(); - - fs::path projectInfo = it->path(); - projectInfo += "/project_info.json"; - pt::ptree root; - pt::read_json(projectInfo.native(), root); - - std::string dbName = root.get("database", ""); - if (dbName.empty()) - dbName = project; - - // LOG(info)<(), - // "database", - // dbName); - - std::shared_ptr db = util::connectDatabase(dbName); - - if (!db) - { - LOG(error) - << "[LSP] Wrong connection string: '" << dbName << "'"; - - throw std::runtime_error("Wrong database!"); - } - - auto datadir = std::make_shared(fs::canonical(it->path()).native()); - _service = std::make_shared(db, datadir, ctx_); - } -} - -int LspHandler::beginRequest(struct mg_connection *conn_) -{ - pt::ptree responseTree; - responseTree.put("jsonrpc", "2.0"); - - try - { - std::string request = getContent(conn_); - LOG(debug) << "[LSP] Request content:\n" << request; - - pt::ptree requestTree; - std::stringstream requestStream(request); - pt::read_json(requestStream, requestTree); - - std::string requestId = requestTree.get("id"); - responseTree.put("id", requestId); - - std::string method = requestTree.get("method"); - pt::ptree& params = requestTree.get_child("params"); - - switch (parseMethod(method)) - { - case LspMethod::Definition: - { - TextDocumentPositionParams gotoDefParams; - gotoDefParams.readNode(params); - - std::vector gotoDefLocations = - _service->definition(gotoDefParams); - - if (gotoDefLocations.size() == 1) - { - responseTree.put_child("result", gotoDefLocations[0].createNode()); - } - else if (gotoDefLocations.size() > 1) - { - pt::ptree resultNode; - for (const Location &location : gotoDefLocations) - { - resultNode.push_back(std::make_pair("", location.createNode())); - } - responseTree.put_child("result", resultNode); - } - break; - } - case LspMethod::Implementation: - { - TextDocumentPositionParams implementationParams; - implementationParams.readNode(params); - - std::vector implementationLocations = - _service->implementation(implementationParams); - - if (implementationLocations.size() == 1) - { - responseTree.put_child("result", implementationLocations[0].createNode()); - } - else if (implementationLocations.size() > 1) - { - pt::ptree resultNode; - for (const Location &location : implementationLocations) - { - resultNode.push_back(std::make_pair("", location.createNode())); - } - responseTree.put_child("result", resultNode); - } - break; - } - case LspMethod::References: - { - ReferenceParams refParams; - refParams.readNode(params); - - std::vector refLocations = _service->references(refParams); - - pt::ptree resultNode; - for (const Location& location : refLocations) - { - resultNode.push_back(std::make_pair("", location.createNode())); - } - responseTree.put_child("result", resultNode); - break; - } - case LspMethod::DiagramTypes: - { - DiagramTypeParams diagramTypeParams; - diagramTypeParams.readNode(params); - - CompletionList diagramTypesResult; - if (!diagramTypeParams.position) - { - diagramTypesResult = _service->fileDiagramTypes(diagramTypeParams); - } - else - { - diagramTypesResult = _service->nodeDiagramTypes(diagramTypeParams); - } - - responseTree.put_child("result", diagramTypesResult.createNode()); - break; - } - case LspMethod::Diagram: - { - DiagramParams diagramParams; - diagramParams.readNode(params); - - Diagram diagramResult; - if (!diagramParams.position) - { - diagramResult = _service->fileDiagram(diagramParams); - } - else - { - diagramResult = _service->nodeDiagram(diagramParams); - } - - responseTree.put("result", diagramResult); - break; - } - default: - { - LOG(warning) << "[LSP] Unsupported method: '" << method << "'"; - - ResponseError error; - error.code = ErrorCode::MethodNotFound; - error.message = std::string("Unsupported method: ").append(method); - responseTree.put_child("error", error.createNode()); - } - } - } - catch (const pt::ptree_error& ex) - { - LOG(warning) << ex.what(); - - ResponseError error; - error.code = ErrorCode::ParseError; - error.message = std::string("JSON RPC parsing error: ").append(ex.what()); - responseTree.put_child("error", error.createNode()); - } - catch (const std::exception& ex) - { - LOG(warning) << ex.what(); - - ResponseError error; - error.code = ErrorCode::InternalError; - error.message = ex.what(); - responseTree.put_child("error", error.createNode()); - } - catch (...) - { - LOG(warning) << "Unknown exception has been caught"; - - ResponseError error; - error.code = ErrorCode::UnknownError; - responseTree.put_child("error", error.createNode()); - } - - try - { - std::stringstream responseStream; - pt::write_json(responseStream, responseTree); - std::string response = responseStream.str(); - LOG(debug) << "[LSP] Response content:\n" << response << std::endl; - - // Send HTTP reply to the client create headers - mg_send_header(conn_, "Content-Type", "application/json"); - mg_send_header( - conn_, "Content-Length", std::to_string(response.length()).c_str()); - - // Terminate headers - mg_write(conn_, "\r\n", 2); - - // Send content - mg_write(conn_, response.c_str(), response.length()); - } - catch (const std::exception& ex) - { - LOG(warning) << ex.what(); - } - catch (...) - { - LOG(warning) << "Unknown exception has been caught"; - } - - // Returning non-zero tells mongoose that our function has replied to - // the client, and mongoose should not send client any more data. - return MG_TRUE; -} - -LspHandler::LspMethod LspHandler::parseMethod(const std::string& method) -{ - auto it = _methodMap.find(method); - if (it != _methodMap.end()) - return it->second; - return LspMethod::Unknown; -} -} // webserver -} // cc From 5dadeade384f4ff9fca108a84ef9c1faa41fa227 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Sun, 19 Mar 2023 22:23:57 +0100 Subject: [PATCH 06/26] Fix thrift to lsp conversion for graphs --- webserver/include/webserver/lsphandler.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/webserver/include/webserver/lsphandler.h b/webserver/include/webserver/lsphandler.h index 77f5e8c65..560736c51 100644 --- a/webserver/include/webserver/lsphandler.h +++ b/webserver/include/webserver/lsphandler.h @@ -77,9 +77,12 @@ int beginRequest(struct mg_connection *conn_) override std::regex_search(response, match, rgx); response = match[1]; - // Remove whitespaces and escape characters - rgx = "\\s*|\\\\n|\\\\"; - response = std::regex_replace(response, rgx, ""); + // Remove escape characters + boost::replace_all(response, "\\\\n", ""); + boost::replace_all(response, "\\n", ""); + boost::replace_all(response, "\\\"", "\""); + boost::replace_all(response, "\\\\/", "/"); + boost::replace_all(response, "\\\\\"", "\\\""); LOG(debug) << "[LSP] Response content:\n" << response << std::endl; From 538e62760ab7a6a212425ea1df7825fd5bd99977 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Wed, 22 Mar 2023 20:10:08 +0100 Subject: [PATCH 07/26] Renaming lsp service to cpp lsp service --- plugins/{lsp => cpp_lsp}/CMakeLists.txt | 0 .../{lsp => cpp_lsp}/service/CMakeLists.txt | 16 ++++----- .../include/cpplspservice/cpplspservice.h} | 14 ++++---- .../include/cpplspservice}/lsp_types.h | 0 plugins/{lsp => cpp_lsp}/service/lsp.thrift | 2 +- .../service/src/cpplspservice.cpp} | 34 +++++++++---------- .../service/src/lsp_types.cpp | 2 +- .../{lsp => cpp_lsp}/service/src/plugin.cpp | 4 +-- service/CMakeLists.txt | 1 + 9 files changed, 37 insertions(+), 36 deletions(-) rename plugins/{lsp => cpp_lsp}/CMakeLists.txt (100%) rename plugins/{lsp => cpp_lsp}/service/CMakeLists.txt (80%) rename plugins/{lsp/service/include/lspservice/lspservice.h => cpp_lsp/service/include/cpplspservice/cpplspservice.h} (86%) rename plugins/{lsp/service/include/lspservice => cpp_lsp/service/include/cpplspservice}/lsp_types.h (100%) rename plugins/{lsp => cpp_lsp}/service/lsp.thrift (82%) rename plugins/{lsp/service/src/lspservice.cpp => cpp_lsp/service/src/cpplspservice.cpp} (92%) rename plugins/{lsp => cpp_lsp}/service/src/lsp_types.cpp (99%) rename plugins/{lsp => cpp_lsp}/service/src/plugin.cpp (88%) diff --git a/plugins/lsp/CMakeLists.txt b/plugins/cpp_lsp/CMakeLists.txt similarity index 100% rename from plugins/lsp/CMakeLists.txt rename to plugins/cpp_lsp/CMakeLists.txt diff --git a/plugins/lsp/service/CMakeLists.txt b/plugins/cpp_lsp/service/CMakeLists.txt similarity index 80% rename from plugins/lsp/service/CMakeLists.txt rename to plugins/cpp_lsp/service/CMakeLists.txt index a84b8a8f6..08f2a076c 100644 --- a/plugins/lsp/service/CMakeLists.txt +++ b/plugins/cpp_lsp/service/CMakeLists.txt @@ -21,8 +21,8 @@ add_custom_command( ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_constants.h ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_types.cpp ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_types.h - ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/LspService.cpp - ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/LspService.h + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/CppLspService.cpp + ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/CppLspService.h ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp COMMAND ${THRIFT_EXECUTABLE} --gen cpp @@ -43,17 +43,17 @@ target_compile_options(lspthrift PUBLIC -fPIC) include_directories(SYSTEM ${THRIFT_LIBTHRIFT_INCLUDE_DIRS}) -add_library(lspservice SHARED - src/lspservice.cpp +add_library(cpplspservice SHARED + src/cpplspservice.cpp src/lsp_types.cpp src/plugin.cpp) -target_link_libraries(lspservice +target_link_libraries(cpplspservice util lspthrift ${THRIFT_LIBTHRIFT_LIBRARIES}) -add_dependencies(lspservice projectthrift) -add_dependencies(lspservice languagethrift) +add_dependencies(cpplspservice projectthrift) +add_dependencies(cpplspservice languagethrift) -install(TARGETS lspservice DESTINATION ${INSTALL_SERVICE_DIR}) \ No newline at end of file +install(TARGETS cpplspservice DESTINATION ${INSTALL_SERVICE_DIR}) \ No newline at end of file diff --git a/plugins/lsp/service/include/lspservice/lspservice.h b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h similarity index 86% rename from plugins/lsp/service/include/lspservice/lspservice.h rename to plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h index b1e0bf2b1..9aff5ceef 100644 --- a/plugins/lsp/service/include/lspservice/lspservice.h +++ b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h @@ -1,5 +1,5 @@ -#ifndef CC_SERVICE_LSP_LSPSERVICE_H -#define CC_SERVICE_LSP_LSPSERVICE_H +#ifndef CC_SERVICE_LSP_CPPLSPSERVICE_H +#define CC_SERVICE_LSP_CPPLSPSERVICE_H #include #include @@ -8,9 +8,9 @@ #include #include -#include "LspService.h" +#include "CppLspService.h" #include -#include +#include namespace cc { @@ -19,10 +19,10 @@ namespace service namespace lsp { -class LspServiceHandler : virtual public LspServiceIf +class CppLspServiceHandler : virtual public CppLspServiceIf { public: - LspServiceHandler( + CppLspServiceHandler( std::shared_ptr db_, std::shared_ptr datadir_, const cc::webserver::ServerContext& context_); @@ -87,4 +87,4 @@ class LspServiceHandler : virtual public LspServiceIf } // service } // cc -#endif // CC_SERVICE_LSP_LSPSERVICE_H \ No newline at end of file +#endif // CC_SERVICE_LSP_CPPLSPSERVICE_H \ No newline at end of file diff --git a/plugins/lsp/service/include/lspservice/lsp_types.h b/plugins/cpp_lsp/service/include/cpplspservice/lsp_types.h similarity index 100% rename from plugins/lsp/service/include/lspservice/lsp_types.h rename to plugins/cpp_lsp/service/include/cpplspservice/lsp_types.h diff --git a/plugins/lsp/service/lsp.thrift b/plugins/cpp_lsp/service/lsp.thrift similarity index 82% rename from plugins/lsp/service/lsp.thrift rename to plugins/cpp_lsp/service/lsp.thrift index a38b8d5e1..6356eb13d 100644 --- a/plugins/lsp/service/lsp.thrift +++ b/plugins/cpp_lsp/service/lsp.thrift @@ -1,7 +1,7 @@ namespace cpp cc.service.lsp namespace java cc.service.lsp -service LspService +service CppLspService { string getLspResponse(1: string request) } \ No newline at end of file diff --git a/plugins/lsp/service/src/lspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp similarity index 92% rename from plugins/lsp/service/src/lspservice.cpp rename to plugins/cpp_lsp/service/src/cpplspservice.cpp index 7de708715..5786c7cc7 100644 --- a/plugins/lsp/service/src/lspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -4,7 +4,7 @@ #include -#include +#include namespace cc { @@ -13,15 +13,15 @@ namespace service namespace lsp { -std::unordered_map LspServiceHandler::_methodMap = { - { "textDocument/definition", LspServiceHandler::LspMethod::Definition }, - { "textDocument/implementation", LspServiceHandler::LspMethod::Implementation }, - { "textDocument/references", LspServiceHandler::LspMethod::References }, - { "diagram/diagramTypes", LspServiceHandler::LspMethod::DiagramTypes }, - { "diagram/diagram", LspServiceHandler::LspMethod::Diagram}, +std::unordered_map CppLspServiceHandler::_methodMap = { + { "textDocument/definition", CppLspServiceHandler::LspMethod::Definition }, + { "textDocument/implementation", CppLspServiceHandler::LspMethod::Implementation }, + { "textDocument/references", CppLspServiceHandler::LspMethod::References }, + { "diagram/diagramTypes", CppLspServiceHandler::LspMethod::DiagramTypes }, + { "diagram/diagram", CppLspServiceHandler::LspMethod::Diagram}, }; -LspServiceHandler::LspServiceHandler( +CppLspServiceHandler::CppLspServiceHandler( std::shared_ptr db_, std::shared_ptr datadir_, const cc::webserver::ServerContext& context_) @@ -31,7 +31,7 @@ LspServiceHandler::LspServiceHandler( { } -void LspServiceHandler::getLspResponse(std::string& _return, const std::string& request) +void CppLspServiceHandler::getLspResponse(std::string& _return, const std::string& request) { pt::ptree responseTree; responseTree.put("jsonrpc", "2.0"); @@ -190,7 +190,7 @@ void LspServiceHandler::getLspResponse(std::string& _return, const std::string& _return = responseStream.str(); } -std::vector LspServiceHandler::definition( +std::vector CppLspServiceHandler::definition( const TextDocumentPositionParams& params_) { language::AstNodeInfo astNodeInfo; @@ -236,7 +236,7 @@ std::vector LspServiceHandler::definition( return definitionLocations; } -std::vector LspServiceHandler::implementation( +std::vector CppLspServiceHandler::implementation( const TextDocumentPositionParams& params_) { language::AstNodeInfo astNodeInfo; @@ -282,7 +282,7 @@ std::vector LspServiceHandler::implementation( return implementationLocations; } -std::vector LspServiceHandler::references( +std::vector CppLspServiceHandler::references( const ReferenceParams& params_) { language::AstNodeInfo astNodeInfo; @@ -364,7 +364,7 @@ std::vector LspServiceHandler::references( return usageLocations; } -CompletionList LspServiceHandler::fileDiagramTypes( +CompletionList CppLspServiceHandler::fileDiagramTypes( const DiagramTypeParams& params_) { model::FilePtr file = _transaction([&, this](){ @@ -395,7 +395,7 @@ CompletionList LspServiceHandler::fileDiagramTypes( return list; } -CompletionList LspServiceHandler::nodeDiagramTypes( +CompletionList CppLspServiceHandler::nodeDiagramTypes( const DiagramTypeParams& params_) { language::AstNodeInfo astNodeInfo; @@ -434,7 +434,7 @@ CompletionList LspServiceHandler::nodeDiagramTypes( return list; } -Diagram LspServiceHandler::fileDiagram( +Diagram CppLspServiceHandler::fileDiagram( const DiagramParams& params_) { model::FilePtr file = _transaction([&, this](){ @@ -457,7 +457,7 @@ Diagram LspServiceHandler::fileDiagram( return diagram; } -Diagram LspServiceHandler::nodeDiagram( +Diagram CppLspServiceHandler::nodeDiagram( const DiagramParams& params_) { language::AstNodeInfo astNodeInfo; @@ -490,7 +490,7 @@ Diagram LspServiceHandler::nodeDiagram( return diagram; } -LspServiceHandler::LspMethod LspServiceHandler::parseMethod(const std::string& method) +CppLspServiceHandler::LspMethod CppLspServiceHandler::parseMethod(const std::string& method) { auto it = _methodMap.find(method); if (it != _methodMap.end()) diff --git a/plugins/lsp/service/src/lsp_types.cpp b/plugins/cpp_lsp/service/src/lsp_types.cpp similarity index 99% rename from plugins/lsp/service/src/lsp_types.cpp rename to plugins/cpp_lsp/service/src/lsp_types.cpp index af1b7bd48..b5f57161d 100644 --- a/plugins/lsp/service/src/lsp_types.cpp +++ b/plugins/cpp_lsp/service/src/lsp_types.cpp @@ -1,4 +1,4 @@ -#include +#include namespace cc { diff --git a/plugins/lsp/service/src/plugin.cpp b/plugins/cpp_lsp/service/src/plugin.cpp similarity index 88% rename from plugins/lsp/service/src/plugin.cpp rename to plugins/cpp_lsp/service/src/plugin.cpp index f338d44cf..bcf9887b4 100644 --- a/plugins/lsp/service/src/plugin.cpp +++ b/plugins/cpp_lsp/service/src/plugin.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreturn-type-c-linkage" @@ -25,7 +25,7 @@ extern "C" cc::webserver::registerLspPluginSimple( context_, pluginHandler_, - CODECOMPASS_LSP_SERVICE_FACTORY_WITH_CFG(Lsp, lsp), + CODECOMPASS_LSP_SERVICE_FACTORY_WITH_CFG(CppLsp, lsp), "LspService"); } } diff --git a/service/CMakeLists.txt b/service/CMakeLists.txt index 21b32b2ae..985f4f5b7 100644 --- a/service/CMakeLists.txt +++ b/service/CMakeLists.txt @@ -3,3 +3,4 @@ add_subdirectory(language) add_subdirectory(plugin) add_subdirectory(project) add_subdirectory(workspace) +add_subdirectory(lsp) From b1269b140415015cb0d55a93285b2e01d5191305 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Sun, 2 Apr 2023 22:55:15 +0200 Subject: [PATCH 08/26] Remove thrift from lsp plugin --- plugins/cpp_lsp/service/CMakeLists.txt | 36 +---------- .../include/cpplspservice/cpplspservice.h | 5 +- plugins/cpp_lsp/service/lsp.thrift | 7 --- plugins/cpp_lsp/service/src/plugin.cpp | 3 +- service/CMakeLists.txt | 1 - webserver/CMakeLists.txt | 2 - webserver/include/webserver/lsphandler.h | 61 ++++--------------- webserver/include/webserver/pluginhelper.h | 6 +- 8 files changed, 19 insertions(+), 102 deletions(-) delete mode 100644 plugins/cpp_lsp/service/lsp.thrift diff --git a/plugins/cpp_lsp/service/CMakeLists.txt b/plugins/cpp_lsp/service/CMakeLists.txt index 08f2a076c..15bfe4e97 100644 --- a/plugins/cpp_lsp/service/CMakeLists.txt +++ b/plugins/cpp_lsp/service/CMakeLists.txt @@ -8,50 +8,16 @@ include_directories( ${PROJECT_SOURCE_DIR}/plugins/cpp/model/include ${CMAKE_BINARY_DIR}/model/include ${CMAKE_BINARY_DIR}/plugins/cpp/model/include - ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp ${PROJECT_SOURCE_DIR}/util/include ${PROJECT_SOURCE_DIR}/webserver/include) -include_directories(SYSTEM - ${THRIFT_LIBTHRIFT_INCLUDE_DIRS}) - -add_custom_command( - OUTPUT - ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_constants.cpp - ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_constants.h - ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_types.cpp - ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_types.h - ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/CppLspService.cpp - ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/CppLspService.h - ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp - COMMAND - ${THRIFT_EXECUTABLE} --gen cpp - -o ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/lsp.thrift - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/lsp.thrift - COMMENT - "Generating Thrift for lsp.thrift") - -add_library(lspthrift STATIC - ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_constants.cpp - ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/lsp_types.cpp - ${CMAKE_CURRENT_BINARY_DIR}/gen-cpp/LspService.cpp) - -target_compile_options(lspthrift PUBLIC -fPIC) - -include_directories(SYSTEM - ${THRIFT_LIBTHRIFT_INCLUDE_DIRS}) - add_library(cpplspservice SHARED src/cpplspservice.cpp src/lsp_types.cpp src/plugin.cpp) target_link_libraries(cpplspservice - util - lspthrift - ${THRIFT_LIBTHRIFT_LIBRARIES}) + util) add_dependencies(cpplspservice projectthrift) add_dependencies(cpplspservice languagethrift) diff --git a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h index 9aff5ceef..36fb82f6a 100644 --- a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h +++ b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h @@ -8,7 +8,6 @@ #include #include -#include "CppLspService.h" #include #include @@ -19,7 +18,7 @@ namespace service namespace lsp { -class CppLspServiceHandler : virtual public CppLspServiceIf +class CppLspServiceHandler { public: CppLspServiceHandler( @@ -27,7 +26,7 @@ class CppLspServiceHandler : virtual public CppLspServiceIf std::shared_ptr datadir_, const cc::webserver::ServerContext& context_); - virtual void getLspResponse(std::string& _return, const std::string& request) override; + void getLspResponse(std::string& _return, const std::string& request); std::vector definition( const TextDocumentPositionParams& params_); diff --git a/plugins/cpp_lsp/service/lsp.thrift b/plugins/cpp_lsp/service/lsp.thrift deleted file mode 100644 index 6356eb13d..000000000 --- a/plugins/cpp_lsp/service/lsp.thrift +++ /dev/null @@ -1,7 +0,0 @@ -namespace cpp cc.service.lsp -namespace java cc.service.lsp - -service CppLspService -{ - string getLspResponse(1: string request) -} \ No newline at end of file diff --git a/plugins/cpp_lsp/service/src/plugin.cpp b/plugins/cpp_lsp/service/src/plugin.cpp index bcf9887b4..a15d0110d 100644 --- a/plugins/cpp_lsp/service/src/plugin.cpp +++ b/plugins/cpp_lsp/service/src/plugin.cpp @@ -1,4 +1,3 @@ -#include "LspService.h" #include #include #include @@ -25,7 +24,7 @@ extern "C" cc::webserver::registerLspPluginSimple( context_, pluginHandler_, - CODECOMPASS_LSP_SERVICE_FACTORY_WITH_CFG(CppLsp, lsp), + CODECOMPASS_LSP_SERVICE_FACTORY_WITH_CFG(Cpp, lsp), "LspService"); } } diff --git a/service/CMakeLists.txt b/service/CMakeLists.txt index 985f4f5b7..21b32b2ae 100644 --- a/service/CMakeLists.txt +++ b/service/CMakeLists.txt @@ -3,4 +3,3 @@ add_subdirectory(language) add_subdirectory(plugin) add_subdirectory(project) add_subdirectory(workspace) -add_subdirectory(lsp) diff --git a/webserver/CMakeLists.txt b/webserver/CMakeLists.txt index 3eaae4857..1d0a2f6f4 100644 --- a/webserver/CMakeLists.txt +++ b/webserver/CMakeLists.txt @@ -24,7 +24,6 @@ target_include_directories(CodeCompass_webserver PUBLIC include ${PROJECT_SOURCE_DIR}/model/include ${PROJECT_SOURCE_DIR}/util/include - ${PROJECT_SOURCE_DIR}/service/lsp/include ${PROJECT_BINARY_DIR}/service/language/gen-cpp ${PROJECT_BINARY_DIR}/service/project/gen-cpp ${PROJECT_SOURCE_DIR}/service/project/include @@ -33,7 +32,6 @@ target_include_directories(CodeCompass_webserver PUBLIC target_link_libraries(CodeCompass_webserver util - lspservice cppservice mongoose ${Boost_LIBRARIES} diff --git a/webserver/include/webserver/lsphandler.h b/webserver/include/webserver/lsphandler.h index 560736c51..25a8ba3a4 100644 --- a/webserver/include/webserver/lsphandler.h +++ b/webserver/include/webserver/lsphandler.h @@ -1,14 +1,14 @@ #ifndef CC_WEBSERVER_LSPHANDLER_H #define CC_WEBSERVER_LSPHANDLER_H +#include #include #include -//#include #include #include -#include "webserver/thrifthandler.h" +#include "webserver/requesthandler.h" #include #include @@ -18,8 +18,8 @@ namespace cc namespace webserver { -template -class LspHandler : public ThriftHandler +template +class LspHandler : public RequestHandler { public: std::string key() const override @@ -27,62 +27,23 @@ class LspHandler : public ThriftHandler return "LspHandler"; } - template - LspHandler(Handler handler_) - : ThriftHandler(handler_) + LspHandler(std::unique_ptr&& service_) : lspService(std::move(service_)) { } - template - LspHandler(Handler *handler_) - : ThriftHandler(handler_) + LspHandler(LspServiceT *service_) : lspService(service_) { } int beginRequest(struct mg_connection *conn_) override { - using namespace ::apache::thrift; - using namespace ::apache::thrift::transport; - using namespace ::apache::thrift::protocol; - try { - std::string content = getContent(conn_); - LOG(debug) << "[LSP] Request content:\n" << content; - - // Place LSP message into thrift message - boost::replace_all(content, "\"", "\\\""); - std::string request = "[1,\"getLspResponse\",1,0,{\"1\":{\"str\":\"" + content + "\"}}]"; - - std::shared_ptr inputBuffer( - new TMemoryBuffer((std::uint8_t*)request.c_str(), request.length())); - - std::shared_ptr outputBuffer(new TMemoryBuffer(4096)); - - std::shared_ptr inputProtocol( - new TJSONProtocol(inputBuffer)); - std::shared_ptr outputProtocol( - new TJSONProtocol(outputBuffer)); + std::string request = getContent(conn_); + LOG(debug) << "[LSP] Request content:\n" << request; - typename LspHandler::CallContext ctx{conn_, nullptr}; - LspHandler::_processor.process(inputProtocol, outputProtocol, &ctx); - - TMemoryBuffer *mBuffer = dynamic_cast(outputBuffer.get()); - - std::string response = mBuffer->getBufferAsString(); - - // Get LSP response from thrift - std::regex rgx("\\[1,\"getLspResponse\",2,0,\\{\"0\":\\{\"str\":\"(.*)\"\\}\\}\\]"); - std::smatch match; - std::regex_search(response, match, rgx); - response = match[1]; - - // Remove escape characters - boost::replace_all(response, "\\\\n", ""); - boost::replace_all(response, "\\n", ""); - boost::replace_all(response, "\\\"", "\""); - boost::replace_all(response, "\\\\/", "/"); - boost::replace_all(response, "\\\\\"", "\\\""); + std::string response{}; + lspService->getLspResponse(response, request); LOG(debug) << "[LSP] Response content:\n" << response << std::endl; @@ -118,6 +79,8 @@ int beginRequest(struct mg_connection *conn_) override { return std::string(conn_->content, conn_->content + conn_->content_len); } + + std::unique_ptr lspService; }; } // webserver diff --git a/webserver/include/webserver/pluginhelper.h b/webserver/include/webserver/pluginhelper.h index 8cb9e1232..83c9ee284 100644 --- a/webserver/include/webserver/pluginhelper.h +++ b/webserver/include/webserver/pluginhelper.h @@ -15,7 +15,7 @@ #include #include -#include "requesthandler.h" +#include "thrifthandler.h" #include "lsphandler.h" namespace cc @@ -198,8 +198,8 @@ inline void registerLspPluginSimple( std::shared_ptr datadir_, \ const cc::webserver::ServerContext& ctx_) { \ return new cc::webserver::LspHandler< \ - cc::service::nspace::serviceName##ServiceProcessor>( \ - new cc::service::nspace::serviceName##ServiceHandler( \ + cc::service::nspace::serviceName##LspServiceHandler>( \ + new cc::service::nspace::serviceName##LspServiceHandler( \ db_, datadir_, ctx_)); \ } From d05a6ec60a18dc218023f2f6bbde262087cd94c8 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Mon, 3 Apr 2023 01:06:37 +0200 Subject: [PATCH 09/26] Remove even more thrift from lsp --- plugins/cpp_lsp/service/CMakeLists.txt | 4 +--- plugins/cpp_lsp/service/src/cpplspservice.cpp | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/plugins/cpp_lsp/service/CMakeLists.txt b/plugins/cpp_lsp/service/CMakeLists.txt index 15bfe4e97..ab1e4bf82 100644 --- a/plugins/cpp_lsp/service/CMakeLists.txt +++ b/plugins/cpp_lsp/service/CMakeLists.txt @@ -17,9 +17,7 @@ add_library(cpplspservice SHARED src/plugin.cpp) target_link_libraries(cpplspservice + cppservice util) -add_dependencies(cpplspservice projectthrift) -add_dependencies(cpplspservice languagethrift) - install(TARGETS cpplspservice DESTINATION ${INSTALL_SERVICE_DIR}) \ No newline at end of file diff --git a/plugins/cpp_lsp/service/src/cpplspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp index 5786c7cc7..4e98609e9 100644 --- a/plugins/cpp_lsp/service/src/cpplspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -2,8 +2,6 @@ #include #include -#include - #include namespace cc From 552593306ea563ba358a366df4da5647c64be700 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Sat, 8 Apr 2023 20:48:27 +0200 Subject: [PATCH 10/26] Create base class for lsp service --- plugins/cpp_lsp/service/CMakeLists.txt | 5 +- .../include/cpplspservice/cpplspservice.h | 38 +-- plugins/cpp_lsp/service/src/cpplspservice.cpp | 254 ++++++------------ service/CMakeLists.txt | 1 + service/lsp/CMakeLists.txt | 10 + .../lsp/include/lspservice}/lsp_types.h | 0 service/lsp/include/lspservice/lspservice.h | 39 +++ .../service => service/lsp}/src/lsp_types.cpp | 2 +- service/lsp/src/lspservice.cpp | 68 +++++ webserver/include/webserver/lsphandler.h | 107 +++++++- 10 files changed, 319 insertions(+), 205 deletions(-) create mode 100644 service/lsp/CMakeLists.txt rename {plugins/cpp_lsp/service/include/cpplspservice => service/lsp/include/lspservice}/lsp_types.h (100%) create mode 100644 service/lsp/include/lspservice/lspservice.h rename {plugins/cpp_lsp/service => service/lsp}/src/lsp_types.cpp (99%) create mode 100644 service/lsp/src/lspservice.cpp diff --git a/plugins/cpp_lsp/service/CMakeLists.txt b/plugins/cpp_lsp/service/CMakeLists.txt index ab1e4bf82..e583819ef 100644 --- a/plugins/cpp_lsp/service/CMakeLists.txt +++ b/plugins/cpp_lsp/service/CMakeLists.txt @@ -9,15 +9,16 @@ include_directories( ${CMAKE_BINARY_DIR}/model/include ${CMAKE_BINARY_DIR}/plugins/cpp/model/include ${PROJECT_SOURCE_DIR}/util/include - ${PROJECT_SOURCE_DIR}/webserver/include) + ${PROJECT_SOURCE_DIR}/webserver/include + ${PROJECT_SOURCE_DIR}/service/lsp/include) add_library(cpplspservice SHARED src/cpplspservice.cpp - src/lsp_types.cpp src/plugin.cpp) target_link_libraries(cpplspservice cppservice + lspservice util) install(TARGETS cpplspservice DESTINATION ${INSTALL_SERVICE_DIR}) \ No newline at end of file diff --git a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h index 36fb82f6a..0eca13e70 100644 --- a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h +++ b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h @@ -9,7 +9,7 @@ #include #include -#include +#include namespace cc { @@ -18,7 +18,7 @@ namespace service namespace lsp { -class CppLspServiceHandler +class CppLspServiceHandler : public LspServiceHandler { public: CppLspServiceHandler( @@ -26,8 +26,13 @@ class CppLspServiceHandler std::shared_ptr datadir_, const cc::webserver::ServerContext& context_); - void getLspResponse(std::string& _return, const std::string& request); + void getDefinition(pt::ptree& responseTree_, const pt::ptree& params_) override final; + void getImplementation(pt::ptree& responseTree_, const pt::ptree& params_) override final; + void getReferences(pt::ptree& responseTree_, const pt::ptree& params_) override final; + void getDiagramTypes(pt::ptree& responseTree_, const pt::ptree& params_) override final; + void getDiagram(pt::ptree& responseTree_, const pt::ptree& params_) override final; +private: std::vector definition( const TextDocumentPositionParams& params_); @@ -49,37 +54,10 @@ class CppLspServiceHandler Diagram nodeDiagram( const DiagramParams& params_); -private: std::shared_ptr _db; util::OdbTransaction _transaction; language::CppServiceHandler _cppService; - - - /** - * Support methods of the Language Server Protocol. - */ - enum class LspMethod - { - Unknown = 0, - Definition, - Implementation, - References, - DiagramTypes, - Diagram - }; - - /** - * Maps a JSON RPC method (string) to inner representation (LspMethod). - * @param method The method as JSON RPC method string. - * @return The matching LspMethod value. - */ - LspMethod parseMethod(const std::string& method); - - /** - * A mapping from JSON RPC method (string) to inner representation (LspMethod). - */ - static std::unordered_map _methodMap; }; } // lsp diff --git a/plugins/cpp_lsp/service/src/cpplspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp index 4e98609e9..22b79ca12 100644 --- a/plugins/cpp_lsp/service/src/cpplspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -11,14 +11,6 @@ namespace service namespace lsp { -std::unordered_map CppLspServiceHandler::_methodMap = { - { "textDocument/definition", CppLspServiceHandler::LspMethod::Definition }, - { "textDocument/implementation", CppLspServiceHandler::LspMethod::Implementation }, - { "textDocument/references", CppLspServiceHandler::LspMethod::References }, - { "diagram/diagramTypes", CppLspServiceHandler::LspMethod::DiagramTypes }, - { "diagram/diagram", CppLspServiceHandler::LspMethod::Diagram}, -}; - CppLspServiceHandler::CppLspServiceHandler( std::shared_ptr db_, std::shared_ptr datadir_, @@ -29,163 +21,27 @@ CppLspServiceHandler::CppLspServiceHandler( { } -void CppLspServiceHandler::getLspResponse(std::string& _return, const std::string& request) +void CppLspServiceHandler::getDefinition(pt::ptree& responseTree_, const pt::ptree& params_) { - pt::ptree responseTree; - responseTree.put("jsonrpc", "2.0"); - - try - { - pt::ptree requestTree; - std::stringstream requestStream(request); - pt::read_json(requestStream, requestTree); - - std::string requestId = requestTree.get("id"); - responseTree.put("id", requestId); + TextDocumentPositionParams gotoDefParams; + gotoDefParams.readNode(params_); - std::string method = requestTree.get("method"); - pt::ptree& params = requestTree.get_child("params"); - - switch (parseMethod(method)) - { - case LspMethod::Definition: - { - TextDocumentPositionParams gotoDefParams; - gotoDefParams.readNode(params); - - std::vector gotoDefLocations = - definition(gotoDefParams); - - if (gotoDefLocations.size() == 1) - { - responseTree.put_child("result", gotoDefLocations[0].createNode()); - } - else if (gotoDefLocations.size() > 1) - { - pt::ptree resultNode; - for (const Location &location : gotoDefLocations) - { - resultNode.push_back(std::make_pair("", location.createNode())); - } - responseTree.put_child("result", resultNode); - } - break; - } - case LspMethod::Implementation: - { - TextDocumentPositionParams implementationParams; - implementationParams.readNode(params); - - std::vector implementationLocations = - implementation(implementationParams); - - if (implementationLocations.size() == 1) - { - responseTree.put_child("result", implementationLocations[0].createNode()); - } - else if (implementationLocations.size() > 1) - { - pt::ptree resultNode; - for (const Location &location : implementationLocations) - { - resultNode.push_back(std::make_pair("", location.createNode())); - } - responseTree.put_child("result", resultNode); - } - break; - } - case LspMethod::References: - { - ReferenceParams refParams; - refParams.readNode(params); - - std::vector refLocations = references(refParams); - - pt::ptree resultNode; - for (const Location& location : refLocations) - { - resultNode.push_back(std::make_pair("", location.createNode())); - } - responseTree.put_child("result", resultNode); - break; - } - case LspMethod::DiagramTypes: - { - DiagramTypeParams diagramTypeParams; - diagramTypeParams.readNode(params); - - CompletionList diagramTypesResult; - if (!diagramTypeParams.position) - { - diagramTypesResult = fileDiagramTypes(diagramTypeParams); - } - else - { - diagramTypesResult = nodeDiagramTypes(diagramTypeParams); - } - - responseTree.put_child("result", diagramTypesResult.createNode()); - break; - } - case LspMethod::Diagram: - { - DiagramParams diagramParams; - diagramParams.readNode(params); - - Diagram diagramResult; - if (!diagramParams.position) - { - diagramResult = fileDiagram(diagramParams); - } - else - { - diagramResult = nodeDiagram(diagramParams); - } - - responseTree.put("result", diagramResult); - break; - } - default: - { - LOG(warning) << "[LSP] Unsupported method: '" << method << "'"; - - ResponseError error; - error.code = ErrorCode::MethodNotFound; - error.message = std::string("Unsupported method: ").append(method); - responseTree.put_child("error", error.createNode()); - } - } - } - catch (const pt::ptree_error& ex) - { - LOG(warning) << ex.what(); + std::vector gotoDefLocations = + definition(gotoDefParams); - ResponseError error; - error.code = ErrorCode::ParseError; - error.message = std::string("JSON RPC parsing error: ").append(ex.what()); - responseTree.put_child("error", error.createNode()); - } - catch (const std::exception& ex) + if (gotoDefLocations.size() == 1) { - LOG(warning) << ex.what(); - - ResponseError error; - error.code = ErrorCode::InternalError; - error.message = ex.what(); - responseTree.put_child("error", error.createNode()); + responseTree_.put_child("result", gotoDefLocations[0].createNode()); } - catch (...) + else if (gotoDefLocations.size() > 1) { - LOG(warning) << "Unknown exception has been caught"; - - ResponseError error; - error.code = ErrorCode::UnknownError; - responseTree.put_child("error", error.createNode()); + pt::ptree resultNode; + for (const Location &location : gotoDefLocations) + { + resultNode.push_back(std::make_pair("", location.createNode())); + } + responseTree_.put_child("result", resultNode); } - - std::stringstream responseStream; - pt::write_json(responseStream, responseTree); - _return = responseStream.str(); } std::vector CppLspServiceHandler::definition( @@ -234,6 +90,29 @@ std::vector CppLspServiceHandler::definition( return definitionLocations; } +void CppLspServiceHandler::getImplementation(pt::ptree& responseTree_, const pt::ptree& params_) +{ + TextDocumentPositionParams implementationParams; + implementationParams.readNode(params_); + + std::vector implementationLocations = + implementation(implementationParams); + + if (implementationLocations.size() == 1) + { + responseTree_.put_child("result", implementationLocations[0].createNode()); + } + else if (implementationLocations.size() > 1) + { + pt::ptree resultNode; + for (const Location &location : implementationLocations) + { + resultNode.push_back(std::make_pair("", location.createNode())); + } + responseTree_.put_child("result", resultNode); + } +} + std::vector CppLspServiceHandler::implementation( const TextDocumentPositionParams& params_) { @@ -280,6 +159,21 @@ std::vector CppLspServiceHandler::implementation( return implementationLocations; } +void CppLspServiceHandler::getReferences(pt::ptree& responseTree_, const pt::ptree& params_) +{ + ReferenceParams refParams; + refParams.readNode(params_); + + std::vector refLocations = references(refParams); + + pt::ptree resultNode; + for (const Location& location : refLocations) + { + resultNode.push_back(std::make_pair("", location.createNode())); + } + responseTree_.put_child("result", resultNode); +} + std::vector CppLspServiceHandler::references( const ReferenceParams& params_) { @@ -362,6 +256,24 @@ std::vector CppLspServiceHandler::references( return usageLocations; } +void CppLspServiceHandler::getDiagramTypes(pt::ptree& responseTree_, const pt::ptree& params_) +{ + DiagramTypeParams diagramTypeParams; + diagramTypeParams.readNode(params_); + + CompletionList diagramTypesResult; + if (!diagramTypeParams.position) + { + diagramTypesResult = fileDiagramTypes(diagramTypeParams); + } + else + { + diagramTypesResult = nodeDiagramTypes(diagramTypeParams); + } + + responseTree_.put_child("result", diagramTypesResult.createNode()); +} + CompletionList CppLspServiceHandler::fileDiagramTypes( const DiagramTypeParams& params_) { @@ -432,6 +344,24 @@ CompletionList CppLspServiceHandler::nodeDiagramTypes( return list; } +void CppLspServiceHandler::getDiagram(pt::ptree& responseTree_, const pt::ptree& params_) +{ + DiagramParams diagramParams; + diagramParams.readNode(params_); + + Diagram diagramResult; + if (!diagramParams.position) + { + diagramResult = fileDiagram(diagramParams); + } + else + { + diagramResult = nodeDiagram(diagramParams); + } + + responseTree_.put("result", diagramResult); +} + Diagram CppLspServiceHandler::fileDiagram( const DiagramParams& params_) { @@ -488,14 +418,6 @@ Diagram CppLspServiceHandler::nodeDiagram( return diagram; } -CppLspServiceHandler::LspMethod CppLspServiceHandler::parseMethod(const std::string& method) -{ - auto it = _methodMap.find(method); - if (it != _methodMap.end()) - return it->second; - return LspMethod::Unknown; -} - } // lsp } // service } // cc diff --git a/service/CMakeLists.txt b/service/CMakeLists.txt index 21b32b2ae..a482ff7bf 100644 --- a/service/CMakeLists.txt +++ b/service/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(authentication) add_subdirectory(language) +add_subdirectory(lsp) add_subdirectory(plugin) add_subdirectory(project) add_subdirectory(workspace) diff --git a/service/lsp/CMakeLists.txt b/service/lsp/CMakeLists.txt new file mode 100644 index 000000000..b7ad6ac60 --- /dev/null +++ b/service/lsp/CMakeLists.txt @@ -0,0 +1,10 @@ +include_directories(include) + +add_library(lspservice STATIC + src/lspservice.cpp + src/lsp_types.cpp) + +target_compile_options(lspservice PUBLIC -fPIC) + +target_link_libraries(lspservice + ${Boost_LIBRARIES}) diff --git a/plugins/cpp_lsp/service/include/cpplspservice/lsp_types.h b/service/lsp/include/lspservice/lsp_types.h similarity index 100% rename from plugins/cpp_lsp/service/include/cpplspservice/lsp_types.h rename to service/lsp/include/lspservice/lsp_types.h diff --git a/service/lsp/include/lspservice/lspservice.h b/service/lsp/include/lspservice/lspservice.h new file mode 100644 index 000000000..1af3c55da --- /dev/null +++ b/service/lsp/include/lspservice/lspservice.h @@ -0,0 +1,39 @@ +#ifndef CC_SERVICE_LSP_LSPSERVICE_H +#define CC_SERVICE_LSP_LSPSERVICE_H + +#include + +#include + +namespace cc +{ +namespace service +{ +namespace lsp +{ + +namespace pt = boost::property_tree; + +class LspServiceHandler +{ +public: + virtual ~LspServiceHandler() = default; + + void virtual getDefinition(pt::ptree& responseTree_, const pt::ptree& params_); + void virtual getImplementation(pt::ptree& responseTree_, const pt::ptree& params_); + void virtual getReferences(pt::ptree& responseTree_, const pt::ptree& params_); + void virtual getDiagramTypes(pt::ptree& responseTree_, const pt::ptree& params_); + void virtual getDiagram(pt::ptree& responseTree_, const pt::ptree& params_); + + void getMethodNotFound(pt::ptree& responseTree_, const std::string& method_); + void getParseError(pt::ptree& responseTree_, const std::exception& ex_); + void getInternalError(pt::ptree& responseTree_, const std::exception& ex_); + void getUnknownError(pt::ptree& responseTree_); + +}; + +} // lsp +} // service +} // cc + +#endif // CC_SERVICE_LSP_LSPSERVICE_H \ No newline at end of file diff --git a/plugins/cpp_lsp/service/src/lsp_types.cpp b/service/lsp/src/lsp_types.cpp similarity index 99% rename from plugins/cpp_lsp/service/src/lsp_types.cpp rename to service/lsp/src/lsp_types.cpp index b5f57161d..af1b7bd48 100644 --- a/plugins/cpp_lsp/service/src/lsp_types.cpp +++ b/service/lsp/src/lsp_types.cpp @@ -1,4 +1,4 @@ -#include +#include namespace cc { diff --git a/service/lsp/src/lspservice.cpp b/service/lsp/src/lspservice.cpp new file mode 100644 index 000000000..4e99b7cd5 --- /dev/null +++ b/service/lsp/src/lspservice.cpp @@ -0,0 +1,68 @@ +#include "lspservice/lspservice.h" + +namespace cc +{ +namespace service +{ +namespace lsp +{ + +void LspServiceHandler::getDefinition(pt::ptree& responseTree_, const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/definition"); +} + +void LspServiceHandler::getImplementation(pt::ptree& responseTree_, const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/implementation"); +} + +void LspServiceHandler::getReferences(pt::ptree& responseTree_, const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/references"); +} + +void LspServiceHandler::getDiagramTypes(pt::ptree& responseTree_, const pt::ptree&) +{ + getMethodNotFound(responseTree_, "diagram/diagramTypes"); +} + +void LspServiceHandler::getDiagram(pt::ptree& responseTree_, const pt::ptree&) +{ + getMethodNotFound(responseTree_, "diagram/diagram"); +} + +void LspServiceHandler::getMethodNotFound(pt::ptree& responseTree_, const std::string& method_) +{ + ResponseError error; + error.code = ErrorCode::MethodNotFound; + error.message = std::string("Unsupported method: ").append(method_); + responseTree_.put_child("error", error.createNode()); +} + +void LspServiceHandler::getParseError(pt::ptree& responseTree_, const std::exception& ex_) +{ + ResponseError error; + error.code = ErrorCode::ParseError; + error.message = std::string("JSON RPC parsing error: ").append(ex_.what()); + responseTree_.put_child("error", error.createNode()); +} + +void LspServiceHandler::getInternalError(pt::ptree& responseTree_, const std::exception& ex_) +{ + ResponseError error; + error.code = ErrorCode::InternalError; + error.message = ex_.what(); + responseTree_.put_child("error", error.createNode()); +} + +void LspServiceHandler::getUnknownError(pt::ptree& responseTree_) +{ + ResponseError error; + error.code = ErrorCode::UnknownError; + responseTree_.put_child("error", error.createNode()); +} + +} // lsp +} // service +} // cc \ No newline at end of file diff --git a/webserver/include/webserver/lsphandler.h b/webserver/include/webserver/lsphandler.h index 25a8ba3a4..3472b068e 100644 --- a/webserver/include/webserver/lsphandler.h +++ b/webserver/include/webserver/lsphandler.h @@ -5,8 +5,8 @@ #include #include -#include -#include +#include +#include #include "webserver/requesthandler.h" @@ -18,6 +18,21 @@ namespace cc namespace webserver { +namespace pt = boost::property_tree; + +/** + * Support methods of the Language Server Protocol. + */ +enum class LspMethod +{ + Unknown = 0, + Definition, + Implementation, + References, + DiagramTypes, + Diagram +}; + template class LspHandler : public RequestHandler { @@ -42,8 +57,74 @@ int beginRequest(struct mg_connection *conn_) override std::string request = getContent(conn_); LOG(debug) << "[LSP] Request content:\n" << request; - std::string response{}; - lspService->getLspResponse(response, request); + pt::ptree responseTree; + responseTree.put("jsonrpc", "2.0"); + + try + { + pt::ptree requestTree; + std::stringstream requestStream(request); + pt::read_json(requestStream, requestTree); + + std::string requestId = requestTree.get("id"); + responseTree.put("id", requestId); + + std::string method = requestTree.get("method"); + pt::ptree& params = requestTree.get_child("params"); + + switch (parseMethod(method)) + { + case LspMethod::Definition: + { + lspService->getDefinition(responseTree, params); + break; + } + case LspMethod::Implementation: + { + lspService->getImplementation(responseTree, params); + break; + } + case LspMethod::References: + { + lspService->getReferences(responseTree, params); + break; + } + case LspMethod::DiagramTypes: + { + lspService->getDiagramTypes(responseTree, params); + break; + } + case LspMethod::Diagram: + { + lspService->getDiagram(responseTree, params); + break; + } + default: + { + LOG(warning) << "[LSP] Unsupported method: '" << method << "'"; + lspService->getMethodNotFound(responseTree, method); + } + } + } + catch (const pt::ptree_error& ex) + { + LOG(warning) << ex.what(); + lspService->getParseError(responseTree, ex); + } + catch (const std::exception& ex) + { + LOG(warning) << ex.what(); + lspService->getInternalError(responseTree, ex); + } + catch (...) + { + LOG(warning) << "Unknown exception has been caught"; + lspService->getUnknownError(responseTree); + } + + std::stringstream responseStream; + pt::write_json(responseStream, responseTree); + std::string response = responseStream.str(); LOG(debug) << "[LSP] Response content:\n" << response << std::endl; @@ -72,14 +153,28 @@ int beginRequest(struct mg_connection *conn_) override return MG_TRUE; } - - private: inline std::string getContent(mg_connection* conn_) { return std::string(conn_->content, conn_->content + conn_->content_len); } + LspMethod parseMethod(const std::string& method) + { + static std::unordered_map methodMap = { + { "textDocument/definition", LspMethod::Definition }, + { "textDocument/implementation", LspMethod::Implementation }, + { "textDocument/references", LspMethod::References }, + { "diagram/diagramTypes", LspMethod::DiagramTypes }, + { "diagram/diagram", LspMethod::Diagram}, + }; + + auto it = methodMap.find(method); + if (it != methodMap.end()) + return it->second; + return LspMethod::Unknown; + } + std::unique_ptr lspService; }; From 9e7b103e26860cff5aeedacd5a18a91065f558b8 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Mon, 24 Apr 2023 20:52:04 +0200 Subject: [PATCH 11/26] Add declaration support --- .../include/cpplspservice/cpplspservice.h | 4 + plugins/cpp_lsp/service/src/cpplspservice.cpp | 73 ++++++++ service/lsp/include/lspservice/lspservice.h | 1 + service/lsp/src/lspservice.cpp | 5 + webserver/include/webserver/lsphandler.h | 171 +++++++++--------- 5 files changed, 172 insertions(+), 82 deletions(-) diff --git a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h index 0eca13e70..d920bfa9d 100644 --- a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h +++ b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h @@ -27,6 +27,7 @@ class CppLspServiceHandler : public LspServiceHandler const cc::webserver::ServerContext& context_); void getDefinition(pt::ptree& responseTree_, const pt::ptree& params_) override final; + void getDeclaration(pt::ptree& responseTree_, const pt::ptree& params_) override final; void getImplementation(pt::ptree& responseTree_, const pt::ptree& params_) override final; void getReferences(pt::ptree& responseTree_, const pt::ptree& params_) override final; void getDiagramTypes(pt::ptree& responseTree_, const pt::ptree& params_) override final; @@ -36,6 +37,9 @@ class CppLspServiceHandler : public LspServiceHandler std::vector definition( const TextDocumentPositionParams& params_); + std::vector declaration( + const TextDocumentPositionParams& params_); + std::vector references( const ReferenceParams& params_); diff --git a/plugins/cpp_lsp/service/src/cpplspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp index 22b79ca12..e5b6d63df 100644 --- a/plugins/cpp_lsp/service/src/cpplspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -90,6 +90,79 @@ std::vector CppLspServiceHandler::definition( return definitionLocations; } +void CppLspServiceHandler::getDeclaration(pt::ptree& responseTree_, const pt::ptree& params_) +{ + TextDocumentPositionParams declarationParams; + declarationParams.readNode(params_); + + std::vector declarationLocations = declaration(declarationParams); + + if (declarationLocations.size() == 1) + { + responseTree_.put_child("result", declarationLocations[0].createNode()); + } + else if (declarationLocations.size() > 1) + { + pt::ptree resultNode; + for (const Location &location : declarationLocations) + { + resultNode.push_back(std::make_pair("", location.createNode())); + } + responseTree_.put_child("result", resultNode); + } +} + +std::vector CppLspServiceHandler::declaration(const TextDocumentPositionParams& params_) +{ + + language::AstNodeInfo astNodeInfo; + core::FilePosition cppPosition; + + model::FilePtr file = _transaction([&, this]() + { + return _db->query_one( + odb::query::path == params_.textDocument.uri); + }); + + if (!file) + { + return {}; + } + + cppPosition.file = std::to_string(file->id); + cppPosition.pos.line = params_.position.line; + cppPosition.pos.column = params_.position.character; + + _cppService.getAstNodeInfoByPosition(astNodeInfo, cppPosition); + + std::vector declarationInfo; + _cppService.getReferences(declarationInfo, astNodeInfo.id, language::CppServiceHandler::DECLARATION, {}); + + std::vector declarationLocations(declarationInfo.size()); + std::transform( + declarationInfo.begin(), declarationInfo.end(), + declarationLocations.begin(), + [&, this](const language::AstNodeInfo &declaration) + { + std::string path = _transaction([&, this]() + { + return _db->load(std::stoull(declaration.range.file))->path; + }); + + Location location; + location.uri = path; + location.range.start.line = declaration.range.range.startpos.line; + location.range.start.character = declaration.range.range.startpos.column; + location.range.end.line = declaration.range.range.endpos.line; + location.range.end.character = declaration.range.range.endpos.column; + + return location; + } + ); + + return declarationLocations; +} + void CppLspServiceHandler::getImplementation(pt::ptree& responseTree_, const pt::ptree& params_) { TextDocumentPositionParams implementationParams; diff --git a/service/lsp/include/lspservice/lspservice.h b/service/lsp/include/lspservice/lspservice.h index 1af3c55da..32bdfa729 100644 --- a/service/lsp/include/lspservice/lspservice.h +++ b/service/lsp/include/lspservice/lspservice.h @@ -20,6 +20,7 @@ class LspServiceHandler virtual ~LspServiceHandler() = default; void virtual getDefinition(pt::ptree& responseTree_, const pt::ptree& params_); + void virtual getDeclaration(pt::ptree& responseTree_, const pt::ptree& params_); void virtual getImplementation(pt::ptree& responseTree_, const pt::ptree& params_); void virtual getReferences(pt::ptree& responseTree_, const pt::ptree& params_); void virtual getDiagramTypes(pt::ptree& responseTree_, const pt::ptree& params_); diff --git a/service/lsp/src/lspservice.cpp b/service/lsp/src/lspservice.cpp index 4e99b7cd5..ca802adde 100644 --- a/service/lsp/src/lspservice.cpp +++ b/service/lsp/src/lspservice.cpp @@ -12,6 +12,11 @@ void LspServiceHandler::getDefinition(pt::ptree& responseTree_, const pt::ptree& getMethodNotFound(responseTree_, "textDocument/definition"); } +void LspServiceHandler::getDeclaration(pt::ptree& responseTree_, const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/declaration"); +} + void LspServiceHandler::getImplementation(pt::ptree& responseTree_, const pt::ptree&) { getMethodNotFound(responseTree_, "textDocument/implementation"); diff --git a/webserver/include/webserver/lsphandler.h b/webserver/include/webserver/lsphandler.h index 3472b068e..df4a56de0 100644 --- a/webserver/include/webserver/lsphandler.h +++ b/webserver/include/webserver/lsphandler.h @@ -27,6 +27,7 @@ enum class LspMethod { Unknown = 0, Definition, + Declaration, Implementation, References, DiagramTypes, @@ -50,108 +51,113 @@ class LspHandler : public RequestHandler { } -int beginRequest(struct mg_connection *conn_) override -{ - try + int beginRequest(struct mg_connection *conn_) override { - std::string request = getContent(conn_); - LOG(debug) << "[LSP] Request content:\n" << request; - - pt::ptree responseTree; - responseTree.put("jsonrpc", "2.0"); - try { - pt::ptree requestTree; - std::stringstream requestStream(request); - pt::read_json(requestStream, requestTree); + std::string request = getContent(conn_); + LOG(debug) << "[LSP] Request content:\n" << request; - std::string requestId = requestTree.get("id"); - responseTree.put("id", requestId); + pt::ptree responseTree; + responseTree.put("jsonrpc", "2.0"); - std::string method = requestTree.get("method"); - pt::ptree& params = requestTree.get_child("params"); - - switch (parseMethod(method)) + try { - case LspMethod::Definition: - { - lspService->getDefinition(responseTree, params); - break; - } - case LspMethod::Implementation: - { - lspService->getImplementation(responseTree, params); - break; - } - case LspMethod::References: - { - lspService->getReferences(responseTree, params); - break; - } - case LspMethod::DiagramTypes: - { - lspService->getDiagramTypes(responseTree, params); - break; - } - case LspMethod::Diagram: - { - lspService->getDiagram(responseTree, params); - break; - } - default: + pt::ptree requestTree; + std::stringstream requestStream(request); + pt::read_json(requestStream, requestTree); + + std::string requestId = requestTree.get("id"); + responseTree.put("id", requestId); + + std::string method = requestTree.get("method"); + pt::ptree& params = requestTree.get_child("params"); + + switch (parseMethod(method)) { - LOG(warning) << "[LSP] Unsupported method: '" << method << "'"; - lspService->getMethodNotFound(responseTree, method); + case LspMethod::Definition: + { + lspService->getDefinition(responseTree, params); + break; + } + case LspMethod::Declaration: + { + lspService->getDeclaration(responseTree, params); + break; + } + case LspMethod::Implementation: + { + lspService->getImplementation(responseTree, params); + break; + } + case LspMethod::References: + { + lspService->getReferences(responseTree, params); + break; + } + case LspMethod::DiagramTypes: + { + lspService->getDiagramTypes(responseTree, params); + break; + } + case LspMethod::Diagram: + { + lspService->getDiagram(responseTree, params); + break; + } + default: + { + LOG(warning) << "[LSP] Unsupported method: '" << method << "'"; + lspService->getMethodNotFound(responseTree, method); + } } } - } - catch (const pt::ptree_error& ex) - { - LOG(warning) << ex.what(); - lspService->getParseError(responseTree, ex); + catch (const pt::ptree_error& ex) + { + LOG(warning) << ex.what(); + lspService->getParseError(responseTree, ex); + } + catch (const std::exception& ex) + { + LOG(warning) << ex.what(); + lspService->getInternalError(responseTree, ex); + } + catch (...) + { + LOG(warning) << "Unknown exception has been caught"; + lspService->getUnknownError(responseTree); + } + + std::stringstream responseStream; + pt::write_json(responseStream, responseTree); + std::string response = responseStream.str(); + + LOG(debug) << "[LSP] Response content:\n" << response << std::endl; + + // Send HTTP reply to the client create headers + mg_send_header(conn_, "Content-Type", "application/json"); + mg_send_header( + conn_, "Content-Length", std::to_string(response.length()).c_str()); + + // Terminate headers + mg_write(conn_, "\r\n", 2); + + // Send content + mg_write(conn_, response.c_str(), response.length()); } catch (const std::exception& ex) { LOG(warning) << ex.what(); - lspService->getInternalError(responseTree, ex); } catch (...) { LOG(warning) << "Unknown exception has been caught"; - lspService->getUnknownError(responseTree); } - std::stringstream responseStream; - pt::write_json(responseStream, responseTree); - std::string response = responseStream.str(); - - LOG(debug) << "[LSP] Response content:\n" << response << std::endl; - - // Send HTTP reply to the client create headers - mg_send_header(conn_, "Content-Type", "application/json"); - mg_send_header( - conn_, "Content-Length", std::to_string(response.length()).c_str()); - - // Terminate headers - mg_write(conn_, "\r\n", 2); - - // Send content - mg_write(conn_, response.c_str(), response.length()); + // Returning non-zero tells mongoose that our function has replied to + // the client, and mongoose should not send client any more data. + return MG_TRUE; } - catch (const std::exception& ex) - { - LOG(warning) << ex.what(); - } - catch (...) - { - LOG(warning) << "Unknown exception has been caught"; - } - - // Returning non-zero tells mongoose that our function has replied to - // the client, and mongoose should not send client any more data. - return MG_TRUE; -} private: inline std::string getContent(mg_connection* conn_) @@ -163,6 +169,7 @@ int beginRequest(struct mg_connection *conn_) override { static std::unordered_map methodMap = { { "textDocument/definition", LspMethod::Definition }, + { "textDocument/declaration", LspMethod::Declaration }, { "textDocument/implementation", LspMethod::Implementation }, { "textDocument/references", LspMethod::References }, { "diagram/diagramTypes", LspMethod::DiagramTypes }, From f2d2c9ab5ea570f2808f4f3eac57e6d60e6f6c35 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Sat, 29 Apr 2023 18:07:22 +0200 Subject: [PATCH 12/26] Refactoring and code convention fixes --- .../include/cpplspservice/cpplspservice.h | 46 ++- plugins/cpp_lsp/service/src/cpplspservice.cpp | 320 ++++-------------- service/lsp/include/lspservice/lsp_types.h | 23 +- service/lsp/include/lspservice/lspservice.h | 31 +- service/lsp/src/lspservice.cpp | 38 ++- webserver/include/webserver/lsphandler.h | 3 +- 6 files changed, 163 insertions(+), 298 deletions(-) diff --git a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h index d920bfa9d..d3b9296ff 100644 --- a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h +++ b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h @@ -12,7 +12,7 @@ #include namespace cc -{ +{ namespace service { namespace lsp @@ -26,25 +26,39 @@ class CppLspServiceHandler : public LspServiceHandler std::shared_ptr datadir_, const cc::webserver::ServerContext& context_); - void getDefinition(pt::ptree& responseTree_, const pt::ptree& params_) override final; - void getDeclaration(pt::ptree& responseTree_, const pt::ptree& params_) override final; - void getImplementation(pt::ptree& responseTree_, const pt::ptree& params_) override final; - void getReferences(pt::ptree& responseTree_, const pt::ptree& params_) override final; - void getDiagramTypes(pt::ptree& responseTree_, const pt::ptree& params_) override final; - void getDiagram(pt::ptree& responseTree_, const pt::ptree& params_) override final; + void getDefinition( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; -private: - std::vector definition( - const TextDocumentPositionParams& params_); + void getDeclaration( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getImplementation( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; - std::vector declaration( - const TextDocumentPositionParams& params_); + void getReferences( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; - std::vector references( - const ReferenceParams& params_); + void getDiagramTypes( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; - std::vector implementation( - const TextDocumentPositionParams& params_); + void getDiagram( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + +private: + void fillResponseTree(pt::ptree& responseTree_, + const pt::ptree& params_, + language::CppServiceHandler::ReferenceType refType_, + bool canBeSingle_ = true); + + std::vector responseLocations( + const TextDocumentPositionParams& params_, + language::CppServiceHandler::ReferenceType refType_); CompletionList fileDiagramTypes( const DiagramTypeParams& params_); diff --git a/plugins/cpp_lsp/service/src/cpplspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp index e5b6d63df..82a923517 100644 --- a/plugins/cpp_lsp/service/src/cpplspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -5,7 +5,7 @@ #include namespace cc -{ +{ namespace service { namespace lsp @@ -21,22 +21,24 @@ CppLspServiceHandler::CppLspServiceHandler( { } -void CppLspServiceHandler::getDefinition(pt::ptree& responseTree_, const pt::ptree& params_) +void CppLspServiceHandler::fillResponseTree(pt::ptree& responseTree_, + const pt::ptree& params_, + language::CppServiceHandler::ReferenceType refType_, + bool canBeSingle_) { - TextDocumentPositionParams gotoDefParams; - gotoDefParams.readNode(params_); + TextDocumentPositionParams positionParams; + positionParams.readNode(params_); - std::vector gotoDefLocations = - definition(gotoDefParams); + std::vector locations = responseLocations(positionParams, refType_); - if (gotoDefLocations.size() == 1) + if (canBeSingle_ && locations.size() == 1) { - responseTree_.put_child("result", gotoDefLocations[0].createNode()); + responseTree_.put_child("result", locations[0].createNode()); } - else if (gotoDefLocations.size() > 1) + else if (locations.size() > 1) { pt::ptree resultNode; - for (const Location &location : gotoDefLocations) + for (const Location &location : locations) { resultNode.push_back(std::make_pair("", location.createNode())); } @@ -44,8 +46,9 @@ void CppLspServiceHandler::getDefinition(pt::ptree& responseTree_, const pt::ptr } } -std::vector CppLspServiceHandler::definition( - const TextDocumentPositionParams& params_) +std::vector CppLspServiceHandler::responseLocations( + const TextDocumentPositionParams& params_, + language::CppServiceHandler::ReferenceType refType_) { language::AstNodeInfo astNodeInfo; core::FilePosition cppPosition; @@ -64,272 +67,76 @@ std::vector CppLspServiceHandler::definition( _cppService.getAstNodeInfoByPosition(astNodeInfo, cppPosition); - std::vector definitionInfo; - _cppService.getReferences(definitionInfo, astNodeInfo.id, language::CppServiceHandler::DEFINITION, {}); + std::vector nodeInfos; + _cppService.getReferences(nodeInfos, astNodeInfo.id, refType_, {}); - std::vector definitionLocations(definitionInfo.size()); + std::vector locations(nodeInfos.size()); std::transform( - definitionInfo.begin(), definitionInfo.end(), - definitionLocations.begin(), - [&, this](const language::AstNodeInfo& definition) + nodeInfos.begin(), nodeInfos.end(), + locations.begin(), + [&, this](const language::AstNodeInfo& nodeInfo) { std::string path = _transaction([&, this](){ - return _db->load(std::stoull(definition.range.file))->path; + return _db->load(std::stoull(nodeInfo.range.file))->path; }); Location location; location.uri = path; - location.range.start.line = definition.range.range.startpos.line; - location.range.start.character = definition.range.range.startpos.column; - location.range.end.line = definition.range.range.endpos.line; - location.range.end.character = definition.range.range.endpos.column; + location.range.start.line = nodeInfo.range.range.startpos.line; + location.range.start.character = nodeInfo.range.range.startpos.column; + location.range.end.line = nodeInfo.range.range.endpos.line; + location.range.end.character = nodeInfo.range.range.endpos.column; return location; }); - return definitionLocations; -} - -void CppLspServiceHandler::getDeclaration(pt::ptree& responseTree_, const pt::ptree& params_) -{ - TextDocumentPositionParams declarationParams; - declarationParams.readNode(params_); - - std::vector declarationLocations = declaration(declarationParams); - - if (declarationLocations.size() == 1) - { - responseTree_.put_child("result", declarationLocations[0].createNode()); - } - else if (declarationLocations.size() > 1) - { - pt::ptree resultNode; - for (const Location &location : declarationLocations) - { - resultNode.push_back(std::make_pair("", location.createNode())); - } - responseTree_.put_child("result", resultNode); - } -} - -std::vector CppLspServiceHandler::declaration(const TextDocumentPositionParams& params_) -{ - - language::AstNodeInfo astNodeInfo; - core::FilePosition cppPosition; - - model::FilePtr file = _transaction([&, this]() - { - return _db->query_one( - odb::query::path == params_.textDocument.uri); - }); - - if (!file) - { - return {}; - } - - cppPosition.file = std::to_string(file->id); - cppPosition.pos.line = params_.position.line; - cppPosition.pos.column = params_.position.character; - - _cppService.getAstNodeInfoByPosition(astNodeInfo, cppPosition); - - std::vector declarationInfo; - _cppService.getReferences(declarationInfo, astNodeInfo.id, language::CppServiceHandler::DECLARATION, {}); - - std::vector declarationLocations(declarationInfo.size()); - std::transform( - declarationInfo.begin(), declarationInfo.end(), - declarationLocations.begin(), - [&, this](const language::AstNodeInfo &declaration) - { - std::string path = _transaction([&, this]() - { - return _db->load(std::stoull(declaration.range.file))->path; - }); - - Location location; - location.uri = path; - location.range.start.line = declaration.range.range.startpos.line; - location.range.start.character = declaration.range.range.startpos.column; - location.range.end.line = declaration.range.range.endpos.line; - location.range.end.character = declaration.range.range.endpos.column; - - return location; - } - ); - - return declarationLocations; + return locations; } -void CppLspServiceHandler::getImplementation(pt::ptree& responseTree_, const pt::ptree& params_) +void CppLspServiceHandler::getDefinition( + pt::ptree& responseTree_, + const pt::ptree& params_) { - TextDocumentPositionParams implementationParams; - implementationParams.readNode(params_); - - std::vector implementationLocations = - implementation(implementationParams); - - if (implementationLocations.size() == 1) - { - responseTree_.put_child("result", implementationLocations[0].createNode()); - } - else if (implementationLocations.size() > 1) - { - pt::ptree resultNode; - for (const Location &location : implementationLocations) - { - resultNode.push_back(std::make_pair("", location.createNode())); - } - responseTree_.put_child("result", resultNode); - } + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::DEFINITION); } -std::vector CppLspServiceHandler::implementation( - const TextDocumentPositionParams& params_) +void CppLspServiceHandler::getDeclaration( + pt::ptree& responseTree_, + const pt::ptree& params_) { - language::AstNodeInfo astNodeInfo; - core::FilePosition cppPosition; - - model::FilePtr file = _transaction([&, this](){ - return _db->query_one( - odb::query::path == params_.textDocument.uri); - }); - - if (!file) - return std::vector(); - - cppPosition.file = std::to_string(file->id); - cppPosition.pos.line = params_.position.line; - cppPosition.pos.column = params_.position.character; - - _cppService.getAstNodeInfoByPosition(astNodeInfo, cppPosition); - - std::vector implementationInfo; - _cppService.getReferences(implementationInfo, astNodeInfo.id, language::CppServiceHandler::INHERIT_BY, {}); - - std::vector implementationLocations(implementationInfo.size()); - std::transform( - implementationInfo.begin(), implementationInfo.end(), - implementationLocations.begin(), - [&, this](const language::AstNodeInfo& definition) - { - std::string path = _transaction([&, this](){ - return _db->load(std::stoull(definition.range.file))->path; - }); - - Location location; - location.uri = path; - location.range.start.line = definition.range.range.startpos.line; - location.range.start.character = definition.range.range.startpos.column; - location.range.end.line = definition.range.range.endpos.line; - location.range.end.character = definition.range.range.endpos.column; - - return location; - }); - - return implementationLocations; + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::DECLARATION); } -void CppLspServiceHandler::getReferences(pt::ptree& responseTree_, const pt::ptree& params_) +void CppLspServiceHandler::getImplementation( + pt::ptree& responseTree_, + const pt::ptree& params_) { - ReferenceParams refParams; - refParams.readNode(params_); - - std::vector refLocations = references(refParams); - - pt::ptree resultNode; - for (const Location& location : refLocations) - { - resultNode.push_back(std::make_pair("", location.createNode())); - } - responseTree_.put_child("result", resultNode); + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::INHERIT_BY); } -std::vector CppLspServiceHandler::references( - const ReferenceParams& params_) +void CppLspServiceHandler::getReferences( + pt::ptree& responseTree_, + const pt::ptree& params_) { - language::AstNodeInfo astNodeInfo; - core::FilePosition cppPosition; - - model::FilePtr file = _transaction([&, this]() - { - return _db->query_one( - odb::query::path == params_.textDocument.uri); - }); - - if (!file) - return std::vector(); - - cppPosition.file = std::to_string(file->id); - cppPosition.pos.line = params_.position.line; - cppPosition.pos.column = params_.position.character; - - _cppService.getAstNodeInfoByPosition(astNodeInfo, cppPosition); - - //--- Usages ---// - std::vector usageInfo; - _cppService.getReferences(usageInfo, astNodeInfo.id, language::CppServiceHandler::USAGE, {}); - - std::vector usageLocations(usageInfo.size()); - std::transform( - usageInfo.begin(), usageInfo.end(), - usageLocations.begin(), - [&, this](const language::AstNodeInfo &usage) - { - std::string path = _transaction([&, this]() - { - return _db->load(std::stoull(usage.range.file))->path; - }); - - Location location; - location.uri = path; - location.range.start.line = usage.range.range.startpos.line; - location.range.start.character = usage.range.range.startpos.column; - location.range.end.line = usage.range.range.endpos.line; - location.range.end.character = usage.range.range.endpos.column; - - return location; - }); - - if (!params_.context.includeDeclaration) - { - return usageLocations; - } - - //--- Declarations ---// - std::vector declarationInfo; - _cppService.getReferences(declarationInfo, astNodeInfo.id, language::CppServiceHandler::DECLARATION, {}); - - std::vector declarationLocations(declarationInfo.size()); - std::transform( - declarationInfo.begin(), declarationInfo.end(), - declarationLocations.begin(), - [&, this](const language::AstNodeInfo &declaration) - { - std::string path = _transaction([&, this]() - { - return _db->load(std::stoull(declaration.range.file))->path; - }); - - Location location; - location.uri = path; - location.range.start.line = declaration.range.range.startpos.line; - location.range.start.character = declaration.range.range.startpos.column; - location.range.end.line = declaration.range.range.endpos.line; - location.range.end.character = declaration.range.range.endpos.column; - - return location; - }); - - usageLocations.insert(usageLocations.end(), - std::make_move_iterator(declarationLocations.begin()), - std::make_move_iterator(declarationLocations.end())); - return usageLocations; + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::USAGE, + false); // the result must always be a vector } -void CppLspServiceHandler::getDiagramTypes(pt::ptree& responseTree_, const pt::ptree& params_) +void CppLspServiceHandler::getDiagramTypes( + pt::ptree& responseTree_, + const pt::ptree& params_) { DiagramTypeParams diagramTypeParams; diagramTypeParams.readNode(params_); @@ -417,7 +224,9 @@ CompletionList CppLspServiceHandler::nodeDiagramTypes( return list; } -void CppLspServiceHandler::getDiagram(pt::ptree& responseTree_, const pt::ptree& params_) +void CppLspServiceHandler::getDiagram( + pt::ptree& responseTree_, + const pt::ptree& params_) { DiagramParams diagramParams; diagramParams.readNode(params_); @@ -454,7 +263,10 @@ Diagram CppLspServiceHandler::fileDiagram( return std::string(); Diagram diagram; - _cppService.getFileDiagram(diagram, std::to_string(file->id), diagramTypeIt->second); + _cppService.getFileDiagram( + diagram, + std::to_string(file->id), + diagramTypeIt->second); return diagram; } diff --git a/service/lsp/include/lspservice/lsp_types.h b/service/lsp/include/lspservice/lsp_types.h index 9ed4b4e1a..a713cf970 100644 --- a/service/lsp/include/lspservice/lsp_types.h +++ b/service/lsp/include/lspservice/lsp_types.h @@ -95,10 +95,12 @@ struct TextDocumentIdentifier : public Readable, public Writeable }; /** - * Position in a text document expressed as zero-based line and zero-based character offset. + * Position in a text document expressed as zero-based line and zero-based + * character offset. * * A position is between two characters like an ‘insert’ cursor in a editor. - * Special values like for example -1 to denote the end of a line are not supported. + * Special values like for example -1 to denote the end of a line are not + * supported. */ struct Position : public Readable, public Writeable { @@ -107,12 +109,12 @@ struct Position : public Readable, public Writeable */ int line; /** - * Character offset on a line in a document (zero-based). Assuming that the line is - * represented as a string, the `character` value represents the gap between the - * `character` and `character + 1`. + * Character offset on a line in a document (zero-based). Assuming that the + * line is represented as a string, the `character` value represents the gap + * between the `character` and `character + 1`. * - * If the character value is greater than the line length it defaults back to the - * line length. + * If the character value is greater than the line length it defaults back to + * the line length. */ int character; @@ -123,9 +125,10 @@ struct Position : public Readable, public Writeable /** * A range in a text document expressed as (zero-based) start and end positions. * - * A range is comparable to a selection in an editor. Therefore the end position is exclusive. - * If you want to specify a range that contains a line including the line ending character(s) - * then use an end position denoting the start of the next line. + * A range is comparable to a selection in an editor. Therefore the end position + * is exclusive. + * If you want to specify a range that contains a line including the line ending + * character(s) then use an end position denoting the start of the next line. */ struct Range : public Readable, public Writeable { diff --git a/service/lsp/include/lspservice/lspservice.h b/service/lsp/include/lspservice/lspservice.h index 32bdfa729..1aae45022 100644 --- a/service/lsp/include/lspservice/lspservice.h +++ b/service/lsp/include/lspservice/lspservice.h @@ -6,7 +6,7 @@ #include namespace cc -{ +{ namespace service { namespace lsp @@ -19,12 +19,29 @@ class LspServiceHandler public: virtual ~LspServiceHandler() = default; - void virtual getDefinition(pt::ptree& responseTree_, const pt::ptree& params_); - void virtual getDeclaration(pt::ptree& responseTree_, const pt::ptree& params_); - void virtual getImplementation(pt::ptree& responseTree_, const pt::ptree& params_); - void virtual getReferences(pt::ptree& responseTree_, const pt::ptree& params_); - void virtual getDiagramTypes(pt::ptree& responseTree_, const pt::ptree& params_); - void virtual getDiagram(pt::ptree& responseTree_, const pt::ptree& params_); + void virtual getDefinition( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getDeclaration( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getImplementation( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getReferences( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getDiagramTypes( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getDiagram( + pt::ptree& responseTree_, + const pt::ptree& params_); void getMethodNotFound(pt::ptree& responseTree_, const std::string& method_); void getParseError(pt::ptree& responseTree_, const std::exception& ex_); diff --git a/service/lsp/src/lspservice.cpp b/service/lsp/src/lspservice.cpp index ca802adde..ca54a067e 100644 --- a/service/lsp/src/lspservice.cpp +++ b/service/lsp/src/lspservice.cpp @@ -1,43 +1,57 @@ #include "lspservice/lspservice.h" namespace cc -{ +{ namespace service { namespace lsp { -void LspServiceHandler::getDefinition(pt::ptree& responseTree_, const pt::ptree&) +void LspServiceHandler::getDefinition( + pt::ptree& responseTree_, + const pt::ptree&) { getMethodNotFound(responseTree_, "textDocument/definition"); } -void LspServiceHandler::getDeclaration(pt::ptree& responseTree_, const pt::ptree&) +void LspServiceHandler::getDeclaration( + pt::ptree& responseTree_, + const pt::ptree&) { getMethodNotFound(responseTree_, "textDocument/declaration"); } -void LspServiceHandler::getImplementation(pt::ptree& responseTree_, const pt::ptree&) +void LspServiceHandler::getImplementation( + pt::ptree& responseTree_, + const pt::ptree&) { getMethodNotFound(responseTree_, "textDocument/implementation"); } -void LspServiceHandler::getReferences(pt::ptree& responseTree_, const pt::ptree&) +void LspServiceHandler::getReferences( + pt::ptree& responseTree_, + const pt::ptree&) { getMethodNotFound(responseTree_, "textDocument/references"); } -void LspServiceHandler::getDiagramTypes(pt::ptree& responseTree_, const pt::ptree&) +void LspServiceHandler::getDiagramTypes( + pt::ptree& responseTree_, + const pt::ptree&) { getMethodNotFound(responseTree_, "diagram/diagramTypes"); } -void LspServiceHandler::getDiagram(pt::ptree& responseTree_, const pt::ptree&) +void LspServiceHandler::getDiagram( + pt::ptree& responseTree_, + const pt::ptree&) { getMethodNotFound(responseTree_, "diagram/diagram"); } -void LspServiceHandler::getMethodNotFound(pt::ptree& responseTree_, const std::string& method_) +void LspServiceHandler::getMethodNotFound( + pt::ptree& responseTree_, + const std::string& method_) { ResponseError error; error.code = ErrorCode::MethodNotFound; @@ -45,7 +59,9 @@ void LspServiceHandler::getMethodNotFound(pt::ptree& responseTree_, const std::s responseTree_.put_child("error", error.createNode()); } -void LspServiceHandler::getParseError(pt::ptree& responseTree_, const std::exception& ex_) +void LspServiceHandler::getParseError( + pt::ptree& responseTree_, + const std::exception& ex_) { ResponseError error; error.code = ErrorCode::ParseError; @@ -53,7 +69,9 @@ void LspServiceHandler::getParseError(pt::ptree& responseTree_, const std::excep responseTree_.put_child("error", error.createNode()); } -void LspServiceHandler::getInternalError(pt::ptree& responseTree_, const std::exception& ex_) +void LspServiceHandler::getInternalError( + pt::ptree& responseTree_, + const std::exception& ex_) { ResponseError error; error.code = ErrorCode::InternalError; diff --git a/webserver/include/webserver/lsphandler.h b/webserver/include/webserver/lsphandler.h index df4a56de0..8961342da 100644 --- a/webserver/include/webserver/lsphandler.h +++ b/webserver/include/webserver/lsphandler.h @@ -43,7 +43,8 @@ class LspHandler : public RequestHandler return "LspHandler"; } - LspHandler(std::unique_ptr&& service_) : lspService(std::move(service_)) + LspHandler(std::unique_ptr&& service_) + : lspService(std::move(service_)) { } From f68feca573037b6abd138fa2c403453d1fdaf116 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Mon, 1 May 2023 23:23:35 +0200 Subject: [PATCH 13/26] Add location request features --- .../include/cpplspservice/cpplspservice.h | 96 ++++++++ plugins/cpp_lsp/service/src/cpplspservice.cpp | 230 ++++++++++++++++++ service/lsp/include/lspservice/lspservice.h | 95 ++++++++ service/lsp/src/lspservice.cpp | 167 +++++++++++++ webserver/include/webserver/lsphandler.h | 175 ++++++++++++- 5 files changed, 756 insertions(+), 7 deletions(-) diff --git a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h index d3b9296ff..7c2d49036 100644 --- a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h +++ b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h @@ -26,6 +26,8 @@ class CppLspServiceHandler : public LspServiceHandler std::shared_ptr datadir_, const cc::webserver::ServerContext& context_); + // Standard LSP methods + void getDefinition( pt::ptree& responseTree_, const pt::ptree& params_) override final; @@ -42,6 +44,8 @@ class CppLspServiceHandler : public LspServiceHandler pt::ptree& responseTree_, const pt::ptree& params_) override final; + // Extended LSP methods + void getDiagramTypes( pt::ptree& responseTree_, const pt::ptree& params_) override final; @@ -50,6 +54,98 @@ class CppLspServiceHandler : public LspServiceHandler pt::ptree& responseTree_, const pt::ptree& params_) override final; + void getParameters( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getLocalVariables( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getReturnType( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getOverridden( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getOverrider( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getRead( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getWrite( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getMethods( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getFriends( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getEnumConstants( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getExpansion( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getUndefinition( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getThisCalls( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getCallsOfThis( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getCallee( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getCaller( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getVirtualCall( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getFunctionPointerCall( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getType( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getAlias( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getImplements( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getDataMember( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + + void getUnderlyingType( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + private: void fillResponseTree(pt::ptree& responseTree_, const pt::ptree& params_, diff --git a/plugins/cpp_lsp/service/src/cpplspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp index 82a923517..ad65197bd 100644 --- a/plugins/cpp_lsp/service/src/cpplspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -134,6 +134,236 @@ void CppLspServiceHandler::getReferences( false); // the result must always be a vector } +void CppLspServiceHandler::getParameters( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::PARAMETER); +} + +void CppLspServiceHandler::getLocalVariables( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::LOCAL_VAR); +} + +void CppLspServiceHandler::getReturnType( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::RETURN_TYPE); +} + +void CppLspServiceHandler::getOverridden( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::OVERRIDE); +} + +void CppLspServiceHandler::getOverrider( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::OVERRIDDEN_BY); +} + +void CppLspServiceHandler::getRead( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::READ); +} + +void CppLspServiceHandler::getWrite( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::WRITE); +} + +void CppLspServiceHandler::getMethods( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::METHOD); +} + +void CppLspServiceHandler::getFriends( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::FRIEND); +} + +void CppLspServiceHandler::getEnumConstants( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::ENUM_CONSTANTS); +} + +void CppLspServiceHandler::getExpansion( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::EXPANSION); +} + +void CppLspServiceHandler::getUndefinition( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::UNDEFINITION); +} + +void CppLspServiceHandler::getThisCalls( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::THIS_CALLS); +} + +void CppLspServiceHandler::getCallsOfThis( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::CALLS_OF_THIS); +} + +void CppLspServiceHandler::getCallee( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::CALLEE); +} + +void CppLspServiceHandler::getCaller( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::CALLER); +} + +void CppLspServiceHandler::getVirtualCall( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::VIRTUAL_CALL); +} + +void CppLspServiceHandler::getFunctionPointerCall( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::FUNC_PTR_CALL); +} + +void CppLspServiceHandler::getType( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::TYPE); +} + +void CppLspServiceHandler::getAlias( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::ALIAS); +} + +void CppLspServiceHandler::getImplements( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::INHERIT_FROM); +} + +void CppLspServiceHandler::getDataMember( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::DATA_MEMBER); +} + +void CppLspServiceHandler::getUnderlyingType( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + fillResponseTree( + responseTree_, + params_, + language::CppServiceHandler::UNDERLYING_TYPE); +} + void CppLspServiceHandler::getDiagramTypes( pt::ptree& responseTree_, const pt::ptree& params_) diff --git a/service/lsp/include/lspservice/lspservice.h b/service/lsp/include/lspservice/lspservice.h index 1aae45022..8a3aac2b9 100644 --- a/service/lsp/include/lspservice/lspservice.h +++ b/service/lsp/include/lspservice/lspservice.h @@ -19,6 +19,7 @@ class LspServiceHandler public: virtual ~LspServiceHandler() = default; + // Standard LSP methods void virtual getDefinition( pt::ptree& responseTree_, const pt::ptree& params_); @@ -35,6 +36,7 @@ class LspServiceHandler pt::ptree& responseTree_, const pt::ptree& params_); + // Extended LSP methods void virtual getDiagramTypes( pt::ptree& responseTree_, const pt::ptree& params_); @@ -43,6 +45,99 @@ class LspServiceHandler pt::ptree& responseTree_, const pt::ptree& params_); + void virtual getParameters( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getLocalVariables( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getReturnType( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getOverridden( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getOverrider( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getRead( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getWrite( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getMethods( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getFriends( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getEnumConstants( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getExpansion( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getUndefinition( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getThisCalls( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getCallsOfThis( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getCallee( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getCaller( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getVirtualCall( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getFunctionPointerCall( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getType( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getAlias( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getImplements( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getDataMember( + pt::ptree& responseTree_, + const pt::ptree& params_); + + void virtual getUnderlyingType( + pt::ptree& responseTree_, + const pt::ptree& params_); + + // Errors void getMethodNotFound(pt::ptree& responseTree_, const std::string& method_); void getParseError(pt::ptree& responseTree_, const std::exception& ex_); void getInternalError(pt::ptree& responseTree_, const std::exception& ex_); diff --git a/service/lsp/src/lspservice.cpp b/service/lsp/src/lspservice.cpp index ca54a067e..2f39a3bd3 100644 --- a/service/lsp/src/lspservice.cpp +++ b/service/lsp/src/lspservice.cpp @@ -7,6 +7,8 @@ namespace service namespace lsp { +// Standard LSP methods + void LspServiceHandler::getDefinition( pt::ptree& responseTree_, const pt::ptree&) @@ -35,6 +37,8 @@ void LspServiceHandler::getReferences( getMethodNotFound(responseTree_, "textDocument/references"); } +// Extended LSP methods + void LspServiceHandler::getDiagramTypes( pt::ptree& responseTree_, const pt::ptree&) @@ -49,6 +53,169 @@ void LspServiceHandler::getDiagram( getMethodNotFound(responseTree_, "diagram/diagram"); } +void LspServiceHandler::getParameters( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/parameters"); +} + +void LspServiceHandler::getLocalVariables( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/localVariables"); +} + +void LspServiceHandler::getReturnType( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/returnType"); +} + +void LspServiceHandler::getOverridden( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/overridden"); +} + +void LspServiceHandler::getOverrider( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/overriders"); +} + +void LspServiceHandler::getRead( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/read"); +} + +void LspServiceHandler::getWrite( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/write"); +} + +void LspServiceHandler::getMethods( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/methods"); +} + +void LspServiceHandler::getFriends( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/friends"); +} + +void LspServiceHandler::getEnumConstants( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/enumConstants"); +} + +void LspServiceHandler::getExpansion( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/expansion"); +} + +void LspServiceHandler::getUndefinition( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/undefinition"); +} + +void LspServiceHandler::getThisCalls( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/thisCalls"); +} + +void LspServiceHandler::getCallsOfThis( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/callsOfThis"); +} + +void LspServiceHandler::getCallee( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/callee"); +} + +void LspServiceHandler::getCaller( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/caller"); +} + +void LspServiceHandler::getVirtualCall( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/virtualCall"); +} + +void LspServiceHandler::getFunctionPointerCall( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/functionPointerCall"); +} + +void LspServiceHandler::getType( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/type"); +} + +void LspServiceHandler::getAlias( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/alias"); +} + +void LspServiceHandler::getImplements( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/implements"); +} + +void LspServiceHandler::getDataMember( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/dataMember"); +} + +void LspServiceHandler::getUnderlyingType( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/underlyingType"); +} + +// Errors + void LspServiceHandler::getMethodNotFound( pt::ptree& responseTree_, const std::string& method_) diff --git a/webserver/include/webserver/lsphandler.h b/webserver/include/webserver/lsphandler.h index 8961342da..e1d901048 100644 --- a/webserver/include/webserver/lsphandler.h +++ b/webserver/include/webserver/lsphandler.h @@ -31,7 +31,30 @@ enum class LspMethod Implementation, References, DiagramTypes, - Diagram + Diagram, + Parameters, + LocalVariables, + ReturnType, + Overridden, + Overriders, + Read, + Write, + Methods, + Friends, + EnumConstants, + Expansion, + Undefinition, + ThisCalls, + CallsOfThis, + Callee, + Caller, + VirtualCall, + FunctionPointerCall, + Type, + Alias, + Implements, + DataMember, + UnderlyingType, }; template @@ -106,6 +129,121 @@ class LspHandler : public RequestHandler lspService->getDiagram(responseTree, params); break; } + case LspMethod::Parameters: + { + lspService->getParameters(responseTree, params); + break; + } + case LspMethod::LocalVariables: + { + lspService->getLocalVariables(responseTree, params); + break; + } + case LspMethod::ReturnType: + { + lspService->getReturnType(responseTree, params); + break; + } + case LspMethod::Overridden: + { + lspService->getOverridden(responseTree, params); + break; + } + case LspMethod::Overriders: + { + lspService->getOverrider(responseTree, params); + break; + } + case LspMethod::Read: + { + lspService->getRead(responseTree, params); + break; + } + case LspMethod::Write: + { + lspService->getWrite(responseTree, params); + break; + } + case LspMethod::Methods: + { + lspService->getMethods(responseTree, params); + break; + } + case LspMethod::Friends: + { + lspService->getFriends(responseTree, params); + break; + } + case LspMethod::EnumConstants: + { + lspService->getEnumConstants(responseTree, params); + break; + } + case LspMethod::Expansion: + { + lspService->getExpansion(responseTree, params); + break; + } + case LspMethod::Undefinition: + { + lspService->getUndefinition(responseTree, params); + break; + } + case LspMethod::ThisCalls: + { + lspService->getThisCalls(responseTree, params); + break; + } + case LspMethod:: CallsOfThis: + { + lspService->getCallsOfThis(responseTree, params); + break; + } + case LspMethod::Callee: + { + lspService->getCallee(responseTree, params); + break; + } + case LspMethod::Caller: + { + lspService->getCaller(responseTree, params); + break; + } + case LspMethod::VirtualCall: + { + lspService->getVirtualCall(responseTree, params); + break; + } + case LspMethod::FunctionPointerCall: + { + lspService->getFunctionPointerCall(responseTree, params); + break; + } + case LspMethod::Type: + { + lspService->getType(responseTree, params); + break; + } + case LspMethod::Alias: + { + lspService->getAlias(responseTree, params); + break; + } + case LspMethod::Implements: + { + lspService->getImplements(responseTree, params); + break; + } + case LspMethod::DataMember: + { + lspService->getDataMember(responseTree, params); + break; + } + case LspMethod::UnderlyingType: + { + lspService->getUnderlyingType(responseTree, params); + break; + } default: { LOG(warning) << "[LSP] Unsupported method: '" << method << "'"; @@ -169,12 +307,35 @@ class LspHandler : public RequestHandler LspMethod parseMethod(const std::string& method) { static std::unordered_map methodMap = { - { "textDocument/definition", LspMethod::Definition }, - { "textDocument/declaration", LspMethod::Declaration }, - { "textDocument/implementation", LspMethod::Implementation }, - { "textDocument/references", LspMethod::References }, - { "diagram/diagramTypes", LspMethod::DiagramTypes }, - { "diagram/diagram", LspMethod::Diagram}, + { "textDocument/definition", LspMethod::Definition }, + { "textDocument/declaration", LspMethod::Declaration }, + { "textDocument/implementation", LspMethod::Implementation }, + { "textDocument/references", LspMethod::References }, + { "diagram/diagramTypes", LspMethod::DiagramTypes }, + { "diagram/diagram", LspMethod::Diagram}, + { "textDocument/parameters", LspMethod::Parameters}, + { "textDocument/localVariables", LspMethod::LocalVariables}, + { "textDocument/returnType", LspMethod::ReturnType}, + { "textDocument/overridden", LspMethod::Overridden}, + { "textDocument/overriders", LspMethod::Overriders}, + { "textDocument/read", LspMethod::Read}, + { "textDocument/write", LspMethod::Write}, + { "textDocument/methods", LspMethod::Methods}, + { "textDocument/friends", LspMethod::Friends}, + { "textDocument/enumConstants", LspMethod::EnumConstants}, + { "textDocument/expansion", LspMethod::Expansion}, + { "textDocument/undefinition", LspMethod::Undefinition}, + { "textDocument/thisCalls", LspMethod::ThisCalls}, + { "textDocument/callsOfThis", LspMethod::CallsOfThis}, + { "textDocument/callee", LspMethod::Callee}, + { "textDocument/caller", LspMethod::Caller}, + { "textDocument/virtualCall", LspMethod::VirtualCall}, + { "textDocument/functionPointerCall", LspMethod::FunctionPointerCall}, + { "textDocument/type", LspMethod::Type}, + { "textDocument/alias", LspMethod::Alias}, + { "textDocument/implements", LspMethod::Implements}, + { "textDocument/dataMember", LspMethod::DataMember}, + { "textDocument/underlyingType", LspMethod::UnderlyingType}, }; auto it = methodMap.find(method); From 45045e1cf83ce1dc840d17ff03aa23ea044ab19c Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Mon, 1 May 2023 23:55:06 +0200 Subject: [PATCH 14/26] Rename and separate diagram methods --- .../service/include/cpplspservice/cpplspservice.h | 4 ++++ plugins/cpp_lsp/service/src/cpplspservice.cpp | 7 +++++++ service/lsp/include/lspservice/lspservice.h | 4 ++++ service/lsp/src/lspservice.cpp | 11 +++++++++-- webserver/include/webserver/lsphandler.h | 11 +++++++++-- 5 files changed, 33 insertions(+), 4 deletions(-) diff --git a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h index 7c2d49036..b5c4324e5 100644 --- a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h +++ b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h @@ -54,6 +54,10 @@ class CppLspServiceHandler : public LspServiceHandler pt::ptree& responseTree_, const pt::ptree& params_) override final; + void getModuleDiagram( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + void getParameters( pt::ptree& responseTree_, const pt::ptree& params_) override final; diff --git a/plugins/cpp_lsp/service/src/cpplspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp index ad65197bd..bbdbcd164 100644 --- a/plugins/cpp_lsp/service/src/cpplspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -474,6 +474,13 @@ void CppLspServiceHandler::getDiagram( responseTree_.put("result", diagramResult); } +void CppLspServiceHandler::getModuleDiagram( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + getDiagram(responseTree_, params_); +} + Diagram CppLspServiceHandler::fileDiagram( const DiagramParams& params_) { diff --git a/service/lsp/include/lspservice/lspservice.h b/service/lsp/include/lspservice/lspservice.h index 8a3aac2b9..263be0c18 100644 --- a/service/lsp/include/lspservice/lspservice.h +++ b/service/lsp/include/lspservice/lspservice.h @@ -45,6 +45,10 @@ class LspServiceHandler pt::ptree& responseTree_, const pt::ptree& params_); + void virtual getModuleDiagram( + pt::ptree& responseTree_, + const pt::ptree& params_); + void virtual getParameters( pt::ptree& responseTree_, const pt::ptree& params_); diff --git a/service/lsp/src/lspservice.cpp b/service/lsp/src/lspservice.cpp index 2f39a3bd3..8316130dc 100644 --- a/service/lsp/src/lspservice.cpp +++ b/service/lsp/src/lspservice.cpp @@ -43,14 +43,21 @@ void LspServiceHandler::getDiagramTypes( pt::ptree& responseTree_, const pt::ptree&) { - getMethodNotFound(responseTree_, "diagram/diagramTypes"); + getMethodNotFound(responseTree_, "textDocument/diagramTypes"); } void LspServiceHandler::getDiagram( pt::ptree& responseTree_, const pt::ptree&) { - getMethodNotFound(responseTree_, "diagram/diagram"); + getMethodNotFound(responseTree_, "textDocument/diagram"); +} + +void LspServiceHandler::getModuleDiagram( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "directory/diagram"); } void LspServiceHandler::getParameters( diff --git a/webserver/include/webserver/lsphandler.h b/webserver/include/webserver/lsphandler.h index e1d901048..f8be1ea14 100644 --- a/webserver/include/webserver/lsphandler.h +++ b/webserver/include/webserver/lsphandler.h @@ -32,6 +32,7 @@ enum class LspMethod References, DiagramTypes, Diagram, + ModuleDiagram, Parameters, LocalVariables, ReturnType, @@ -129,6 +130,11 @@ class LspHandler : public RequestHandler lspService->getDiagram(responseTree, params); break; } + case LspMethod::ModuleDiagram: + { + lspService->getModuleDiagram(responseTree, params); + break; + } case LspMethod::Parameters: { lspService->getParameters(responseTree, params); @@ -311,8 +317,9 @@ class LspHandler : public RequestHandler { "textDocument/declaration", LspMethod::Declaration }, { "textDocument/implementation", LspMethod::Implementation }, { "textDocument/references", LspMethod::References }, - { "diagram/diagramTypes", LspMethod::DiagramTypes }, - { "diagram/diagram", LspMethod::Diagram}, + { "textDocument/diagramTypes", LspMethod::DiagramTypes }, + { "textDocument/diagram", LspMethod::Diagram}, + { "directory/diagram", LspMethod::ModuleDiagram}, { "textDocument/parameters", LspMethod::Parameters}, { "textDocument/localVariables", LspMethod::LocalVariables}, { "textDocument/returnType", LspMethod::ReturnType}, From cd67f0278e09a7a1783d6c9b0aa76615884116bd Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Tue, 2 May 2023 14:01:21 +0200 Subject: [PATCH 15/26] Fix file diagrams for directories --- plugins/cpp_lsp/service/src/cpplspservice.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/cpp_lsp/service/src/cpplspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp index bbdbcd164..54a353d57 100644 --- a/plugins/cpp_lsp/service/src/cpplspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -492,8 +492,16 @@ Diagram CppLspServiceHandler::fileDiagram( if (!file) return std::string(); - std::map diagramTypes; - _cppService.getFileDiagramTypes(diagramTypes, std::to_string(file->id)); + const static std::map diagramTypes = { + {"Internal architecture of this module", + language::CppServiceHandler::SUBSYSTEM_DEPENDENCY}, + {"This module depends on", + language::CppServiceHandler::EXTERNAL_DEPENDENCY}, + {"Users of this module", language::CppServiceHandler::EXTERNAL_USERS}, + {"Include Dependency", language::CppServiceHandler::INCLUDE_DEPENDENCY}, + {"Component Users", language::CppServiceHandler::COMPONENT_USERS}, + {"Interface Diagram", language::CppServiceHandler::INTERFACE}, + }; auto diagramTypeIt = diagramTypes.find(params_.diagramType); if(diagramTypeIt == diagramTypes.end()) From 67269b695c8f9382ef6e2123d61b84c2482154e0 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Tue, 2 May 2023 22:27:13 +0200 Subject: [PATCH 16/26] Separate diagram graph creation from svg creation --- .../cpp/service/include/service/cppservice.h | 9 ++++++ plugins/cpp/service/src/cppservice.cpp | 30 +++++++++++++++---- util/include/util/graph.h | 8 +++-- util/src/graph.cpp | 9 ++++++ 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/plugins/cpp/service/include/service/cppservice.h b/plugins/cpp/service/include/service/cppservice.h index 7bcec09a4..9b0ca0523 100644 --- a/plugins/cpp/service/include/service/cppservice.h +++ b/plugins/cpp/service/include/service/cppservice.h @@ -1,6 +1,7 @@ #ifndef CC_SERVICE_LANGUAGE_CPPSERVICE_H #define CC_SERVICE_LANGUAGE_CPPSERVICE_H +#include "util/graph.h" #include #include #include @@ -69,6 +70,10 @@ class CppServiceHandler : virtual public LanguageServiceIf const core::AstNodeId& astNodeId_, const std::int32_t diagramId_) override; + util::Graph returnDiagram( + const core::AstNodeId& astNodeId_, + const std::int32_t diagramId_); + void getDiagramLegend( std::string& return_, const std::int32_t diagramId_) override; @@ -82,6 +87,10 @@ class CppServiceHandler : virtual public LanguageServiceIf const core::FileId& fileId_, const int32_t diagramId_) override; + util::Graph returnFileDiagram( + const core::FileId& fileId_, + const int32_t diagramId_); + void getFileDiagramLegend( std::string& return_, const std::int32_t diagramId_) override; diff --git a/plugins/cpp/service/src/cppservice.cpp b/plugins/cpp/service/src/cppservice.cpp index 3031ecae9..316d0e91a 100644 --- a/plugins/cpp/service/src/cppservice.cpp +++ b/plugins/cpp/service/src/cppservice.cpp @@ -280,7 +280,7 @@ void CppServiceHandler::getProperties( { VarResult variables = _db->query( VarQuery::entityHash == node.entityHash); - + if (!variables.empty()) { model::CppVariable variable = *variables.begin(); @@ -355,7 +355,7 @@ void CppServiceHandler::getProperties( else LOG(warning) << "Database query result was not expected to be empty. " << __FILE__ << ", line #" << __LINE__; - + break; } @@ -1265,6 +1265,16 @@ void CppServiceHandler::getDiagram( std::string& return_, const core::AstNodeId& astNodeId_, const std::int32_t diagramId_) +{ + util::Graph graph = returnDiagram(astNodeId_, diagramId_); + + if (graph.nodeCount() != 0) + return_ = graph.output(util::Graph::SVG); +} + +util::Graph CppServiceHandler::returnDiagram( + const core::AstNodeId& astNodeId_, + const std::int32_t diagramId_) { Diagram diagram(_db, _datadir, _context); util::Graph graph; @@ -1284,8 +1294,7 @@ void CppServiceHandler::getDiagram( break; } - if (graph.nodeCount() != 0) - return_ = graph.output(util::Graph::SVG); + return graph; } void CppServiceHandler::getDiagramLegend( @@ -1340,6 +1349,16 @@ void CppServiceHandler::getFileDiagram( std::string& return_, const core::FileId& fileId_, const int32_t diagramId_) +{ + util::Graph graph = returnFileDiagram(fileId_, diagramId_); + + if (graph.nodeCount() != 0) + return_ = graph.output(util::Graph::SVG); +} + +util::Graph CppServiceHandler::returnFileDiagram( + const core::FileId& fileId_, + const int32_t diagramId_) { FileDiagram diagram(_db, _datadir, _context); util::Graph graph; @@ -1372,8 +1391,7 @@ void CppServiceHandler::getFileDiagram( break; } - if (graph.nodeCount() != 0) - return_ = graph.output(util::Graph::SVG); + return graph; } void CppServiceHandler::getFileDiagramLegend( diff --git a/util/include/util/graph.h b/util/include/util/graph.h index af93a9921..c58ae5914 100644 --- a/util/include/util/graph.h +++ b/util/include/util/graph.h @@ -11,9 +11,9 @@ #include -namespace cc +namespace cc { -namespace util +namespace util { struct GraphPimpl; @@ -46,6 +46,8 @@ class Graph bool directed_ = true, bool strict_ = false); + Graph(Graph&& other) noexcept; + ~Graph(); /** @@ -246,7 +248,7 @@ class Graph std::unordered_set _ids; std::string _currentId; - GraphPimpl* _graphPimpl; + GraphPimpl* _graphPimpl = nullptr; bool _directed; bool _strict; diff --git a/util/src/graph.cpp b/util/src/graph.cpp index e26f4ff96..7d15c5936 100644 --- a/util/src/graph.cpp +++ b/util/src/graph.cpp @@ -13,6 +13,15 @@ Graph::Graph(const std::string name_, bool directed_, bool strict_) setAttribute("fontsize", "11"); } +Graph::Graph(Graph&& other) noexcept + : _ids(std::move(other._ids)), + _directed(other._directed), + _strict(other._strict), + _isSubgraph(other._isSubgraph) +{ + std::swap(this->_graphPimpl, other._graphPimpl); +} + Graph::~Graph() { delete _graphPimpl; From a4c92684c09e1fc72c3b026c1cc35fb510b74401 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Wed, 3 May 2023 09:54:25 +0200 Subject: [PATCH 17/26] Replace id with location in svg diagram nodes --- plugins/cpp/service/src/diagram.cpp | 11 -- plugins/cpp/service/src/filediagram.cpp | 1 - .../include/cpplspservice/cpplspservice.h | 6 + plugins/cpp_lsp/service/src/cpplspservice.cpp | 117 ++++++++++++++++-- 4 files changed, 114 insertions(+), 21 deletions(-) diff --git a/plugins/cpp/service/src/diagram.cpp b/plugins/cpp/service/src/diagram.cpp index 8f7f340b4..10f2bc8ec 100644 --- a/plugins/cpp/service/src/diagram.cpp +++ b/plugins/cpp/service/src/diagram.cpp @@ -427,17 +427,6 @@ util::Graph::Node Diagram::addNode( graph_.setNodeAttribute(node, "label", nodeInfo_.astNodeValue); - std::stringstream ss; - ss<<_cppHandler._transaction([&, this](){ - return _cppHandler._db->load(std::stoull(nodeInfo_.range.file))->path; - }) - <<';' - < #include @@ -172,10 +174,14 @@ class CppLspServiceHandler : public LspServiceHandler Diagram nodeDiagram( const DiagramParams& params_); + void addLocationToIdInDiagram(util::Graph& graph_, const std::string& root_); + void addPathToIdInFileDiagram(util::Graph& graph_, const std::string& root_); + std::shared_ptr _db; util::OdbTransaction _transaction; language::CppServiceHandler _cppService; + core::ProjectServiceHandler _projectHandler; }; } // lsp diff --git a/plugins/cpp_lsp/service/src/cpplspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp index 54a353d57..a542309a6 100644 --- a/plugins/cpp_lsp/service/src/cpplspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -1,8 +1,11 @@ #include -#include #include +#include +#include +#include #include +#include "language_types.h" namespace cc { @@ -17,7 +20,8 @@ CppLspServiceHandler::CppLspServiceHandler( const cc::webserver::ServerContext& context_) : _db(db_), _transaction(db_), - _cppService(db_, datadir_, context_) + _cppService(db_, datadir_, context_), + _projectHandler(db_, datadir_, context_) { } @@ -507,12 +511,16 @@ Diagram CppLspServiceHandler::fileDiagram( if(diagramTypeIt == diagramTypes.end()) return std::string(); - Diagram diagram; - _cppService.getFileDiagram( - diagram, + auto graph = _cppService.returnFileDiagram( std::to_string(file->id), diagramTypeIt->second); - return diagram; + + if (graph.nodeCount() != 0) + { + addPathToIdInFileDiagram(graph, std::to_string(file->id)); + return graph.output(util::Graph::SVG); + } + return std::string(); } Diagram CppLspServiceHandler::nodeDiagram( @@ -542,10 +550,101 @@ Diagram CppLspServiceHandler::nodeDiagram( if(diagramTypeIt == diagramTypes.end()) return std::string(); - Diagram diagram; - _cppService.getDiagram(diagram, astNodeInfo.id, diagramTypeIt->second); + auto graph = _cppService.returnDiagram(astNodeInfo.id, diagramTypeIt->second); + + if (graph.nodeCount() != 0) + { + addLocationToIdInDiagram(graph, astNodeInfo.id); + return graph.output(util::Graph::SVG); + } + return std::string(); +} - return diagram; +void CppLspServiceHandler::addLocationToIdInDiagram( + util::Graph& graph_, + const std::string& root_) +{ + std::stack unvisited; + std::map visited; + unvisited.push(root_); + + while (!unvisited.empty()) + { + std::string current = unvisited.top(); + unvisited.pop(); + std::vector nodes; + _cppService.getReferences( + nodes, current, language::CppServiceHandler::DEFINITION, {}); + language::AstNodeInfo& nodeInfo = nodes.front(); + if (visited.find(nodeInfo.id) == visited.end() || !visited[nodeInfo.id]) + { + visited[nodeInfo.id] = true; + for (auto& child : graph_.getChildren(nodeInfo.id)) + { + if(visited.find(child) == visited.end()) + { + unvisited.push(child); + visited[child] = false; + } + } + for (auto& parent : graph_.getParents(nodeInfo.id)) + { + if(visited.find(parent) == visited.end()) + { + unvisited.push(parent); + visited[parent] = false; + } + } + + std::stringstream ss; + ss<<_transaction([&, this](){ + return _db->load(std::stoull(nodeInfo.range.file))->path; + }) + <<';' + < unvisited; + std::map visited; + unvisited.push(root_); + + while (!unvisited.empty()) + { + std::string current = unvisited.top(); + unvisited.pop(); + core::FileInfo fileInfo; + _projectHandler.getFileInfo(fileInfo, current); + if (visited.find(fileInfo.id) == visited.end() || !visited[fileInfo.id]) + { + visited[fileInfo.id] = true; + for (auto& child : graph_.getChildren(fileInfo.id)) + { + if(visited.find(child) == visited.end()) + { + unvisited.push(child); + visited[child] = false; + } + } + for (auto& parent : graph_.getParents(fileInfo.id)) + { + if(visited.find(parent) == visited.end()) + { + unvisited.push(parent); + visited[parent] = false; + } + } + graph_.setNodeAttribute(fileInfo.id, "id", fileInfo.path, true); + } + } } } // lsp From d3973b2e571064d4289de8b68787476c93e321f1 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Wed, 3 May 2023 12:01:27 +0200 Subject: [PATCH 18/26] Fix diagram types for position dependant diagrams --- plugins/cpp_lsp/service/src/cpplspservice.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/cpp_lsp/service/src/cpplspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp index a542309a6..116e8e210 100644 --- a/plugins/cpp_lsp/service/src/cpplspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -543,8 +543,12 @@ Diagram CppLspServiceHandler::nodeDiagram( _cppService.getAstNodeInfoByPosition(astNodeInfo, cppPosition); - std::map diagramTypes; - _cppService.getDiagramTypes(diagramTypes, astNodeInfo.id); + const static std::map diagramTypes = { + {"Function call diagram", language::CppServiceHandler::FUNCTION_CALL}, + {"Detailed class diagram", language::CppServiceHandler::DETAILED_CLASS}, + {"Class collaboration diagram", + language::CppServiceHandler::CLASS_COLLABORATION}, + }; auto diagramTypeIt = diagramTypes.find(params_.diagramType); if(diagramTypeIt == diagramTypes.end()) From afb1b533133dade45271dc94b4835475d75e3479 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Thu, 11 May 2023 09:12:03 +0200 Subject: [PATCH 19/26] Add signature, remove unused types --- .../include/cpplspservice/cpplspservice.h | 12 ++--- plugins/cpp_lsp/service/src/cpplspservice.cpp | 47 +++++++++++-------- service/lsp/include/lspservice/lspservice.h | 12 ++--- service/lsp/src/lspservice.cpp | 21 +++------ webserver/include/webserver/lsphandler.h | 21 +++------ 5 files changed, 49 insertions(+), 64 deletions(-) diff --git a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h index 24adfb86d..fe0830d78 100644 --- a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h +++ b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h @@ -30,6 +30,10 @@ class CppLspServiceHandler : public LspServiceHandler // Standard LSP methods + void getSignature( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + void getDefinition( pt::ptree& responseTree_, const pt::ptree& params_) override final; @@ -68,10 +72,6 @@ class CppLspServiceHandler : public LspServiceHandler pt::ptree& responseTree_, const pt::ptree& params_) override final; - void getReturnType( - pt::ptree& responseTree_, - const pt::ptree& params_) override final; - void getOverridden( pt::ptree& responseTree_, const pt::ptree& params_) override final; @@ -132,10 +132,6 @@ class CppLspServiceHandler : public LspServiceHandler pt::ptree& responseTree_, const pt::ptree& params_) override final; - void getType( - pt::ptree& responseTree_, - const pt::ptree& params_) override final; - void getAlias( pt::ptree& responseTree_, const pt::ptree& params_) override final; diff --git a/plugins/cpp_lsp/service/src/cpplspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp index 116e8e210..14f67c7b8 100644 --- a/plugins/cpp_lsp/service/src/cpplspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -97,6 +97,33 @@ std::vector CppLspServiceHandler::responseLocations( return locations; } +void CppLspServiceHandler::getSignature( + pt::ptree& responseTree_, + const pt::ptree& params_) +{ + TextDocumentPositionParams positionParams; + positionParams.readNode(params_); + + language::AstNodeInfo astNodeInfo; + core::FilePosition cppPosition; + + model::FilePtr file = _transaction([&, this](){ + return _db->query_one( + odb::query::path == positionParams.textDocument.uri); + }); + + if (file) + { + cppPosition.file = std::to_string(file->id); + cppPosition.pos.line = positionParams.position.line; + cppPosition.pos.column = positionParams.position.character; + + _cppService.getAstNodeInfoByPosition(astNodeInfo, cppPosition); + + responseTree_.put("result", astNodeInfo.astNodeValue); + } +} + void CppLspServiceHandler::getDefinition( pt::ptree& responseTree_, const pt::ptree& params_) @@ -158,16 +185,6 @@ void CppLspServiceHandler::getLocalVariables( language::CppServiceHandler::LOCAL_VAR); } -void CppLspServiceHandler::getReturnType( - pt::ptree& responseTree_, - const pt::ptree& params_) -{ - fillResponseTree( - responseTree_, - params_, - language::CppServiceHandler::RETURN_TYPE); -} - void CppLspServiceHandler::getOverridden( pt::ptree& responseTree_, const pt::ptree& params_) @@ -318,16 +335,6 @@ void CppLspServiceHandler::getFunctionPointerCall( language::CppServiceHandler::FUNC_PTR_CALL); } -void CppLspServiceHandler::getType( - pt::ptree& responseTree_, - const pt::ptree& params_) -{ - fillResponseTree( - responseTree_, - params_, - language::CppServiceHandler::TYPE); -} - void CppLspServiceHandler::getAlias( pt::ptree& responseTree_, const pt::ptree& params_) diff --git a/service/lsp/include/lspservice/lspservice.h b/service/lsp/include/lspservice/lspservice.h index 263be0c18..c8a5bfdca 100644 --- a/service/lsp/include/lspservice/lspservice.h +++ b/service/lsp/include/lspservice/lspservice.h @@ -20,6 +20,10 @@ class LspServiceHandler virtual ~LspServiceHandler() = default; // Standard LSP methods + void virtual getSignature( + pt::ptree& responseTree_, + const pt::ptree& params_); + void virtual getDefinition( pt::ptree& responseTree_, const pt::ptree& params_); @@ -57,10 +61,6 @@ class LspServiceHandler pt::ptree& responseTree_, const pt::ptree& params_); - void virtual getReturnType( - pt::ptree& responseTree_, - const pt::ptree& params_); - void virtual getOverridden( pt::ptree& responseTree_, const pt::ptree& params_); @@ -121,10 +121,6 @@ class LspServiceHandler pt::ptree& responseTree_, const pt::ptree& params_); - void virtual getType( - pt::ptree& responseTree_, - const pt::ptree& params_); - void virtual getAlias( pt::ptree& responseTree_, const pt::ptree& params_); diff --git a/service/lsp/src/lspservice.cpp b/service/lsp/src/lspservice.cpp index 8316130dc..592d23e3f 100644 --- a/service/lsp/src/lspservice.cpp +++ b/service/lsp/src/lspservice.cpp @@ -9,6 +9,13 @@ namespace lsp // Standard LSP methods +void LspServiceHandler::getSignature( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/signature"); +} + void LspServiceHandler::getDefinition( pt::ptree& responseTree_, const pt::ptree&) @@ -74,13 +81,6 @@ void LspServiceHandler::getLocalVariables( getMethodNotFound(responseTree_, "textDocument/localVariables"); } -void LspServiceHandler::getReturnType( - pt::ptree& responseTree_, - const pt::ptree&) -{ - getMethodNotFound(responseTree_, "textDocument/returnType"); -} - void LspServiceHandler::getOverridden( pt::ptree& responseTree_, const pt::ptree&) @@ -186,13 +186,6 @@ void LspServiceHandler::getFunctionPointerCall( getMethodNotFound(responseTree_, "textDocument/functionPointerCall"); } -void LspServiceHandler::getType( - pt::ptree& responseTree_, - const pt::ptree&) -{ - getMethodNotFound(responseTree_, "textDocument/type"); -} - void LspServiceHandler::getAlias( pt::ptree& responseTree_, const pt::ptree&) diff --git a/webserver/include/webserver/lsphandler.h b/webserver/include/webserver/lsphandler.h index f8be1ea14..0e63e16d9 100644 --- a/webserver/include/webserver/lsphandler.h +++ b/webserver/include/webserver/lsphandler.h @@ -26,6 +26,7 @@ namespace pt = boost::property_tree; enum class LspMethod { Unknown = 0, + Signature, Definition, Declaration, Implementation, @@ -35,7 +36,6 @@ enum class LspMethod ModuleDiagram, Parameters, LocalVariables, - ReturnType, Overridden, Overriders, Read, @@ -51,7 +51,6 @@ enum class LspMethod Caller, VirtualCall, FunctionPointerCall, - Type, Alias, Implements, DataMember, @@ -100,6 +99,11 @@ class LspHandler : public RequestHandler switch (parseMethod(method)) { + case LspMethod::Signature: + { + lspService->getSignature(responseTree, params); + break; + } case LspMethod::Definition: { lspService->getDefinition(responseTree, params); @@ -145,11 +149,6 @@ class LspHandler : public RequestHandler lspService->getLocalVariables(responseTree, params); break; } - case LspMethod::ReturnType: - { - lspService->getReturnType(responseTree, params); - break; - } case LspMethod::Overridden: { lspService->getOverridden(responseTree, params); @@ -225,11 +224,6 @@ class LspHandler : public RequestHandler lspService->getFunctionPointerCall(responseTree, params); break; } - case LspMethod::Type: - { - lspService->getType(responseTree, params); - break; - } case LspMethod::Alias: { lspService->getAlias(responseTree, params); @@ -313,6 +307,7 @@ class LspHandler : public RequestHandler LspMethod parseMethod(const std::string& method) { static std::unordered_map methodMap = { + { "textDocument/signature", LspMethod::Signature }, { "textDocument/definition", LspMethod::Definition }, { "textDocument/declaration", LspMethod::Declaration }, { "textDocument/implementation", LspMethod::Implementation }, @@ -322,7 +317,6 @@ class LspHandler : public RequestHandler { "directory/diagram", LspMethod::ModuleDiagram}, { "textDocument/parameters", LspMethod::Parameters}, { "textDocument/localVariables", LspMethod::LocalVariables}, - { "textDocument/returnType", LspMethod::ReturnType}, { "textDocument/overridden", LspMethod::Overridden}, { "textDocument/overriders", LspMethod::Overriders}, { "textDocument/read", LspMethod::Read}, @@ -338,7 +332,6 @@ class LspHandler : public RequestHandler { "textDocument/caller", LspMethod::Caller}, { "textDocument/virtualCall", LspMethod::VirtualCall}, { "textDocument/functionPointerCall", LspMethod::FunctionPointerCall}, - { "textDocument/type", LspMethod::Type}, { "textDocument/alias", LspMethod::Alias}, { "textDocument/implements", LspMethod::Implements}, { "textDocument/dataMember", LspMethod::DataMember}, From 11415b5434228cc791324ab1d6b8e3e908fca4a6 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Sat, 13 May 2023 13:09:16 +0200 Subject: [PATCH 20/26] Remove unneeded registerLspPluginSimple helper function --- plugins/cpp_lsp/service/src/plugin.cpp | 4 +- webserver/include/webserver/pluginhelper.h | 79 ---------------------- 2 files changed, 2 insertions(+), 81 deletions(-) diff --git a/plugins/cpp_lsp/service/src/plugin.cpp b/plugins/cpp_lsp/service/src/plugin.cpp index a15d0110d..ec22357f7 100644 --- a/plugins/cpp_lsp/service/src/plugin.cpp +++ b/plugins/cpp_lsp/service/src/plugin.cpp @@ -21,11 +21,11 @@ extern "C" const cc::webserver::ServerContext& context_, cc::webserver::PluginHandler* pluginHandler_) { - cc::webserver::registerLspPluginSimple( + cc::webserver::registerPluginSimple( context_, pluginHandler_, CODECOMPASS_LSP_SERVICE_FACTORY_WITH_CFG(Cpp, lsp), - "LspService"); + "CppLspService"); } } #pragma clang diagnostic pop diff --git a/webserver/include/webserver/pluginhelper.h b/webserver/include/webserver/pluginhelper.h index 83c9ee284..3807ed363 100644 --- a/webserver/include/webserver/pluginhelper.h +++ b/webserver/include/webserver/pluginhelper.h @@ -31,7 +31,6 @@ inline void registerPluginSimple( const std::string& serviceName_) { namespace fs = boost::filesystem; - namespace po = boost::program_options; namespace pt = boost::property_tree; for (fs::directory_iterator it(ctx_.options["workspace"].as()); @@ -105,84 +104,6 @@ inline void registerPluginSimple( "There are no parsed projects in the given workspace directory."); } -template -inline void registerLspPluginSimple( - const ServerContext& ctx_, - PluginHandler* pluginHandler_, - ServiceFactoryT serviceFactory_, - const std::string& serviceName_) -{ - namespace fs = boost::filesystem; - namespace pt = boost::property_tree; - - for (fs::directory_iterator it(ctx_.options["workspace"].as()); - it != fs::directory_iterator(); - ++it) - { - std::string project = it->path().filename().native(); - - fs::path projectInfo = it->path(); - if ( fs::is_regular_file( projectInfo) ) - continue; - - projectInfo += "/project_info.json"; - if (!fs::exists(projectInfo.native())) - { - LOG(error) - << "Skip project '" << project << "', because no project info file " - << "can be found at: " << projectInfo; - continue; - } - - pt::ptree root; - pt::read_json(projectInfo.native(), root); - - std::string connStr = root.get("database", ""); - if (connStr.empty()) { - LOG(error) - << "Skip project '" << project << "', because no database " - << "connection string can be found for it in the '" - << projectInfo << "' file!"; - continue; - } - - std::shared_ptr db = util::connectDatabase(connStr); - - if (!db) - { - LOG(error) - << "Wrong connection string: '" << connStr << "' " - << "for project: '" << project << "' " - << "for service: '" << serviceName_ << "'"; - - continue; - } - - try - { - // Create handler - std::shared_ptr servicePtr( - serviceFactory_( - db, - std::make_shared(fs::canonical(it->path()).native()), - ctx_)); - - // Register implementation - pluginHandler_->registerImplementation(serviceName_, servicePtr); - } - catch (const util::ServiceNotAvailException& ex) - { - LOG(warning) - << "Exception: " << ex.what() - << " in workspace " << project; - } - } - - if (pluginHandler_->getImplementationMap().empty()) - throw std::runtime_error( - "There are no parsed projects in the given workspace directory."); -} - #define CODECOMPASS_SERVICE_FACTORY_WITH_CFG(serviceName, nspace) \ [](std::shared_ptr& db_, \ std::shared_ptr datadir_, \ From 5b14e759b0544cdc55d1bd46e9034dacc4ebeee6 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Mon, 15 May 2023 23:20:16 +0200 Subject: [PATCH 21/26] Cleanup and convention checking --- .../cpp/service/include/service/cppservice.h | 2 +- plugins/cpp/service/src/cppservice.cpp | 34 ++++++++++--------- plugins/cpp_lsp/service/CMakeLists.txt | 2 +- .../include/cpplspservice/cpplspservice.h | 16 ++++----- plugins/cpp_lsp/service/src/cpplspservice.cpp | 1 + plugins/cpp_lsp/service/src/plugin.cpp | 1 + service/lsp/include/lspservice/lsp_types.h | 2 +- service/lsp/include/lspservice/lspservice.h | 10 +++--- service/lsp/src/lspservice.cpp | 16 ++++----- webserver/CMakeLists.txt | 12 +------ webserver/include/webserver/lsphandler.h | 10 +++--- webserver/include/webserver/thrifthandler.h | 2 +- 12 files changed, 50 insertions(+), 58 deletions(-) diff --git a/plugins/cpp/service/include/service/cppservice.h b/plugins/cpp/service/include/service/cppservice.h index ff84cef73..e8d5b0de7 100644 --- a/plugins/cpp/service/include/service/cppservice.h +++ b/plugins/cpp/service/include/service/cppservice.h @@ -1,7 +1,6 @@ #ifndef CC_SERVICE_LANGUAGE_CPPSERVICE_H #define CC_SERVICE_LANGUAGE_CPPSERVICE_H -#include "util/graph.h" #include #include #include @@ -20,6 +19,7 @@ #include #include +#include "util/graph.h" #include namespace cc diff --git a/plugins/cpp/service/src/cppservice.cpp b/plugins/cpp/service/src/cppservice.cpp index cf5103ab7..516043a74 100644 --- a/plugins/cpp/service/src/cppservice.cpp +++ b/plugins/cpp/service/src/cppservice.cpp @@ -289,7 +289,7 @@ void CppServiceHandler::getProperties( return_["Type"] = variable.qualifiedType; } else - LOG(warning) + LOG(warning) << "Unexpected empty result when querying properties " "of C++ variable: " << toShortDiagnosticString(node); @@ -312,7 +312,7 @@ void CppServiceHandler::getProperties( return_["Signature"] = function.name; } else - LOG(warning) + LOG(warning) << "Unexpected empty result when querying properties " "of C++ function: " << toShortDiagnosticString(node); @@ -338,7 +338,7 @@ void CppServiceHandler::getProperties( return_["Qualified name"] = type.qualifiedName; } else - LOG(warning) + LOG(warning) << "Unexpected empty result when querying properties " "of C++ type: " << toShortDiagnosticString(node); @@ -363,7 +363,7 @@ void CppServiceHandler::getProperties( << "Unexpected empty result when querying properties " "of C++ typedef: " << toShortDiagnosticString(node); - + break; } @@ -381,7 +381,7 @@ void CppServiceHandler::getProperties( return_["Value"] = std::to_string(enumConst.value); } else - LOG(warning) + LOG(warning) << "Unexpected empty result when querying properties " "of C++ enum constant: " << toShortDiagnosticString(node); @@ -502,7 +502,7 @@ std::int32_t CppServiceHandler::getReferenceCount( TypeQuery::entityHash == function.typeHash).count; } else - LOG(warning) + LOG(warning) << "Unexpected empty result when counting return types " "of C++ function: " << toShortDiagnosticString(node); @@ -538,7 +538,7 @@ std::int32_t CppServiceHandler::getReferenceCount( TypeQuery::entityHash == variable.typeHash).count; } else - LOG(warning) + LOG(warning) << "Unexpected empty result when counting types " "of C++ variable: " << toShortDiagnosticString(node); @@ -788,7 +788,7 @@ void CppServiceHandler::getReferences( std::to_string(var.load()->astNodeId))); } else - LOG(warning) + LOG(warning) << "Unexpected empty result when querying parameters " "of C++ function: " << toShortDiagnosticString(node); @@ -811,7 +811,7 @@ void CppServiceHandler::getReferences( std::to_string(var.load()->astNodeId))); } else - LOG(warning) + LOG(warning) << "Unexpected empty result when querying local variables " "of C++ function: " << toShortDiagnosticString(node); @@ -840,7 +840,7 @@ void CppServiceHandler::getReferences( } } else - LOG(warning) + LOG(warning) << "Unexpected empty result when querying return type " "of C++ function: " << toShortDiagnosticString(node); @@ -904,7 +904,7 @@ void CppServiceHandler::getReferences( } } else - LOG(warning) + LOG(warning) << "Unexpected empty result when querying type " "of C++ variable: " << toShortDiagnosticString(node); @@ -1005,7 +1005,7 @@ void CppServiceHandler::getReferences( nodes = std::vector(result.begin(), result.end()); } else - LOG(warning) + LOG(warning) << "Unexpected empty result when querying underlying type " "of C++ typedef: " << toShortDiagnosticString(node); @@ -1033,7 +1033,7 @@ void CppServiceHandler::getReferences( }); } else - LOG(warning) + LOG(warning) << "Unexpected empty result when querying enum constants " "of C++ enum: " << toShortDiagnosticString(node); @@ -1253,7 +1253,9 @@ void CppServiceHandler::getSyntaxHighlight( // Regular expression to find element position const std::regex specialChars { R"([-[\]{}()*+?.,\^$|#\s])" }; - std::string sanitizedAstValue = std::regex_replace(node.astValue, specialChars, R"(\$&)"); + std::string sanitizedAstValue = std::regex_replace(node.astValue, + specialChars, + R"(\$&)"); std::string reg = "\\b" + sanitizedAstValue + "\\b"; for (std::size_t i = node.location.range.start.line - 1; @@ -1667,7 +1669,7 @@ CppServiceHandler::getTags(const std::vector& nodes_) tags[node.id].push_back(model::tagToString(tag)); } else - LOG(warning) + LOG(warning) << "Unexpected empty result when querying tags " "of C++ function: " << toShortDiagnosticString(node); @@ -1702,7 +1704,7 @@ CppServiceHandler::getTags(const std::vector& nodes_) tags[node.id].push_back(model::tagToString(tag)); } else - LOG(warning) + LOG(warning) << "Unexpected empty result when querying tags " "of C++ variable: " << toShortDiagnosticString(node); diff --git a/plugins/cpp_lsp/service/CMakeLists.txt b/plugins/cpp_lsp/service/CMakeLists.txt index e583819ef..934c19777 100644 --- a/plugins/cpp_lsp/service/CMakeLists.txt +++ b/plugins/cpp_lsp/service/CMakeLists.txt @@ -21,4 +21,4 @@ target_link_libraries(cpplspservice lspservice util) -install(TARGETS cpplspservice DESTINATION ${INSTALL_SERVICE_DIR}) \ No newline at end of file +install(TARGETS cpplspservice DESTINATION ${INSTALL_SERVICE_DIR}) diff --git a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h index fe0830d78..b08ebb82a 100644 --- a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h +++ b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h @@ -1,17 +1,17 @@ #ifndef CC_SERVICE_LSP_CPPLSPSERVICE_H #define CC_SERVICE_LSP_CPPLSPSERVICE_H -#include "projectservice/projectservice.h" -#include "util/graph.h" #include #include #include + #include #include - #include #include +#include "projectservice/projectservice.h" +#include "util/graph.h" namespace cc { @@ -30,10 +30,6 @@ class CppLspServiceHandler : public LspServiceHandler // Standard LSP methods - void getSignature( - pt::ptree& responseTree_, - const pt::ptree& params_) override final; - void getDefinition( pt::ptree& responseTree_, const pt::ptree& params_) override final; @@ -64,6 +60,10 @@ class CppLspServiceHandler : public LspServiceHandler pt::ptree& responseTree_, const pt::ptree& params_) override final; + void getSignature( + pt::ptree& responseTree_, + const pt::ptree& params_) override final; + void getParameters( pt::ptree& responseTree_, const pt::ptree& params_) override final; @@ -184,4 +184,4 @@ class CppLspServiceHandler : public LspServiceHandler } // service } // cc -#endif // CC_SERVICE_LSP_CPPLSPSERVICE_H \ No newline at end of file +#endif // CC_SERVICE_LSP_CPPLSPSERVICE_H diff --git a/plugins/cpp_lsp/service/src/cpplspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp index 14f67c7b8..0ce392e68 100644 --- a/plugins/cpp_lsp/service/src/cpplspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -2,6 +2,7 @@ #include #include #include + #include #include diff --git a/plugins/cpp_lsp/service/src/plugin.cpp b/plugins/cpp_lsp/service/src/plugin.cpp index ec22357f7..c0488fc0c 100644 --- a/plugins/cpp_lsp/service/src/plugin.cpp +++ b/plugins/cpp_lsp/service/src/plugin.cpp @@ -1,4 +1,5 @@ #include + #include #include #include diff --git a/service/lsp/include/lspservice/lsp_types.h b/service/lsp/include/lspservice/lsp_types.h index a713cf970..50cf06566 100644 --- a/service/lsp/include/lspservice/lsp_types.h +++ b/service/lsp/include/lspservice/lsp_types.h @@ -274,4 +274,4 @@ struct CompletionList : public Writeable } // service } // cc -#endif // CC_MODEL_LSP_TYPES_H \ No newline at end of file +#endif // CC_MODEL_LSP_TYPES_H diff --git a/service/lsp/include/lspservice/lspservice.h b/service/lsp/include/lspservice/lspservice.h index c8a5bfdca..931502e00 100644 --- a/service/lsp/include/lspservice/lspservice.h +++ b/service/lsp/include/lspservice/lspservice.h @@ -20,10 +20,6 @@ class LspServiceHandler virtual ~LspServiceHandler() = default; // Standard LSP methods - void virtual getSignature( - pt::ptree& responseTree_, - const pt::ptree& params_); - void virtual getDefinition( pt::ptree& responseTree_, const pt::ptree& params_); @@ -53,6 +49,10 @@ class LspServiceHandler pt::ptree& responseTree_, const pt::ptree& params_); + void virtual getSignature( + pt::ptree& responseTree_, + const pt::ptree& params_); + void virtual getParameters( pt::ptree& responseTree_, const pt::ptree& params_); @@ -149,4 +149,4 @@ class LspServiceHandler } // service } // cc -#endif // CC_SERVICE_LSP_LSPSERVICE_H \ No newline at end of file +#endif // CC_SERVICE_LSP_LSPSERVICE_H diff --git a/service/lsp/src/lspservice.cpp b/service/lsp/src/lspservice.cpp index 592d23e3f..399876cd9 100644 --- a/service/lsp/src/lspservice.cpp +++ b/service/lsp/src/lspservice.cpp @@ -9,13 +9,6 @@ namespace lsp // Standard LSP methods -void LspServiceHandler::getSignature( - pt::ptree& responseTree_, - const pt::ptree&) -{ - getMethodNotFound(responseTree_, "textDocument/signature"); -} - void LspServiceHandler::getDefinition( pt::ptree& responseTree_, const pt::ptree&) @@ -67,6 +60,13 @@ void LspServiceHandler::getModuleDiagram( getMethodNotFound(responseTree_, "directory/diagram"); } +void LspServiceHandler::getSignature( + pt::ptree& responseTree_, + const pt::ptree&) +{ + getMethodNotFound(responseTree_, "textDocument/signature"); +} + void LspServiceHandler::getParameters( pt::ptree& responseTree_, const pt::ptree&) @@ -255,4 +255,4 @@ void LspServiceHandler::getUnknownError(pt::ptree& responseTree_) } // lsp } // service -} // cc \ No newline at end of file +} // cc diff --git a/webserver/CMakeLists.txt b/webserver/CMakeLists.txt index 1d0a2f6f4..368c3793e 100644 --- a/webserver/CMakeLists.txt +++ b/webserver/CMakeLists.txt @@ -23,26 +23,16 @@ target_link_libraries(mongoose PRIVATE ssl) target_include_directories(CodeCompass_webserver PUBLIC include ${PROJECT_SOURCE_DIR}/model/include - ${PROJECT_SOURCE_DIR}/util/include - ${PROJECT_BINARY_DIR}/service/language/gen-cpp - ${PROJECT_BINARY_DIR}/service/project/gen-cpp - ${PROJECT_SOURCE_DIR}/service/project/include - ${PROJECT_SOURCE_DIR}/plugins/cpp/service/include - ${PROJECT_SOURCE_DIR}/plugins/cpp/model/include) + ${PROJECT_SOURCE_DIR}/util/include) target_link_libraries(CodeCompass_webserver util - cppservice mongoose ${Boost_LIBRARIES} ${ODB_LIBRARIES} - ${THRIFT_LIBTHRIFT_LIBRARIES} pthread dl) -add_dependencies(CodeCompass_webserver projectthrift) -add_dependencies(CodeCompass_webserver languagethrift) - install(TARGETS CodeCompass_webserver RUNTIME DESTINATION ${INSTALL_BIN_DIR} LIBRARY DESTINATION ${INSTALL_LIB_DIR}) diff --git a/webserver/include/webserver/lsphandler.h b/webserver/include/webserver/lsphandler.h index 0e63e16d9..7a647d61f 100644 --- a/webserver/include/webserver/lsphandler.h +++ b/webserver/include/webserver/lsphandler.h @@ -2,16 +2,14 @@ #define CC_WEBSERVER_LSPHANDLER_H #include -#include #include #include #include -#include "webserver/requesthandler.h" - #include -#include + +#include "webserver/requesthandler.h" namespace cc { @@ -304,9 +302,9 @@ class LspHandler : public RequestHandler return std::string(conn_->content, conn_->content + conn_->content_len); } - LspMethod parseMethod(const std::string& method) + LspMethod parseMethod(const std::string& method) const { - static std::unordered_map methodMap = { + const static std::unordered_map methodMap = { { "textDocument/signature", LspMethod::Signature }, { "textDocument/definition", LspMethod::Definition }, { "textDocument/declaration", LspMethod::Declaration }, diff --git a/webserver/include/webserver/thrifthandler.h b/webserver/include/webserver/thrifthandler.h index 32924cc10..c13db6b0c 100644 --- a/webserver/include/webserver/thrifthandler.h +++ b/webserver/include/webserver/thrifthandler.h @@ -137,7 +137,7 @@ class ThriftHandler : public RequestHandler return MG_TRUE; } -protected: +private: LoggingProcessor _processor; }; From 618b3abaaafeee29b64251f5e7f37c6a7eda55d9 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Wed, 17 May 2023 00:10:03 +0200 Subject: [PATCH 22/26] Use strings instead of CompletionItems for DiagramTypes --- .../include/cpplspservice/cpplspservice.h | 4 +- plugins/cpp_lsp/service/src/cpplspservice.cpp | 42 ++++++++----------- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h index b08ebb82a..6caeb4245 100644 --- a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h +++ b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h @@ -158,10 +158,10 @@ class CppLspServiceHandler : public LspServiceHandler const TextDocumentPositionParams& params_, language::CppServiceHandler::ReferenceType refType_); - CompletionList fileDiagramTypes( + std::vector fileDiagramTypes( const DiagramTypeParams& params_); - CompletionList nodeDiagramTypes( + std::vector nodeDiagramTypes( const DiagramTypeParams& params_); Diagram fileDiagram( diff --git a/plugins/cpp_lsp/service/src/cpplspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp index 0ce392e68..8469d84aa 100644 --- a/plugins/cpp_lsp/service/src/cpplspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -383,7 +384,7 @@ void CppLspServiceHandler::getDiagramTypes( DiagramTypeParams diagramTypeParams; diagramTypeParams.readNode(params_); - CompletionList diagramTypesResult; + std::vector diagramTypesResult; if (!diagramTypeParams.position) { diagramTypesResult = fileDiagramTypes(diagramTypeParams); @@ -393,10 +394,15 @@ void CppLspServiceHandler::getDiagramTypes( diagramTypesResult = nodeDiagramTypes(diagramTypeParams); } - responseTree_.put_child("result", diagramTypesResult.createNode()); + pt::ptree resultNode; + for (const std::string& diagramType : diagramTypesResult) + { + resultNode.push_back(std::make_pair("", pt::ptree(diagramType))); + } + responseTree_.put_child("result", resultNode); } -CompletionList CppLspServiceHandler::fileDiagramTypes( +std::vector CppLspServiceHandler::fileDiagramTypes( const DiagramTypeParams& params_) { model::FilePtr file = _transaction([&, this](){ @@ -405,29 +411,23 @@ CompletionList CppLspServiceHandler::fileDiagramTypes( }); if (!file) - return CompletionList(); + return {}; std::map result; _cppService.getFileDiagramTypes(result, std::to_string(file->id)); - std::vector diagramTypes(result.size()); + std::vector diagramTypes(result.size()); std::transform(result.begin(), result.end(), diagramTypes.begin(), [](std::pair item) { - CompletionItem ci; - ci.label = item.first; - ci.data = std::to_string(item.second); - return ci; + return item.first; } ); - CompletionList list; - list.isIncomplete = false; - list.items = diagramTypes; - return list; + return diagramTypes; } -CompletionList CppLspServiceHandler::nodeDiagramTypes( +std::vector CppLspServiceHandler::nodeDiagramTypes( const DiagramTypeParams& params_) { language::AstNodeInfo astNodeInfo; @@ -439,7 +439,7 @@ CompletionList CppLspServiceHandler::nodeDiagramTypes( }); if (!file) - return CompletionList(); + return {}; cppPosition.file = std::to_string(file->id); cppPosition.pos.line = params_.position->line; @@ -449,21 +449,15 @@ CompletionList CppLspServiceHandler::nodeDiagramTypes( std::map result; _cppService.getDiagramTypes(result, astNodeInfo.id); - std::vector diagramTypes(result.size()); + std::vector diagramTypes(result.size()); std::transform(result.begin(), result.end(), diagramTypes.begin(), [](std::pair item) { - CompletionItem ci; - ci.label = item.first; - ci.data = std::to_string(item.second); - return ci; + return item.first; } ); - CompletionList list; - list.isIncomplete = false; - list.items = diagramTypes; - return list; + return diagramTypes; } void CppLspServiceHandler::getDiagram( From f1c90840bd9c013b3c4c936ec532d3126dabe3b7 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Mon, 22 May 2023 23:28:45 +0200 Subject: [PATCH 23/26] More cleanup and code convention fixes --- .../cpp/service/include/service/cppservice.h | 2 +- plugins/cpp/service/src/diagram.cpp | 2 - .../include/cpplspservice/cpplspservice.h | 13 ++-- service/lsp/include/lspservice/lsp_types.h | 64 +++++++++---------- webserver/CMakeLists.txt | 3 - webserver/include/webserver/lsphandler.h | 3 +- 6 files changed, 43 insertions(+), 44 deletions(-) diff --git a/plugins/cpp/service/include/service/cppservice.h b/plugins/cpp/service/include/service/cppservice.h index e8d5b0de7..49944c974 100644 --- a/plugins/cpp/service/include/service/cppservice.h +++ b/plugins/cpp/service/include/service/cppservice.h @@ -19,7 +19,7 @@ #include #include -#include "util/graph.h" +#include #include namespace cc diff --git a/plugins/cpp/service/src/diagram.cpp b/plugins/cpp/service/src/diagram.cpp index 10f2bc8ec..4a241c1ef 100644 --- a/plugins/cpp/service/src/diagram.cpp +++ b/plugins/cpp/service/src/diagram.cpp @@ -1,5 +1,3 @@ -#include - #include #include #include diff --git a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h index 6caeb4245..f0c6b31b3 100644 --- a/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h +++ b/plugins/cpp_lsp/service/include/cpplspservice/cpplspservice.h @@ -10,8 +10,8 @@ #include #include #include -#include "projectservice/projectservice.h" -#include "util/graph.h" +#include +#include namespace cc { @@ -170,8 +170,13 @@ class CppLspServiceHandler : public LspServiceHandler Diagram nodeDiagram( const DiagramParams& params_); - void addLocationToIdInDiagram(util::Graph& graph_, const std::string& root_); - void addPathToIdInFileDiagram(util::Graph& graph_, const std::string& root_); + void addLocationToIdInDiagram( + util::Graph& graph_, + const std::string& root_); + + void addPathToIdInFileDiagram( + util::Graph& graph_, + const std::string& root_); std::shared_ptr _db; util::OdbTransaction _transaction; diff --git a/service/lsp/include/lspservice/lsp_types.h b/service/lsp/include/lspservice/lsp_types.h index 50cf06566..5722ef767 100644 --- a/service/lsp/include/lspservice/lsp_types.h +++ b/service/lsp/include/lspservice/lsp_types.h @@ -67,12 +67,12 @@ struct Writeable struct ResponseError : public Writeable { /** - * A number indicating the error type that occurred. - */ + * A number indicating the error type that occurred. + */ ErrorCode code; /** - * A string providing a short description of the error. - */ + * A string providing a short description of the error. + */ std::string message; void writeNode(pt::ptree& node) const override; @@ -86,8 +86,8 @@ struct ResponseError : public Writeable struct TextDocumentIdentifier : public Readable, public Writeable { /** - * The text document's URI. - */ + * The text document's URI. + */ DocumentUri uri; void readNode(const pt::ptree& node) override; @@ -105,17 +105,17 @@ struct TextDocumentIdentifier : public Readable, public Writeable struct Position : public Readable, public Writeable { /** - * Line position in a document (zero-based). - */ + * Line position in a document (zero-based). + */ int line; /** - * Character offset on a line in a document (zero-based). Assuming that the + * Character offset on a line in a document (zero-based). Assuming that the * line is represented as a string, the `character` value represents the gap * between the `character` and `character + 1`. - * - * If the character value is greater than the line length it defaults back to - * the line length. - */ + * + * If the character value is greater than the line length it defaults back to + * the line length. + */ int character; void readNode(const pt::ptree& node) override; @@ -133,12 +133,12 @@ struct Position : public Readable, public Writeable struct Range : public Readable, public Writeable { /** - * The range's start position. - */ + * The range's start position. + */ Position start; /** - * The range's end position. - */ + * The range's end position. + */ Position end; void readNode(const pt::ptree& node) override; @@ -229,23 +229,23 @@ struct CompletionItem final : public Readable, public Writeable */ std::string label; /** - * The kind of this completion item. Based of the kind + * The kind of this completion item. Based of the kind * an icon is chosen by the editor. - */ + */ boost::optional kind; /** - * A human-readable string with additional information - * about this item, like type or symbol information. - */ + * A human-readable string with additional information + * about this item, like type or symbol information. + */ boost::optional detail; /** - * A human-readable string that represents a doc-comment. - */ + * A human-readable string that represents a doc-comment. + */ boost::optional documentation; /** - * A data entry field that is preserved on a completion item between - * a completion and a completion resolve request. - */ + * A data entry field that is preserved on a completion item between + * a completion and a completion resolve request. + */ boost::optional data; void readNode(const pt::ptree& node) override; @@ -258,13 +258,13 @@ struct CompletionItem final : public Readable, public Writeable struct CompletionList : public Writeable { /** - * This list it not complete. Further typing should result in recomputing - * this list. - */ + * This list it not complete. Further typing should result in recomputing + * this list. + */ bool isIncomplete; /** - * The completion items. - */ + * The completion items. + */ std::vector items; void writeNode(pt::ptree& node) const override; diff --git a/webserver/CMakeLists.txt b/webserver/CMakeLists.txt index 368c3793e..534f4a341 100644 --- a/webserver/CMakeLists.txt +++ b/webserver/CMakeLists.txt @@ -1,6 +1,3 @@ -include_directories(SYSTEM - ${THRIFT_LIBTHRIFT_INCLUDE_DIRS}) - add_subdirectory(authenticators) add_executable(CodeCompass_webserver diff --git a/webserver/include/webserver/lsphandler.h b/webserver/include/webserver/lsphandler.h index 7a647d61f..77bb6a467 100644 --- a/webserver/include/webserver/lsphandler.h +++ b/webserver/include/webserver/lsphandler.h @@ -8,8 +8,7 @@ #include #include - -#include "webserver/requesthandler.h" +#include namespace cc { From 53b32a35475003d1015a72408e94b1ebc5eeb3af Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Sun, 28 May 2023 21:36:37 +0200 Subject: [PATCH 24/26] Adding const specifier and convention fixes --- plugins/cpp_lsp/service/src/cpplspservice.cpp | 14 ++++++++------ service/lsp/src/lspservice.cpp | 2 +- webserver/include/webserver/thrifthandler.h | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/plugins/cpp_lsp/service/src/cpplspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp index 8469d84aa..9e2e1e612 100644 --- a/plugins/cpp_lsp/service/src/cpplspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -498,7 +498,8 @@ Diagram CppLspServiceHandler::fileDiagram( if (!file) return std::string(); - const static std::map diagramTypes = { + const static std::map diagramTypes = + { {"Internal architecture of this module", language::CppServiceHandler::SUBSYSTEM_DEPENDENCY}, {"This module depends on", @@ -545,7 +546,8 @@ Diagram CppLspServiceHandler::nodeDiagram( _cppService.getAstNodeInfoByPosition(astNodeInfo, cppPosition); - const static std::map diagramTypes = { + const static std::map diagramTypes = + { {"Function call diagram", language::CppServiceHandler::FUNCTION_CALL}, {"Detailed class diagram", language::CppServiceHandler::DETAILED_CLASS}, {"Class collaboration diagram", @@ -585,7 +587,7 @@ void CppLspServiceHandler::addLocationToIdInDiagram( if (visited.find(nodeInfo.id) == visited.end() || !visited[nodeInfo.id]) { visited[nodeInfo.id] = true; - for (auto& child : graph_.getChildren(nodeInfo.id)) + for (const auto& child : graph_.getChildren(nodeInfo.id)) { if(visited.find(child) == visited.end()) { @@ -593,7 +595,7 @@ void CppLspServiceHandler::addLocationToIdInDiagram( visited[child] = false; } } - for (auto& parent : graph_.getParents(nodeInfo.id)) + for (const auto& parent : graph_.getParents(nodeInfo.id)) { if(visited.find(parent) == visited.end()) { @@ -632,7 +634,7 @@ void CppLspServiceHandler::addPathToIdInFileDiagram( if (visited.find(fileInfo.id) == visited.end() || !visited[fileInfo.id]) { visited[fileInfo.id] = true; - for (auto& child : graph_.getChildren(fileInfo.id)) + for (const auto& child : graph_.getChildren(fileInfo.id)) { if(visited.find(child) == visited.end()) { @@ -640,7 +642,7 @@ void CppLspServiceHandler::addPathToIdInFileDiagram( visited[child] = false; } } - for (auto& parent : graph_.getParents(fileInfo.id)) + for (const auto& parent : graph_.getParents(fileInfo.id)) { if(visited.find(parent) == visited.end()) { diff --git a/service/lsp/src/lspservice.cpp b/service/lsp/src/lspservice.cpp index 399876cd9..21f4edc0c 100644 --- a/service/lsp/src/lspservice.cpp +++ b/service/lsp/src/lspservice.cpp @@ -1,4 +1,4 @@ -#include "lspservice/lspservice.h" +#include namespace cc { diff --git a/webserver/include/webserver/thrifthandler.h b/webserver/include/webserver/thrifthandler.h index c13db6b0c..a91b96fdb 100644 --- a/webserver/include/webserver/thrifthandler.h +++ b/webserver/include/webserver/thrifthandler.h @@ -10,9 +10,9 @@ #include #include +#include #include "mongoose.h" -#include "webserver/requesthandler.h" namespace cc { From 3a391fa839f71d1ebdd2364aeecef3137ad09096 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Sun, 25 Jun 2023 23:37:34 +0200 Subject: [PATCH 25/26] Add LSP details to README --- doc/lsp.md | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++ doc/usage.md | 15 +++- 2 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 doc/lsp.md diff --git a/doc/lsp.md b/doc/lsp.md new file mode 100644 index 000000000..d4e4ebc37 --- /dev/null +++ b/doc/lsp.md @@ -0,0 +1,227 @@ +# Supported LSP Requests + +## Standard + +- [textDocument/declaration](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_declaration) +- [textDocument/definition](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_definition) +- [textDocument/implementation](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_implementation) +- [textDocument/references](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_references) + +## CodeCompass Specific Methods + +### textDocument/thisCalls + +Returns the locations of function calls inside the function at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/callsOfThis + +Returns the locations where the function at the selected position is called. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/callee + +Returns the locations of the definitions of the functions called by the function at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/caller + +Returns the locations of the definitions of the functions that call the function at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/virtualCall + +Returns the locations where the function at the selected position may be virtually called. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/functionPointerCall + +Returns the locations where the function at the selected position is called through a function pointer. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/parameters + +Returns the locations of the parameters of the function at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/localVariables + +Returns the locations of the local variables of the function at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/overridden + +Returns the locations of the functions the function at the selected position overrides. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/overriders + +Returns the locations of the functions that override the function at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/read + +Returns the locations the variable at the selected position is read. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/write + +Returns the locations where the variable at the selected position is written. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/signature + +Returns the name of the AST node of the entity at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* string | null + +### textDocument/alias + +Returns the locations of the type aliases of the type at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/implements + +Returns the locations of the types that inherit from the type at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/dataMember + +Returns the locations of the data members of the class at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/methods + +Returns the locations of the methods of the class at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/friends + +Returns the locations of the friends of the class at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/underlyingType + +Returns the location of the underlying type of the type alias at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/enumConstants + +Returns the locations of the constants of the enumeration at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/expansion + +Returns the locations of the expansions of the macro at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/undefinition + +Returns the locations of the undefinitions of the macro at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location) | [Location](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#location)[] | null + +### textDocument/diagramTypes + +Returns the names of diagram types available at the selected position. + +*Params:* [TextDocumentPositionParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocumentPositionParams) + +*Response:* string[] | null + +### textDocument/diagram + +Returns a diagram of the selected type based on the selected position in SVG format. + +*Params:* diagramParams + +*Response:* string | null + +### directory/diagram + +Returns a diagram of the selected type based on the selected module in SVG format. + +*Params:* diagramParams + +*Response:* string | null + +## CodeCompass Specific Types + +### DiagramParams + +Parameters needed for diagram requests. +Directory based diagrams do not need the position parameter. +The diagramType should contain a valid diagram type name for the given language plugin. +The `textDocument/diagramTypes` method can be used to access these for position dependant diagrams. + +```javascript +interface DiagramParams { + textDocument: TextDocumentIdentifier; + position?: Position; + diagramType: string; +} +``` diff --git a/doc/usage.md b/doc/usage.md index 7bf61704c..4aeac132f 100644 --- a/doc/usage.md +++ b/doc/usage.md @@ -291,4 +291,17 @@ The server will be available in a browser on In both the parser and the webserver it is possible to write the logs to a given directory. This feature can be enabled by passing the `--logtarget` command line option with the full path to the directory to be used for storing the log files. -If this argument is not specified, the logs will be written to the terminal only. \ No newline at end of file +If this argument is not specified, the logs will be written to the terminal only. + +### Language Server Protocol support + +The CodeCompass_webserver is not a fully fledged LSP server on its own, +but it does support some standard and non-standard LSP requests for C and C++ projects. +The full list can be found here: [Supported LSP Requests](lsp.md) + +To access this feature, requests must be sent to the following address: +`http://://CppLspService` + +e.g.: [`http://localhost:6251/MyProject/CppLspService`](http://localhost:6251/MyProject/CppLspService) + +The project name should match the name of the project used by the CodeCompass_parser. From 2b29feb56d71fd8db1a875fb52f318ad677af567 Mon Sep 17 00:00:00 2001 From: tamasdunai Date: Fri, 29 Sep 2023 21:29:33 +0200 Subject: [PATCH 26/26] Convention fixes --- plugins/cpp_lsp/service/src/cpplspservice.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/cpp_lsp/service/src/cpplspservice.cpp b/plugins/cpp_lsp/service/src/cpplspservice.cpp index 9e2e1e612..0d80ea329 100644 --- a/plugins/cpp_lsp/service/src/cpplspservice.cpp +++ b/plugins/cpp_lsp/service/src/cpplspservice.cpp @@ -511,7 +511,7 @@ Diagram CppLspServiceHandler::fileDiagram( }; auto diagramTypeIt = diagramTypes.find(params_.diagramType); - if(diagramTypeIt == diagramTypes.end()) + if (diagramTypeIt == diagramTypes.end()) return std::string(); auto graph = _cppService.returnFileDiagram( @@ -555,7 +555,7 @@ Diagram CppLspServiceHandler::nodeDiagram( }; auto diagramTypeIt = diagramTypes.find(params_.diagramType); - if(diagramTypeIt == diagramTypes.end()) + if (diagramTypeIt == diagramTypes.end()) return std::string(); auto graph = _cppService.returnDiagram(astNodeInfo.id, diagramTypeIt->second); @@ -589,7 +589,7 @@ void CppLspServiceHandler::addLocationToIdInDiagram( visited[nodeInfo.id] = true; for (const auto& child : graph_.getChildren(nodeInfo.id)) { - if(visited.find(child) == visited.end()) + if (visited.find(child) == visited.end()) { unvisited.push(child); visited[child] = false; @@ -597,7 +597,7 @@ void CppLspServiceHandler::addLocationToIdInDiagram( } for (const auto& parent : graph_.getParents(nodeInfo.id)) { - if(visited.find(parent) == visited.end()) + if (visited.find(parent) == visited.end()) { unvisited.push(parent); visited[parent] = false; @@ -636,7 +636,7 @@ void CppLspServiceHandler::addPathToIdInFileDiagram( visited[fileInfo.id] = true; for (const auto& child : graph_.getChildren(fileInfo.id)) { - if(visited.find(child) == visited.end()) + if (visited.find(child) == visited.end()) { unvisited.push(child); visited[child] = false; @@ -644,7 +644,7 @@ void CppLspServiceHandler::addPathToIdInFileDiagram( } for (const auto& parent : graph_.getParents(fileInfo.id)) { - if(visited.find(parent) == visited.end()) + if (visited.find(parent) == visited.end()) { unvisited.push(parent); visited[parent] = false;