diff options
author | Jordan Rupprecht <rupprecht@google.com> | 2019-05-14 21:58:59 +0000 |
---|---|---|
committer | Jordan Rupprecht <rupprecht@google.com> | 2019-05-14 21:58:59 +0000 |
commit | 46054fed6aeeabea27b9ba4a3ef81ab5ff9b9645 (patch) | |
tree | d12279f80b5729d0324f066002c838baa736fbd2 /clangd/unittests/IndexActionTests.cpp | |
parent | 5026a9a16d10a2edf09be54c7225f49b5789c69e (diff) | |
parent | 0eb1ac6d1df856f065717226ef34d00679a211fe (diff) |
Creating branches/google/stable and tags/google/stable/2019-05-14 from r360103upstream/stable
git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/branches/google/stable@360714 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'clangd/unittests/IndexActionTests.cpp')
-rw-r--r-- | clangd/unittests/IndexActionTests.cpp | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/clangd/unittests/IndexActionTests.cpp b/clangd/unittests/IndexActionTests.cpp new file mode 100644 index 00000000..6adc8cc1 --- /dev/null +++ b/clangd/unittests/IndexActionTests.cpp @@ -0,0 +1,253 @@ +//===------ IndexActionTests.cpp -------------------------------*- 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 "TestFS.h" +#include "index/IndexAction.h" +#include "clang/Tooling/Tooling.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace clang { +namespace clangd { +namespace { + +using ::testing::AllOf; +using ::testing::ElementsAre; +using ::testing::Not; +using ::testing::Pair; +using ::testing::UnorderedElementsAre; +using ::testing::UnorderedPointwise; + +std::string toUri(llvm::StringRef Path) { return URI::create(Path).toString(); } + +MATCHER(IsTU, "") { return arg.IsTU; } + +MATCHER_P(HasDigest, Digest, "") { return arg.Digest == Digest; } + +MATCHER_P(HasName, Name, "") { return arg.Name == Name; } + +MATCHER(HasSameURI, "") { + llvm::StringRef URI = ::testing::get<0>(arg); + const std::string &Path = ::testing::get<1>(arg); + return toUri(Path) == URI; +} + +::testing::Matcher<const IncludeGraphNode &> +IncludesAre(const std::vector<std::string> &Includes) { + return ::testing::Field(&IncludeGraphNode::DirectIncludes, + UnorderedPointwise(HasSameURI(), Includes)); +} + +void checkNodesAreInitialized(const IndexFileIn &IndexFile, + const std::vector<std::string> &Paths) { + ASSERT_TRUE(IndexFile.Sources); + EXPECT_THAT(Paths.size(), IndexFile.Sources->size()); + for (llvm::StringRef Path : Paths) { + auto URI = toUri(Path); + const auto &Node = IndexFile.Sources->lookup(URI); + // Uninitialized nodes will have an empty URI. + EXPECT_EQ(Node.URI.data(), IndexFile.Sources->find(URI)->getKeyData()); + } +} + +std::map<std::string, const IncludeGraphNode &> toMap(const IncludeGraph &IG) { + std::map<std::string, const IncludeGraphNode &> Nodes; + for (auto &I : IG) + Nodes.emplace(I.getKey(), I.getValue()); + return Nodes; +} + +class IndexActionTest : public ::testing::Test { +public: + IndexActionTest() : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem) {} + + IndexFileIn + runIndexingAction(llvm::StringRef MainFilePath, + const std::vector<std::string> &ExtraArgs = {}) { + IndexFileIn IndexFile; + llvm::IntrusiveRefCntPtr<FileManager> Files( + new FileManager(FileSystemOptions(), InMemoryFileSystem)); + + auto Action = createStaticIndexingAction( + SymbolCollector::Options(), + [&](SymbolSlab S) { IndexFile.Symbols = std::move(S); }, + [&](RefSlab R) { IndexFile.Refs = std::move(R); }, + [&](IncludeGraph IG) { IndexFile.Sources = std::move(IG); }); + + std::vector<std::string> Args = {"index_action", "-fsyntax-only", + "-xc++", "-std=c++11", + "-iquote", testRoot()}; + Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end()); + Args.push_back(MainFilePath); + + tooling::ToolInvocation Invocation( + Args, Action.release(), Files.get(), + std::make_shared<PCHContainerOperations>()); + + Invocation.run(); + + checkNodesAreInitialized(IndexFile, FilePaths); + return IndexFile; + } + + void addFile(llvm::StringRef Path, llvm::StringRef Content) { + InMemoryFileSystem->addFile(Path, 0, + llvm::MemoryBuffer::getMemBuffer(Content)); + FilePaths.push_back(Path); + } + +protected: + std::vector<std::string> FilePaths; + llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem; +}; + +TEST_F(IndexActionTest, CollectIncludeGraph) { + std::string MainFilePath = testPath("main.cpp"); + std::string MainCode = "#include \"level1.h\""; + std::string Level1HeaderPath = testPath("level1.h"); + std::string Level1HeaderCode = "#include \"level2.h\""; + std::string Level2HeaderPath = testPath("level2.h"); + std::string Level2HeaderCode = ""; + + addFile(MainFilePath, MainCode); + addFile(Level1HeaderPath, Level1HeaderCode); + addFile(Level2HeaderPath, Level2HeaderCode); + + IndexFileIn IndexFile = runIndexingAction(MainFilePath); + auto Nodes = toMap(*IndexFile.Sources); + + EXPECT_THAT(Nodes, + UnorderedElementsAre( + Pair(toUri(MainFilePath), + AllOf(IsTU(), IncludesAre({Level1HeaderPath}), + HasDigest(digest(MainCode)))), + Pair(toUri(Level1HeaderPath), + AllOf(Not(IsTU()), IncludesAre({Level2HeaderPath}), + HasDigest(digest(Level1HeaderCode)))), + Pair(toUri(Level2HeaderPath), + AllOf(Not(IsTU()), IncludesAre({}), + HasDigest(digest(Level2HeaderCode)))))); +} + +TEST_F(IndexActionTest, IncludeGraphSelfInclude) { + std::string MainFilePath = testPath("main.cpp"); + std::string MainCode = "#include \"header.h\""; + std::string HeaderPath = testPath("header.h"); + std::string HeaderCode = R"cpp( + #ifndef _GUARD_ + #define _GUARD_ + #include "header.h" + #endif)cpp"; + + addFile(MainFilePath, MainCode); + addFile(HeaderPath, HeaderCode); + + IndexFileIn IndexFile = runIndexingAction(MainFilePath); + auto Nodes = toMap(*IndexFile.Sources); + + EXPECT_THAT( + Nodes, + UnorderedElementsAre( + Pair(toUri(MainFilePath), AllOf(IsTU(), IncludesAre({HeaderPath}), + HasDigest(digest(MainCode)))), + Pair(toUri(HeaderPath), AllOf(Not(IsTU()), IncludesAre({HeaderPath}), + HasDigest(digest(HeaderCode)))))); +} + +TEST_F(IndexActionTest, IncludeGraphSkippedFile) { + std::string MainFilePath = testPath("main.cpp"); + std::string MainCode = R"cpp( + #include "common.h" + #include "header.h" + )cpp"; + + std::string CommonHeaderPath = testPath("common.h"); + std::string CommonHeaderCode = R"cpp( + #ifndef _GUARD_ + #define _GUARD_ + void f(); + #endif)cpp"; + + std::string HeaderPath = testPath("header.h"); + std::string HeaderCode = R"cpp( + #include "common.h" + void g();)cpp"; + + addFile(MainFilePath, MainCode); + addFile(HeaderPath, HeaderCode); + addFile(CommonHeaderPath, CommonHeaderCode); + + IndexFileIn IndexFile = runIndexingAction(MainFilePath); + auto Nodes = toMap(*IndexFile.Sources); + + EXPECT_THAT( + Nodes, UnorderedElementsAre( + Pair(toUri(MainFilePath), + AllOf(IsTU(), IncludesAre({HeaderPath, CommonHeaderPath}), + HasDigest(digest(MainCode)))), + Pair(toUri(HeaderPath), + AllOf(Not(IsTU()), IncludesAre({CommonHeaderPath}), + HasDigest(digest(HeaderCode)))), + Pair(toUri(CommonHeaderPath), + AllOf(Not(IsTU()), IncludesAre({}), + HasDigest(digest(CommonHeaderCode)))))); +} + +TEST_F(IndexActionTest, IncludeGraphDynamicInclude) { + std::string MainFilePath = testPath("main.cpp"); + std::string MainCode = R"cpp( + #ifndef FOO + #define FOO "main.cpp" + #else + #define FOO "header.h" + #endif + + #include FOO)cpp"; + std::string HeaderPath = testPath("header.h"); + std::string HeaderCode = ""; + + addFile(MainFilePath, MainCode); + addFile(HeaderPath, HeaderCode); + + IndexFileIn IndexFile = runIndexingAction(MainFilePath); + auto Nodes = toMap(*IndexFile.Sources); + + EXPECT_THAT( + Nodes, + UnorderedElementsAre( + Pair(toUri(MainFilePath), + AllOf(IsTU(), IncludesAre({MainFilePath, HeaderPath}), + HasDigest(digest(MainCode)))), + Pair(toUri(HeaderPath), AllOf(Not(IsTU()), IncludesAre({}), + HasDigest(digest(HeaderCode)))))); +} + +TEST_F(IndexActionTest, NoWarnings) { + std::string MainFilePath = testPath("main.cpp"); + std::string MainCode = R"cpp( + void foo(int x) { + if (x = 1) // -Wparentheses + return; + if (x = 1) // -Wparentheses + return; + } + void bar() {} + )cpp"; + addFile(MainFilePath, MainCode); + // We set -ferror-limit so the warning-promoted-to-error would be fatal. + // This would cause indexing to stop (if warnings weren't disabled). + IndexFileIn IndexFile = runIndexingAction( + MainFilePath, {"-ferror-limit=1", "-Wparentheses", "-Werror"}); + ASSERT_TRUE(IndexFile.Sources); + ASSERT_NE(0u, IndexFile.Sources->size()); + EXPECT_THAT(*IndexFile.Symbols, ElementsAre(HasName("foo"), HasName("bar"))); +} + +} // namespace +} // namespace clangd +} // namespace clang |