stanionascu created this revision.

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.


https://reviews.llvm.org/D31401

Files:
  clangd/ASTManager.cpp
  clangd/Protocol.cpp
  clangd/Protocol.h
  clangd/clients/clangd-vscode/src/extension.ts

Index: clangd/clients/clangd-vscode/src/extension.ts
===================================================================
--- clangd/clients/clangd-vscode/src/extension.ts
+++ clangd/clients/clangd-vscode/src/extension.ts
@@ -23,7 +23,12 @@
 
     const clientOptions: vscodelc.LanguageClientOptions = {
         // Register the server for C/C++ files
-        documentSelector: ['c', 'cc', 'cpp', 'h', 'hh', 'hpp']
+        documentSelector: ['c', 'cc', 'cpp', 'h', 'hh', 'hpp'],
+        uriConverters: {
+            // FIXME: implement percent decoding in clangd
+            code2Protocol: (uri: vscode.Uri) : string => uri.toString(true),
+            protocol2Code: (file: string) : vscode.Uri => vscode.Uri.file(file)
+        }
     };
 
     const clangdClient = new vscodelc.LanguageClient('Clang Language Server', serverOptions, clientOptions);
Index: clangd/Protocol.h
===================================================================
--- clangd/Protocol.h
+++ clangd/Protocol.h
@@ -29,6 +29,11 @@
 namespace clang {
 namespace clangd {
 
+struct Uri {
+  static std::string parse(llvm::StringRef uri);
+  static std::string unparse(llvm::StringRef file);
+};
+
 struct TextDocumentIdentifier {
   /// The text document's URI.
   std::string uri;
Index: clangd/Protocol.cpp
===================================================================
--- clangd/Protocol.cpp
+++ clangd/Protocol.cpp
@@ -17,8 +17,30 @@
 #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;
 
+std::string Uri::parse(llvm::StringRef 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
+  std::string Result = llvm::sys::path::convert_to_slash(uri);
+  return Result;
+}
+
+std::string Uri::unparse(llvm::StringRef file) {
+  using namespace llvm::sys;
+  std::string Result = "file://";
+  // For Windows paths e.g. X:
+  if (file.size() > 1 && file[1] == ':')
+    Result += "/";
+  // Make sure that uri paths are with posix separators
+  Result += path::convert_to_slash(file, path::Style::posix);
+  return Result;
+}
+
 llvm::Optional<TextDocumentIdentifier>
 TextDocumentIdentifier::parse(llvm::yaml::MappingNode *Params) {
   TextDocumentIdentifier Result;
@@ -36,7 +58,7 @@
 
     llvm::SmallString<10> Storage;
     if (KeyValue == "uri") {
-      Result.uri = Value->getValue(Storage);
+      Result.uri = Uri::parse(Value->getValue(Storage));
     } else if (KeyValue == "version") {
       // FIXME: parse version, but only for VersionedTextDocumentIdentifiers.
     } else {
@@ -142,7 +164,7 @@
 
     llvm::SmallString<10> Storage;
     if (KeyValue == "uri") {
-      Result.uri = Value->getValue(Storage);
+      Result.uri = Uri::parse(Value->getValue(Storage));
     } else if (KeyValue == "languageId") {
       Result.languageId = Value->getValue(Storage);
     } else if (KeyValue == "version") {
Index: clangd/ASTManager.cpp
===================================================================
--- clangd/ASTManager.cpp
+++ clangd/ASTManager.cpp
@@ -28,7 +28,6 @@
   std::vector<ASTUnit::RemappedFile> RemappedFiles;
   for (const auto &P : Docs.getAllDocuments()) {
     StringRef FileName = P.first;
-    FileName.consume_front("file://");
     RemappedFiles.push_back(ASTUnit::RemappedFile(
         FileName,
         llvm::MemoryBuffer::getMemBufferCopy(P.second, FileName).release()));
@@ -138,7 +137,7 @@
     Diagnostics.pop_back(); // Drop trailing comma.
   Output.writeMessage(
       R"({"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":")" +
-      File + R"(","diagnostics":[)" + Diagnostics + R"(]}})");
+      Uri::unparse(File) + R"(","diagnostics":[)" + Diagnostics + R"(]}})");
 }
 
 ASTManager::~ASTManager() {
@@ -169,8 +168,6 @@
   if (I)
     return I.get();
 
-  Uri.consume_front("file://");
-
   std::string Error;
   I = tooling::CompilationDatabase::autoDetectFromSource(Uri, Error);
   Output.log("Failed to load compilation database: " + Twine(Error) + "\n");
@@ -182,7 +179,6 @@
   tooling::CompilationDatabase *CDB =
       getOrCreateCompilationDatabaseForFile(Uri);
 
-  Uri.consume_front("file://");
   std::vector<tooling::CompileCommand> Commands;
 
   if (CDB) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to