14#include "clang/Basic/SourceLocation.h"
15#include "clang/Basic/SourceManager.h"
16#include "clang/Tooling/Tooling.h"
17#include "gmock/gmock.h"
18#include "gtest/gtest.h"
25using ::testing::AllOf;
26using ::testing::ElementsAre;
27using ::testing::EndsWith;
30using ::testing::UnorderedElementsAre;
31using ::testing::UnorderedPointwise;
37MATCHER_P(hasDigest, Digest,
"") {
return arg.Digest == Digest; }
42 llvm::StringRef URI = ::testing::get<0>(arg);
43 const std::string &
Path = ::testing::get<1>(arg);
44 return toUri(
Path) == URI;
48 return (arg.IncludeHeaders.size() == 1) &&
49 (arg.IncludeHeaders.begin()->IncludeHeader == P);
52::testing::Matcher<const IncludeGraphNode &>
53includesAre(
const std::vector<std::string> &Includes) {
55 UnorderedPointwise(hasSameURI(), Includes));
58void checkNodesAreInitialized(
const IndexFileIn &IndexFile,
59 const std::vector<std::string> &Paths) {
60 ASSERT_TRUE(IndexFile.Sources);
61 EXPECT_THAT(Paths.size(), IndexFile.Sources->size());
62 for (llvm::StringRef
Path : Paths) {
63 auto URI = toUri(
Path);
64 const auto &
Node = IndexFile.Sources->lookup(URI);
66 EXPECT_EQ(
Node.URI.data(), IndexFile.Sources->find(URI)->getKeyData());
70std::map<std::string, const IncludeGraphNode &> toMap(
const IncludeGraph &IG) {
71 std::map<std::string, const IncludeGraphNode &> Nodes;
73 Nodes.emplace(std::string(I.getKey()), I.getValue());
77class IndexActionTest :
public ::testing::Test {
82 runIndexingAction(llvm::StringRef MainFilePath,
83 const std::vector<std::string> &ExtraArgs = {}) {
84 IndexFileIn IndexFile;
85 llvm::IntrusiveRefCntPtr<FileManager> Files(
89 Opts, [&](SymbolSlab S) { IndexFile.Symbols = std::move(S); },
90 [&](RefSlab R) { IndexFile.Refs = std::move(R); },
91 [&](RelationSlab R) { IndexFile.Relations = std::move(R); },
92 [&](
IncludeGraph IG) { IndexFile.Sources = std::move(IG); });
94 std::vector<std::string>
Args = {
"index_action",
"-fsyntax-only",
95 "-xc++",
"-std=c++11",
97 Args.insert(
Args.end(), ExtraArgs.begin(), ExtraArgs.end());
98 Args.push_back(std::string(MainFilePath));
100 tooling::ToolInvocation Invocation(
102 std::make_shared<PCHContainerOperations>());
106 checkNodesAreInitialized(IndexFile, FilePaths);
110 void addFile(llvm::StringRef
Path, llvm::StringRef Content) {
112 llvm::MemoryBuffer::getMemBufferCopy(Content));
113 FilePaths.push_back(std::string(
Path));
117 SymbolCollector::Options Opts;
118 std::vector<std::string> FilePaths;
122TEST_F(IndexActionTest, CollectIncludeGraph) {
123 std::string MainFilePath =
testPath(
"main.cpp");
124 std::string MainCode =
"#include \"level1.h\"";
125 std::string Level1HeaderPath =
testPath(
"level1.h");
126 std::string Level1HeaderCode =
"#include \"level2.h\"";
127 std::string Level2HeaderPath =
testPath(
"level2.h");
128 std::string Level2HeaderCode =
"";
130 addFile(MainFilePath, MainCode);
131 addFile(Level1HeaderPath, Level1HeaderCode);
132 addFile(Level2HeaderPath, Level2HeaderCode);
134 IndexFileIn IndexFile = runIndexingAction(MainFilePath);
135 auto Nodes = toMap(*IndexFile.Sources);
138 UnorderedElementsAre(
139 Pair(toUri(MainFilePath),
140 AllOf(isTU(), includesAre({Level1HeaderPath}),
141 hasDigest(
digest(MainCode)))),
142 Pair(toUri(Level1HeaderPath),
143 AllOf(Not(isTU()), includesAre({Level2HeaderPath}),
144 hasDigest(
digest(Level1HeaderCode)))),
145 Pair(toUri(Level2HeaderPath),
146 AllOf(Not(isTU()), includesAre({}),
147 hasDigest(
digest(Level2HeaderCode))))));
150TEST_F(IndexActionTest, IncludeGraphSelfInclude) {
151 std::string MainFilePath =
testPath(
"main.cpp");
152 std::string MainCode =
"#include \"header.h\"";
153 std::string HeaderPath =
testPath(
"header.h");
154 std::string HeaderCode = R
"cpp(
160 addFile(MainFilePath, MainCode);
161 addFile(HeaderPath, HeaderCode);
163 IndexFileIn IndexFile = runIndexingAction(MainFilePath);
164 auto Nodes = toMap(*IndexFile.Sources);
168 UnorderedElementsAre(
169 Pair(toUri(MainFilePath), AllOf(isTU(), includesAre({HeaderPath}),
170 hasDigest(
digest(MainCode)))),
171 Pair(toUri(HeaderPath), AllOf(Not(isTU()), includesAre({HeaderPath}),
172 hasDigest(
digest(HeaderCode))))));
175TEST_F(IndexActionTest, IncludeGraphSkippedFile) {
176 std::string MainFilePath =
testPath(
"main.cpp");
177 std::string MainCode = R
"cpp(
182 std::string CommonHeaderPath = testPath("common.h");
183 std::string CommonHeaderCode = R
"cpp(
189 std::string HeaderPath = testPath("header.h");
190 std::string HeaderCode = R
"cpp(
194 addFile(MainFilePath, MainCode);
195 addFile(HeaderPath, HeaderCode);
196 addFile(CommonHeaderPath, CommonHeaderCode);
198 IndexFileIn IndexFile = runIndexingAction(MainFilePath);
199 auto Nodes = toMap(*IndexFile.Sources);
202 Nodes, UnorderedElementsAre(
203 Pair(toUri(MainFilePath),
204 AllOf(isTU(), includesAre({HeaderPath, CommonHeaderPath}),
205 hasDigest(
digest(MainCode)))),
206 Pair(toUri(HeaderPath),
207 AllOf(Not(isTU()), includesAre({CommonHeaderPath}),
208 hasDigest(
digest(HeaderCode)))),
209 Pair(toUri(CommonHeaderPath),
210 AllOf(Not(isTU()), includesAre({}),
211 hasDigest(
digest(CommonHeaderCode))))));
214TEST_F(IndexActionTest, IncludeGraphDynamicInclude) {
215 std::string MainFilePath =
testPath(
"main.cpp");
216 std::string MainCode = R
"cpp(
218 #define FOO "main.cpp"
220 #define FOO "header.h"
224 std::string HeaderPath = testPath("header.h");
225 std::string HeaderCode =
"";
227 addFile(MainFilePath, MainCode);
228 addFile(HeaderPath, HeaderCode);
230 IndexFileIn IndexFile = runIndexingAction(MainFilePath);
231 auto Nodes = toMap(*IndexFile.Sources);
235 UnorderedElementsAre(
236 Pair(toUri(MainFilePath),
237 AllOf(isTU(), includesAre({MainFilePath, HeaderPath}),
238 hasDigest(
digest(MainCode)))),
239 Pair(toUri(HeaderPath), AllOf(Not(isTU()), includesAre({}),
240 hasDigest(
digest(HeaderCode))))));
243TEST_F(IndexActionTest, NoWarnings) {
244 std::string MainFilePath =
testPath(
"main.cpp");
245 std::string MainCode = R
"cpp(
247 if (x = 1) // -Wparentheses
249 if (x = 1) // -Wparentheses
254 addFile(MainFilePath, MainCode);
257 IndexFileIn IndexFile = runIndexingAction(
258 MainFilePath, {
"-ferror-limit=1",
"-Wparentheses",
"-Werror"});
259 ASSERT_TRUE(IndexFile.Sources);
260 ASSERT_NE(0u, IndexFile.Sources->size());
261 EXPECT_THAT(*IndexFile.Symbols, ElementsAre(hasName(
"foo"), hasName(
"bar")));
264TEST_F(IndexActionTest, SkipFiles) {
265 std::string MainFilePath =
testPath(
"main.cpp");
266 addFile(MainFilePath, R
"cpp(
275 auto unskippable1() { return S(); }
280 auto unskippable2() { return S(); }
282 Opts.FileFilter = [](const SourceManager &SM, FileID F) {
283 return !SM.getFileEntryRefForID(F)->getName().ends_with(
"bad.h");
285 IndexFileIn IndexFile = runIndexingAction(MainFilePath, {
"-std=c++14"});
286 EXPECT_THAT(*IndexFile.Symbols,
287 UnorderedElementsAre(hasName(
"S"), hasName(
"s"), hasName(
"f1"),
288 hasName(
"unskippable1")));
289 for (
const auto &Pair : *IndexFile.Refs)
290 for (
const auto &Ref :
Pair.second)
291 EXPECT_THAT(Ref.Location.FileURI, EndsWith(
"good.h"));
294TEST_F(IndexActionTest, SkipNestedSymbols) {
295 std::string MainFilePath =
testPath(
"main.cpp");
296 addFile(MainFilePath, R
"cpp(
319 IndexFileIn IndexFile = runIndexingAction(MainFilePath, {"-std=c++14"});
320 EXPECT_THAT(*IndexFile.Symbols, testing::Contains(hasName(
"foo")));
321 EXPECT_THAT(*IndexFile.Symbols, testing::Contains(hasName(
"Bar")));
322 EXPECT_THAT(*IndexFile.Symbols, Not(testing::Contains(hasName(
"Baz"))));
325TEST_F(IndexActionTest, SymbolFromCC) {
326 std::string MainFilePath =
testPath(
"main.cpp");
327 addFile(MainFilePath, R
"cpp(
335 Opts.FileFilter = [](const SourceManager &SM, FileID F) {
336 return !SM.getFileEntryRefForID(F)->getName().ends_with(
"main.h");
338 IndexFileIn IndexFile = runIndexingAction(MainFilePath, {
"-std=c++14"});
339 EXPECT_THAT(*IndexFile.Symbols,
340 UnorderedElementsAre(AllOf(
345TEST_F(IndexActionTest, IncludeHeaderForwardDecls) {
346 std::string MainFilePath =
testPath(
"main.cpp");
347 addFile(MainFilePath, R
"cpp(
362// This decl is important, as otherwise we detect control macro for the file,
363// before handling definition of Foo.
367 IndexFileIn IndexFile = runIndexingAction(MainFilePath);
368 EXPECT_THAT(*IndexFile.Symbols,
369 testing::Contains(AllOf(
372 << *IndexFile.Symbols->begin();
llvm::SmallString< 256U > Name
std::vector< HeaderHandle > Path
::clang::DynTypedNode Node
llvm::IntrusiveRefCntPtr< llvm::vfs::InMemoryFileSystem > InMemoryFileSystem
static llvm::Expected< URI > create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme)
Creates a URI for a file in the given scheme.
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
std::string Path
A typedef to represent a file path.
FileDigest digest(llvm::StringRef Content)
static const char * toString(OffsetEncoding OE)
std::string testPath(PathRef File, llvm::sys::path::Style Style)
llvm::StringMap< IncludeGraphNode > IncludeGraph
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)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Some operations such as code completion produce a set of candidates.
std::vector< llvm::StringRef > DirectIncludes