12 #include "clang/Tooling/Tooling.h"
13 #include "gmock/gmock.h"
14 #include "gtest/gtest.h"
20 using ::testing::AllOf;
21 using ::testing::ElementsAre;
22 using ::testing::EndsWith;
24 using ::testing::Pair;
25 using ::testing::UnorderedElementsAre;
26 using ::testing::UnorderedPointwise;
32 MATCHER_P(HasDigest, Digest,
"") {
return arg.Digest == Digest; }
37 llvm::StringRef URI = ::testing::get<0>(arg);
38 const std::string &
Path = ::testing::get<1>(arg);
39 return toUri(
Path) == URI;
42 ::testing::Matcher<const IncludeGraphNode &>
43 IncludesAre(
const std::vector<std::string> &Includes) {
45 UnorderedPointwise(HasSameURI(), Includes));
48 void checkNodesAreInitialized(
const IndexFileIn &IndexFile,
49 const std::vector<std::string> &Paths) {
50 ASSERT_TRUE(IndexFile.Sources);
51 EXPECT_THAT(Paths.size(), IndexFile.Sources->size());
52 for (llvm::StringRef
Path : Paths) {
53 auto URI = toUri(
Path);
54 const auto &Node = IndexFile.Sources->lookup(URI);
56 EXPECT_EQ(Node.URI.data(), IndexFile.Sources->find(URI)->getKeyData());
60 std::map<std::string, const IncludeGraphNode &> toMap(
const IncludeGraph &IG) {
61 std::map<std::string, const IncludeGraphNode &> Nodes;
63 Nodes.emplace(std::string(I.getKey()), I.getValue());
67 class IndexActionTest :
public ::testing::Test {
72 runIndexingAction(llvm::StringRef MainFilePath,
73 const std::vector<std::string> &ExtraArgs = {}) {
74 IndexFileIn IndexFile;
75 llvm::IntrusiveRefCntPtr<FileManager> Files(
79 Opts, [&](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); });
84 std::vector<std::string> Args = {
"index_action",
"-fsyntax-only",
85 "-xc++",
"-std=c++11",
87 Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
88 Args.push_back(std::string(MainFilePath));
90 tooling::ToolInvocation Invocation(
91 Args, std::move(
Action), Files.get(),
92 std::make_shared<PCHContainerOperations>());
96 checkNodesAreInitialized(IndexFile,
FilePaths);
100 void addFile(llvm::StringRef
Path, llvm::StringRef Content) {
102 llvm::MemoryBuffer::getMemBufferCopy(Content));
112 TEST_F(IndexActionTest, CollectIncludeGraph) {
113 std::string MainFilePath =
testPath(
"main.cpp");
114 std::string MainCode =
"#include \"level1.h\"";
115 std::string Level1HeaderPath =
testPath(
"level1.h");
116 std::string Level1HeaderCode =
"#include \"level2.h\"";
117 std::string Level2HeaderPath =
testPath(
"level2.h");
118 std::string Level2HeaderCode =
"";
120 addFile(MainFilePath, MainCode);
121 addFile(Level1HeaderPath, Level1HeaderCode);
122 addFile(Level2HeaderPath, Level2HeaderCode);
124 IndexFileIn IndexFile = runIndexingAction(MainFilePath);
125 auto Nodes = toMap(*IndexFile.Sources);
128 UnorderedElementsAre(
129 Pair(toUri(MainFilePath),
130 AllOf(IsTU(), IncludesAre({Level1HeaderPath}),
131 HasDigest(
digest(MainCode)))),
132 Pair(toUri(Level1HeaderPath),
133 AllOf(Not(IsTU()), IncludesAre({Level2HeaderPath}),
134 HasDigest(
digest(Level1HeaderCode)))),
135 Pair(toUri(Level2HeaderPath),
136 AllOf(Not(IsTU()), IncludesAre({}),
137 HasDigest(
digest(Level2HeaderCode))))));
140 TEST_F(IndexActionTest, IncludeGraphSelfInclude) {
141 std::string MainFilePath =
testPath(
"main.cpp");
142 std::string MainCode =
"#include \"header.h\"";
143 std::string HeaderPath =
testPath(
"header.h");
144 std::string HeaderCode = R
"cpp(
150 addFile(MainFilePath, MainCode);
151 addFile(HeaderPath, HeaderCode);
153 IndexFileIn IndexFile = runIndexingAction(MainFilePath);
154 auto Nodes = toMap(*IndexFile.Sources);
158 UnorderedElementsAre(
159 Pair(toUri(MainFilePath), AllOf(IsTU(), IncludesAre({HeaderPath}),
160 HasDigest(
digest(MainCode)))),
161 Pair(toUri(HeaderPath), AllOf(Not(IsTU()), IncludesAre({HeaderPath}),
162 HasDigest(
digest(HeaderCode))))));
165 TEST_F(IndexActionTest, IncludeGraphSkippedFile) {
166 std::string MainFilePath =
testPath(
"main.cpp");
167 std::string MainCode = R
"cpp(
172 std::string CommonHeaderPath = testPath("common.h");
173 std::string CommonHeaderCode = R
"cpp(
179 std::string HeaderPath = testPath("header.h");
180 std::string HeaderCode = R
"cpp(
184 addFile(MainFilePath, MainCode);
185 addFile(HeaderPath, HeaderCode);
186 addFile(CommonHeaderPath, CommonHeaderCode);
188 IndexFileIn IndexFile = runIndexingAction(MainFilePath);
189 auto Nodes = toMap(*IndexFile.Sources);
192 Nodes, UnorderedElementsAre(
193 Pair(toUri(MainFilePath),
194 AllOf(IsTU(), IncludesAre({HeaderPath, CommonHeaderPath}),
195 HasDigest(
digest(MainCode)))),
196 Pair(toUri(HeaderPath),
197 AllOf(Not(IsTU()), IncludesAre({CommonHeaderPath}),
198 HasDigest(
digest(HeaderCode)))),
199 Pair(toUri(CommonHeaderPath),
200 AllOf(Not(IsTU()), IncludesAre({}),
201 HasDigest(
digest(CommonHeaderCode))))));
204 TEST_F(IndexActionTest, IncludeGraphDynamicInclude) {
205 std::string MainFilePath =
testPath(
"main.cpp");
206 std::string MainCode = R
"cpp(
208 #define FOO "main.cpp"
210 #define FOO "header.h"
214 std::string HeaderPath = testPath("header.h");
215 std::string HeaderCode =
"";
217 addFile(MainFilePath, MainCode);
218 addFile(HeaderPath, HeaderCode);
220 IndexFileIn IndexFile = runIndexingAction(MainFilePath);
221 auto Nodes = toMap(*IndexFile.Sources);
225 UnorderedElementsAre(
226 Pair(toUri(MainFilePath),
227 AllOf(IsTU(), IncludesAre({MainFilePath, HeaderPath}),
228 HasDigest(
digest(MainCode)))),
229 Pair(toUri(HeaderPath), AllOf(Not(IsTU()), IncludesAre({}),
230 HasDigest(
digest(HeaderCode))))));
233 TEST_F(IndexActionTest, NoWarnings) {
234 std::string MainFilePath =
testPath(
"main.cpp");
235 std::string MainCode = R
"cpp(
237 if (x = 1) // -Wparentheses
239 if (x = 1) // -Wparentheses
244 addFile(MainFilePath, MainCode);
247 IndexFileIn IndexFile = runIndexingAction(
248 MainFilePath, {
"-ferror-limit=1",
"-Wparentheses",
"-Werror"});
249 ASSERT_TRUE(IndexFile.Sources);
250 ASSERT_NE(0u, IndexFile.Sources->size());
251 EXPECT_THAT(*IndexFile.Symbols, ElementsAre(HasName(
"foo"), HasName(
"bar")));
254 TEST_F(IndexActionTest, SkipFiles) {
255 std::string MainFilePath =
testPath(
"main.cpp");
256 addFile(MainFilePath, R
"cpp(
265 auto unskippable1() { return S(); }
270 auto unskippable2() { return S(); }
273 return !SM.getFileEntryForID(F)->getName().endswith(
"bad.h");
275 IndexFileIn IndexFile = runIndexingAction(MainFilePath, {
"-std=c++14"});
276 EXPECT_THAT(*IndexFile.Symbols,
277 UnorderedElementsAre(HasName(
"S"), HasName(
"s"), HasName(
"f1"),
278 HasName(
"unskippable1")));
279 for (
const auto &Pair : *IndexFile.Refs)
280 for (
const auto &Ref : Pair.second)
281 EXPECT_THAT(Ref.Location.FileURI, EndsWith(
"good.h"));