[clangd] Change FSProvider::getFileSystem to take CurrentWorkingDirectory

Summary:
We've faced a couple of problems when the returned FS didn't have the
proper working directory. New signature makes the API safer against such
problems.

Reviewers: sammccall

Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D81920
diff --git a/clang-tools-extra/clangd/support/FSProvider.cpp b/clang-tools-extra/clangd/support/FSProvider.cpp
index 6474a3c..080bd06 100644
--- a/clang-tools-extra/clangd/support/FSProvider.cpp
+++ b/clang-tools-extra/clangd/support/FSProvider.cpp
@@ -7,6 +7,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "support/FSProvider.h"
+#include "Logger.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"
@@ -72,7 +75,15 @@
 } // namespace
 
 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
-clang::clangd::RealFileSystemProvider::getFileSystem() const {
+FileSystemProvider::getFileSystem(PathRef CWD) const {
+  auto FS = getFileSystem(/*CWD=*/llvm::None);
+  if (auto EC = FS->setCurrentWorkingDirectory(CWD))
+    elog("VFS: failed to set CWD to {0}: {1}", CWD, EC.message());
+  return FS;
+}
+
+llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
+clang::clangd::RealFileSystemProvider::getFileSystem(llvm::NoneType) const {
   // Avoid using memory-mapped files.
   // FIXME: Try to use a similar approach in Sema instead of relying on
   //        propagation of the 'isVolatile' flag through all layers.
diff --git a/clang-tools-extra/clangd/support/FSProvider.h b/clang-tools-extra/clangd/support/FSProvider.h
index 2686e3e..8c6b8c8 100644
--- a/clang-tools-extra/clangd/support/FSProvider.h
+++ b/clang-tools-extra/clangd/support/FSProvider.h
@@ -9,7 +9,10 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_FSPROVIDER_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_FSPROVIDER_H
 
+#include "Path.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include <memory>
 
@@ -25,14 +28,21 @@
   /// Context::current() will be the context passed to the clang entrypoint,
   /// such as addDocument(), and will also be propagated to result callbacks.
   /// Embedders may use this to isolate filesystem accesses.
+  /// Initial working directory is arbitrary.
   virtual llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
-  getFileSystem() const = 0;
+  getFileSystem(llvm::NoneType CWD) const = 0;
+
+  /// As above, except it will try to set current working directory to \p CWD.
+  /// This is an overload instead of an optional to make implicit string ->
+  /// StringRef conversion possible.
+  virtual llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
+  getFileSystem(PathRef CWD) const;
 };
 
 class RealFileSystemProvider : public FileSystemProvider {
 public:
   llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
-  getFileSystem() const override;
+      getFileSystem(llvm::NoneType) const override;
 };
 
 } // namespace clangd