Author: Kadir Cetinkaya Date: 2020-06-08T13:23:55+02:00 New Revision: f693ce4aa97e7afe34a3f41609ffbbaf32b571de
URL: https://github.com/llvm/llvm-project/commit/f693ce4aa97e7afe34a3f41609ffbbaf32b571de DIFF: https://github.com/llvm/llvm-project/commit/f693ce4aa97e7afe34a3f41609ffbbaf32b571de.diff LOG: [clangd] Change ParseInputs to store FSProvider rather than VFS Summary: This ensures ParseInputs provides a read-only access to FS. Reviewers: sammccall Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D81173 Added: Modified: clang-tools-extra/clangd/ClangdServer.cpp clang-tools-extra/clangd/CodeComplete.cpp clang-tools-extra/clangd/Compiler.cpp clang-tools-extra/clangd/Compiler.h clang-tools-extra/clangd/ParsedAST.cpp clang-tools-extra/clangd/Preamble.cpp clang-tools-extra/clangd/index/Background.cpp clang-tools-extra/clangd/support/FSProvider.h clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp clang-tools-extra/clangd/unittests/CompilerTests.cpp clang-tools-extra/clangd/unittests/FileIndexTests.cpp clang-tools-extra/clangd/unittests/HeadersTests.cpp clang-tools-extra/clangd/unittests/ParsedASTTests.cpp clang-tools-extra/clangd/unittests/PreambleTests.cpp clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp clang-tools-extra/clangd/unittests/TestFS.h clang-tools-extra/clangd/unittests/TestTU.cpp clang-tools-extra/clangd/unittests/TestTU.h Removed: ################################################################################ diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index 0721c8ddaf73..3539de0e561e 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -179,18 +179,16 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB, void ClangdServer::addDocument(PathRef File, llvm::StringRef Contents, llvm::StringRef Version, WantDiagnostics WantDiags, bool ForceRebuild) { - auto FS = FSProvider.getFileSystem(); - ParseOptions Opts; Opts.ClangTidyOpts = tidy::ClangTidyOptions::getDefaults(); // FIXME: call tidy options builder on the worker thread, it can do IO. if (GetClangTidyOptions) - Opts.ClangTidyOpts = GetClangTidyOptions(*FS, File); + Opts.ClangTidyOpts = GetClangTidyOptions(*FSProvider.getFileSystem(), File); Opts.SuggestMissingIncludes = SuggestMissingIncludes; // Compile command is set asynchronously during update, as it can be slow. ParseInputs Inputs; - Inputs.FS = FS; + Inputs.FSProvider = &FSProvider; Inputs.Contents = std::string(Contents); Inputs.Version = Version.str(); Inputs.ForceRebuild = ForceRebuild; @@ -214,8 +212,7 @@ void ClangdServer::codeComplete(PathRef File, Position Pos, if (!CodeCompleteOpts.Index) // Respect overridden index. CodeCompleteOpts.Index = Index; - auto Task = [Pos, FS = FSProvider.getFileSystem(), CodeCompleteOpts, - File = File.str(), CB = std::move(CB), + auto Task = [Pos, CodeCompleteOpts, File = File.str(), CB = std::move(CB), this](llvm::Expected<InputsAndPreamble> IP) mutable { if (!IP) return CB(IP.takeError()); @@ -238,7 +235,7 @@ void ClangdServer::codeComplete(PathRef File, Position Pos, } } } - ParseInputs ParseInput{IP->Command, FS, IP->Contents.str()}; + ParseInputs ParseInput{IP->Command, &FSProvider, IP->Contents.str()}; ParseInput.Index = Index; ParseInput.Opts.BuildRecoveryAST = BuildRecoveryAST; ParseInput.Opts.PreserveRecoveryASTType = PreserveRecoveryASTType; @@ -275,8 +272,7 @@ void ClangdServer::codeComplete(PathRef File, Position Pos, void ClangdServer::signatureHelp(PathRef File, Position Pos, Callback<SignatureHelp> CB) { - auto Action = [Pos, FS = FSProvider.getFileSystem(), File = File.str(), - CB = std::move(CB), + auto Action = [Pos, File = File.str(), CB = std::move(CB), this](llvm::Expected<InputsAndPreamble> IP) mutable { if (!IP) return CB(IP.takeError()); @@ -286,7 +282,7 @@ void ClangdServer::signatureHelp(PathRef File, Position Pos, return CB(llvm::createStringError(llvm::inconvertibleErrorCode(), "Failed to parse includes")); - ParseInputs ParseInput{IP->Command, FS, IP->Contents.str()}; + ParseInputs ParseInput{IP->Command, &FSProvider, IP->Contents.str()}; ParseInput.Index = Index; ParseInput.Opts.BuildRecoveryAST = BuildRecoveryAST; ParseInput.Opts.PreserveRecoveryASTType = PreserveRecoveryASTType; @@ -399,8 +395,9 @@ void ClangdServer::rename(PathRef File, Position Pos, llvm::StringRef NewName, return CB(Edits.takeError()); if (Opts.WantFormat) { - auto Style = getFormatStyleForFile(File, InpAST->Inputs.Contents, - InpAST->Inputs.FS.get()); + auto Style = getFormatStyleForFile( + File, InpAST->Inputs.Contents, + InpAST->Inputs.FSProvider->getFileSystem().get()); llvm::Error Err = llvm::Error::success(); for (auto &E : *Edits) Err = @@ -600,8 +597,9 @@ void ClangdServer::findHover(PathRef File, Position Pos, this](llvm::Expected<InputsAndAST> InpAST) mutable { if (!InpAST) return CB(InpAST.takeError()); - format::FormatStyle Style = getFormatStyleForFile( - File, InpAST->Inputs.Contents, InpAST->Inputs.FS.get()); + format::FormatStyle Style = + getFormatStyleForFile(File, InpAST->Inputs.Contents, + InpAST->Inputs.FSProvider->getFileSystem().get()); 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 index 4c05daac61bf..3cfdac1c3bc8 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -36,6 +36,7 @@ #include "index/Index.h" #include "index/Symbol.h" #include "index/SymbolOrigin.h" +#include "support/FSProvider.h" #include "support/Logger.h" #include "support/Threading.h" #include "support/Trace.h" @@ -1060,9 +1061,6 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer, const SemaCompleteInput &Input, IncludeStructure *Includes = nullptr) { trace::Span Tracer("Sema completion"); - llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = Input.ParseInput.FS; - if (Input.Preamble.StatCache) - VFS = Input.Preamble.StatCache->getConsumingFS(std::move(VFS)); IgnoreDiagnostics IgnoreDiags; auto CI = buildCompilerInvocation(Input.ParseInput, IgnoreDiags); @@ -1103,6 +1101,10 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer, Input.Patch->apply(*CI); // NOTE: we must call BeginSourceFile after prepareCompilerInstance. Otherwise // the remapped buffers do not get freed. + llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = + Input.ParseInput.FSProvider->getFileSystem(); + if (Input.Preamble.StatCache) + VFS = Input.Preamble.StatCache->getConsumingFS(std::move(VFS)); auto Clang = prepareCompilerInstance( std::move(CI), !CompletingInPreamble ? &Input.Preamble.Preamble : nullptr, std::move(ContentsBuffer), std::move(VFS), IgnoreDiags); @@ -1272,9 +1274,9 @@ class CodeCompleteFlow { assert(Recorder && "Recorder is not set"); CCContextKind = Recorder->CCContext.getKind(); IsUsingDeclaration = Recorder->CCContext.isUsingDeclaration(); - auto Style = getFormatStyleForFile(SemaCCInput.FileName, - SemaCCInput.ParseInput.Contents, - SemaCCInput.ParseInput.FS.get()); + auto Style = getFormatStyleForFile( + SemaCCInput.FileName, SemaCCInput.ParseInput.Contents, + SemaCCInput.ParseInput.FSProvider->getFileSystem().get()); // If preprocessor was run, inclusions from preprocessor callback should // already be added to Includes. Inserter.emplace( @@ -1759,8 +1761,9 @@ CodeCompleteResult codeComplete(PathRef FileName, Position Pos, FileName, Preamble ? Preamble->Includes : IncludeStructure(), SpecFuzzyFind, Opts); return (!Preamble || Opts.RunParser == CodeCompleteOptions::NeverParse) - ? std::move(Flow).runWithoutSema(ParseInput.Contents, *Offset, - ParseInput.FS) + ? std::move(Flow).runWithoutSema( + ParseInput.Contents, *Offset, + ParseInput.FSProvider->getFileSystem()) : 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 index 9eb86a4265b4..3dfa77057e9f 100644 --- a/clang-tools-extra/clangd/Compiler.cpp +++ b/clang-tools-extra/clangd/Compiler.cpp @@ -47,7 +47,8 @@ buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, for (const auto &S : Inputs.CompileCommand.CommandLine) ArgStrs.push_back(S.c_str()); - if (Inputs.FS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) { + 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. @@ -56,7 +57,7 @@ buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, llvm::IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine = CompilerInstance::createDiagnostics(new DiagnosticOptions, &D, false); std::unique_ptr<CompilerInvocation> CI = createInvocationFromCommandLine( - ArgStrs, CommandLineDiagsEngine, Inputs.FS, + ArgStrs, CommandLineDiagsEngine, std::move(VFS), /*ShouldRecoverOnErrors=*/true, CC1Args); if (!CI) return nullptr; diff --git a/clang-tools-extra/clangd/Compiler.h b/clang-tools-extra/clangd/Compiler.h index 4b507f34adc4..a4edf957549e 100644 --- a/clang-tools-extra/clangd/Compiler.h +++ b/clang-tools-extra/clangd/Compiler.h @@ -18,6 +18,7 @@ #include "../clang-tidy/ClangTidyOptions.h" #include "GlobalCompilationDatabase.h" #include "index/Index.h" +#include "support/FSProvider.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/PrecompiledPreamble.h" #include "clang/Tooling/CompilationDatabase.h" @@ -45,7 +46,7 @@ struct ParseOptions { /// Information required to run clang, e.g. to parse AST or do code completion. struct ParseInputs { tooling::CompileCommand CompileCommand; - IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; + const FileSystemProvider *FSProvider; std::string Contents; // Version identifier for Contents, provided by the client and opaque to us. std::string Version = "null"; diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp index f3568c34f99a..e85f1b30cd3a 100644 --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -248,7 +248,7 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs, trace::Span Tracer("BuildAST"); SPAN_ATTACH(Tracer, "File", Filename); - auto VFS = Inputs.FS; + auto VFS = Inputs.FSProvider->getFileSystem(); if (Preamble && Preamble->StatCache) VFS = Preamble->StatCache->getConsumingFS(std::move(VFS)); if (VFS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) { diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp index d02685f4bf46..af7229ecb888 100644 --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -10,6 +10,7 @@ #include "Compiler.h" #include "Headers.h" #include "SourceCode.h" +#include "support/FSProvider.h" #include "support/Logger.h" #include "support/Trace.h" #include "clang/Basic/Diagnostic.h" @@ -212,10 +213,29 @@ llvm::Expected<ScannedPreamble> scanPreamble(llvm::StringRef Contents, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, const tooling::CompileCommand &Cmd) { + // FIXME: Change PreambleStatCache to operate on FileSystemProvider rather + // than vfs::FileSystem, that way we can just use ParseInputs without this + // hack. + auto GetFSProvider = [](llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) { + class VFSProvider : public FileSystemProvider { + public: + VFSProvider(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) + : VFS(std::move(FS)) {} + llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> + getFileSystem() const override { + return VFS; + } + + private: + const llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS; + }; + return std::make_unique<VFSProvider>(std::move(FS)); + }; + auto FSProvider = GetFSProvider(std::move(VFS)); // Build and run Preprocessor over the preamble. ParseInputs PI; PI.Contents = Contents.str(); - PI.FS = std::move(VFS); + PI.FSProvider = FSProvider.get(); PI.CompileCommand = Cmd; IgnoringDiagConsumer IgnoreDiags; auto CI = buildCompilerInvocation(PI, IgnoreDiags); @@ -320,18 +340,19 @@ buildPreamble(PathRef FileName, CompilerInvocation CI, CI.getPreprocessorOpts().WriteCommentListToPCH = false; CppFilePreambleCallbacks SerializedDeclsCollector(FileName, PreambleCallback); - if (Inputs.FS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) { + 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. } llvm::SmallString<32> AbsFileName(FileName); - Inputs.FS->makeAbsolute(AbsFileName); + VFS->makeAbsolute(AbsFileName); auto StatCache = std::make_unique<PreambleFileStatusCache>(AbsFileName); auto BuiltPreamble = PrecompiledPreamble::Build( CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine, - StatCache->getProducingFS(Inputs.FS), + StatCache->getProducingFS(VFS), std::make_shared<PCHContainerOperations>(), StoreInMemory, SerializedDeclsCollector); @@ -365,7 +386,7 @@ bool isPreambleCompatible(const PreambleData &Preamble, return compileCommandsAreEqual(Inputs.CompileCommand, Preamble.CompileCommand) && Preamble.Preamble.CanReuse(CI, ContentsBuffer.get(), Bounds, - Inputs.FS.get()); + Inputs.FSProvider->getFileSystem().get()); } void escapeBackslashAndQuotes(llvm::StringRef Text, llvm::raw_ostream &OS) { @@ -388,6 +409,8 @@ PreamblePatch PreamblePatch::create(llvm::StringRef FileName, 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()); // 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: @@ -398,16 +421,14 @@ PreamblePatch PreamblePatch::create(llvm::StringRef FileName, // there's nothing to do but generate an empty patch. auto BaselineScan = scanPreamble( // Contents needs to be null-terminated. - Baseline.Preamble.getContents().str(), - Baseline.StatCache->getConsumingFS(Modified.FS), Modified.CompileCommand); + Baseline.Preamble.getContents().str(), VFS, Modified.CompileCommand); if (!BaselineScan) { elog("Failed to scan baseline of {0}: {1}", FileName, BaselineScan.takeError()); return PreamblePatch::unmodified(Baseline); } - auto ModifiedScan = scanPreamble( - Modified.Contents, Baseline.StatCache->getConsumingFS(Modified.FS), - Modified.CompileCommand); + auto ModifiedScan = + scanPreamble(Modified.Contents, std::move(VFS), Modified.CompileCommand); if (!ModifiedScan) { elog("Failed to scan modified contents of {0}: {1}", FileName, ModifiedScan.takeError()); diff --git a/clang-tools-extra/clangd/index/Background.cpp b/clang-tools-extra/clangd/index/Background.cpp index cc2c288c090e..de6dd9c60113 100644 --- a/clang-tools-extra/clangd/index/Background.cpp +++ b/clang-tools-extra/clangd/index/Background.cpp @@ -245,6 +245,7 @@ llvm::Error BackgroundIndex::index(tooling::CompileCommand Cmd) { auto AbsolutePath = getAbsolutePath(Cmd); auto FS = FSProvider.getFileSystem(); + FS->setCurrentWorkingDirectory(Cmd.Directory); auto Buf = FS->getBufferForFile(AbsolutePath); if (!Buf) return llvm::errorCodeToError(Buf.getError()); @@ -259,16 +260,17 @@ llvm::Error BackgroundIndex::index(tooling::CompileCommand Cmd) { vlog("Indexing {0} (digest:={1})", Cmd.Filename, llvm::toHex(Hash)); ParseInputs Inputs; - Inputs.FS = std::move(FS); - Inputs.FS->setCurrentWorkingDirectory(Cmd.Directory); + Inputs.FSProvider = &FSProvider; Inputs.CompileCommand = std::move(Cmd); IgnoreDiagnostics IgnoreDiags; auto CI = buildCompilerInvocation(Inputs, IgnoreDiags); if (!CI) return llvm::createStringError(llvm::inconvertibleErrorCode(), "Couldn't build compiler invocation"); - auto Clang = prepareCompilerInstance(std::move(CI), /*Preamble=*/nullptr, - std::move(*Buf), Inputs.FS, IgnoreDiags); + + auto Clang = + prepareCompilerInstance(std::move(CI), /*Preamble=*/nullptr, + std::move(*Buf), std::move(FS), IgnoreDiags); if (!Clang) return llvm::createStringError(llvm::inconvertibleErrorCode(), "Couldn't build compiler instance"); diff --git a/clang-tools-extra/clangd/support/FSProvider.h b/clang-tools-extra/clangd/support/FSProvider.h index a53a4149a47b..2686e3ec4c43 100644 --- a/clang-tools-extra/clangd/support/FSProvider.h +++ b/clang-tools-extra/clangd/support/FSProvider.h @@ -11,6 +11,7 @@ #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/Support/VirtualFileSystem.h" +#include <memory> namespace clang { namespace clangd { diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index ab1947844bbe..6114fac2dace 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -108,7 +108,10 @@ CodeCompleteResult completions(const TestTU &TU, Position Point, Opts.Index = OverrideIndex.get(); } - auto Inputs = TU.inputs(); + MockFSProvider FS; + auto Inputs = TU.inputs(FS); + Inputs.Opts.BuildRecoveryAST = true; + Inputs.Opts.PreserveRecoveryASTType = true; IgnoreDiagnostics Diags; auto CI = buildCompilerInvocation(Inputs, Diags); if (!CI) { @@ -117,10 +120,7 @@ CodeCompleteResult completions(const TestTU &TU, Position Point, } auto Preamble = buildPreamble(testPath(TU.Filename), *CI, Inputs, /*InMemory=*/true, /*Callback=*/nullptr); - ParseInputs ParseInput{Inputs.CompileCommand, Inputs.FS, TU.Code}; - ParseInput.Opts.BuildRecoveryAST = true; - ParseInput.Opts.PreserveRecoveryASTType = true; - return codeComplete(testPath(TU.Filename), Point, Preamble.get(), ParseInput, + return codeComplete(testPath(TU.Filename), Point, Preamble.get(), Inputs, Opts); } @@ -151,8 +151,7 @@ CodeCompleteResult completionsNoCompile(llvm::StringRef Text, MockFSProvider FS; Annotations Test(Text); - ParseInputs ParseInput{tooling::CompileCommand(), FS.getFileSystem(), - Test.code().str()}; + ParseInputs ParseInput{tooling::CompileCommand(), &FS, Test.code().str()}; return codeComplete(FilePath, Test.point(), /*Preamble=*/nullptr, ParseInput, Opts); } @@ -1058,7 +1057,11 @@ SignatureHelp signatures(llvm::StringRef Text, Position Point, Index = memIndex(IndexSymbols); auto TU = TestTU::withCode(Text); - auto Inputs = TU.inputs(); + MockFSProvider FS; + auto Inputs = TU.inputs(FS); + Inputs.Index = Index.get(); + Inputs.Opts.BuildRecoveryAST = true; + Inputs.Opts.PreserveRecoveryASTType = true; IgnoreDiagnostics Diags; auto CI = buildCompilerInvocation(Inputs, Diags); if (!CI) { @@ -1071,11 +1074,7 @@ SignatureHelp signatures(llvm::StringRef Text, Position Point, ADD_FAILURE() << "Couldn't build Preamble"; return {}; } - ParseInputs ParseInput{Inputs.CompileCommand, Inputs.FS, Text.str()}; - ParseInput.Index = Index.get(); - ParseInput.Opts.BuildRecoveryAST = true; - ParseInput.Opts.PreserveRecoveryASTType = true; - return signatureHelp(testPath(TU.Filename), Point, *Preamble, ParseInput); + return signatureHelp(testPath(TU.Filename), Point, *Preamble, Inputs); } SignatureHelp signatures(llvm::StringRef Text, @@ -1213,7 +1212,8 @@ TEST(SignatureHelpTest, StalePreamble) { TestTU TU; TU.Code = ""; IgnoreDiagnostics Diags; - auto Inputs = TU.inputs(); + MockFSProvider FS; + auto Inputs = TU.inputs(FS); auto CI = buildCompilerInvocation(Inputs, Diags); ASSERT_TRUE(CI); auto EmptyPreamble = buildPreamble(testPath(TU.Filename), *CI, Inputs, @@ -1225,11 +1225,8 @@ TEST(SignatureHelpTest, StalePreamble) { #include "a.h" void bar() { foo(^2); })cpp"); TU.Code = Test.code().str(); - Inputs = TU.inputs(); - - ParseInputs ParseInput{Inputs.CompileCommand, Inputs.FS, TU.Code}; auto Results = signatureHelp(testPath(TU.Filename), Test.point(), - *EmptyPreamble, ParseInput); + *EmptyPreamble, TU.inputs(FS)); EXPECT_THAT(Results.signatures, ElementsAre(Sig("foo([[int x]]) -> int"))); EXPECT_EQ(0, Results.activeSignature); EXPECT_EQ(0, Results.activeParameter); diff --git a/clang-tools-extra/clangd/unittests/CompilerTests.cpp b/clang-tools-extra/clangd/unittests/CompilerTests.cpp index a12a7b9ce9af..58210a95df3c 100644 --- a/clang-tools-extra/clangd/unittests/CompilerTests.cpp +++ b/clang-tools-extra/clangd/unittests/CompilerTests.cpp @@ -19,19 +19,20 @@ namespace { using testing::IsEmpty; TEST(BuildCompilerInvocation, DropsPCH) { + MockFSProvider FS; IgnoreDiagnostics Diags; TestTU TU; TU.AdditionalFiles["test.h.pch"] = ""; TU.ExtraArgs = {"-include-pch", "test.h.pch"}; - EXPECT_THAT(buildCompilerInvocation(TU.inputs(), Diags) + EXPECT_THAT(buildCompilerInvocation(TU.inputs(FS), Diags) ->getPreprocessorOpts() .ImplicitPCHInclude, IsEmpty()); // Transparent include translation TU.ExtraArgs = {"-include", "test.h"}; - EXPECT_THAT(buildCompilerInvocation(TU.inputs(), Diags) + EXPECT_THAT(buildCompilerInvocation(TU.inputs(FS), Diags) ->getPreprocessorOpts() .ImplicitPCHInclude, IsEmpty()); @@ -40,11 +41,11 @@ TEST(BuildCompilerInvocation, DropsPCH) { TU.AdditionalFiles["test.pch"] = ""; TU.ExtraArgs = {"--driver-mode=cl"}; TU.ExtraArgs.push_back("/Yutest.h"); - EXPECT_THAT(buildCompilerInvocation(TU.inputs(), Diags) + EXPECT_THAT(buildCompilerInvocation(TU.inputs(FS), Diags) ->getPreprocessorOpts() .ImplicitPCHInclude, IsEmpty()); - EXPECT_THAT(buildCompilerInvocation(TU.inputs(), Diags) + EXPECT_THAT(buildCompilerInvocation(TU.inputs(FS), Diags) ->getPreprocessorOpts() .PCHThroughHeader, IsEmpty()); diff --git a/clang-tools-extra/clangd/unittests/FileIndexTests.cpp b/clang-tools-extra/clangd/unittests/FileIndexTests.cpp index 371388ef8e22..bd8a089df238 100644 --- a/clang-tools-extra/clangd/unittests/FileIndexTests.cpp +++ b/clang-tools-extra/clangd/unittests/FileIndexTests.cpp @@ -272,14 +272,14 @@ TEST(FileIndexTest, RebuildWithPreamble) { PI.CompileCommand.Filename = FooCpp; PI.CompileCommand.CommandLine = {"clang", "-xc++", FooCpp}; - llvm::StringMap<std::string> Files; - Files[FooCpp] = ""; - Files[FooH] = R"cpp( + MockFSProvider FSProvider; + FSProvider.Files[FooCpp] = ""; + FSProvider.Files[FooH] = R"cpp( namespace ns_in_header { int func_in_header(); } )cpp"; - PI.FS = buildTestFS(std::move(Files)); + PI.FSProvider = &FSProvider; PI.Contents = R"cpp( #include "foo.h" diff --git a/clang-tools-extra/clangd/unittests/HeadersTests.cpp b/clang-tools-extra/clangd/unittests/HeadersTests.cpp index 07ab835bdb67..4e81b799f19f 100644 --- a/clang-tools-extra/clangd/unittests/HeadersTests.cpp +++ b/clang-tools-extra/clangd/unittests/HeadersTests.cpp @@ -44,20 +44,20 @@ class HeadersTest : public ::testing::Test { std::unique_ptr<CompilerInstance> setupClang() { auto Cmd = CDB.getCompileCommand(MainFile); assert(static_cast<bool>(Cmd)); - auto VFS = FS.getFileSystem(); - VFS->setCurrentWorkingDirectory(Cmd->Directory); ParseInputs PI; PI.CompileCommand = *Cmd; - PI.FS = VFS; + PI.FSProvider = &FS; auto CI = buildCompilerInvocation(PI, IgnoreDiags); EXPECT_TRUE(static_cast<bool>(CI)); // The diagnostic options must be set before creating a CompilerInstance. CI->getDiagnosticOpts().IgnoreWarnings = true; + auto VFS = FS.getFileSystem(); + VFS->setCurrentWorkingDirectory(Cmd->Directory); auto Clang = prepareCompilerInstance( std::move(CI), /*Preamble=*/nullptr, - llvm::MemoryBuffer::getMemBuffer(FS.Files[MainFile], MainFile), VFS, - IgnoreDiags); + llvm::MemoryBuffer::getMemBuffer(FS.Files[MainFile], MainFile), + std::move(VFS), IgnoreDiags); EXPECT_FALSE(Clang->getFrontendOpts().Inputs.empty()); return Clang; diff --git a/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp b/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp index 0ad4a9f20ccb..810bb28a7d13 100644 --- a/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp +++ b/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp @@ -249,9 +249,11 @@ TEST(ParsedASTTest, NoCrashOnTokensWithTidyCheck) { } TEST(ParsedASTTest, CanBuildInvocationWithUnknownArgs) { + MockFSProvider FSProvider; + FSProvider.Files = {{testPath("foo.cpp"), "void test() {}"}}; // Unknown flags should not prevent a build of compiler invocation. ParseInputs Inputs; - Inputs.FS = buildTestFS({{testPath("foo.cpp"), "void test() {}"}}); + Inputs.FSProvider = &FSProvider; Inputs.CompileCommand.CommandLine = {"clang", "-fsome-unknown-flag", testPath("foo.cpp")}; IgnoreDiagnostics IgnoreDiags; @@ -445,14 +447,15 @@ TEST(ParsedASTTest, ReplayPreambleForTidyCheckers) { // Make sure replay logic works with patched preambles. TU.Code = ""; StoreDiags Diags; - auto Inputs = TU.inputs(); + MockFSProvider FS; + auto Inputs = TU.inputs(FS); auto CI = buildCompilerInvocation(Inputs, Diags); auto EmptyPreamble = buildPreamble(testPath(TU.Filename), *CI, Inputs, true, nullptr); ASSERT_TRUE(EmptyPreamble); TU.Code = "#include <a.h>"; Includes.clear(); - auto PatchedAST = ParsedAST::build(testPath(TU.Filename), TU.inputs(), + auto PatchedAST = ParsedAST::build(testPath(TU.Filename), TU.inputs(FS), std::move(CI), {}, EmptyPreamble); ASSERT_TRUE(PatchedAST); // Make sure includes were seen only once. @@ -484,7 +487,8 @@ TEST(ParsedASTTest, PatchesAdditionalIncludes) { // Build preamble with no includes. TU.Code = ""; StoreDiags Diags; - auto Inputs = TU.inputs(); + MockFSProvider FS; + auto Inputs = TU.inputs(FS); auto CI = buildCompilerInvocation(Inputs, Diags); auto EmptyPreamble = buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr); @@ -493,7 +497,7 @@ TEST(ParsedASTTest, PatchesAdditionalIncludes) { // Now build an AST using empty preamble and ensure patched includes worked. TU.Code = ModifiedContents.str(); - Inputs = TU.inputs(); + Inputs = TU.inputs(FS); auto PatchedAST = ParsedAST::build(testPath("foo.cpp"), Inputs, std::move(CI), {}, EmptyPreamble); ASSERT_TRUE(PatchedAST); @@ -526,7 +530,8 @@ TEST(ParsedASTTest, PatchesDeletedIncludes) { // Build preamble with no includes. TU.Code = R"cpp(#include <foo.h>)cpp"; StoreDiags Diags; - auto Inputs = TU.inputs(); + MockFSProvider FS; + auto Inputs = TU.inputs(FS); auto CI = buildCompilerInvocation(Inputs, Diags); auto BaselinePreamble = buildPreamble(testPath("foo.cpp"), *CI, Inputs, true, nullptr); @@ -537,7 +542,7 @@ TEST(ParsedASTTest, PatchesDeletedIncludes) { // Now build an AST using additional includes and check that locations are // correctly parsed. TU.Code = ""; - Inputs = TU.inputs(); + Inputs = TU.inputs(FS); auto PatchedAST = ParsedAST::build(testPath("foo.cpp"), Inputs, std::move(CI), {}, BaselinePreamble); ASSERT_TRUE(PatchedAST); diff --git a/clang-tools-extra/clangd/unittests/PreambleTests.cpp b/clang-tools-extra/clangd/unittests/PreambleTests.cpp index 87a68ceea048..8d00fa0b2ee7 100644 --- a/clang-tools-extra/clangd/unittests/PreambleTests.cpp +++ b/clang-tools-extra/clangd/unittests/PreambleTests.cpp @@ -50,6 +50,7 @@ IncludeStructure collectPatchedIncludes(llvm::StringRef ModifiedContents, llvm::StringRef BaselineContents, llvm::StringRef MainFileName = "main.cpp") { + MockFSProvider FS; auto TU = TestTU::withCode(BaselineContents); TU.Filename = MainFileName.str(); // ms-compatibility changes meaning of #import, make sure it is turned off. @@ -57,7 +58,7 @@ collectPatchedIncludes(llvm::StringRef ModifiedContents, auto BaselinePreamble = TU.preamble(); // Create the patch. TU.Code = ModifiedContents.str(); - auto PI = TU.inputs(); + auto PI = TU.inputs(FS); auto PP = PreamblePatch::create(testPath(TU.Filename), PI, *BaselinePreamble); // Collect patch contents. IgnoreDiagnostics Diags; @@ -73,7 +74,7 @@ collectPatchedIncludes(llvm::StringRef ModifiedContents, prepareCompilerInstance(std::move(CI), &BaselinePreamble->Preamble, llvm::MemoryBuffer::getMemBufferCopy( ModifiedContents.slice(0, Bounds.Size).str()), - PI.FS, Diags); + PI.FSProvider->getFileSystem(), Diags); PreprocessOnlyAction Action; if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) { ADD_FAILURE() << "failed begin source file"; @@ -164,6 +165,7 @@ TEST(PreamblePatchTest, MainFileIsEscaped) { } TEST(PreamblePatchTest, PatchesPreambleIncludes) { + MockFSProvider FS; IgnoreDiagnostics Diags; auto TU = TestTU::withCode(R"cpp( #include "a.h" @@ -172,7 +174,7 @@ TEST(PreamblePatchTest, PatchesPreambleIncludes) { TU.AdditionalFiles["a.h"] = "#include \"b.h\""; TU.AdditionalFiles["b.h"] = ""; TU.AdditionalFiles["c.h"] = ""; - auto PI = TU.inputs(); + auto PI = TU.inputs(FS); auto BaselinePreamble = buildPreamble( TU.Filename, *buildCompilerInvocation(PI, Diags), PI, true, nullptr); // We drop c.h from modified and add a new header. Since the latter is patched @@ -181,7 +183,7 @@ TEST(PreamblePatchTest, PatchesPreambleIncludes) { #include "a.h" #include "b.h" )cpp"; - auto PP = PreamblePatch::create(testPath(TU.Filename), TU.inputs(), + auto PP = PreamblePatch::create(testPath(TU.Filename), TU.inputs(FS), *BaselinePreamble); // Only a.h should exists in the preamble, as c.h has been dropped and b.h was // newly introduced. @@ -199,14 +201,15 @@ llvm::Optional<ParsedAST> createPatchedAST(llvm::StringRef Baseline, } IgnoreDiagnostics Diags; + MockFSProvider FS; auto TU = TestTU::withCode(Modified); - auto CI = buildCompilerInvocation(TU.inputs(), Diags); + auto CI = buildCompilerInvocation(TU.inputs(FS), Diags); if (!CI) { ADD_FAILURE() << "Failed to build compiler invocation"; return llvm::None; } - return ParsedAST::build(testPath(TU.Filename), TU.inputs(), std::move(CI), {}, - BaselinePreamble); + return ParsedAST::build(testPath(TU.Filename), TU.inputs(FS), std::move(CI), + {}, BaselinePreamble); } std::string getPreamblePatch(llvm::StringRef Baseline, @@ -216,8 +219,9 @@ std::string getPreamblePatch(llvm::StringRef Baseline, ADD_FAILURE() << "Failed to build baseline preamble"; return ""; } + MockFSProvider FS; auto TU = TestTU::withCode(Modified); - return PreamblePatch::create(testPath("main.cpp"), TU.inputs(), + return PreamblePatch::create(testPath("main.cpp"), TU.inputs(FS), *BaselinePreamble) .text() .str(); diff --git a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp index 8c8520aae620..ee54a2f71e10 100644 --- a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp +++ b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp @@ -16,6 +16,7 @@ #include "TestFS.h" #include "support/Cancellation.h" #include "support/Context.h" +#include "support/FSProvider.h" #include "support/Path.h" #include "support/TestTracer.h" #include "support/Threading.h" @@ -73,7 +74,7 @@ class TUSchedulerTests : public ::testing::Test { ParseInputs getInputs(PathRef File, std::string Contents) { ParseInputs Inputs; Inputs.CompileCommand = *CDB.getCompileCommand(File); - Inputs.FS = buildTestFS(Files, Timestamps); + Inputs.FSProvider = &FSProvider; Inputs.Contents = std::move(Contents); Inputs.Opts = ParseOptions(); return Inputs; @@ -149,8 +150,7 @@ class TUSchedulerTests : public ::testing::Test { std::move(CB)); } - llvm::StringMap<std::string> Files; - llvm::StringMap<time_t> Timestamps; + MockFSProvider FSProvider; MockCompilationDatabase CDB; }; @@ -161,10 +161,10 @@ TEST_F(TUSchedulerTests, MissingFiles) { TUScheduler S(CDB, optsForTest()); auto Added = testPath("added.cpp"); - Files[Added] = "x"; + FSProvider.Files[Added] = "x"; auto Missing = testPath("missing.cpp"); - Files[Missing] = ""; + FSProvider.Files[Missing] = ""; S.update(Added, getInputs(Added, "x"), WantDiagnostics::No); @@ -425,7 +425,7 @@ TEST_F(TUSchedulerTests, ManyUpdates) { for (int I = 0; I < FilesCount; ++I) { std::string Name = "foo" + std::to_string(I) + ".cpp"; Files.push_back(testPath(Name)); - this->Files[Files.back()] = ""; + this->FSProvider.Files[Files.back()] = ""; } StringRef Contents1 = R"cpp(int a;)cpp"; @@ -476,7 +476,6 @@ TEST_F(TUSchedulerTests, ManyUpdates) { EXPECT_THAT(Context::current().get(NonceKey), Pointee(Nonce)); ASSERT_TRUE((bool)AST); - EXPECT_EQ(AST->Inputs.FS, Inputs.FS); EXPECT_EQ(AST->Inputs.Contents, Inputs.Contents); EXPECT_EQ(AST->Inputs.Version, Inputs.Version); EXPECT_EQ(AST->AST.version(), Inputs.Version); @@ -617,8 +616,8 @@ TEST_F(TUSchedulerTests, EmptyPreamble) { auto Foo = testPath("foo.cpp"); auto Header = testPath("foo.h"); - Files[Header] = "void foo()"; - Timestamps[Header] = time_t(0); + FSProvider.Files[Header] = "void foo()"; + FSProvider.Timestamps[Header] = time_t(0); auto WithPreamble = R"cpp( #include "foo.h" int main() {} @@ -686,8 +685,8 @@ TEST_F(TUSchedulerTests, NoopOnEmptyChanges) { auto Source = testPath("foo.cpp"); auto Header = testPath("foo.h"); - Files[Header] = "int a;"; - Timestamps[Header] = time_t(0); + FSProvider.Files[Header] = "int a;"; + FSProvider.Timestamps[Header] = time_t(0); std::string SourceContents = R"cpp( #include "foo.h" @@ -715,7 +714,7 @@ TEST_F(TUSchedulerTests, NoopOnEmptyChanges) { ASSERT_EQ(S.fileStats().lookup(Source).PreambleBuilds, 1u); // Update to a header should cause a rebuild, though. - Timestamps[Header] = time_t(1); + FSProvider.Timestamps[Header] = time_t(1); ASSERT_TRUE(DoUpdate(SourceContents)); ASSERT_FALSE(DoUpdate(SourceContents)); ASSERT_EQ(S.fileStats().lookup(Source).ASTBuilds, 2u); @@ -761,11 +760,12 @@ TEST_F(TUSchedulerTests, ForceRebuild) { Field(&Diag::Message, "use of undeclared identifier 'a'"))); }); + S.blockUntilIdle(timeoutSeconds(10)); // Add the header file. We need to recreate the inputs since we changed a // file from underneath the test FS. - Files[Header] = "int a;"; - Timestamps[Header] = time_t(1); + FSProvider.Files[Header] = "int a;"; + FSProvider.Timestamps[Header] = time_t(1); Inputs = getInputs(Source, SourceContents); // The addition of the missing header file shouldn't trigger a rebuild since diff --git a/clang-tools-extra/clangd/unittests/TestFS.h b/clang-tools-extra/clangd/unittests/TestFS.h index 7dde78d9c157..0472380f7a58 100644 --- a/clang-tools-extra/clangd/unittests/TestFS.h +++ b/clang-tools-extra/clangd/unittests/TestFS.h @@ -31,11 +31,12 @@ buildTestFS(llvm::StringMap<std::string> const &Files, class MockFSProvider : public FileSystemProvider { public: IntrusiveRefCntPtr<llvm::vfs::FileSystem> getFileSystem() const override { - return buildTestFS(Files); + return buildTestFS(Files, Timestamps); } // If relative paths are used, they are resolved with testPath(). llvm::StringMap<std::string> Files; + llvm::StringMap<time_t> Timestamps; }; // A Compilation database that returns a fixed set of compile flags. diff --git a/clang-tools-extra/clangd/unittests/TestTU.cpp b/clang-tools-extra/clangd/unittests/TestTU.cpp index b4781425943c..9c812298742e 100644 --- a/clang-tools-extra/clangd/unittests/TestTU.cpp +++ b/clang-tools-extra/clangd/unittests/TestTU.cpp @@ -20,7 +20,7 @@ namespace clang { namespace clangd { -ParseInputs TestTU::inputs() const { +ParseInputs TestTU::inputs(MockFSProvider &FSProvider) const { std::string FullFilename = testPath(Filename), FullHeaderName = testPath(HeaderFilename), ImportThunk = testPath("import_thunk.h"); @@ -29,10 +29,10 @@ ParseInputs TestTU::inputs() const { // guard without messing up offsets). In this case, use an intermediate file. std::string ThunkContents = "#import \"" + FullHeaderName + "\"\n"; - llvm::StringMap<std::string> Files(AdditionalFiles); - Files[FullFilename] = Code; - Files[FullHeaderName] = HeaderCode; - Files[ImportThunk] = ThunkContents; + FSProvider.Files = AdditionalFiles; + FSProvider.Files[FullFilename] = Code; + FSProvider.Files[FullHeaderName] = HeaderCode; + FSProvider.Files[ImportThunk] = ThunkContents; ParseInputs Inputs; auto &Argv = Inputs.CompileCommand.CommandLine; @@ -54,7 +54,7 @@ ParseInputs TestTU::inputs() const { Inputs.CompileCommand.Filename = FullFilename; Inputs.CompileCommand.Directory = testRoot(); Inputs.Contents = Code; - Inputs.FS = buildTestFS(Files); + Inputs.FSProvider = &FSProvider; Inputs.Opts = ParseOptions(); Inputs.Opts.BuildRecoveryAST = true; Inputs.Opts.PreserveRecoveryASTType = true; @@ -67,7 +67,8 @@ ParseInputs TestTU::inputs() const { } std::shared_ptr<const PreambleData> TestTU::preamble() const { - auto Inputs = inputs(); + MockFSProvider FSProvider; + auto Inputs = inputs(FSProvider); IgnoreDiagnostics Diags; auto CI = buildCompilerInvocation(Inputs, Diags); assert(CI && "Failed to build compilation invocation."); @@ -77,7 +78,8 @@ std::shared_ptr<const PreambleData> TestTU::preamble() const { } ParsedAST TestTU::build() const { - auto Inputs = inputs(); + MockFSProvider FSProvider; + auto Inputs = inputs(FSProvider); StoreDiags Diags; auto CI = buildCompilerInvocation(Inputs, Diags); assert(CI && "Failed to build compilation invocation."); diff --git a/clang-tools-extra/clangd/unittests/TestTU.h b/clang-tools-extra/clangd/unittests/TestTU.h index 57017f4a9175..05629a891bef 100644 --- a/clang-tools-extra/clangd/unittests/TestTU.h +++ b/clang-tools-extra/clangd/unittests/TestTU.h @@ -19,6 +19,7 @@ #include "Compiler.h" #include "ParsedAST.h" +#include "TestFS.h" #include "index/Index.h" #include "support/Path.h" #include "llvm/ADT/StringMap.h" @@ -69,7 +70,7 @@ struct TestTU { // Suppress this behavior by adding an 'error-ok' comment to the code. ParsedAST build() const; std::shared_ptr<const PreambleData> preamble() const; - ParseInputs inputs() const; + ParseInputs inputs(MockFSProvider &FSProvider) const; SymbolSlab headerSymbols() const; RefSlab headerRefs() const; std::unique_ptr<SymbolIndex> index() const; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits