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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits