Index: clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp =================================================================== --- clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp +++ clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp @@ -43,8 +43,8 @@ LSPDiagnosticsConsumer(ClangdLSPServer &Server) : Server(Server) {} virtual void onDiagnosticsReady(PathRef File, - std::vector Diagnostics) { - Server.consumeDiagnostics(File, Diagnostics); + Tagged> Diagnostics) { + Server.consumeDiagnostics(File, Diagnostics.Value); } private: @@ -181,7 +181,7 @@ auto Items = LangServer.Server.codeComplete( Params.textDocument.uri.file, - Position{Params.position.line, Params.position.character}); + Position{Params.position.line, Params.position.character}).Value; std::string Completions; for (const auto &Item : Items) { Index: clang-tools-extra/trunk/clangd/ClangdServer.h =================================================================== --- clang-tools-extra/trunk/clangd/ClangdServer.h +++ clang-tools-extra/trunk/clangd/ClangdServer.h @@ -28,6 +28,7 @@ #include #include #include +#include #include namespace clang { @@ -41,24 +42,54 @@ /// Turn an offset in Code into a [line, column] pair. Position offsetToPosition(StringRef Code, size_t Offset); +/// A tag supplied by the FileSytemProvider. +typedef int VFSTag; + +/// A value of an arbitrary type and VFSTag that was supplied by the +/// FileSystemProvider when this value was computed. +template class Tagged { +public: + template + Tagged(U &&Value, VFSTag Tag) : Value(std::forward(Value)), Tag(Tag) {} + + template + Tagged(const Tagged &Other) : Value(Other.Value), Tag(Other.Tag) {} + + template + Tagged(Tagged &&Other) : Value(std::move(Other.Value)), Tag(Other.Tag) {} + + T Value; + VFSTag Tag; +}; + +template +Tagged::type> make_tagged(T &&Value, VFSTag Tag) { + return Tagged(std::forward(Value), Tag); +} + class DiagnosticsConsumer { public: virtual ~DiagnosticsConsumer() = default; /// Called by ClangdServer when \p Diagnostics for \p File are ready. - virtual void onDiagnosticsReady(PathRef File, - std::vector Diagnostics) = 0; + virtual void + onDiagnosticsReady(PathRef File, + Tagged> Diagnostics) = 0; }; class FileSystemProvider { public: virtual ~FileSystemProvider() = default; - virtual IntrusiveRefCntPtr getFileSystem() = 0; + /// \return A filesystem that will be used for all file accesses in clangd. + /// A Tag returned by this method will be propagated to all results of clangd + /// that will use this filesystem. + virtual Tagged> getTaggedFileSystem() = 0; }; class RealFileSystemProvider : public FileSystemProvider { public: - IntrusiveRefCntPtr getFileSystem() override; + /// \return getRealFileSystem() tagged with default tag, i.e. VFSTag() + Tagged> getTaggedFileSystem() override; }; class ClangdServer; @@ -120,7 +151,7 @@ void forceReparse(PathRef File); /// Run code completion for \p File at \p Pos. - std::vector codeComplete(PathRef File, Position Pos); + Tagged> codeComplete(PathRef File, Position Pos); /// Run formatting for \p Rng inside \p File. std::vector formatRange(PathRef File, Range Rng); Index: clang-tools-extra/trunk/clangd/ClangdServer.cpp =================================================================== --- clang-tools-extra/trunk/clangd/ClangdServer.cpp +++ clang-tools-extra/trunk/clangd/ClangdServer.cpp @@ -58,8 +58,9 @@ return {Lines, Cols}; } -IntrusiveRefCntPtr RealFileSystemProvider::getFileSystem() { - return vfs::getRealFileSystem(); +Tagged> +RealFileSystemProvider::getTaggedFileSystem() { + return make_tagged(vfs::getRealFileSystem(), VFSTag()); } ClangdScheduler::ClangdScheduler(bool RunSynchronously) @@ -156,11 +157,13 @@ assert(FileContents.Draft && "No contents inside a file that was scheduled for reparse"); - Units.runOnUnit(FileStr, *FileContents.Draft, *CDB, PCHs, - FSProvider->getFileSystem(), [&](ClangdUnit const &Unit) { - DiagConsumer->onDiagnosticsReady( - FileStr, Unit.getLocalDiagnostics()); - }); + auto TaggedFS = FSProvider->getTaggedFileSystem(); + Units.runOnUnit( + FileStr, *FileContents.Draft, *CDB, PCHs, TaggedFS.Value, + [&](ClangdUnit const &Unit) { + DiagConsumer->onDiagnosticsReady( + FileStr, make_tagged(Unit.getLocalDiagnostics(), TaggedFS.Tag)); + }); }); } @@ -181,18 +184,18 @@ addDocument(File, getDocument(File)); } -std::vector ClangdServer::codeComplete(PathRef File, - Position Pos) { +Tagged> ClangdServer::codeComplete(PathRef File, + Position Pos) { auto FileContents = DraftMgr.getDraft(File); assert(FileContents.Draft && "codeComplete is called for non-added document"); std::vector Result; - auto VFS = FSProvider->getFileSystem(); + auto TaggedFS = FSProvider->getTaggedFileSystem(); Units.runOnUnitWithoutReparse( - File, *FileContents.Draft, *CDB, PCHs, VFS, [&](ClangdUnit &Unit) { - Result = Unit.codeComplete(*FileContents.Draft, Pos, VFS); + File, *FileContents.Draft, *CDB, PCHs, TaggedFS.Value, [&](ClangdUnit &Unit) { + Result = Unit.codeComplete(*FileContents.Draft, Pos, TaggedFS.Value); }); - return Result; + return make_tagged(std::move(Result), TaggedFS.Tag); } std::vector ClangdServer::formatRange(PathRef File, Index: clang-tools-extra/trunk/unittests/clangd/ClangdTests.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clangd/ClangdTests.cpp +++ clang-tools-extra/trunk/unittests/clangd/ClangdTests.cpp @@ -133,9 +133,9 @@ class ErrorCheckingDiagConsumer : public DiagnosticsConsumer { public: void onDiagnosticsReady(PathRef File, - std::vector Diagnostics) override { + Tagged> Diagnostics) override { bool HadError = false; - for (const auto &DiagAndFixIts : Diagnostics) { + for (const auto &DiagAndFixIts : Diagnostics.Value) { // FIXME: severities returned by clangd should have a descriptive // diagnostic severity enum const int ErrorSeverity = 1; @@ -144,6 +144,7 @@ std::lock_guard Lock(Mutex); HadErrorInLastDiags = HadError; + LastVFSTag = Diagnostics.Tag; } bool hadErrorInLastDiags() { @@ -151,9 +152,14 @@ return HadErrorInLastDiags; } + VFSTag lastVFSTag() { + return LastVFSTag; + } + private: std::mutex Mutex; bool HadErrorInLastDiags = false; + VFSTag LastVFSTag = VFSTag(); }; class MockCompilationDatabase : public GlobalCompilationDatabase { @@ -166,7 +172,7 @@ class MockFSProvider : public FileSystemProvider { public: - IntrusiveRefCntPtr getFileSystem() override { + Tagged> getTaggedFileSystem() override { IntrusiveRefCntPtr MemFS( new vfs::InMemoryFileSystem); for (auto &FileAndContents : Files) @@ -177,10 +183,11 @@ auto OverlayFS = IntrusiveRefCntPtr( new vfs::OverlayFileSystem(vfs::getTempOnlyFS())); OverlayFS->pushOverlay(std::move(MemFS)); - return OverlayFS; + return make_tagged(OverlayFS, Tag); } llvm::StringMap Files; + VFSTag Tag = VFSTag(); }; /// Replaces all patterns of the form 0x123abc with spaces @@ -366,5 +373,30 @@ EXPECT_NE(DumpParse1, DumpParseDifferent); } +TEST_F(ClangdVFSTest, CheckVersions) { + MockFSProvider *FS; + ErrorCheckingDiagConsumer *DiagConsumer; + + ClangdServer Server( + llvm::make_unique(), + getAndMove(llvm::make_unique(), DiagConsumer), + getAndMove(llvm::make_unique(), FS), + /*RunSynchronously=*/true); + + auto FooCpp = getVirtualTestFilePath("foo.cpp"); + const auto SourceContents = "int a;"; + FS->Files[FooCpp] = SourceContents; + FS->Tag = 123; + + Server.addDocument(FooCpp, SourceContents); + EXPECT_EQ(DiagConsumer->lastVFSTag(), FS->Tag); + EXPECT_EQ(Server.codeComplete(FooCpp, Position{0, 0}).Tag, FS->Tag); + + FS->Tag = 321; + Server.addDocument(FooCpp, SourceContents); + EXPECT_EQ(DiagConsumer->lastVFSTag(), FS->Tag); + EXPECT_EQ(Server.codeComplete(FooCpp, Position{0, 0}).Tag, FS->Tag); +} + } // namespace clangd } // namespace clang