diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -183,7 +183,8 @@ Opts.ClangTidyOpts = tidy::ClangTidyOptions::getDefaults(); // FIXME: call tidy options builder on the worker thread, it can do IO. if (GetClangTidyOptions) - Opts.ClangTidyOpts = GetClangTidyOptions(*FSProvider.getFileSystem(), File); + Opts.ClangTidyOpts = GetClangTidyOptions( + *FSProvider.getFileSystem(/*CWD=*/llvm::None), File); Opts.SuggestMissingIncludes = SuggestMissingIncludes; // Compile command is set asynchronously during update, as it can be slow. @@ -317,9 +318,9 @@ llvm::Expected CursorPos = positionToOffset(Code, Pos); if (!CursorPos) return CursorPos.takeError(); - auto FS = FSProvider.getFileSystem(); - auto Style = format::getStyle(format::DefaultFormatStyle, File, - format::DefaultFallbackStyle, Code, FS.get()); + auto Style = format::getStyle( + format::DefaultFormatStyle, File, format::DefaultFallbackStyle, Code, + FSProvider.getFileSystem(/*CWD=*/llvm::None).get()); if (!Style) return Style.takeError(); @@ -395,9 +396,8 @@ return CB(Edits.takeError()); if (Opts.WantFormat) { - auto Style = getFormatStyleForFile( - File, InpAST->Inputs.Contents, - InpAST->Inputs.FSProvider->getFileSystem().get()); + auto Style = getFormatStyleForFile(File, InpAST->Inputs.Contents, + *InpAST->Inputs.FSProvider); llvm::Error Err = llvm::Error::success(); for (auto &E : *Edits) Err = @@ -473,38 +473,38 @@ static constexpr trace::Metric TweakAttempt( "tweak_attempt", trace::Metric::Counter, "tweak_id"); TweakAttempt.record(1, TweakID); - auto Action = - [File = File.str(), Sel, TweakID = TweakID.str(), CB = std::move(CB), - FS = FSProvider.getFileSystem()](Expected InpAST) mutable { - if (!InpAST) - return CB(InpAST.takeError()); - auto Selections = tweakSelection(Sel, *InpAST); - if (!Selections) - return CB(Selections.takeError()); - llvm::Optional> Effect; - // Try each selection, take the first one that prepare()s. - // If they all fail, Effect will hold get the last error. - for (const auto &Selection : *Selections) { - auto T = prepareTweak(TweakID, *Selection); - if (T) { - Effect = (*T)->apply(*Selection); - break; - } - Effect = T.takeError(); - } - assert(Effect.hasValue() && "Expected at least one selection"); - if (*Effect) { - // Tweaks don't apply clang-format, do that centrally here. - for (auto &It : (*Effect)->ApplyEdits) { - Edit &E = It.second; - format::FormatStyle Style = - getFormatStyleForFile(File, E.InitialCode, FS.get()); - if (llvm::Error Err = reformatEdit(E, Style)) - elog("Failed to format {0}: {1}", It.first(), std::move(Err)); - } - } - return CB(std::move(*Effect)); - }; + auto Action = [File = File.str(), Sel, TweakID = TweakID.str(), + CB = std::move(CB), + this](Expected InpAST) mutable { + if (!InpAST) + return CB(InpAST.takeError()); + auto Selections = tweakSelection(Sel, *InpAST); + if (!Selections) + return CB(Selections.takeError()); + llvm::Optional> Effect; + // Try each selection, take the first one that prepare()s. + // If they all fail, Effect will hold get the last error. + for (const auto &Selection : *Selections) { + auto T = prepareTweak(TweakID, *Selection); + if (T) { + Effect = (*T)->apply(*Selection); + break; + } + Effect = T.takeError(); + } + assert(Effect.hasValue() && "Expected at least one selection"); + if (*Effect) { + // Tweaks don't apply clang-format, do that centrally here. + for (auto &It : (*Effect)->ApplyEdits) { + Edit &E = It.second; + format::FormatStyle Style = + getFormatStyleForFile(File, E.InitialCode, FSProvider); + if (llvm::Error Err = reformatEdit(E, Style)) + elog("Failed to format {0}: {1}", It.first(), std::move(Err)); + } + } + return CB(std::move(*Effect)); + }; WorkScheduler.runWithAST("ApplyTweak", File, std::move(Action)); } @@ -549,7 +549,7 @@ // 2) if 1) fails, we use the AST&Index approach, it is slower but supports // different code layout. if (auto CorrespondingFile = getCorrespondingHeaderOrSource( - std::string(Path), FSProvider.getFileSystem())) + std::string(Path), FSProvider.getFileSystem(llvm::None))) return CB(std::move(CorrespondingFile)); auto Action = [Path = Path.str(), CB = std::move(CB), this](llvm::Expected InpAST) mutable { @@ -564,8 +564,7 @@ ClangdServer::formatCode(llvm::StringRef Code, PathRef File, llvm::ArrayRef Ranges) { // Call clang-format. - format::FormatStyle Style = - getFormatStyleForFile(File, Code, FSProvider.getFileSystem().get()); + format::FormatStyle Style = getFormatStyleForFile(File, Code, FSProvider); tooling::Replacements IncludeReplaces = format::sortIncludes(Style, Code, Ranges, File); auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces); @@ -597,9 +596,8 @@ this](llvm::Expected InpAST) mutable { if (!InpAST) return CB(InpAST.takeError()); - format::FormatStyle Style = - getFormatStyleForFile(File, InpAST->Inputs.Contents, - InpAST->Inputs.FSProvider->getFileSystem().get()); + format::FormatStyle Style = getFormatStyleForFile( + File, InpAST->Inputs.Contents, *InpAST->Inputs.FSProvider); CB(clangd::getHover(InpAST->AST, Pos, std::move(Style), Index)); }; diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1113,12 +1113,10 @@ // NOTE: we must call BeginSourceFile after prepareCompilerInstance. Otherwise // the remapped buffers do not get freed. llvm::IntrusiveRefCntPtr VFS = - Input.ParseInput.FSProvider->getFileSystem(); + Input.ParseInput.FSProvider->getFileSystem( + Input.ParseInput.CompileCommand.Directory); if (Input.Preamble.StatCache) VFS = Input.Preamble.StatCache->getConsumingFS(std::move(VFS)); - if (VFS->setCurrentWorkingDirectory( - Input.ParseInput.CompileCommand.Directory)) - elog("Couldn't set working directory during code completion"); auto Clang = prepareCompilerInstance( std::move(CI), !CompletingInPreamble ? &Input.Preamble.Preamble : nullptr, std::move(ContentsBuffer), std::move(VFS), IgnoreDiags); @@ -1292,9 +1290,9 @@ assert(Recorder && "Recorder is not set"); CCContextKind = Recorder->CCContext.getKind(); IsUsingDeclaration = Recorder->CCContext.isUsingDeclaration(); - auto Style = getFormatStyleForFile( - SemaCCInput.FileName, SemaCCInput.ParseInput.Contents, - SemaCCInput.ParseInput.FSProvider->getFileSystem().get()); + auto Style = getFormatStyleForFile(SemaCCInput.FileName, + SemaCCInput.ParseInput.Contents, + *SemaCCInput.ParseInput.FSProvider); const auto NextToken = Lexer::findNextToken( Recorder->CCSema->getPreprocessor().getCodeCompletionLoc(), Recorder->CCSema->getSourceManager(), Recorder->CCSema->LangOpts); @@ -1365,9 +1363,8 @@ // Indexes may choose to impose their own limits even if we don't have one. } - CodeCompleteResult - runWithoutSema(llvm::StringRef Content, size_t Offset, - llvm::IntrusiveRefCntPtr VFS) && { + CodeCompleteResult runWithoutSema(llvm::StringRef Content, size_t Offset, + const FileSystemProvider &FSProvider) && { trace::Span Tracer("CodeCompleteWithoutSema"); // Fill in fields normally set by runWithSema() HeuristicPrefix = guessCompletionPrefix(Content, Offset); @@ -1383,7 +1380,7 @@ ProxSources[FileName].Cost = 0; FileProximity.emplace(ProxSources); - auto Style = getFormatStyleForFile(FileName, Content, VFS.get()); + auto Style = getFormatStyleForFile(FileName, Content, FSProvider); // This will only insert verbatim headers. Inserter.emplace(FileName, Content, Style, /*BuildDir=*/"", /*HeaderSearchInfo=*/nullptr); @@ -1783,9 +1780,8 @@ FileName, Preamble ? Preamble->Includes : IncludeStructure(), SpecFuzzyFind, Opts); return (!Preamble || Opts.RunParser == CodeCompleteOptions::NeverParse) - ? std::move(Flow).runWithoutSema( - ParseInput.Contents, *Offset, - ParseInput.FSProvider->getFileSystem()) + ? std::move(Flow).runWithoutSema(ParseInput.Contents, *Offset, + *ParseInput.FSProvider) : std::move(Flow).run({FileName, *Offset, *Preamble, // We want to serve code completions with // low latency, so don't bother patching. diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp --- a/clang-tools-extra/clangd/Compiler.cpp +++ b/clang-tools-extra/clangd/Compiler.cpp @@ -11,6 +11,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Serialization/PCHContainerOperations.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" @@ -47,13 +48,7 @@ for (const auto &S : Inputs.CompileCommand.CommandLine) ArgStrs.push_back(S.c_str()); - auto VFS = Inputs.FSProvider->getFileSystem(); - if (VFS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) { - log("Couldn't set working directory when creating compiler invocation."); - // We proceed anyway, our lit-tests rely on results for non-existing working - // dirs. - } - + auto VFS = Inputs.FSProvider->getFileSystem(Inputs.CompileCommand.Directory); llvm::IntrusiveRefCntPtr CommandLineDiagsEngine = CompilerInstance::createDiagnostics(new DiagnosticOptions, &D, false); std::unique_ptr CI = createInvocationFromCommandLine( diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -46,6 +46,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -248,14 +249,9 @@ trace::Span Tracer("BuildAST"); SPAN_ATTACH(Tracer, "File", Filename); - auto VFS = Inputs.FSProvider->getFileSystem(); + auto VFS = Inputs.FSProvider->getFileSystem(Inputs.CompileCommand.Directory); if (Preamble && Preamble->StatCache) VFS = Preamble->StatCache->getConsumingFS(std::move(VFS)); - if (VFS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) { - log("Couldn't set working directory when building the preamble."); - // We proceed anyway, our lit-tests rely on results for non-existing working - // dirs. - } assert(CI); // Command-line parsing sets DisableFree to true by default, but we don't want @@ -359,7 +355,8 @@ auto BuildDir = VFS->getCurrentWorkingDirectory(); if (Inputs.Opts.SuggestMissingIncludes && Inputs.Index && !BuildDir.getError()) { - auto Style = getFormatStyleForFile(Filename, Inputs.Contents, VFS.get()); + auto Style = + getFormatStyleForFile(Filename, Inputs.Contents, *Inputs.FSProvider); auto Inserter = std::make_shared( Filename, Inputs.Contents, Style, BuildDir.get(), &Clang->getPreprocessor().getHeaderSearchInfo()); diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -30,6 +30,8 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" @@ -237,7 +239,7 @@ VFSProvider(llvm::IntrusiveRefCntPtr FS) : VFS(std::move(FS)) {} llvm::IntrusiveRefCntPtr - getFileSystem() const override { + getFileSystem(llvm::NoneType) const override { return VFS; } @@ -356,13 +358,7 @@ CI.getPreprocessorOpts().WriteCommentListToPCH = false; CppFilePreambleCallbacks SerializedDeclsCollector(FileName, PreambleCallback); - auto VFS = Inputs.FSProvider->getFileSystem(); - if (VFS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) { - log("Couldn't set working directory when building the preamble."); - // We proceed anyway, our lit-tests rely on results for non-existing working - // dirs. - } - + auto VFS = Inputs.FSProvider->getFileSystem(Inputs.CompileCommand.Directory); llvm::SmallString<32> AbsFileName(FileName); VFS->makeAbsolute(AbsFileName); auto StatCache = std::make_unique(AbsFileName); @@ -399,8 +395,7 @@ llvm::MemoryBuffer::getMemBuffer(Inputs.Contents, FileName); auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), ContentsBuffer.get(), 0); - auto VFS = Inputs.FSProvider->getFileSystem(); - VFS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory); + auto VFS = Inputs.FSProvider->getFileSystem(Inputs.CompileCommand.Directory); return compileCommandsAreEqual(Inputs.CompileCommand, Preamble.CompileCommand) && Preamble.Preamble.CanReuse(CI, ContentsBuffer.get(), Bounds, @@ -427,8 +422,8 @@ trace::Span Tracer("CreatePreamblePatch"); SPAN_ATTACH(Tracer, "File", FileName); assert(llvm::sys::path::is_absolute(FileName) && "relative FileName!"); - auto VFS = - Baseline.StatCache->getConsumingFS(Modified.FSProvider->getFileSystem()); + auto VFS = Baseline.StatCache->getConsumingFS( + Modified.FSProvider->getFileSystem(/*CWD=*/llvm::None)); // First scan preprocessor directives in Baseline and Modified. These will be // used to figure out newly added directives in Modified. Scanning can fail, // the code just bails out and creates an empty patch in such cases, as: diff --git a/clang-tools-extra/clangd/SourceCode.h b/clang-tools-extra/clangd/SourceCode.h --- a/clang-tools-extra/clangd/SourceCode.h +++ b/clang-tools-extra/clangd/SourceCode.h @@ -15,6 +15,7 @@ #include "Protocol.h" #include "support/Context.h" +#include "support/FSProvider.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" @@ -167,7 +168,7 @@ /// though the latter may have been overridden in main()! format::FormatStyle getFormatStyleForFile(llvm::StringRef File, llvm::StringRef Content, - llvm::vfs::FileSystem *FS); + const FileSystemProvider &FSProvider); /// Cleanup and format the given replacements. llvm::Expected diff --git a/clang-tools-extra/clangd/SourceCode.cpp b/clang-tools-extra/clangd/SourceCode.cpp --- a/clang-tools-extra/clangd/SourceCode.cpp +++ b/clang-tools-extra/clangd/SourceCode.cpp @@ -12,6 +12,7 @@ #include "Protocol.h" #include "refactor/Tweak.h" #include "support/Context.h" +#include "support/FSProvider.h" #include "support/Logger.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/LangOptions.h" @@ -574,11 +575,12 @@ return digest(Content); } -format::FormatStyle getFormatStyleForFile(llvm::StringRef File, - llvm::StringRef Content, - llvm::vfs::FileSystem *FS) { - auto Style = format::getStyle(format::DefaultFormatStyle, File, - format::DefaultFallbackStyle, Content, FS); +format::FormatStyle +getFormatStyleForFile(llvm::StringRef File, llvm::StringRef Content, + const FileSystemProvider &FSProvider) { + auto Style = format::getStyle( + format::DefaultFormatStyle, File, format::DefaultFallbackStyle, Content, + FSProvider.getFileSystem(/*CWD=*/llvm::None).get()); if (!Style) { log("getStyle() failed for file {0}: {1}. Fallback is LLVM style.", File, Style.takeError()); diff --git a/clang-tools-extra/clangd/index/Background.cpp b/clang-tools-extra/clangd/index/Background.cpp --- a/clang-tools-extra/clangd/index/Background.cpp +++ b/clang-tools-extra/clangd/index/Background.cpp @@ -244,8 +244,7 @@ SPAN_ATTACH(Tracer, "file", Cmd.Filename); auto AbsolutePath = getAbsolutePath(Cmd); - auto FS = FSProvider.getFileSystem(); - FS->setCurrentWorkingDirectory(Cmd.Directory); + auto FS = FSProvider.getFileSystem(Cmd.Directory); auto Buf = FS->getBufferForFile(AbsolutePath); if (!Buf) return llvm::errorCodeToError(Buf.getError()); @@ -382,7 +381,7 @@ Rebuilder.loadedShard(LoadedShards); Rebuilder.doneLoading(); - auto FS = FSProvider.getFileSystem(); + auto FS = FSProvider.getFileSystem(/*CWD=*/llvm::None); llvm::DenseSet TUsToIndex; // We'll accept data from stale shards, but ensure the files get reindexed // soon. diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp --- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp @@ -424,10 +424,8 @@ return llvm::createStringError(Buffer.getError(), Buffer.getError().message()); auto Contents = Buffer->get()->getBuffer(); - auto LangOpts = format::getFormattingLangOpts( - getFormatStyleForFile(*CCFile, Contents, &FS)); auto InsertionPoint = getInsertionPoint( - Contents, Source->getQualifiedNameAsString(), LangOpts); + Contents, Source->getQualifiedNameAsString(), Sel.AST->getLangOpts()); if (!InsertionPoint) return InsertionPoint.takeError(); diff --git a/clang-tools-extra/clangd/support/FSProvider.h b/clang-tools-extra/clangd/support/FSProvider.h --- 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 @@ -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 - 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 + getFileSystem(PathRef CWD) const; }; class RealFileSystemProvider : public FileSystemProvider { public: llvm::IntrusiveRefCntPtr - getFileSystem() const override; + getFileSystem(llvm::NoneType) const override; }; } // namespace clangd diff --git a/clang-tools-extra/clangd/support/FSProvider.cpp b/clang-tools-extra/clangd/support/FSProvider.cpp --- 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 -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 +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/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -21,6 +21,7 @@ #include "clang/Basic/Version.h" #include "clang/Format/Format.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" @@ -717,7 +718,8 @@ ClangTidyOptProvider = std::make_unique( tidy::ClangTidyGlobalOptions(), /* Default */ EmptyDefaults, - /* Override */ OverrideClangTidyOptions, FSProvider.getFileSystem()); + /* Override */ OverrideClangTidyOptions, + FSProvider.getFileSystem(/*CWD=*/llvm::None)); Opts.GetClangTidyOptions = [&](llvm::vfs::FileSystem &, llvm::StringRef File) { // This function must be thread-safe and tidy option providers are not. diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp b/clang-tools-extra/clangd/unittests/ClangdTests.cpp --- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp +++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp @@ -15,9 +15,12 @@ #include "SyncAPI.h" #include "TestFS.h" #include "URI.h" +#include "support/Path.h" #include "support/Threading.h" #include "clang/Config/config.h" #include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/Errc.h" @@ -270,7 +273,8 @@ TEST_F(ClangdVFSTest, PropagatesContexts) { static Key Secret; struct FSProvider : public FileSystemProvider { - IntrusiveRefCntPtr getFileSystem() const override { + IntrusiveRefCntPtr + getFileSystem(llvm::NoneType) const override { Got = Context::current().getExisting(Secret); return buildTestFS({}); } @@ -925,7 +929,8 @@ ListenStatsFSProvider(llvm::StringMap &CountStats) : CountStats(CountStats) {} - IntrusiveRefCntPtr getFileSystem() const override { + IntrusiveRefCntPtr + getFileSystem(llvm::NoneType) const override { class ListenStatVFS : public llvm::vfs::ProxyFileSystem { public: ListenStatVFS(IntrusiveRefCntPtr FS, diff --git a/clang-tools-extra/clangd/unittests/FSTests.cpp b/clang-tools-extra/clangd/unittests/FSTests.cpp --- a/clang-tools-extra/clangd/unittests/FSTests.cpp +++ b/clang-tools-extra/clangd/unittests/FSTests.cpp @@ -21,7 +21,6 @@ Files["y"] = ""; Files["main"] = ""; auto FS = buildTestFS(Files); - FS->setCurrentWorkingDirectory(testRoot()); PreambleFileStatusCache StatCache(testPath("main")); auto ProduceFS = StatCache.getProducingFS(FS); diff --git a/clang-tools-extra/clangd/unittests/HeadersTests.cpp b/clang-tools-extra/clangd/unittests/HeadersTests.cpp --- a/clang-tools-extra/clangd/unittests/HeadersTests.cpp +++ b/clang-tools-extra/clangd/unittests/HeadersTests.cpp @@ -16,6 +16,7 @@ #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Lex/PreprocessorOptions.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" #include "gmock/gmock.h" @@ -52,8 +53,7 @@ EXPECT_TRUE(static_cast(CI)); // The diagnostic options must be set before creating a CompilerInstance. CI->getDiagnosticOpts().IgnoreWarnings = true; - auto VFS = FS.getFileSystem(); - VFS->setCurrentWorkingDirectory(Cmd->Directory); + auto VFS = PI.FSProvider->getFileSystem(Cmd->Directory); auto Clang = prepareCompilerInstance( std::move(CI), /*Preamble=*/nullptr, llvm::MemoryBuffer::getMemBuffer(FS.Files[MainFile], MainFile), diff --git a/clang-tools-extra/clangd/unittests/PreambleTests.cpp b/clang-tools-extra/clangd/unittests/PreambleTests.cpp --- a/clang-tools-extra/clangd/unittests/PreambleTests.cpp +++ b/clang-tools-extra/clangd/unittests/PreambleTests.cpp @@ -70,11 +70,11 @@ // We don't run PP directly over the patch cotents to test production // behaviour. auto Bounds = Lexer::ComputePreamble(ModifiedContents, *CI->getLangOpts()); - auto Clang = - prepareCompilerInstance(std::move(CI), &BaselinePreamble->Preamble, - llvm::MemoryBuffer::getMemBufferCopy( - ModifiedContents.slice(0, Bounds.Size).str()), - PI.FSProvider->getFileSystem(), Diags); + auto Clang = prepareCompilerInstance( + std::move(CI), &BaselinePreamble->Preamble, + llvm::MemoryBuffer::getMemBufferCopy( + ModifiedContents.slice(0, Bounds.Size).str()), + PI.FSProvider->getFileSystem(PI.CompileCommand.Directory), Diags); PreprocessOnlyAction Action; if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) { ADD_FAILURE() << "failed begin source file"; diff --git a/clang-tools-extra/clangd/unittests/TestFS.h b/clang-tools-extra/clangd/unittests/TestFS.h --- a/clang-tools-extra/clangd/unittests/TestFS.h +++ b/clang-tools-extra/clangd/unittests/TestFS.h @@ -13,8 +13,11 @@ #define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_TESTFS_H #include "ClangdServer.h" #include "GlobalCompilationDatabase.h" +#include "support/FSProvider.h" #include "support/Path.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/Support/Path.h" #include "llvm/Support/VirtualFileSystem.h" @@ -30,10 +33,18 @@ // A VFS provider that returns TestFSes containing a provided set of files. class MockFSProvider : public FileSystemProvider { public: - IntrusiveRefCntPtr getFileSystem() const override { + // Prevent name hiding caused by the overload below. + using FileSystemProvider::getFileSystem; + + IntrusiveRefCntPtr getFileSystem() const { return buildTestFS(Files, Timestamps); } + IntrusiveRefCntPtr + getFileSystem(llvm::NoneType) const override { + return getFileSystem(); + } + // If relative paths are used, they are resolved with testPath(). llvm::StringMap Files; llvm::StringMap Timestamps;