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;
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"})
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) {
91 RelationSlab Slab = std::move(
Builder).build();
97 TEST(RelationSlab, Duplicates) {
107 RelationSlab Slab = std::move(
Builder).build();
112 TEST(SwapIndexTest, OldIndexRecycled) {
113 auto Token = std::make_shared<int>();
114 std::weak_ptr<int> WeakToken = Token;
116 SwapIndex S(std::make_unique<MemIndex>(SymbolSlab(), RefSlab(),
117 RelationSlab(), std::move(Token),
119 EXPECT_FALSE(WeakToken.expired());
120 S.reset(std::make_unique<MemIndex>());
121 EXPECT_TRUE(WeakToken.expired());
124 TEST(MemIndexTest, MemIndexDeduplicate) {
127 FuzzyFindRequest Req;
130 MemIndex I(
Symbols, RefSlab(), RelationSlab());
131 EXPECT_THAT(
match(I, Req), ElementsAre(
"2"));
134 TEST(MemIndexTest, MemIndexLimitedNumMatches) {
137 FuzzyFindRequest Req;
142 auto Matches =
match(*I, Req, &Incomplete);
143 EXPECT_TRUE(Req.Limit);
144 EXPECT_EQ(Matches.size(), *Req.Limit);
145 EXPECT_TRUE(Incomplete);
148 TEST(MemIndexTest, FuzzyMatch) {
150 generateSymbols({
"LaughingOutLoud",
"LionPopulation",
"LittleOldLady"}),
151 RefSlab(), RelationSlab());
152 FuzzyFindRequest Req;
156 EXPECT_THAT(
match(*I, Req),
157 UnorderedElementsAre(
"LaughingOutLoud",
"LittleOldLady"));
160 TEST(MemIndexTest, MatchQualifiedNamesWithoutSpecificScope) {
163 FuzzyFindRequest Req;
166 EXPECT_THAT(
match(*I, Req), UnorderedElementsAre(
"a::y1",
"b::y2",
"y3"));
169 TEST(MemIndexTest, MatchQualifiedNamesWithGlobalScope) {
172 FuzzyFindRequest Req;
175 EXPECT_THAT(
match(*I, Req), UnorderedElementsAre(
"y3"));
178 TEST(MemIndexTest, MatchQualifiedNamesWithOneScope) {
182 FuzzyFindRequest Req;
184 Req.Scopes = {
"a::"};
185 EXPECT_THAT(
match(*I, Req), UnorderedElementsAre(
"a::y1",
"a::y2"));
188 TEST(MemIndexTest, MatchQualifiedNamesWithMultipleScopes) {
192 FuzzyFindRequest Req;
194 Req.Scopes = {
"a::",
"b::"};
195 EXPECT_THAT(
match(*I, Req), UnorderedElementsAre(
"a::y1",
"a::y2",
"b::y3"));
198 TEST(MemIndexTest, NoMatchNestedScopes) {
201 FuzzyFindRequest Req;
203 Req.Scopes = {
"a::"};
204 EXPECT_THAT(
match(*I, Req), UnorderedElementsAre(
"a::y1"));
207 TEST(MemIndexTest, IgnoreCases) {
210 FuzzyFindRequest Req;
212 Req.Scopes = {
"ns::"};
213 EXPECT_THAT(
match(*I, Req), UnorderedElementsAre(
"ns::ABC",
"ns::abc"));
216 TEST(MemIndexTest, Lookup) {
219 EXPECT_THAT(
lookup(*I,
SymbolID(
"ns::abc")), UnorderedElementsAre(
"ns::abc"));
221 UnorderedElementsAre(
"ns::abc",
"ns::xyz"));
223 UnorderedElementsAre(
"ns::xyz"));
224 EXPECT_THAT(
lookup(*I,
SymbolID(
"ns::nonono")), UnorderedElementsAre());
227 TEST(MemIndexTest, TemplateSpecialization) {
230 Symbol S =
symbol(
"TempSpec");
236 S.TemplateSpecializationArgs =
"<int, bool>";
237 S.SymInfo.Properties = static_cast<index::SymbolPropertySet>(
238 index::SymbolProperty::TemplateSpecialization);
243 S.TemplateSpecializationArgs =
"<int, U>";
244 S.SymInfo.Properties = static_cast<index::SymbolPropertySet>(
245 index::SymbolProperty::TemplatePartialSpecialization);
248 auto I =
MemIndex::build(std::move(B).build(), RefSlab(), RelationSlab());
249 FuzzyFindRequest Req;
252 Req.Query =
"TempSpec";
253 EXPECT_THAT(
match(*I, Req),
254 UnorderedElementsAre(
"TempSpec",
"TempSpec<int, bool>",
255 "TempSpec<int, U>"));
258 Req.Query =
"TempSpec<int";
259 EXPECT_THAT(
match(*I, Req), IsEmpty());
262 TEST(MergeIndexTest, Lookup) {
267 MergedIndex M(I.get(), J.get());
268 EXPECT_THAT(
lookup(M,
SymbolID(
"ns::A")), UnorderedElementsAre(
"ns::A"));
269 EXPECT_THAT(
lookup(M,
SymbolID(
"ns::B")), UnorderedElementsAre(
"ns::B"));
270 EXPECT_THAT(
lookup(M,
SymbolID(
"ns::C")), UnorderedElementsAre(
"ns::C"));
272 UnorderedElementsAre(
"ns::A",
"ns::B"));
274 UnorderedElementsAre(
"ns::A",
"ns::C"));
275 EXPECT_THAT(
lookup(M,
SymbolID(
"ns::D")), UnorderedElementsAre());
276 EXPECT_THAT(
lookup(M, {}), UnorderedElementsAre());
279 TEST(MergeIndexTest, FuzzyFind) {
284 FuzzyFindRequest Req;
285 Req.Scopes = {
"ns::"};
286 EXPECT_THAT(
match(MergedIndex(I.get(), J.get()), Req),
287 UnorderedElementsAre(
"ns::A",
"ns::B",
"ns::C"));
290 TEST(MergeTest, Merge) {
293 L.Name = R.Name =
"Foo";
294 L.CanonicalDeclaration.FileURI =
"file:///left.h";
295 R.CanonicalDeclaration.FileURI =
"file:///right.h";
299 R.CompletionSnippetSuffix =
"{$1:0}";
300 R.Documentation =
"--doc--";
303 R.Type =
"expectedType";
306 EXPECT_EQ(M.Name,
"Foo");
307 EXPECT_EQ(StringRef(M.CanonicalDeclaration.FileURI),
"file:///left.h");
308 EXPECT_EQ(M.References, 3u);
309 EXPECT_EQ(M.Signature,
"()");
310 EXPECT_EQ(M.CompletionSnippetSuffix,
"{$1:0}");
311 EXPECT_EQ(M.Documentation,
"--doc--");
312 EXPECT_EQ(M.Type,
"expectedType");
317 TEST(MergeTest, PreferSymbolWithDefn) {
321 L.CanonicalDeclaration.FileURI =
"file:/left.h";
322 R.CanonicalDeclaration.FileURI =
"file:/right.h";
327 EXPECT_EQ(StringRef(M.CanonicalDeclaration.FileURI),
"file:/left.h");
328 EXPECT_EQ(StringRef(M.Definition.FileURI),
"");
329 EXPECT_EQ(M.Name,
"left");
331 R.Definition.FileURI =
"file:/right.cpp";
333 EXPECT_EQ(StringRef(M.CanonicalDeclaration.FileURI),
"file:/right.h");
334 EXPECT_EQ(StringRef(M.Definition.FileURI),
"file:/right.cpp");
335 EXPECT_EQ(M.Name,
"right");
338 TEST(MergeTest, PreferSymbolLocationInCodegenFile) {
342 L.CanonicalDeclaration.FileURI =
"file:/x.proto.h";
343 R.CanonicalDeclaration.FileURI =
"file:/x.proto";
346 EXPECT_EQ(StringRef(M.CanonicalDeclaration.FileURI),
"file:/x.proto");
349 L.CanonicalDeclaration.FileURI =
"file:/y.proto";
351 EXPECT_EQ(StringRef(M.CanonicalDeclaration.FileURI),
"file:/y.proto");
356 FileIndex StaticIndex;
357 MergedIndex
Merge(&Dyn, &StaticIndex);
359 const char *HeaderCode =
"class Foo;";
364 Annotations Test1Code(R
"(class $Foo[[Foo]];)");
366 Test.HeaderCode = HeaderCode;
367 Test.Code = std::string(Test1Code.code());
368 Test.Filename = "test.cc";
369 auto AST = Test.
build();
370 Dyn.updateMain(Test.Filename, AST);
373 Test.HeaderCode = HeaderCode;
374 Test.Code =
"// static\nclass Foo {};";
375 Test.Filename =
"test.cc";
376 auto StaticAST = Test.build();
378 StaticIndex.updateMain(Test.Filename, StaticAST);
381 Annotations Test2Code(R
"(class $Foo[[Foo]] {};)");
383 Test2.HeaderCode = HeaderCode;
384 Test2.Code = std::string(Test2Code.code());
385 Test2.Filename = "test2.cc";
386 StaticAST = Test2.build();
387 StaticIndex.updateMain(Test2.Filename, StaticAST);
390 Request.IDs = {Foo.ID};
393 Merge.refs(Request, [&](
const Ref &O) { Results.insert(Foo.ID, O); }));
397 _, UnorderedElementsAre(AllOf(RefRange(Test1Code.range(
"Foo")),
398 FileURI(
"unittest:///test.cc")),
399 AllOf(RefRange(Test2Code.range(
"Foo")),
400 FileURI(
"unittest:///test2.cc"))))));
405 Merge.refs(Request, [&](
const Ref &O) { Results2.insert(Foo.ID, O); }));
406 EXPECT_THAT(std::move(Results2).build(),
408 _, ElementsAre(AnyOf(FileURI(
"unittest:///test.cc"),
409 FileURI(
"unittest:///test2.cc"))))));
412 TEST(MergeIndexTest, NonDocumentation) {
416 L.Definition.FileURI =
"file:/x.h";
417 R.Documentation =
"Forward declarations because x.h is too big to include";
418 for (
auto ClassLikeKind :
420 L.SymInfo.Kind = ClassLikeKind;
425 R.Documentation =
"Documentation from non-class symbols should be included";
429 MATCHER_P2(IncludeHeaderWithRef, IncludeHeader,
References,
"") {
430 return (arg.IncludeHeader == IncludeHeader) && (arg.References ==
References);
433 TEST(MergeTest, MergeIncludesOnDifferentDefinitions) {
438 L.IncludeHeaders.emplace_back(
"common", 1);
439 R.IncludeHeaders.emplace_back(
"common", 1);
440 R.IncludeHeaders.emplace_back(
"new", 1);
444 EXPECT_THAT(M.IncludeHeaders,
445 UnorderedElementsAre(IncludeHeaderWithRef(
"common", 2u),
446 IncludeHeaderWithRef(
"new", 1u)));
449 L.Definition.FileURI =
"file:/left.h";
451 EXPECT_THAT(M.IncludeHeaders,
452 UnorderedElementsAre(IncludeHeaderWithRef(
"common", 2u)));
455 R.Definition.FileURI =
"file:/right.h";
457 EXPECT_THAT(M.IncludeHeaders,
458 UnorderedElementsAre(IncludeHeaderWithRef(
"common", 2u),
459 IncludeHeaderWithRef(
"new", 1u)));
462 R.Definition.FileURI =
"file:/right.h";
464 EXPECT_THAT(M.IncludeHeaders,
465 UnorderedElementsAre(IncludeHeaderWithRef(
"common", 2u),
466 IncludeHeaderWithRef(
"new", 1u)));