malaperle-ericsson updated this revision to Diff 95414.
malaperle-ericsson added a comment.

Handle other control characters and add test


https://reviews.llvm.org/D31992

Files:
  clangd/ASTManager.cpp
  clangd/Protocol.cpp
  clangd/Protocol.h
  clangd/ProtocolHandlers.cpp
  test/clangd/encoding.test

Index: test/clangd/encoding.test
===================================================================
--- /dev/null
+++ test/clangd/encoding.test
@@ -0,0 +1,17 @@
+# RUN: clangd -run-synchronously < %s | FileCheck %s
+# It is absolutely vital that this file has CRLF line endings.
+#
+Content-Length: 125
+
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+#
+Content-Length: 154
+
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///foo.c","languageId":"c","version":1,"text":"void main() {é;}"}}}
+#
+# CHECK: {"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///foo.c","diagnostics":[{"range":{"start": {"line": 0, "character": 1}, "end": {"line": 0, "character": 1}},"severity":2,"message":"return type of 'main' is not 'int'"},{"range":{"start": {"line": 0, "character": 1}, "end": {"line": 0, "character": 1}},"severity":3,"message":"change return type to 'int'"},{"range":{"start": {"line": 0, "character": 14}, "end": {"line": 0, "character": 14}},"severity":1,"message":"use of undeclared identifier 'é'"}]}}
+#
+#
+Content-Length: 44
+
+{"jsonrpc":"2.0","id":5,"method":"shutdown"}
Index: clangd/ProtocolHandlers.cpp
===================================================================
--- clangd/ProtocolHandlers.cpp
+++ clangd/ProtocolHandlers.cpp
@@ -172,9 +172,9 @@
 
     if (!Edits.empty())
       Commands +=
-          R"({"title":"Apply FixIt ')" + llvm::yaml::escape(D.message) +
+          R"({"title":"Apply FixIt ')" + jsonEscape(D.message) +
           R"('", "command": "clangd.applyFix", "arguments": [")" +
-          llvm::yaml::escape(CAP->textDocument.uri.uri) +
+          jsonEscape(CAP->textDocument.uri.uri) +
           R"(", [)" + Edits +
           R"(]]},)";
   }
Index: clangd/Protocol.h
===================================================================
--- clangd/Protocol.h
+++ clangd/Protocol.h
@@ -29,6 +29,8 @@
 namespace clang {
 namespace clangd {
 
+std::string jsonEscape(llvm::StringRef Input);
+
 struct URI {
   std::string uri;
   std::string file;
Index: clangd/Protocol.cpp
===================================================================
--- clangd/Protocol.cpp
+++ clangd/Protocol.cpp
@@ -15,12 +15,48 @@
 #include "Protocol.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/SmallString.h"
+#include <llvm/ADT/StringExtras.h>
 #include "llvm/Support/Format.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/Path.h"
 using namespace clang::clangd;
 
 
+std::string clang::clangd::jsonEscape(llvm::StringRef Input) {
+  std::string EscapedInput;
+  for (llvm::StringRef::iterator i = Input.begin(), e = Input.end(); i != e; ++i) {
+    if (*i == '\\')
+      EscapedInput += "\\\\";
+    else if (*i == '"')
+      EscapedInput += "\\\"";
+    // bell
+    else if (*i == 0x07)
+      EscapedInput += "\\a";
+    // backspace
+    else if (*i == 0x08)
+      EscapedInput += "\\b";
+    // hoz tab
+    else if (*i == 0x09)
+      EscapedInput += "\\t";
+    // new line
+    else if (*i == 0x0A)
+      EscapedInput += "\\n";
+    // form feed
+    else if (*i == 0x0C)
+      EscapedInput += "\\f";
+    // carr return
+    else if (*i == 0x0D)
+      EscapedInput += "\\r";
+    else if ((unsigned char)*i < 0x20) { // Control characters not handled above.
+      std::string HexStr = llvm::utohexstr(*i);
+      EscapedInput += "\\u" + std::string(4 - HexStr.size(), '0') + HexStr;
+    }
+    else
+      EscapedInput.push_back(*i);
+  }
+  return EscapedInput;
+}
+
 URI URI::fromUri(llvm::StringRef uri) {
   URI Result;
   Result.uri = uri;
@@ -230,7 +266,7 @@
   std::string Result;
   llvm::raw_string_ostream(Result) << llvm::format(
       R"({"range": %s, "newText": "%s"})", Range::unparse(P.range).c_str(),
-      llvm::yaml::escape(P.newText).c_str());
+      jsonEscape(P.newText).c_str());
   return Result;
 }
 
@@ -670,20 +706,20 @@
   std::string Result = "{";
   llvm::raw_string_ostream Os(Result);
   assert(!CI.label.empty() && "completion item label is required");
-  Os << R"("label":")" << llvm::yaml::escape(CI.label) << R"(",)";
+  Os << R"("label":")" << jsonEscape(CI.label) << R"(",)";
   if (CI.kind != CompletionItemKind::Missing)
     Os << R"("kind":)" << static_cast<int>(CI.kind) << R"(,)";
   if (!CI.detail.empty())
-    Os << R"("detail":")" << llvm::yaml::escape(CI.detail) << R"(",)";
+    Os << R"("detail":")" << jsonEscape(CI.detail) << R"(",)";
   if (!CI.documentation.empty())
-    Os << R"("documentation":")" << llvm::yaml::escape(CI.documentation)
+    Os << R"("documentation":")" << jsonEscape(CI.documentation)
        << R"(",)";
   if (!CI.sortText.empty())
-    Os << R"("sortText":")" << llvm::yaml::escape(CI.sortText) << R"(",)";
+    Os << R"("sortText":")" << jsonEscape(CI.sortText) << R"(",)";
   if (!CI.filterText.empty())
-    Os << R"("filterText":")" << llvm::yaml::escape(CI.filterText) << R"(",)";
+    Os << R"("filterText":")" << jsonEscape(CI.filterText) << R"(",)";
   if (!CI.insertText.empty())
-    Os << R"("insertText":")" << llvm::yaml::escape(CI.insertText) << R"(",)";
+    Os << R"("insertText":")" << jsonEscape(CI.insertText) << R"(",)";
   if (CI.insertTextFormat != InsertTextFormat::Missing) {
     Os << R"("insertTextFormat":")" << static_cast<int>(CI.insertTextFormat)
        << R"(",)";
Index: clangd/ASTManager.cpp
===================================================================
--- clangd/ASTManager.cpp
+++ clangd/ASTManager.cpp
@@ -227,7 +227,7 @@
     Diagnostics +=
         R"({"range":)" + Range::unparse(R) +
         R"(,"severity":)" + std::to_string(getSeverity(D->getLevel())) +
-        R"(,"message":")" + llvm::yaml::escape(D->getMessage()) +
+        R"(,"message":")" + jsonEscape(D->getMessage()) +
         R"("},)";
 
     // We convert to Replacements to become independent of the SourceManager.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to