rwols updated this revision to Diff 122606.
rwols added a comment.

- Merge with upstream, fix merge conflicts
- Add a FIXME for a caching strategy for .clang-format files


https://reviews.llvm.org/D39430

Files:
  clangd/ClangdLSPServer.cpp
  clangd/ClangdServer.cpp
  clangd/ClangdServer.h
  clangd/JSONRPCDispatcher.cpp
  clangd/JSONRPCDispatcher.h

Index: clangd/JSONRPCDispatcher.h
===================================================================
--- clangd/JSONRPCDispatcher.h
+++ clangd/JSONRPCDispatcher.h
@@ -16,6 +16,7 @@
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/YAMLParser.h"
 #include <iosfwd>
 #include <mutex>
@@ -58,11 +59,13 @@
   RequestContext(JSONOutput &Out, llvm::Optional<json::Expr> ID)
       : Out(Out), ID(std::move(ID)) {}
 
-  /// Sends a successful reply.
+  /// Send a response to a request from the client.
   void reply(json::Expr &&Result);
-  /// Sends an error response to the client, and logs it.
+  /// Send an error response to the client, and logs it.
   void replyError(ErrorCode code, const llvm::StringRef &Message);
-  /// Sends a request to the client.
+  /// Send all error messages contained in Err to the client, and log them.
+  void replyError(llvm::Error Err);
+  /// Send a request to the client.
   void call(llvm::StringRef Method, json::Expr &&Params);
 
 private:
Index: clangd/JSONRPCDispatcher.cpp
===================================================================
--- clangd/JSONRPCDispatcher.cpp
+++ clangd/JSONRPCDispatcher.cpp
@@ -59,24 +59,28 @@
     Out.log("Attempted to reply to a notification!\n");
     return;
   }
-  Out.writeMessage(json::obj{
-      {"jsonrpc", "2.0"},
-      {"id", *ID},
-      {"result", std::move(Result)},
-  });
+  Out.writeMessage(
+      json::obj{{"jsonrpc", "2.0"}, {"id", *ID}, {"result", Result}});
 }
 
-void RequestContext::replyError(ErrorCode code, const llvm::StringRef &Message) {
+void RequestContext::replyError(ErrorCode code,
+                                const llvm::StringRef &Message) {
   Out.log("Error " + Twine(static_cast<int>(code)) + ": " + Message + "\n");
   if (ID) {
     Out.writeMessage(json::obj{
         {"jsonrpc", "2.0"},
         {"id", *ID},
-        {"error", json::obj{{"code", static_cast<int>(code)}, {"message", Message}}},
+        {"error",
+         json::obj{{"code", static_cast<int>(code)}, {"message", Message}}},
     });
   }
 }
 
+void RequestContext::replyError(llvm::Error Err) {
+  const auto Message = llvm::toString(std::move(Err));
+  replyError(ErrorCode::UnknownErrorCode, Message);
+}
+
 void RequestContext::call(StringRef Method, json::Expr &&Params) {
   // FIXME: Generate/Increment IDs for every request so that we can get proper
   // replies once we need to.
Index: clangd/ClangdServer.h
===================================================================
--- clangd/ClangdServer.h
+++ clangd/ClangdServer.h
@@ -284,12 +284,18 @@
   /// given a header file and vice versa.
   llvm::Optional<Path> switchSourceHeader(PathRef Path);
 
-  /// Run formatting for \p Rng inside \p File.
-  std::vector<tooling::Replacement> formatRange(PathRef File, Range Rng);
-  /// Run formatting for the whole \p File.
-  std::vector<tooling::Replacement> formatFile(PathRef File);
-  /// Run formatting after a character was typed at \p Pos in \p File.
-  std::vector<tooling::Replacement> formatOnType(PathRef File, Position Pos);
+  /// Run formatting for \p Rng inside \p File with content \p Code.
+  llvm::Expected<std::vector<tooling::Replacement>>
+  formatRange(llvm::StringRef Code, PathRef File, Range Rng);
+
+  /// Run formatting for the whole \p File with content \p Code.
+  llvm::Expected<std::vector<tooling::Replacement>>
+  formatFile(llvm::StringRef Code, PathRef File);
+
+  /// Run formatting after a character was typed at \p Pos in \p File with
+  /// content \p Code.
+  llvm::Expected<std::vector<tooling::Replacement>>
+  formatOnType(llvm::StringRef Code, PathRef File, Position Pos);
 
   /// Gets current document contents for \p File. \p File must point to a
   /// currently tracked file.
@@ -305,6 +311,12 @@
   void onFileEvent(const DidChangeWatchedFilesParams &Params);
 
 private:
+  /// FIXME: This stats several files to find a .clang-format file. I/O can be
+  /// slow. Think of a way to cache this.
+  llvm::Expected<std::vector<tooling::Replacement>>
+  formatCode(llvm::StringRef Code, PathRef File,
+             ArrayRef<tooling::Range> Ranges);
+
   std::future<void>
   scheduleReparseAndDiags(PathRef File, VersionedDraft Contents,
                           std::shared_ptr<CppFile> Resources,
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -36,16 +36,6 @@
   std::promise<void> &Promise;
 };
 
-std::vector<tooling::Replacement> formatCode(StringRef Code, StringRef Filename,
-                                             ArrayRef<tooling::Range> Ranges) {
-  // Call clang-format.
-  // FIXME: Don't ignore style.
-  format::FormatStyle Style = format::getLLVMStyle();
-  auto Result = format::reformat(Style, Code, Ranges, Filename);
-
-  return std::vector<tooling::Replacement>(Result.begin(), Result.end());
-}
-
 std::string getStandardResourceDir() {
   static int Dummy; // Just an address in this process.
   return CompilerInvocation::GetResourcesPath("clangd", (void *)&Dummy);
@@ -304,28 +294,25 @@
   return make_tagged(std::move(Result), TaggedFS.Tag);
 }
 
-std::vector<tooling::Replacement> ClangdServer::formatRange(PathRef File,
-                                                            Range Rng) {
-  std::string Code = getDocument(File);
-
+llvm::Expected<std::vector<tooling::Replacement>>
+ClangdServer::formatRange(llvm::StringRef Code, PathRef File, Range Rng) {
   size_t Begin = positionToOffset(Code, Rng.start);
   size_t Len = positionToOffset(Code, Rng.end) - Begin;
   return formatCode(Code, File, {tooling::Range(Begin, Len)});
 }
 
-std::vector<tooling::Replacement> ClangdServer::formatFile(PathRef File) {
+llvm::Expected<std::vector<tooling::Replacement>>
+ClangdServer::formatFile(llvm::StringRef Code, PathRef File) {
   // Format everything.
-  std::string Code = getDocument(File);
   return formatCode(Code, File, {tooling::Range(0, Code.size())});
 }
 
-std::vector<tooling::Replacement> ClangdServer::formatOnType(PathRef File,
-                                                             Position Pos) {
+llvm::Expected<std::vector<tooling::Replacement>>
+ClangdServer::formatOnType(llvm::StringRef Code, PathRef File, Position Pos) {
   // Look for the previous opening brace from the character position and
   // format starting from there.
-  std::string Code = getDocument(File);
   size_t CursorPos = positionToOffset(Code, Pos);
-  size_t PreviousLBracePos = StringRef(Code).find_last_of('{', CursorPos);
+  size_t PreviousLBracePos = Code.find_last_of('{', CursorPos);
   if (PreviousLBracePos == StringRef::npos)
     PreviousLBracePos = CursorPos;
   size_t Len = 1 + CursorPos - PreviousLBracePos;
@@ -434,6 +421,21 @@
   return llvm::None;
 }
 
+llvm::Expected<std::vector<tooling::Replacement>>
+ClangdServer::formatCode(llvm::StringRef Code, PathRef File,
+                         ArrayRef<tooling::Range> Ranges) {
+  // Call clang-format.
+  auto TaggedFS = FSProvider.getTaggedFileSystem(File);
+  auto StyleOrError =
+      format::getStyle("file", File, "LLVM", Code, TaggedFS.Value.get());
+  if (!StyleOrError) {
+    return StyleOrError.takeError();
+  } else {
+    auto Result = format::reformat(StyleOrError.get(), Code, Ranges, File);
+    return std::vector<tooling::Replacement>(Result.begin(), Result.end());
+  }
+}
+
 std::future<void> ClangdServer::scheduleReparseAndDiags(
     PathRef File, VersionedDraft Contents, std::shared_ptr<CppFile> Resources,
     Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS) {
Index: clangd/ClangdLSPServer.cpp
===================================================================
--- clangd/ClangdLSPServer.cpp
+++ clangd/ClangdLSPServer.cpp
@@ -23,7 +23,7 @@
   // Turn the replacements into the format specified by the Language Server
   // Protocol. Fuse them into one big JSON array.
   std::vector<TextEdit> Edits;
-  for (auto &R : Replacements) {
+  for (const auto &R : Replacements) {
     Range ReplacementRange = {
         offsetToPosition(Code, R.getOffset()),
         offsetToPosition(Code, R.getOffset() + R.getLength())};
@@ -134,35 +134,47 @@
 
 void ClangdLSPServer::onDocumentOnTypeFormatting(
     Ctx C, DocumentOnTypeFormattingParams &Params) {
-  auto File = Params.textDocument.uri.file;
-  std::string Code = Server.getDocument(File);
-  C.reply(json::ary(
-      replacementsToEdits(Code, Server.formatOnType(File, Params.position))));
+  const PathRef File = Params.textDocument.uri.file;
+  const auto Code = Server.getDocument(File);
+  auto ReplacementsOrError = Server.formatOnType(Code, File, Params.position);
+  if (ReplacementsOrError) {
+    C.reply(json::ary{replacementsToEdits(Code, ReplacementsOrError.get())});
+  } else {
+    C.replyError(ReplacementsOrError.takeError());
+  }
 }
 
 void ClangdLSPServer::onDocumentRangeFormatting(
     Ctx C, DocumentRangeFormattingParams &Params) {
-  auto File = Params.textDocument.uri.file;
-  std::string Code = Server.getDocument(File);
-  C.reply(json::ary(
-      replacementsToEdits(Code, Server.formatRange(File, Params.range))));
+  const PathRef File = Params.textDocument.uri.file;
+  const auto Code = Server.getDocument(File);
+  auto ReplacementsOrError = Server.formatRange(Code, File, Params.range);
+  if (ReplacementsOrError) {
+    C.reply(json::ary{replacementsToEdits(Code, ReplacementsOrError.get())});
+  } else {
+    C.replyError(ReplacementsOrError.takeError());
+  }
 }
 
 void ClangdLSPServer::onDocumentFormatting(Ctx C,
                                            DocumentFormattingParams &Params) {
-  auto File = Params.textDocument.uri.file;
-  std::string Code = Server.getDocument(File);
-  C.reply(json::ary(replacementsToEdits(Code, Server.formatFile(File))));
+  const PathRef File = Params.textDocument.uri.file;
+  const auto Code = Server.getDocument(File);
+  auto ReplacementsOrError = Server.formatFile(Code, File);
+  if (ReplacementsOrError) {
+    C.reply(json::ary{replacementsToEdits(Code, ReplacementsOrError.get())});
+  } else {
+    C.replyError(ReplacementsOrError.takeError());
+  }
 }
 
 void ClangdLSPServer::onCodeAction(Ctx C, CodeActionParams &Params) {
   // We provide a code action for each diagnostic at the requested location
   // which has FixIts available.
   std::string Code = Server.getDocument(Params.textDocument.uri.file);
   json::ary Commands;
   for (Diagnostic &D : Params.context.diagnostics) {
-    std::vector<clang::tooling::Replacement> Fixes =
-        getFixIts(Params.textDocument.uri.file, D);
+    const auto Fixes = getFixIts(Params.textDocument.uri.file, D);
     auto Edits = replacementsToEdits(Code, Fixes);
     if (!Edits.empty()) {
       WorkspaceEdit WE;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to