From aaa8b44d19918ea1764339224cec68c27445aa8e Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Tue, 13 Oct 2020 02:09:45 -0400 Subject: [PATCH] [clangd] Add a TestWorkspace utility TestWorkspace allows easily writing tests involving multiple files that can have inclusion relationships between them. BackgroundIndexTest.RelationsMultiFile is refactored to use TestWorkspace, and moved to FileIndexTest as it no longer depends on BackgroundIndex. Differential Revision: https://reviews.llvm.org/D89297 --- .../clangd/unittests/BackgroundIndexTests.cpp | 43 -------------- .../clangd/unittests/CMakeLists.txt | 1 + .../clangd/unittests/FileIndexTests.cpp | 28 +++++++++ clang-tools-extra/clangd/unittests/TestTU.cpp | 6 +- clang-tools-extra/clangd/unittests/TestTU.h | 3 +- .../clangd/unittests/TestWorkspace.cpp | 49 +++++++++++++++ .../clangd/unittests/TestWorkspace.h | 59 +++++++++++++++++++ .../clangd/unittests/BUILD.gn | 1 + 8 files changed, 143 insertions(+), 47 deletions(-) create mode 100644 clang-tools-extra/clangd/unittests/TestWorkspace.cpp create mode 100644 clang-tools-extra/clangd/unittests/TestWorkspace.h diff --git a/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp b/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp index cc0ca6f54a7f..b25d3fde0002 100644 --- a/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp +++ b/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp @@ -230,49 +230,6 @@ TEST_F(BackgroundIndexTest, IndexTwoFiles) { FileURI("unittest:///root/B.cc")})); } -TEST_F(BackgroundIndexTest, RelationsMultiFile) { - MockFS FS; - FS.Files[testPath("root/Base.h")] = "class Base {};"; - FS.Files[testPath("root/A.cc")] = R"cpp( - #include "Base.h" - class A : public Base {}; - )cpp"; - FS.Files[testPath("root/B.cc")] = R"cpp( - #include "Base.h" - class B : public Base {}; - )cpp"; - - llvm::StringMap Storage; - size_t CacheHits = 0; - MemoryShardStorage MSS(Storage, CacheHits); - OverlayCDB CDB(/*Base=*/nullptr); - BackgroundIndex Index(FS, CDB, [&](llvm::StringRef) { return &MSS; }, - /*Opts=*/{}); - - tooling::CompileCommand Cmd; - Cmd.Filename = testPath("root/A.cc"); - Cmd.Directory = testPath("root"); - Cmd.CommandLine = {"clang++", Cmd.Filename}; - CDB.setCompileCommand(testPath("root/A.cc"), Cmd); - ASSERT_TRUE(Index.blockUntilIdleForTest()); - - Cmd.Filename = testPath("root/B.cc"); - Cmd.CommandLine = {"clang++", Cmd.Filename}; - CDB.setCompileCommand(testPath("root/B.cc"), Cmd); - ASSERT_TRUE(Index.blockUntilIdleForTest()); - - auto HeaderShard = MSS.loadShard(testPath("root/Base.h")); - EXPECT_NE(HeaderShard, nullptr); - SymbolID Base = findSymbol(*HeaderShard->Symbols, "Base").ID; - - RelationsRequest Req; - Req.Subjects.insert(Base); - Req.Predicate = RelationKind::BaseOf; - uint32_t Results = 0; - Index.relations(Req, [&](const SymbolID &, const Symbol &) { ++Results; }); - EXPECT_EQ(Results, 2u); -} - TEST_F(BackgroundIndexTest, MainFileRefs) { MockFS FS; FS.Files[testPath("root/A.h")] = R"cpp( diff --git a/clang-tools-extra/clangd/unittests/CMakeLists.txt b/clang-tools-extra/clangd/unittests/CMakeLists.txt index de8eaca6059f..bf964484bc6c 100644 --- a/clang-tools-extra/clangd/unittests/CMakeLists.txt +++ b/clang-tools-extra/clangd/unittests/CMakeLists.txt @@ -88,6 +88,7 @@ add_unittest(ClangdUnitTests ClangdTests TestFS.cpp TestIndex.cpp TestTU.cpp + TestWorkspace.cpp TypeHierarchyTests.cpp TweakTests.cpp TweakTesting.cpp diff --git a/clang-tools-extra/clangd/unittests/FileIndexTests.cpp b/clang-tools-extra/clangd/unittests/FileIndexTests.cpp index 4abe0bf5e5dc..80c4798fc65b 100644 --- a/clang-tools-extra/clangd/unittests/FileIndexTests.cpp +++ b/clang-tools-extra/clangd/unittests/FileIndexTests.cpp @@ -14,6 +14,7 @@ #include "SyncAPI.h" #include "TestFS.h" #include "TestTU.h" +#include "TestWorkspace.h" #include "URI.h" #include "index/CanonicalIncludes.h" #include "index/FileIndex.h" @@ -426,6 +427,33 @@ TEST(FileIndexTest, Relations) { EXPECT_EQ(Results, 1u); } +TEST(FileIndexTest, RelationsMultiFile) { + TestWorkspace Workspace; + Workspace.addSource("Base.h", "class Base {};"); + Workspace.addMainFile("A.cpp", R"cpp( + #include "Base.h" + class A : public Base {}; + )cpp"); + Workspace.addMainFile("B.cpp", R"cpp( + #include "Base.h" + class B : public Base {}; + )cpp"); + + auto Index = Workspace.index(); + FuzzyFindRequest FFReq; + FFReq.Query = "Base"; + FFReq.AnyScope = true; + SymbolID Base; + Index->fuzzyFind(FFReq, [&](const Symbol &S) { Base = S.ID; }); + + RelationsRequest Req; + Req.Subjects.insert(Base); + Req.Predicate = RelationKind::BaseOf; + uint32_t Results = 0; + Index->relations(Req, [&](const SymbolID &, const Symbol &) { ++Results; }); + EXPECT_EQ(Results, 2u); +} + TEST(FileIndexTest, ReferencesInMainFileWithPreamble) { TestTU TU; TU.HeaderCode = "class Foo{};"; diff --git a/clang-tools-extra/clangd/unittests/TestTU.cpp b/clang-tools-extra/clangd/unittests/TestTU.cpp index 81b6b43da94b..d0f011ef5649 100644 --- a/clang-tools-extra/clangd/unittests/TestTU.cpp +++ b/clang-tools-extra/clangd/unittests/TestTU.cpp @@ -80,7 +80,8 @@ void deleteModuleCache(const std::string ModuleCachePath) { } } -std::shared_ptr TestTU::preamble() const { +std::shared_ptr +TestTU::preamble(PreambleParsedCallback PreambleCallback) const { MockFS FS; auto Inputs = inputs(FS); IgnoreDiagnostics Diags; @@ -91,8 +92,7 @@ std::shared_ptr TestTU::preamble() const { auto ModuleCacheDeleter = llvm::make_scope_exit( std::bind(deleteModuleCache, CI->getHeaderSearchOpts().ModuleCachePath)); return clang::clangd::buildPreamble(testPath(Filename), *CI, Inputs, - /*StoreInMemory=*/true, - /*PreambleCallback=*/nullptr); + /*StoreInMemory=*/true, PreambleCallback); } ParsedAST TestTU::build() const { diff --git a/clang-tools-extra/clangd/unittests/TestTU.h b/clang-tools-extra/clangd/unittests/TestTU.h index dd0cecc406ac..f383e693408c 100644 --- a/clang-tools-extra/clangd/unittests/TestTU.h +++ b/clang-tools-extra/clangd/unittests/TestTU.h @@ -79,7 +79,8 @@ struct TestTU { // By default, build() will report Error diagnostics as GTest errors. // Suppress this behavior by adding an 'error-ok' comment to the code. ParsedAST build() const; - std::shared_ptr preamble() const; + std::shared_ptr + preamble(PreambleParsedCallback PreambleCallback = nullptr) const; ParseInputs inputs(MockFS &FS) const; SymbolSlab headerSymbols() const; RefSlab headerRefs() const; diff --git a/clang-tools-extra/clangd/unittests/TestWorkspace.cpp b/clang-tools-extra/clangd/unittests/TestWorkspace.cpp new file mode 100644 index 000000000000..52cf45f5be24 --- /dev/null +++ b/clang-tools-extra/clangd/unittests/TestWorkspace.cpp @@ -0,0 +1,49 @@ +//===--- TestWorkspace.cpp - Utility for writing multi-file tests -*- C++-*===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "TestWorkspace.h" + +namespace clang { +namespace clangd { + +std::unique_ptr TestWorkspace::index() { + auto Index = std::make_unique(); + for (const auto &Input : Inputs) { + if (!Input.second.IsMainFile) + continue; + TU.Code = Input.second.Code; + TU.Filename = Input.first().str(); + TU.preamble([&](ASTContext &Ctx, std::shared_ptr PP, + const CanonicalIncludes &CanonIncludes) { + Index->updatePreamble(testPath(Input.first()), "null", Ctx, PP, + CanonIncludes); + }); + ParsedAST MainAST = TU.build(); + Index->updateMain(testPath(Input.first()), MainAST); + } + return Index; +} + +Optional TestWorkspace::openFile(llvm::StringRef Filename) { + auto It = Inputs.find(Filename); + if (It == Inputs.end()) { + ADD_FAILURE() << "Accessing non-existing file: " << Filename; + return llvm::None; + } + TU.Code = It->second.Code; + TU.Filename = It->first().str(); + return TU.build(); +} + +void TestWorkspace::addInput(llvm::StringRef Filename, + const SourceFile &Input) { + Inputs.insert(std::make_pair(Filename, Input)); + TU.AdditionalFiles.insert(std::make_pair(Filename, Input.Code)); +} +} // namespace clangd +} // namespace clang \ No newline at end of file diff --git a/clang-tools-extra/clangd/unittests/TestWorkspace.h b/clang-tools-extra/clangd/unittests/TestWorkspace.h new file mode 100644 index 000000000000..eb5112f198dd --- /dev/null +++ b/clang-tools-extra/clangd/unittests/TestWorkspace.h @@ -0,0 +1,59 @@ +//===--- TestWorkspace.h - Utility for writing multi-file tests --*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// TestWorkspace builds on TestTU to provide a way to write tests involving +// several related files with inclusion relationships between them. +// +// The tests can exercise both index and AST based operations. +// +//===---------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_TESTWORKSPACE_H +#define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_TESTWORKSPACE_H + +#include "TestFS.h" +#include "TestTU.h" +#include "index/FileIndex.h" +#include "index/Index.h" +#include "llvm/ADT/StringRef.h" +#include +#include + +namespace clang { +namespace clangd { + +class TestWorkspace { +public: + // The difference between addSource() and addMainFile() is that only main + // files will be indexed. + void addSource(llvm::StringRef Filename, llvm::StringRef Code) { + addInput(Filename.str(), {Code.str(), /*IsMainFile=*/false}); + } + void addMainFile(llvm::StringRef Filename, llvm::StringRef Code) { + addInput(Filename.str(), {Code.str(), /*IsMainFile=*/true}); + } + + std::unique_ptr index(); + + Optional openFile(llvm::StringRef Filename); + +private: + struct SourceFile { + std::string Code; + bool IsMainFile = false; + }; + llvm::StringMap Inputs; + TestTU TU; + + void addInput(llvm::StringRef Filename, const SourceFile &Input); +}; + +} // namespace clangd +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_TESTWORKSPACE_H diff --git a/llvm/utils/gn/secondary/clang-tools-extra/clangd/unittests/BUILD.gn b/llvm/utils/gn/secondary/clang-tools-extra/clangd/unittests/BUILD.gn index 8872b36e4a89..4e8ac3144512 100644 --- a/llvm/utils/gn/secondary/clang-tools-extra/clangd/unittests/BUILD.gn +++ b/llvm/utils/gn/secondary/clang-tools-extra/clangd/unittests/BUILD.gn @@ -96,6 +96,7 @@ unittest("ClangdTests") { "TestFS.cpp", "TestIndex.cpp", "TestTU.cpp", + "TestWorkspace.cpp", "TweakTesting.cpp", "TweakTests.cpp", "TypeHierarchyTests.cpp",