17 #include "clang/Index/IndexSymbol.h" 18 #include "gmock/gmock.h" 19 #include "gtest/gtest.h" 22 using ::testing::AllOf;
23 using ::testing::AnyOf;
24 using ::testing::ElementsAre;
25 using ::testing::IsEmpty;
26 using ::testing::Pair;
27 using ::testing::Pointee;
28 using ::testing::UnorderedElementsAre;
34 MATCHER_P(Named, N,
"") {
return arg.Name == N; }
36 return std::make_tuple(arg.Location.Start.line(), arg.Location.Start.column(),
37 arg.Location.End.line(), arg.Location.End.column()) ==
38 std::make_tuple(
Range.start.line,
Range.start.character,
41 MATCHER_P(FileURI, F,
"") {
return StringRef(arg.Location.FileURI) == F; }
43 TEST(SymbolLocation, Position) {
44 using Position = SymbolLocation::Position;
48 EXPECT_EQ(1u, Pos.line());
50 EXPECT_EQ(2u, Pos.column());
51 EXPECT_FALSE(Pos.hasOverflow());
53 Pos.setLine(Position::MaxLine + 1);
54 EXPECT_TRUE(Pos.hasOverflow());
55 EXPECT_EQ(Pos.line(), Position::MaxLine);
58 Pos.setColumn(Position::MaxColumn + 1);
59 EXPECT_TRUE(Pos.hasOverflow());
60 EXPECT_EQ(Pos.column(), Position::MaxColumn);
63 TEST(SymbolSlab, FindAndIterate) {
68 EXPECT_EQ(
nullptr, B.find(
SymbolID(
"W")));
69 for (
const char *Sym : {
"X",
"Y",
"Z"})
70 EXPECT_THAT(B.find(
SymbolID(Sym)), Pointee(Named(Sym)));
72 SymbolSlab S = std::move(B).build();
73 EXPECT_THAT(S, UnorderedElementsAre(Named(
"X"), Named(
"Y"), Named(
"Z")));
74 EXPECT_EQ(S.end(), S.find(
SymbolID(
"W")));
75 for (
const char *Sym : {
"X",
"Y",
"Z"})
76 EXPECT_THAT(*S.find(
SymbolID(Sym)), Named(Sym));
79 TEST(RelationSlab, Lookup) {
86 Builder.insert(Relation{A, index::SymbolRole::RelationBaseOf, B});
87 Builder.insert(Relation{A, index::SymbolRole::RelationBaseOf, C});
88 Builder.insert(Relation{B, index::SymbolRole::RelationBaseOf,
D});
89 Builder.insert(Relation{C, index::SymbolRole::RelationBaseOf,
D});
90 Builder.insert(Relation{B, index::SymbolRole::RelationChildOf, A});
91 Builder.insert(Relation{C, index::SymbolRole::RelationChildOf, A});
92 Builder.insert(Relation{
D, index::SymbolRole::RelationChildOf, B});
93 Builder.insert(Relation{
D, index::SymbolRole::RelationChildOf, C});
95 RelationSlab Slab = std::move(Builder).build();
97 Slab.lookup(A, index::SymbolRole::RelationBaseOf),
98 UnorderedElementsAre(Relation{A, index::SymbolRole::RelationBaseOf, B},
99 Relation{A, index::SymbolRole::RelationBaseOf, C}));
102 TEST(RelationSlab, Duplicates) {
108 Builder.insert(Relation{A, index::SymbolRole::RelationBaseOf, B});
109 Builder.insert(Relation{A, index::SymbolRole::RelationBaseOf, C});
110 Builder.insert(Relation{A, index::SymbolRole::RelationBaseOf, B});
112 RelationSlab Slab = std::move(Builder).build();
113 EXPECT_THAT(Slab, UnorderedElementsAre(
114 Relation{A, index::SymbolRole::RelationBaseOf, B},
115 Relation{A, index::SymbolRole::RelationBaseOf, C}));
118 TEST(SwapIndexTest, OldIndexRecycled) {
119 auto Token = std::make_shared<int>();
120 std::weak_ptr<int> WeakToken = Token;
122 SwapIndex S(llvm::make_unique<MemIndex>(SymbolSlab(), RefSlab(),
123 RelationSlab(), std::move(Token),
125 EXPECT_FALSE(WeakToken.expired());
126 S.reset(llvm::make_unique<MemIndex>());
127 EXPECT_TRUE(WeakToken.expired());
130 TEST(MemIndexTest, MemIndexDeduplicate) {
133 FuzzyFindRequest Req;
136 MemIndex I(Symbols, RefSlab(), RelationSlab());
137 EXPECT_THAT(
match(I, Req), ElementsAre(
"2"));
140 TEST(MemIndexTest, MemIndexLimitedNumMatches) {
143 FuzzyFindRequest Req;
148 auto Matches =
match(*I, Req, &Incomplete);
149 EXPECT_TRUE(Req.Limit);
150 EXPECT_EQ(Matches.size(), *Req.Limit);
151 EXPECT_TRUE(Incomplete);
154 TEST(MemIndexTest, FuzzyMatch) {
156 generateSymbols({
"LaughingOutLoud",
"LionPopulation",
"LittleOldLady"}),
157 RefSlab(), RelationSlab());
158 FuzzyFindRequest Req;
162 EXPECT_THAT(
match(*I, Req),
163 UnorderedElementsAre(
"LaughingOutLoud",
"LittleOldLady"));
166 TEST(MemIndexTest, MatchQualifiedNamesWithoutSpecificScope) {
169 FuzzyFindRequest Req;
172 EXPECT_THAT(
match(*I, Req), UnorderedElementsAre(
"a::y1",
"b::y2",
"y3"));
175 TEST(MemIndexTest, MatchQualifiedNamesWithGlobalScope) {
178 FuzzyFindRequest Req;
181 EXPECT_THAT(
match(*I, Req), UnorderedElementsAre(
"y3"));
184 TEST(MemIndexTest, MatchQualifiedNamesWithOneScope) {
188 FuzzyFindRequest Req;
190 Req.Scopes = {
"a::"};
191 EXPECT_THAT(
match(*I, Req), UnorderedElementsAre(
"a::y1",
"a::y2"));
194 TEST(MemIndexTest, MatchQualifiedNamesWithMultipleScopes) {
198 FuzzyFindRequest Req;
200 Req.Scopes = {
"a::",
"b::"};
201 EXPECT_THAT(
match(*I, Req), UnorderedElementsAre(
"a::y1",
"a::y2",
"b::y3"));
204 TEST(MemIndexTest, NoMatchNestedScopes) {
207 FuzzyFindRequest Req;
209 Req.Scopes = {
"a::"};
210 EXPECT_THAT(
match(*I, Req), UnorderedElementsAre(
"a::y1"));
213 TEST(MemIndexTest, IgnoreCases) {
216 FuzzyFindRequest Req;
218 Req.Scopes = {
"ns::"};
219 EXPECT_THAT(
match(*I, Req), UnorderedElementsAre(
"ns::ABC",
"ns::abc"));
222 TEST(MemIndexTest, Lookup) {
225 EXPECT_THAT(
lookup(*I,
SymbolID(
"ns::abc")), UnorderedElementsAre(
"ns::abc"));
227 UnorderedElementsAre(
"ns::abc",
"ns::xyz"));
229 UnorderedElementsAre(
"ns::xyz"));
230 EXPECT_THAT(
lookup(*I,
SymbolID(
"ns::nonono")), UnorderedElementsAre());
233 TEST(MemIndexTest, TemplateSpecialization) {
236 Symbol S =
symbol(
"TempSpec");
242 S.TemplateSpecializationArgs =
"<int, bool>";
243 S.SymInfo.Properties =
static_cast<index::SymbolPropertySet
>(
244 index::SymbolProperty::TemplateSpecialization);
249 S.TemplateSpecializationArgs =
"<int, U>";
250 S.SymInfo.Properties =
static_cast<index::SymbolPropertySet
>(
251 index::SymbolProperty::TemplatePartialSpecialization);
254 auto I =
MemIndex::build(std::move(B).build(), RefSlab(), RelationSlab());
255 FuzzyFindRequest Req;
258 Req.Query =
"TempSpec";
259 EXPECT_THAT(
match(*I, Req),
260 UnorderedElementsAre(
"TempSpec",
"TempSpec<int, bool>",
261 "TempSpec<int, U>"));
264 Req.Query =
"TempSpec<int";
265 EXPECT_THAT(
match(*I, Req), IsEmpty());
268 TEST(MergeIndexTest, Lookup) {
273 MergedIndex M(I.get(), J.get());
274 EXPECT_THAT(
lookup(M,
SymbolID(
"ns::A")), UnorderedElementsAre(
"ns::A"));
275 EXPECT_THAT(
lookup(M,
SymbolID(
"ns::B")), UnorderedElementsAre(
"ns::B"));
276 EXPECT_THAT(
lookup(M,
SymbolID(
"ns::C")), UnorderedElementsAre(
"ns::C"));
278 UnorderedElementsAre(
"ns::A",
"ns::B"));
280 UnorderedElementsAre(
"ns::A",
"ns::C"));
281 EXPECT_THAT(
lookup(M,
SymbolID(
"ns::D")), UnorderedElementsAre());
282 EXPECT_THAT(
lookup(M, {}), UnorderedElementsAre());
285 TEST(MergeIndexTest, FuzzyFind) {
290 FuzzyFindRequest Req;
291 Req.Scopes = {
"ns::"};
292 EXPECT_THAT(
match(MergedIndex(I.get(), J.get()), Req),
293 UnorderedElementsAre(
"ns::A",
"ns::B",
"ns::C"));
296 TEST(MergeTest, Merge) {
299 L.Name = R.Name =
"Foo";
300 L.CanonicalDeclaration.FileURI =
"file:///left.h";
301 R.CanonicalDeclaration.FileURI =
"file:///right.h";
305 R.CompletionSnippetSuffix =
"{$1:0}";
306 R.Documentation =
"--doc--";
309 R.Type =
"expectedType";
312 EXPECT_EQ(M.Name,
"Foo");
313 EXPECT_EQ(StringRef(M.CanonicalDeclaration.FileURI),
"file:///left.h");
314 EXPECT_EQ(M.References, 3u);
315 EXPECT_EQ(M.Signature,
"()");
316 EXPECT_EQ(M.CompletionSnippetSuffix,
"{$1:0}");
317 EXPECT_EQ(M.Documentation,
"--doc--");
318 EXPECT_EQ(M.Type,
"expectedType");
323 TEST(MergeTest, PreferSymbolWithDefn) {
327 L.CanonicalDeclaration.FileURI =
"file:/left.h";
328 R.CanonicalDeclaration.FileURI =
"file:/right.h";
333 EXPECT_EQ(StringRef(M.CanonicalDeclaration.FileURI),
"file:/left.h");
334 EXPECT_EQ(StringRef(M.Definition.FileURI),
"");
335 EXPECT_EQ(M.Name,
"left");
337 R.Definition.FileURI =
"file:/right.cpp";
339 EXPECT_EQ(StringRef(M.CanonicalDeclaration.FileURI),
"file:/right.h");
340 EXPECT_EQ(StringRef(M.Definition.FileURI),
"file:/right.cpp");
341 EXPECT_EQ(M.Name,
"right");
344 TEST(MergeTest, PreferSymbolLocationInCodegenFile) {
348 L.CanonicalDeclaration.FileURI =
"file:/x.proto.h";
349 R.CanonicalDeclaration.FileURI =
"file:/x.proto";
352 EXPECT_EQ(StringRef(M.CanonicalDeclaration.FileURI),
"file:/x.proto");
355 L.CanonicalDeclaration.FileURI =
"file:/y.proto";
357 EXPECT_EQ(StringRef(M.CanonicalDeclaration.FileURI),
"file:/y.proto");
362 FileIndex StaticIndex;
363 MergedIndex
Merge(&Dyn, &StaticIndex);
365 const char *HeaderCode =
"class Foo;";
370 Annotations Test1Code(R
"(class $Foo[[Foo]];)"); 372 Test.HeaderCode = HeaderCode; 373 Test.Code = Test1Code.code(); 374 Test.Filename = "test.cc";
375 auto AST = Test.
build();
376 Dyn.updateMain(Test.Filename, AST);
379 Test.HeaderCode = HeaderCode;
380 Test.Code =
"// static\nclass Foo {};";
381 Test.Filename =
"test.cc";
382 auto StaticAST = Test.build();
384 StaticIndex.updateMain(Test.Filename, StaticAST);
387 Annotations Test2Code(R
"(class $Foo[[Foo]] {};)"); 389 Test2.HeaderCode = HeaderCode; 390 Test2.Code = Test2Code.code(); 391 Test2.Filename = "test2.cc";
392 StaticAST = Test2.build();
393 StaticIndex.updateMain(Test2.Filename, StaticAST);
396 Request.IDs = {Foo.ID};
398 Merge.refs(Request, [&](
const Ref &O) { Results.insert(Foo.ID, O); });
400 std::move(Results).build(),
402 _, UnorderedElementsAre(AllOf(RefRange(Test1Code.range(
"Foo")),
403 FileURI(
"unittest:///test.cc")),
404 AllOf(RefRange(Test2Code.range(
"Foo")),
405 FileURI(
"unittest:///test2.cc"))))));
409 Merge.refs(Request, [&](
const Ref &O) { Results2.insert(Foo.ID, O); });
410 EXPECT_THAT(std::move(Results2).build(),
412 _, ElementsAre(AnyOf(FileURI(
"unittest:///test.cc"),
413 FileURI(
"unittest:///test2.cc"))))));
420 TEST(MergeTest, MergeIncludesOnDifferentDefinitions) {
425 L.IncludeHeaders.emplace_back(
"common", 1);
426 R.IncludeHeaders.emplace_back(
"common", 1);
427 R.IncludeHeaders.emplace_back(
"new", 1);
431 EXPECT_THAT(M.IncludeHeaders,
432 UnorderedElementsAre(IncludeHeaderWithRef(
"common", 2u),
433 IncludeHeaderWithRef(
"new", 1u)));
436 L.Definition.FileURI =
"file:/left.h";
438 EXPECT_THAT(M.IncludeHeaders,
439 UnorderedElementsAre(IncludeHeaderWithRef(
"common", 2u)));
442 R.Definition.FileURI =
"file:/right.h";
444 EXPECT_THAT(M.IncludeHeaders,
445 UnorderedElementsAre(IncludeHeaderWithRef(
"common", 2u),
446 IncludeHeaderWithRef(
"new", 1u)));
449 R.Definition.FileURI =
"file:/right.h";
451 EXPECT_THAT(M.IncludeHeaders,
452 UnorderedElementsAre(IncludeHeaderWithRef(
"common", 2u),
453 IncludeHeaderWithRef(
"new", 1u)));
Symbol symbol(llvm::StringRef QName)
static llvm::Optional< ParsedAST > build(std::unique_ptr< clang::CompilerInvocation > CI, std::shared_ptr< const PreambleData > Preamble, std::unique_ptr< llvm::MemoryBuffer > Buffer, IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, const SymbolIndex *Index, const ParseOptions &Opts)
Attempts to run Clang and store parsed AST.
std::vector< CodeCompletionResult > Results
static std::unique_ptr< SymbolIndex > build(SymbolSlab Symbols, RefSlab Refs, RelationSlab Relations)
Builds an index from slabs. The index takes ownership of the data.
static TestTU withHeaderCode(llvm::StringRef HeaderCode)
std::vector< std::string > lookup(const SymbolIndex &I, llvm::ArrayRef< SymbolID > IDs)
TEST(BackgroundQueueTest, Priority)
std::vector< std::string > match(const SymbolIndex &I, const FuzzyFindRequest &Req, bool *Incomplete)
SymbolSlab generateSymbols(std::vector< std::string > QualifiedNames)
Symbol mergeSymbol(const Symbol &L, const Symbol &R)
CodeCompletionBuilder Builder
SymbolSlab headerSymbols() const
SymbolSlab generateNumSymbols(int Begin, int End)
bool Merge(llvm::StringRef MergeDir, llvm::StringRef OutputFile)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
const Symbol & findSymbol(const SymbolSlab &Slab, llvm::StringRef QName)
CharSourceRange Range
SourceRange for the file name.
std::string IncludeHeader
std::array< uint8_t, 20 > SymbolID