forked from OSchip/llvm-project
Revert "Revert r315214 since diff -Z isn't portable, this is breaking:"
This reverts commit r315242 and restores r315214. To fix original failure, replaced non-portable `diff -Z` with portable alternative: `diff -b`. llvm-svn: 315287
This commit is contained in:
parent
eac034b992
commit
e6dbb58f95
|
@ -37,6 +37,14 @@ void JSONOutput::log(const Twine &Message) {
|
|||
Logs.flush();
|
||||
}
|
||||
|
||||
void JSONOutput::mirrorInput(const Twine &Message) {
|
||||
if (!InputMirror)
|
||||
return;
|
||||
|
||||
*InputMirror << Message;
|
||||
InputMirror->flush();
|
||||
}
|
||||
|
||||
void Handler::handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) {
|
||||
Output.log("Method ignored.\n");
|
||||
// Return that this method is unsupported.
|
||||
|
@ -147,6 +155,14 @@ void clangd::runLanguageServerLoop(std::istream &In, JSONOutput &Out,
|
|||
continue;
|
||||
}
|
||||
|
||||
Out.mirrorInput(Line);
|
||||
// Mirror '\n' that gets consumed by std::getline, but is not included in
|
||||
// the resulting Line.
|
||||
// Note that '\r' is part of Line, so we don't need to mirror it
|
||||
// separately.
|
||||
if (!In.eof())
|
||||
Out.mirrorInput("\n");
|
||||
|
||||
llvm::StringRef LineRef(Line);
|
||||
|
||||
// We allow YAML-style comments in headers. Technically this isn't part
|
||||
|
@ -163,9 +179,8 @@ void clangd::runLanguageServerLoop(std::istream &In, JSONOutput &Out,
|
|||
if (LineRef.consume_front("Content-Length: ")) {
|
||||
if (ContentLength != 0) {
|
||||
Out.log("Warning: Duplicate Content-Length header received. "
|
||||
"The previous value for this message ("
|
||||
+ std::to_string(ContentLength)
|
||||
+ ") was ignored.\n");
|
||||
"The previous value for this message (" +
|
||||
std::to_string(ContentLength) + ") was ignored.\n");
|
||||
}
|
||||
|
||||
llvm::getAsUnsignedInteger(LineRef.trim(), 0, ContentLength);
|
||||
|
@ -185,15 +200,13 @@ void clangd::runLanguageServerLoop(std::istream &In, JSONOutput &Out,
|
|||
// parser.
|
||||
std::vector<char> JSON(ContentLength + 1, '\0');
|
||||
In.read(JSON.data(), ContentLength);
|
||||
Out.mirrorInput(StringRef(JSON.data(), In.gcount()));
|
||||
|
||||
// If the stream is aborted before we read ContentLength bytes, In
|
||||
// will have eofbit and failbit set.
|
||||
if (!In) {
|
||||
Out.log("Input was aborted. Read only "
|
||||
+ std::to_string(In.gcount())
|
||||
+ " bytes of expected "
|
||||
+ std::to_string(ContentLength)
|
||||
+ ".\n");
|
||||
Out.log("Input was aborted. Read only " + std::to_string(In.gcount()) +
|
||||
" bytes of expected " + std::to_string(ContentLength) + ".\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -209,8 +222,8 @@ void clangd::runLanguageServerLoop(std::istream &In, JSONOutput &Out,
|
|||
if (IsDone)
|
||||
break;
|
||||
} else {
|
||||
Out.log( "Warning: Missing Content-Length header, or message has zero "
|
||||
"length.\n" );
|
||||
Out.log("Warning: Missing Content-Length header, or message has zero "
|
||||
"length.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,8 +24,9 @@ namespace clangd {
|
|||
/// them.
|
||||
class JSONOutput : public Logger {
|
||||
public:
|
||||
JSONOutput(llvm::raw_ostream &Outs, llvm::raw_ostream &Logs)
|
||||
: Outs(Outs), Logs(Logs) {}
|
||||
JSONOutput(llvm::raw_ostream &Outs, llvm::raw_ostream &Logs,
|
||||
llvm::raw_ostream *InputMirror = nullptr)
|
||||
: Outs(Outs), Logs(Logs), InputMirror(InputMirror) {}
|
||||
|
||||
/// Emit a JSONRPC message.
|
||||
void writeMessage(const Twine &Message);
|
||||
|
@ -33,9 +34,15 @@ public:
|
|||
/// Write to the logging stream.
|
||||
void log(const Twine &Message) override;
|
||||
|
||||
/// Mirror \p Message into InputMirror stream. Does nothing if InputMirror is
|
||||
/// null.
|
||||
/// Unlike other methods of JSONOutput, mirrorInput is not thread-safe.
|
||||
void mirrorInput(const Twine &Message);
|
||||
|
||||
private:
|
||||
llvm::raw_ostream &Outs;
|
||||
llvm::raw_ostream &Logs;
|
||||
llvm::raw_ostream *InputMirror;
|
||||
|
||||
std::mutex StreamMutex;
|
||||
};
|
||||
|
|
|
@ -9,10 +9,12 @@
|
|||
|
||||
#include "ClangdLSPServer.h"
|
||||
#include "JSONRPCDispatcher.h"
|
||||
#include "Path.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
@ -43,11 +45,17 @@ static llvm::cl::opt<bool> RunSynchronously(
|
|||
llvm::cl::desc("Parse on main thread. If set, -j is ignored"),
|
||||
llvm::cl::init(false), llvm::cl::Hidden);
|
||||
|
||||
static llvm::cl::opt<std::string>
|
||||
static llvm::cl::opt<Path>
|
||||
ResourceDir("resource-dir",
|
||||
llvm::cl::desc("Directory for system clang headers"),
|
||||
llvm::cl::init(""), llvm::cl::Hidden);
|
||||
|
||||
static llvm::cl::opt<Path> InputMirrorFile(
|
||||
"input-mirror-file",
|
||||
llvm::cl::desc(
|
||||
"Mirror all LSP input to the specified file. Useful for debugging."),
|
||||
llvm::cl::init(""), llvm::cl::Hidden);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
llvm::cl::ParseCommandLineOptions(argc, argv, "clangd");
|
||||
|
||||
|
@ -63,9 +71,21 @@ int main(int argc, char *argv[]) {
|
|||
WorkerThreadsCount = 0;
|
||||
|
||||
/// Validate command line arguments.
|
||||
llvm::Optional<llvm::raw_fd_ostream> InputMirrorStream;
|
||||
if (!InputMirrorFile.empty()) {
|
||||
std::error_code EC;
|
||||
InputMirrorStream.emplace(InputMirrorFile, /*ref*/ EC, llvm::sys::fs::F_RW);
|
||||
if (EC) {
|
||||
InputMirrorStream.reset();
|
||||
llvm::errs() << "Error while opening an input mirror file: "
|
||||
<< EC.message();
|
||||
}
|
||||
}
|
||||
|
||||
llvm::raw_ostream &Outs = llvm::outs();
|
||||
llvm::raw_ostream &Logs = llvm::errs();
|
||||
JSONOutput Out(Outs, Logs);
|
||||
JSONOutput Out(Outs, Logs,
|
||||
InputMirrorStream ? InputMirrorStream.getPointer() : nullptr);
|
||||
|
||||
// If --compile-commands-dir arg was invoked, check value and override default
|
||||
// path.
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
# RUN: clangd -run-synchronously -input-mirror-file %t < %s
|
||||
# Note that we have to use '-Z' as -input-mirror-file does not have a newline at the end of file.
|
||||
# RUN: diff -b %t %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: 172
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"int main() {\nint a;\na;\n}\n"}}}
|
||||
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":0}}}
|
||||
# Go to local variable
|
||||
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":1}}}
|
||||
# Go to local variable, end of token
|
||||
|
||||
Content-Length: 214
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":2},"contentChanges":[{"text":"struct Foo {\nint x;\n};\nint main() {\n Foo bar = { x : 1 };\n}\n"}]}}
|
||||
|
||||
Content-Length: 149
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":14}}}
|
||||
# Go to field, GNU old-style field designator
|
||||
|
||||
Content-Length: 215
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":3},"contentChanges":[{"text":"struct Foo {\nint x;\n};\nint main() {\n Foo baz = { .x = 2 };\n}\n"}]}}
|
||||
|
||||
Content-Length: 149
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":15}}}
|
||||
# Go to field, field designator
|
||||
|
||||
Content-Length: 187
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":4},"contentChanges":[{"text":"int main() {\n main();\n return 0;\n}"}]}}
|
||||
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":1,"character":3}}}
|
||||
# Go to function declaration, function call
|
||||
|
||||
Content-Length: 208
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":5},"contentChanges":[{"text":"struct Foo {\n};\nint main() {\n Foo bar;\n return 0;\n}\n"}]}}
|
||||
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":3}}}
|
||||
# Go to struct declaration, new struct instance
|
||||
|
||||
Content-Length: 231
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":5},"contentChanges":[{"text":"namespace n1 {\nstruct Foo {\n};\n}\nint main() {\n n1::Foo bar;\n return 0;\n}\n"}]}}
|
||||
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":5,"character":4}}}
|
||||
# Go to struct declaration, new struct instance, qualified name
|
||||
|
||||
Content-Length: 215
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":6},"contentChanges":[{"text":"struct Foo {\n int x;\n};\nint main() {\n Foo bar;\n bar.x;\n}\n"}]}}
|
||||
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":5,"character":7}}}
|
||||
# Go to field declaration, field reference
|
||||
|
||||
Content-Length: 220
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"struct Foo {\n void x();\n};\nint main() {\n Foo bar;\n bar.x();\n}\n"}]}}
|
||||
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":5,"character":7}}}
|
||||
# Go to method declaration, method call
|
||||
|
||||
Content-Length: 240
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"struct Foo {\n};\ntypedef Foo TypedefFoo;\nint main() {\n TypedefFoo bar;\n return 0;\n}\n"}]}}
|
||||
|
||||
Content-Length: 149
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":10}}}
|
||||
# Go to typedef
|
||||
|
||||
Content-Length: 254
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"template <typename MyTemplateParam>\nvoid foo() {\n MyTemplateParam a;\n}\nint main() {\n return 0;\n}\n"}]}}
|
||||
|
||||
Content-Length: 149
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":13}}}
|
||||
# Go to template type parameter. Fails until clangIndex is modified to handle those.
|
||||
# no-CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 10}, "end": {"line": 0, "character": 34}}}]}
|
||||
|
||||
Content-Length: 256
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"namespace ns {\nstruct Foo {\nstatic void bar() {}\n};\n}\nint main() {\n ns::Foo::bar();\n return 0;\n}\n"}]}}
|
||||
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":6,"character":4}}}
|
||||
# Go to namespace, static method call
|
||||
|
||||
Content-Length: 265
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"namespace ns {\nstruct Foo {\n int field;\n Foo(int param) : field(param) {}\n};\n}\nint main() {\n return 0;\n}\n"}]}}
|
||||
|
||||
Content-Length: 149
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":21}}}
|
||||
# Go to field, member initializer
|
||||
|
||||
Content-Length: 204
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"#define MY_MACRO 0\nint main() {\n return MY_MACRO;\n}\n"}]}}
|
||||
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":9}}}
|
||||
# Go to macro.
|
||||
|
||||
Content-Length: 217
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"#define FOO 1\nint a = FOO;\n#define FOO 2\nint b = FOO;\n#undef FOO\n"}]}}
|
||||
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":1,"character":8}}}
|
||||
# Go to macro, re-defined later
|
||||
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":8}}}
|
||||
# Go to macro, undefined later
|
||||
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":7}}}
|
||||
# Go to macro, being undefined
|
||||
|
||||
Content-Length: 44
|
||||
|
||||
{"jsonrpc":"2.0","id":3,"method":"shutdown"}
|
Loading…
Reference in New Issue