[clangd] Extract FsPath from file:// uri
Patch contributed by stanionascu!
rfc8089#appendix-E.2 specifies that paths can begin with a drive letter e.g. as file:///c:/.
In this case just consuming front file:// is not enough and the 3rd slash must be consumed to produce a valid path on windows.
The patch introduce a generic way of converting an uri to a filesystem path and back.
Differential Revision: https://reviews.llvm.org/D31401
llvm-svn: 299758
diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp
index 163d982..bcb796f 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -17,8 +17,44 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Path.h"
using namespace clang::clangd;
+
+URI URI::fromUri(llvm::StringRef uri) {
+ URI Result;
+ Result.uri = uri;
+ uri.consume_front("file://");
+ // For Windows paths e.g. /X:
+ if (uri.size() > 2 && uri[0] == '/' && uri[2] == ':')
+ uri.consume_front("/");
+ // Make sure that file paths are in native separators
+ Result.file = llvm::sys::path::convert_to_slash(uri);
+ return Result;
+}
+
+URI URI::fromFile(llvm::StringRef file) {
+ using namespace llvm::sys;
+ URI Result;
+ Result.file = file;
+ Result.uri = "file://";
+ // For Windows paths e.g. X:
+ if (file.size() > 1 && file[1] == ':')
+ Result.uri += "/";
+ // Make sure that uri paths are with posix separators
+ Result.uri += path::convert_to_slash(file, path::Style::posix);
+ return Result;
+}
+
+URI URI::parse(llvm::yaml::ScalarNode *Param) {
+ llvm::SmallString<10> Storage;
+ return URI::fromUri(Param->getValue(Storage));
+}
+
+std::string URI::unparse(const URI &U) {
+ return U.uri;
+}
+
llvm::Optional<TextDocumentIdentifier>
TextDocumentIdentifier::parse(llvm::yaml::MappingNode *Params) {
TextDocumentIdentifier Result;
@@ -34,9 +70,8 @@
if (!Value)
return llvm::None;
- llvm::SmallString<10> Storage;
if (KeyValue == "uri") {
- Result.uri = Value->getValue(Storage);
+ Result.uri = URI::parse(Value);
} else if (KeyValue == "version") {
// FIXME: parse version, but only for VersionedTextDocumentIdentifiers.
} else {
@@ -142,7 +177,7 @@
llvm::SmallString<10> Storage;
if (KeyValue == "uri") {
- Result.uri = Value->getValue(Storage);
+ Result.uri = URI::parse(Value);
} else if (KeyValue == "languageId") {
Result.languageId = Value->getValue(Storage);
} else if (KeyValue == "version") {