wwagner19 updated this revision to Diff 229721.
wwagner19 marked 5 inline comments as done.
wwagner19 added a comment.

Thanks for the second review Sam, I addressed most of your comments, notably:

- Changed the bool IsIncoming to an enum
- Fixed the "doxygen" comments,
- Removed some redundant incudes/variables
- Switched `replace_path_prefix` to string replace


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D64305/new/

https://reviews.llvm.org/D64305

Files:
  clang-tools-extra/clangd/PathMapping.cpp
  clang-tools-extra/clangd/PathMapping.h
  clang-tools-extra/clangd/tool/ClangdMain.cpp
  clang-tools-extra/clangd/unittests/PathMappingTests.cpp

Index: clang-tools-extra/clangd/unittests/PathMappingTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/PathMappingTests.cpp
+++ clang-tools-extra/clangd/unittests/PathMappingTests.cpp
@@ -82,12 +82,11 @@
 }
 
 bool mapsProperly(llvm::StringRef Orig, llvm::StringRef Expected,
-                  llvm::StringRef RawMappings, bool IsIncoming) {
+                  llvm::StringRef RawMappings, PathMapping::Direction Dir) {
   llvm::Expected<PathMappings> Mappings = parsePathMappings(RawMappings);
   if (!Mappings)
     return false;
-  llvm::Optional<std::string> MappedPath =
-      doPathMapping(Orig, IsIncoming, *Mappings);
+  llvm::Optional<std::string> MappedPath = doPathMapping(Orig, Dir, *Mappings);
   std::string Actual = MappedPath ? *MappedPath : Orig.str();
   EXPECT_STREQ(Expected.str().c_str(), Actual.c_str());
   return Expected == Actual;
@@ -95,48 +94,54 @@
 
 TEST(DoPathMappingTests, PreservesOriginal) {
   // Preserves original path when no mapping
-  EXPECT_TRUE(mapsProperly("file:///home", "file:///home", "", true));
+  EXPECT_TRUE(mapsProperly("file:///home", "file:///home", "",
+                           PathMapping::Direction::ClientToServer));
 }
 
 TEST(DoPathMappingTests, UsesFirstMatch) {
   EXPECT_TRUE(mapsProperly("file:///home/foo.cpp", "file:///workarea1/foo.cpp",
-                           "/home=/workarea1,/home=/workarea2", true));
+                           "/home=/workarea1,/home=/workarea2",
+                           PathMapping::Direction::ClientToServer));
 }
 
 TEST(DoPathMappingTests, IgnoresSubstrings) {
   // Doesn't map substrings that aren't a proper path prefix
   EXPECT_TRUE(mapsProperly("file://home/foo-bar.cpp", "file://home/foo-bar.cpp",
-                           "/home/foo=/home/bar", true));
+                           "/home/foo=/home/bar",
+                           PathMapping::Direction::ClientToServer));
 }
 
 TEST(DoPathMappingTests, MapsOutgoingPaths) {
   // When IsIncoming is false (i.e.a  response), map the other way
   EXPECT_TRUE(mapsProperly("file:///workarea/foo.cpp", "file:///home/foo.cpp",
-                           "/home=/workarea", false));
+                           "/home=/workarea",
+                           PathMapping::Direction::ServerToClient));
 }
 
 TEST(DoPathMappingTests, OnlyMapFileUris) {
   EXPECT_TRUE(mapsProperly("test:///home/foo.cpp", "test:///home/foo.cpp",
-                           "/home=/workarea", true));
+                           "/home=/workarea",
+                           PathMapping::Direction::ClientToServer));
 }
 
 TEST(DoPathMappingTests, RespectsCaseSensitivity) {
   EXPECT_TRUE(mapsProperly("file:///HOME/foo.cpp", "file:///HOME/foo.cpp",
-                           "/home=/workarea", true));
+                           "/home=/workarea",
+                           PathMapping::Direction::ClientToServer));
 }
 
 TEST(DoPathMappingTests, MapsWindowsPaths) {
   // Maps windows properly
   EXPECT_TRUE(mapsProperly("file:///C:/home/foo.cpp",
-                           "file:///C:/workarea/foo.cpp", "C:/home=C:/workarea",
-                           true));
+                           "file:///C:/workarea/foo.cpp", R"(C:\home=C:\workarea)",
+                           PathMapping::Direction::ClientToServer));
 }
 
 TEST(DoPathMappingTests, MapsWindowsUnixInterop) {
   // Path mappings with a windows-style client path and unix-style server path
-  EXPECT_TRUE(mapsProperly("file:///C:/home/foo.cpp",
-                           "file:///C:/workarea/foo.cpp",
-                           "C:/home=/C:/workarea", true));
+  EXPECT_TRUE(mapsProperly(
+      "file:///C:/home/foo.cpp", "file:///workarea/foo.cpp",
+      R"(C:\home=/workarea)", PathMapping::Direction::ClientToServer));
 }
 
 TEST(ApplyPathMappingTests, PreservesOriginalParams) {
@@ -147,7 +152,7 @@
   ASSERT_TRUE(bool(Params));
   llvm::json::Value ExpectedParams = *Params;
   PathMappings Mappings;
-  applyPathMappings(*Params, /*IsIncoming=*/true, Mappings);
+  applyPathMappings(*Params, PathMapping::Direction::ClientToServer, Mappings);
   EXPECT_EQ(*Params, ExpectedParams);
 }
 
@@ -163,7 +168,7 @@
   })");
   auto Mappings = parsePathMappings("/home=/workarea");
   ASSERT_TRUE(bool(Params) && bool(ExpectedParams) && bool(Mappings));
-  applyPathMappings(*Params, /*IsIncoming=*/true, *Mappings);
+  applyPathMappings(*Params, PathMapping::Direction::ClientToServer, *Mappings);
   EXPECT_EQ(*Params, *ExpectedParams);
 }
 
@@ -183,7 +188,7 @@
   auto Mappings =
       parsePathMappings("/home=/workarea,/home/.includes=/opt/include");
   ASSERT_TRUE(bool(Params) && bool(ExpectedParams) && bool(Mappings));
-  applyPathMappings(*Params, /*IsIncoming=*/false, *Mappings);
+  applyPathMappings(*Params, PathMapping::Direction::ServerToClient, *Mappings);
   EXPECT_EQ(*Params, *ExpectedParams);
 }
 
@@ -202,7 +207,7 @@
   })");
   auto Mappings = parsePathMappings("/home=/workarea");
   ASSERT_TRUE(bool(Params) && bool(ExpectedParams) && bool(Mappings));
-  applyPathMappings(*Params, /*IsIncoming=*/true, *Mappings);
+  applyPathMappings(*Params, PathMapping::Direction::ClientToServer, *Mappings);
   EXPECT_EQ(*Params, *ExpectedParams);
 }
 
Index: clang-tools-extra/clangd/tool/ClangdMain.cpp
===================================================================
--- clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -346,7 +346,7 @@
         "location where clangd is running,"
         "e.g. "
         "/home/project=/workarea/project,/home/project/.includes=/opt/include"
-        "opt/include"),
+        ),
     llvm::cl::init(""));
 
 opt<Path> InputMirrorFile{
Index: clang-tools-extra/clangd/PathMapping.h
===================================================================
--- clang-tools-extra/clangd/PathMapping.h
+++ clang-tools-extra/clangd/PathMapping.h
@@ -11,7 +11,7 @@
 #include "llvm/Support/JSON.h"
 #include "llvm/Support/raw_ostream.h"
 #include <memory>
-#include <tuple>
+#include <string>
 #include <vector>
 
 namespace clang {
@@ -22,43 +22,43 @@
 /// PathMappings are a collection of paired client and server paths.
 /// These pairs are used to alter file:// URIs appearing in inbound and outbound
 /// LSP messages, as the client's environment may have source files or
-/// dependencies at different locations than the server.
+/// dependencies at different locations than the server. Therefore, both
+/// paths are stored as they appear in file URI bodies, e.g. /usr/include or
+/// /C:/config
 ///
 /// For example, if the mappings were {{"/home/user", "/workarea"}}, then
-/// an inbound LSP message would have file:///home/user/foo.cpp remapped to
-/// file:///workarea/foo.cpp, and the same would happen for replies (in the
-/// opposite order).
+/// a client-to-server LSP message would have file:///home/user/foo.cpp
+/// remapped to file:///workarea/foo.cpp, and the same would happen for replies
+/// (in the opposite order).
 struct PathMapping {
-  PathMapping() {}
-  PathMapping(llvm::StringRef ClientPath, llvm::StringRef ServerPath)
-      : ClientPath(ClientPath), ServerPath(ServerPath) {}
   std::string ClientPath;
   std::string ServerPath;
+  enum class Direction { ClientToServer, ServerToClient };
 };
 using PathMappings = std::vector<PathMapping>;
 
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const PathMapping &M);
 
-/// Parse the command line \pRawPathMappings (e.g. "/client=/server") into
+/// Parse the command line \p RawPathMappings (e.g. "/client=/server") into
 /// pairs. Returns an error if the mappings are malformed, i.e. not absolute or
 /// not a proper pair.
 llvm::Expected<PathMappings> parsePathMappings(llvm::StringRef RawPathMappings);
 
-/// Returns a modified \pS with the first matching path in \pPathMappings
+/// Returns a modified \p S with the first matching path in \p Mappings
 /// substituted, if applicable
-llvm::Optional<std::string> doPathMapping(llvm::StringRef S, bool IsIncoming,
+llvm::Optional<std::string> doPathMapping(llvm::StringRef S,
+                                          PathMapping::Direction Dir,
                                           const PathMappings &Mappings);
 
-/// Applies the \pMappings to all the file:// URIs in \pParams.
-/// \pIsIncoming affects which direction the mappings are applied.
-/// NOTE: The first matching mapping will be applied, otherwise \pParams will be
-/// untouched.
-void applyPathMappings(llvm::json::Value &Params, bool IsIncoming,
+/// Applies the \p Mappings to all the file:// URIs in \p Params.
+/// NOTE: The first matching mapping will be applied, otherwise \p Params will
+/// be untouched.
+void applyPathMappings(llvm::json::Value &Params, PathMapping::Direction Dir,
                        const PathMappings &Mappings);
 
-/// Creates a wrapping transport over \pTransp that applies the \pMappings to
+/// Creates a wrapping transport over \p Transp that applies the \p Mappings to
 /// all inbound and outbound LSP messages. All calls are then delegated to the
-/// regular \pTransp (e.g. XPC, JSON).
+/// regular transport (e.g. XPC, JSON).
 std::unique_ptr<Transport>
 createPathMappingTransport(std::unique_ptr<Transport> Transp,
                            PathMappings Mappings);
Index: clang-tools-extra/clangd/PathMapping.cpp
===================================================================
--- clang-tools-extra/clangd/PathMapping.cpp
+++ clang-tools-extra/clangd/PathMapping.cpp
@@ -6,41 +6,33 @@
 //
 //===----------------------------------------------------------------------===//
 #include "PathMapping.h"
-#include "Logger.h"
 #include "Transport.h"
 #include "URI.h"
 #include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Errno.h"
-#include "llvm/Support/JSON.h"
 #include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
 #include <algorithm>
-#include <memory>
 #include <tuple>
-#include <vector>
 
 namespace clang {
 namespace clangd {
 namespace {
 using MapperFunc = llvm::function_ref<llvm::Optional<std::string>(
-    llvm::StringRef, bool, const PathMappings &)>;
+    llvm::StringRef, PathMapping::Direction, const PathMappings &)>;
 
-// Recursively apply the \pMF to all string keys/values in \pV
-void recursivelyMap(llvm::json::Value &V, bool IsIncoming,
+// Recursively apply the MF to all string keys/values in V
+void recursivelyMap(llvm::json::Value &V, PathMapping::Direction Dir,
                     const PathMappings &Mappings, const MapperFunc &MF) {
   using Kind = llvm::json::Value::Kind;
-  const Kind &K = V.kind();
+  Kind K = V.kind();
   if (K == Kind::Object) {
     llvm::json::Object *Obj = V.getAsObject();
     llvm::json::Object MappedObj;
     // 1. Map all the Keys
     for (auto &KV : *Obj) {
       if (llvm::Optional<std::string> MappedKey =
-              MF(KV.first.str(), IsIncoming, Mappings)) {
+              MF(KV.first.str(), Dir, Mappings)) {
         MappedObj.try_emplace(std::move(*MappedKey), std::move(KV.second));
       } else {
         MappedObj.try_emplace(std::move(KV.first), std::move(KV.second));
@@ -49,15 +41,15 @@
     *Obj = std::move(MappedObj);
     // 2. Map all the values
     for (auto &KV : *Obj) {
-      recursivelyMap(KV.second, IsIncoming, Mappings, MF);
+      recursivelyMap(KV.second, Dir, Mappings, MF);
     }
   } else if (K == Kind::Array) {
     for (llvm::json::Value &Val : *V.getAsArray()) {
-      recursivelyMap(Val, IsIncoming, Mappings, MF);
+      recursivelyMap(Val, Dir, Mappings, MF);
     }
   } else if (K == Kind::String) {
     if (llvm::Optional<std::string> Mapped =
-            MF(*V.getAsString(), IsIncoming, Mappings)) {
+            MF(*V.getAsString(), Dir, Mappings)) {
       V = std::move(*Mapped);
     }
   }
@@ -70,20 +62,21 @@
       : WrappedHandler(Handler), Mappings(Mappings) {}
 
   bool onNotify(llvm::StringRef Method, llvm::json::Value Params) override {
-    applyPathMappings(Params, /*IsIncoming=*/true, Mappings);
+    applyPathMappings(Params, PathMapping::Direction::ClientToServer, Mappings);
     return WrappedHandler.onNotify(Method, std::move(Params));
   }
 
   bool onCall(llvm::StringRef Method, llvm::json::Value Params,
               llvm::json::Value ID) override {
-    applyPathMappings(Params, /*IsIncoming=*/true, Mappings);
+    applyPathMappings(Params, PathMapping::Direction::ClientToServer, Mappings);
     return WrappedHandler.onCall(Method, std::move(Params), std::move(ID));
   }
 
   bool onReply(llvm::json::Value ID,
                llvm::Expected<llvm::json::Value> Result) override {
     if (Result) {
-      applyPathMappings(*Result, /*IsIncoming=*/true, Mappings);
+      applyPathMappings(*Result, PathMapping::Direction::ClientToServer,
+                        Mappings);
     }
     return WrappedHandler.onReply(std::move(ID), std::move(Result));
   }
@@ -101,20 +94,21 @@
       : WrappedTransport(std::move(Transp)), Mappings(std::move(Mappings)) {}
 
   void notify(llvm::StringRef Method, llvm::json::Value Params) override {
-    applyPathMappings(Params, /*IsIncoming=*/false, Mappings);
+    applyPathMappings(Params, PathMapping::Direction::ServerToClient, Mappings);
     WrappedTransport->notify(Method, std::move(Params));
   }
 
   void call(llvm::StringRef Method, llvm::json::Value Params,
             llvm::json::Value ID) override {
-    applyPathMappings(Params, /*IsIncoming=*/false, Mappings);
+    applyPathMappings(Params, PathMapping::Direction::ServerToClient, Mappings);
     WrappedTransport->call(Method, std::move(Params), std::move(ID));
   }
 
   void reply(llvm::json::Value ID,
              llvm::Expected<llvm::json::Value> Result) override {
     if (Result) {
-      applyPathMappings(*Result, /*IsIncoming=*/false, Mappings);
+      applyPathMappings(*Result, PathMapping::Direction::ServerToClient,
+                        Mappings);
     }
     WrappedTransport->reply(std::move(ID), std::move(Result));
   }
@@ -134,8 +128,8 @@
                                              llvm::inconvertibleErrorCode());
 }
 
-// Returns whether a path mapping should take place for \pOrigPath
-// i.e. \pMappingPath is a proper sub-path of \p OrigPath
+// Returns whether a path mapping should take place for OrigPath
+// i.e. MappingPath is a proper sub-path of  OrigPath
 bool mappingMatches(llvm::StringRef OrigPath, llvm::StringRef MappingPath) {
   namespace path = llvm::sys::path;
   auto OrigPathItr = path::begin(OrigPath, path::Style::posix);
@@ -149,11 +143,10 @@
   return std::equal(MappingPathItr, MappingPathEnd, OrigPathItr);
 }
 
-// Converts \pPath to a posix-style absolute, i.e. if it's a windows path
-// then the backward-slash notation will be converted to forward slash
+// Converts a unix/windows path to the path portion of a file URI
+// e.g. "C:\foo" -> "/C:/foo"
 llvm::Expected<std::string> parsePath(llvm::StringRef Path) {
   namespace path = llvm::sys::path;
-  std::string ParsedPath;
   if (path::is_absolute(Path, path::Style::posix)) {
     return Path;
   } else if (path::is_absolute(Path, path::Style::windows)) {
@@ -190,38 +183,43 @@
     if (!ParsedServerPath) {
       return ParsedServerPath.takeError();
     }
-    ParsedMappings.emplace_back(std::move(*ParsedClientPath),
-                                std::move(*ParsedServerPath));
+    ParsedMappings.push_back(
+        {std::move(*ParsedClientPath), std::move(*ParsedServerPath)});
   }
   return ParsedMappings;
 }
 
-llvm::Optional<std::string> doPathMapping(llvm::StringRef S, bool IsIncoming,
+llvm::Optional<std::string> doPathMapping(llvm::StringRef S,
+                                          PathMapping::Direction Dir,
                                           const PathMappings &Mappings) {
+  // Retrun early to optimize for the common case, wherein S is not a file URI
   if (!S.startswith("file://"))
     return llvm::None;
   auto Uri = URI::parse(S);
   if (!Uri) {
+    llvm::consumeError(Uri.takeError());
     return llvm::None;
   }
   for (const auto &Mapping : Mappings) {
-    const std::string &From =
-        IsIncoming ? Mapping.ClientPath : Mapping.ServerPath;
-    const std::string &To =
-        IsIncoming ? Mapping.ServerPath : Mapping.ClientPath;
+    const std::string &From = Dir == PathMapping::Direction::ClientToServer
+                                  ? Mapping.ClientPath
+                                  : Mapping.ServerPath;
+    const std::string &To = Dir == PathMapping::Direction::ClientToServer
+                                ? Mapping.ServerPath
+                                : Mapping.ClientPath;
     if (mappingMatches(Uri->body(), From)) {
-      llvm::SmallString<256> MappedPath(Uri->body());
-      llvm::sys::path::replace_path_prefix(MappedPath, From, To);
-      auto MappedUri = URI(Uri->scheme(), Uri->authority(), MappedPath.c_str());
+      std::string MappedBody = std::move(Uri->body());
+      MappedBody.replace(MappedBody.find(From), From.length(), To);
+      auto MappedUri = URI(Uri->scheme(), Uri->authority(), MappedBody.c_str());
       return MappedUri.toString();
     }
   }
   return llvm::None;
 }
 
-void applyPathMappings(llvm::json::Value &Params, bool IsIncoming,
+void applyPathMappings(llvm::json::Value &Params, PathMapping::Direction Dir,
                        const PathMappings &Mappings) {
-  recursivelyMap(Params, IsIncoming, Mappings, doPathMapping);
+  recursivelyMap(Params, Dir, Mappings, doPathMapping);
 }
 
 std::unique_ptr<Transport>
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to