-
Notifications
You must be signed in to change notification settings - Fork 12.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ClangD] Refactor clangd into separate components
Summary: Major refactoring to split LSP implementation, Clang API calls and threading(mostly synchronization) Reviewers: bkramer, krasimir Reviewed By: bkramer Subscribers: cfe-commits, mgorny, klimek Tags: #clang-tools-extra Differential Revision: https://reviews.llvm.org/D33047 llvm-svn: 303067
- Loading branch information
1 parent
e890d5b
commit 96a1363
Showing
20 changed files
with
1,199 additions
and
737 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
//===--- ClangdLSPServer.cpp - LSP server ------------------------*- C++-*-===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===---------------------------------------------------------------------===// | ||
|
||
#include "ClangdLSPServer.h" | ||
#include "JSONRPCDispatcher.h" | ||
|
||
using namespace clang::clangd; | ||
using namespace clang; | ||
|
||
class ClangdLSPServer::LSPDiagnosticsConsumer : public DiagnosticsConsumer { | ||
public: | ||
LSPDiagnosticsConsumer(ClangdLSPServer &Server) : Server(Server) {} | ||
|
||
virtual void onDiagnosticsReady(PathRef File, | ||
std::vector<DiagWithFixIts> Diagnostics) { | ||
Server.consumeDiagnostics(File, Diagnostics); | ||
} | ||
|
||
private: | ||
ClangdLSPServer &Server; | ||
}; | ||
|
||
ClangdLSPServer::ClangdLSPServer(JSONOutput &Out, bool RunSynchronously) | ||
: Out(Out), | ||
Server(llvm::make_unique<DirectoryBasedGlobalCompilationDatabase>(), | ||
llvm::make_unique<LSPDiagnosticsConsumer>(*this), | ||
RunSynchronously) {} | ||
|
||
void ClangdLSPServer::openDocument(StringRef File, StringRef Contents) { | ||
Server.addDocument(File, Contents); | ||
} | ||
|
||
void ClangdLSPServer::closeDocument(StringRef File) { | ||
Server.removeDocument(File); | ||
} | ||
|
||
std::vector<CompletionItem> ClangdLSPServer::codeComplete(PathRef File, | ||
Position Pos) { | ||
return Server.codeComplete(File, Pos); | ||
} | ||
|
||
std::vector<clang::tooling::Replacement> | ||
ClangdLSPServer::getFixIts(StringRef File, const clangd::Diagnostic &D) { | ||
std::lock_guard<std::mutex> Lock(FixItsMutex); | ||
auto DiagToFixItsIter = FixItsMap.find(File); | ||
if (DiagToFixItsIter == FixItsMap.end()) | ||
return {}; | ||
|
||
const auto &DiagToFixItsMap = DiagToFixItsIter->second; | ||
auto FixItsIter = DiagToFixItsMap.find(D); | ||
if (FixItsIter == DiagToFixItsMap.end()) | ||
return {}; | ||
|
||
return FixItsIter->second; | ||
} | ||
|
||
std::string ClangdLSPServer::getDocument(PathRef File) { | ||
return Server.getDocument(File); | ||
} | ||
|
||
void ClangdLSPServer::consumeDiagnostics( | ||
PathRef File, std::vector<DiagWithFixIts> Diagnostics) { | ||
std::string DiagnosticsJSON; | ||
|
||
DiagnosticToReplacementMap LocalFixIts; // Temporary storage | ||
for (auto &DiagWithFixes : Diagnostics) { | ||
auto Diag = DiagWithFixes.Diag; | ||
DiagnosticsJSON += | ||
R"({"range":)" + Range::unparse(Diag.range) + | ||
R"(,"severity":)" + std::to_string(Diag.severity) + | ||
R"(,"message":")" + llvm::yaml::escape(Diag.message) + | ||
R"("},)"; | ||
|
||
// We convert to Replacements to become independent of the SourceManager. | ||
auto &FixItsForDiagnostic = LocalFixIts[Diag]; | ||
std::copy(DiagWithFixes.FixIts.begin(), DiagWithFixes.FixIts.end(), | ||
std::back_inserter(FixItsForDiagnostic)); | ||
} | ||
|
||
// Cache FixIts | ||
{ | ||
// FIXME(ibiryukov): should be deleted when documents are removed | ||
std::lock_guard<std::mutex> Lock(FixItsMutex); | ||
FixItsMap[File] = LocalFixIts; | ||
} | ||
|
||
// Publish diagnostics. | ||
if (!DiagnosticsJSON.empty()) | ||
DiagnosticsJSON.pop_back(); // Drop trailing comma. | ||
Out.writeMessage( | ||
R"({"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":")" + | ||
URI::fromFile(File).uri + R"(","diagnostics":[)" + DiagnosticsJSON + | ||
R"(]}})"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
//===--- ClangdLSPServer.h - LSP server --------------------------*- C++-*-===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===---------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H | ||
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H | ||
|
||
#include "ClangdServer.h" | ||
#include "Path.h" | ||
#include "Protocol.h" | ||
#include "clang/Tooling/Core/Replacement.h" | ||
|
||
namespace clang { | ||
namespace clangd { | ||
|
||
class JSONOutput; | ||
|
||
/// This class serves as an intermediate layer of LSP server implementation, | ||
/// glueing the JSON LSP protocol layer and ClangdServer together. It doesn't | ||
/// directly handle input from LSP client. | ||
/// Most methods are synchronous and return their result directly, but | ||
/// diagnostics are provided asynchronously when ready via | ||
/// JSONOutput::writeMessage. | ||
class ClangdLSPServer { | ||
public: | ||
ClangdLSPServer(JSONOutput &Out, bool RunSynchronously); | ||
|
||
/// Update the document text for \p File with \p Contents, schedule update of | ||
/// diagnostics. Out.writeMessage will called to push diagnostics to LSP | ||
/// client asynchronously when they are ready. | ||
void openDocument(PathRef File, StringRef Contents); | ||
/// Stop tracking the document for \p File. | ||
void closeDocument(PathRef File); | ||
|
||
/// Run code completion synchronously. | ||
std::vector<CompletionItem> codeComplete(PathRef File, Position Pos); | ||
|
||
/// Get the fixes associated with a certain diagnostic in a specified file as | ||
/// replacements. | ||
/// | ||
/// This function is thread-safe. It returns a copy to avoid handing out | ||
/// references to unguarded data. | ||
std::vector<clang::tooling::Replacement> | ||
getFixIts(StringRef File, const clangd::Diagnostic &D); | ||
|
||
/// Get the current document contents stored for \p File. | ||
/// FIXME(ibiryukov): This function is here to allow implementation of | ||
/// formatCode from ProtocolHandlers.cpp. We should move formatCode to | ||
/// ClangdServer class and remove this function from public interface. | ||
std::string getDocument(PathRef File); | ||
|
||
private: | ||
class LSPDiagnosticsConsumer; | ||
|
||
/// Function that will be called on a separate thread when diagnostics are | ||
/// ready. Sends the Dianostics to LSP client via Out.writeMessage and caches | ||
/// corresponding fixits in the FixItsMap. | ||
void consumeDiagnostics(PathRef File, | ||
std::vector<DiagWithFixIts> Diagnostics); | ||
|
||
JSONOutput &Out; | ||
ClangdServer Server; | ||
|
||
std::mutex FixItsMutex; | ||
typedef std::map<clangd::Diagnostic, std::vector<clang::tooling::Replacement>> | ||
DiagnosticToReplacementMap; | ||
/// Caches FixIts per file and diagnostics | ||
llvm::StringMap<DiagnosticToReplacementMap> FixItsMap; | ||
}; | ||
|
||
} // namespace clangd | ||
} // namespace clang | ||
|
||
#endif |
Oops, something went wrong.