clang-tools 10.0.0

IndexActionTests.cpp
Go to the documentation of this file.
1 //===------ IndexActionTests.cpp -------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "Headers.h"
10 #include "TestFS.h"
11 #include "index/IndexAction.h"
12 #include "clang/Tooling/Tooling.h"
13 #include "gmock/gmock.h"
14 #include "gtest/gtest.h"
15
16 namespace clang {
17 namespace clangd {
18 namespace {
19
20 using ::testing::AllOf;
21 using ::testing::ElementsAre;
22 using ::testing::Not;
23 using ::testing::Pair;
24 using ::testing::UnorderedElementsAre;
25 using ::testing::UnorderedPointwise;
26
27 std::string toUri(llvm::StringRef Path) { return URI::create(Path).toString(); }
28
29 MATCHER(IsTU, "") { return arg.Flags & IncludeGraphNode::SourceFlag::IsTU; }
30
31 MATCHER_P(HasDigest, Digest, "") { return arg.Digest == Digest; }
32
33 MATCHER_P(HasName, Name, "") { return arg.Name == Name; }
34
35 MATCHER(HasSameURI, "") {
36 llvm::StringRef URI = ::testing::get<0>(arg);
37 const std::string &Path = ::testing::get<1>(arg);
38 return toUri(Path) == URI;
39 }
40
41 ::testing::Matcher<const IncludeGraphNode &>
42 IncludesAre(const std::vector<std::string> &Includes) {
43 return ::testing::Field(&IncludeGraphNode::DirectIncludes,
44 UnorderedPointwise(HasSameURI(), Includes));
45 }
46
47 void checkNodesAreInitialized(const IndexFileIn &IndexFile,
48 const std::vector<std::string> &Paths) {
49 ASSERT_TRUE(IndexFile.Sources);
50 EXPECT_THAT(Paths.size(), IndexFile.Sources->size());
51 for (llvm::StringRef Path : Paths) {
52 auto URI = toUri(Path);
53 const auto &Node = IndexFile.Sources->lookup(URI);
54 // Uninitialized nodes will have an empty URI.
55 EXPECT_EQ(Node.URI.data(), IndexFile.Sources->find(URI)->getKeyData());
56 }
57 }
58
59 std::map<std::string, const IncludeGraphNode &> toMap(const IncludeGraph &IG) {
60 std::map<std::string, const IncludeGraphNode &> Nodes;
61 for (auto &I : IG)
62 Nodes.emplace(I.getKey(), I.getValue());
63 return Nodes;
64 }
65
66 class IndexActionTest : public ::testing::Test {
67 public:
68 IndexActionTest() : InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem) {}
69
70 IndexFileIn
71 runIndexingAction(llvm::StringRef MainFilePath,
72 const std::vector<std::string> &ExtraArgs = {}) {
73 IndexFileIn IndexFile;
74 llvm::IntrusiveRefCntPtr<FileManager> Files(
75 new FileManager(FileSystemOptions(), InMemoryFileSystem));
76
77 auto Action = createStaticIndexingAction(
78 SymbolCollector::Options(),
79 [&](SymbolSlab S) { IndexFile.Symbols = std::move(S); },
80 [&](RefSlab R) { IndexFile.Refs = std::move(R); },
81 [&](RelationSlab R) { IndexFile.Relations = std::move(R); },
82 [&](IncludeGraph IG) { IndexFile.Sources = std::move(IG); });
83
84 std::vector<std::string> Args = {"index_action", "-fsyntax-only",
85 "-xc++", "-std=c++11",
86 "-iquote", testRoot()};
87 Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
88 Args.push_back(MainFilePath);
89
90 tooling::ToolInvocation Invocation(
91 Args, std::move(Action), Files.get(),
92 std::make_shared<PCHContainerOperations>());
93
94 Invocation.run();
95
96 checkNodesAreInitialized(IndexFile, FilePaths);
97 return IndexFile;
98 }
99
100 void addFile(llvm::StringRef Path, llvm::StringRef Content) {
101 InMemoryFileSystem->addFile(Path, 0,
102 llvm::MemoryBuffer::getMemBuffer(Content));
103 FilePaths.push_back(Path);
104 }
105
106 protected:
107 std::vector<std::string> FilePaths;
108 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem;
109 };
110
111 TEST_F(IndexActionTest, CollectIncludeGraph) {
112 std::string MainFilePath = testPath("main.cpp");
113 std::string MainCode = "#include \"level1.h\"";
114 std::string Level1HeaderPath = testPath("level1.h");
115 std::string Level1HeaderCode = "#include \"level2.h\"";
116 std::string Level2HeaderPath = testPath("level2.h");
117 std::string Level2HeaderCode = "";
118
119 addFile(MainFilePath, MainCode);
120 addFile(Level1HeaderPath, Level1HeaderCode);
121 addFile(Level2HeaderPath, Level2HeaderCode);
122
123 IndexFileIn IndexFile = runIndexingAction(MainFilePath);
124 auto Nodes = toMap(*IndexFile.Sources);
125
126 EXPECT_THAT(Nodes,
127 UnorderedElementsAre(
128 Pair(toUri(MainFilePath),
129 AllOf(IsTU(), IncludesAre({Level1HeaderPath}),
130 HasDigest(digest(MainCode)))),
131 Pair(toUri(Level1HeaderPath),
132 AllOf(Not(IsTU()), IncludesAre({Level2HeaderPath}),
133 HasDigest(digest(Level1HeaderCode)))),
134 Pair(toUri(Level2HeaderPath),
135 AllOf(Not(IsTU()), IncludesAre({}),
136 HasDigest(digest(Level2HeaderCode))))));
137 }
138
139 TEST_F(IndexActionTest, IncludeGraphSelfInclude) {
140 std::string MainFilePath = testPath("main.cpp");
141 std::string MainCode = "#include \"header.h\"";
142 std::string HeaderPath = testPath("header.h");
143 std::string HeaderCode = R"cpp(
144 #ifndef _GUARD_
145 #define _GUARD_
146 #include "header.h"
147 #endif)cpp";
148
149 addFile(MainFilePath, MainCode);
150 addFile(HeaderPath, HeaderCode);
151
152 IndexFileIn IndexFile = runIndexingAction(MainFilePath);
153 auto Nodes = toMap(*IndexFile.Sources);
154
155 EXPECT_THAT(
156 Nodes,
157 UnorderedElementsAre(
158 Pair(toUri(MainFilePath), AllOf(IsTU(), IncludesAre({HeaderPath}),
159 HasDigest(digest(MainCode)))),
160 Pair(toUri(HeaderPath), AllOf(Not(IsTU()), IncludesAre({HeaderPath}),
161 HasDigest(digest(HeaderCode))))));
162 }
163
164 TEST_F(IndexActionTest, IncludeGraphSkippedFile) {
165 std::string MainFilePath = testPath("main.cpp");
166 std::string MainCode = R"cpp(
167 #include "common.h"
168 #include "header.h"
169 )cpp";
170
171 std::string CommonHeaderPath = testPath("common.h");
172 std::string CommonHeaderCode = R"cpp(
173 #ifndef _GUARD_
174 #define _GUARD_
175 void f();
176 #endif)cpp";
177
178 std::string HeaderPath = testPath("header.h");
179 std::string HeaderCode = R"cpp(
180 #include "common.h"
181 void g();)cpp";
182
183 addFile(MainFilePath, MainCode);
184 addFile(HeaderPath, HeaderCode);
185 addFile(CommonHeaderPath, CommonHeaderCode);
186
187 IndexFileIn IndexFile = runIndexingAction(MainFilePath);
188 auto Nodes = toMap(*IndexFile.Sources);
189
190 EXPECT_THAT(
191 Nodes, UnorderedElementsAre(
192 Pair(toUri(MainFilePath),
193 AllOf(IsTU(), IncludesAre({HeaderPath, CommonHeaderPath}),
194 HasDigest(digest(MainCode)))),
195 Pair(toUri(HeaderPath),
196 AllOf(Not(IsTU()), IncludesAre({CommonHeaderPath}),
197 HasDigest(digest(HeaderCode)))),
198 Pair(toUri(CommonHeaderPath),
199 AllOf(Not(IsTU()), IncludesAre({}),
200 HasDigest(digest(CommonHeaderCode))))));
201 }
202
203 TEST_F(IndexActionTest, IncludeGraphDynamicInclude) {
204 std::string MainFilePath = testPath("main.cpp");
205 std::string MainCode = R"cpp(
206 #ifndef FOO
207 #define FOO "main.cpp"
208 #else
209 #define FOO "header.h"
210 #endif
211
212 #include FOO)cpp";
213 std::string HeaderPath = testPath("header.h");
214 std::string HeaderCode = "";
215
216 addFile(MainFilePath, MainCode);
217 addFile(HeaderPath, HeaderCode);
218
219 IndexFileIn IndexFile = runIndexingAction(MainFilePath);
220 auto Nodes = toMap(*IndexFile.Sources);
221
222 EXPECT_THAT(
223 Nodes,
224 UnorderedElementsAre(
225 Pair(toUri(MainFilePath),
226 AllOf(IsTU(), IncludesAre({MainFilePath, HeaderPath}),
227 HasDigest(digest(MainCode)))),
228 Pair(toUri(HeaderPath), AllOf(Not(IsTU()), IncludesAre({}),
229 HasDigest(digest(HeaderCode))))));
230 }
231
232 TEST_F(IndexActionTest, NoWarnings) {
233 std::string MainFilePath = testPath("main.cpp");
234 std::string MainCode = R"cpp(
235 void foo(int x) {
236 if (x = 1) // -Wparentheses
237 return;
238 if (x = 1) // -Wparentheses
239 return;
240 }
241 void bar() {}
242 )cpp";
243 addFile(MainFilePath, MainCode);
244 // We set -ferror-limit so the warning-promoted-to-error would be fatal.
245 // This would cause indexing to stop (if warnings weren't disabled).
246 IndexFileIn IndexFile = runIndexingAction(
247 MainFilePath, {"-ferror-limit=1", "-Wparentheses", "-Werror"});
248 ASSERT_TRUE(IndexFile.Sources);
249 ASSERT_NE(0u, IndexFile.Sources->size());
250 EXPECT_THAT(*IndexFile.Symbols, ElementsAre(HasName("foo"), HasName("bar")));
251 }
252
253 } // namespace
254 } // namespace clangd
255 } // namespace clang
clang::clangd::MATCHER_P
MATCHER_P(Named, N, "")
Definition: BackgroundIndexTests.cpp:26
llvm
Some operations such as code completion produce a set of candidates.
Definition: YAMLGenerator.cpp:28
InMemoryFileSystem
llvm::IntrusiveRefCntPtr< llvm::vfs::InMemoryFileSystem > InMemoryFileSystem
Definition: IndexActionTests.cpp:108
TestFS.h
Headers.h
clang::clangd::IncludeGraphNode::DirectIncludes
std::vector< llvm::StringRef > DirectIncludes
Definition: Headers.h:76
clang::clangd::TEST_F
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
Definition: BackgroundIndexTests.cpp:88
clang::clangd::IncludeGraph
llvm::StringMap< IncludeGraphNode > IncludeGraph
Definition: Headers.h:82
clang::clangd::testPath
std::string testPath(PathRef File)
Definition: TestFS.cpp:82
Action
llvm::unique_function< void()> Action
Definition: TUScheduler.cpp:234
clang::clangd::Path
std::string Path
A typedef to represent a file path.
Definition: Path.h:20
clang::clangd::MATCHER
MATCHER(Declared, "")
Definition: BackgroundIndexTests.cpp:27
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
clang::clangd::testRoot
const char * testRoot()
Definition: TestFS.cpp:74
FilePaths
std::vector< std::string > FilePaths
Definition: IndexActionTests.cpp:107
clang::clangd::digest
FileDigest digest(llvm::StringRef Content)
Definition: SourceCode.cpp:675
clang::clangd::URI::create
static llvm::Expected< URI > create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme)
Creates a URI for a file in the given scheme.
Definition: URI.cpp:197
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::createStaticIndexingAction
std::unique_ptr< FrontendAction > createStaticIndexingAction(SymbolCollector::Options Opts, std::function< void(SymbolSlab)> SymbolsCallback, std::function< void(RefSlab)> RefsCallback, std::function< void(RelationSlab)> RelationsCallback, std::function< void(IncludeGraph)> IncludeGraphCallback)
Definition: IndexAction.cpp:205
IndexAction.h
clang::clangd::IncludeGraphNode::SourceFlag::IsTU
Files
llvm::StringMap< std::string > Files
Definition: TUSchedulerTests.cpp:119