15#include "clang/AST/DeclCXX.h"
16#include "clang/AST/DeclTemplate.h"
17#include "llvm/Support/Path.h"
18#include "gmock/gmock.h"
19#include "gtest/gtest.h"
26using ::testing::AllOf;
27using ::testing::ElementsAre;
28using ::testing::Field;
29using ::testing::IsEmpty;
30using ::testing::Matcher;
31using ::testing::SizeIs;
32using ::testing::UnorderedElementsAre;
35MATCHER_P(withName, N,
"") {
return arg.name == N; }
37MATCHER_P(selectionRangeIs, R,
"") {
return arg.selectionRange == R; }
38template <
class... ParentMatchers>
39::testing::Matcher<TypeHierarchyItem> parents(ParentMatchers... ParentsM) {
41 HasValue(UnorderedElementsAre(ParentsM...)));
43template <
class... ChildMatchers>
44::testing::Matcher<TypeHierarchyItem> children(ChildMatchers... ChildrenM) {
46 HasValue(UnorderedElementsAre(ChildrenM...)));
49MATCHER(parentsNotResolved,
"") {
return !arg.parents; }
50MATCHER(childrenNotResolved,
"") {
return !arg.children; }
51MATCHER_P(withResolveID, SID,
"") {
return arg.symbolID.str() == SID; }
53 return testing::ExplainMatchResult(
M, arg.data.parents, result_listener);
56TEST(FindRecordTypeAt, TypeOrVariable) {
57 Annotations Source(R
"cpp(
71 auto AST = TU.build();
73 for (Position Pt : Source.points()) {
75 ASSERT_THAT(Records, SizeIs(1));
77 static_cast<const NamedDecl *
>(Records.front()));
81TEST(FindRecordTypeAt, Nonexistent) {
82 Annotations Source(R
"cpp(
86 auto AST = TU.build();
88 for (Position Pt : Source.points()) {
90 ASSERT_THAT(Records, SizeIs(0));
95 Annotations Source(R
"cpp(
108 auto AST = TU.build();
110 for (Position Pt : Source.points()) {
112 ASSERT_THAT(Records, SizeIs(1));
114 static_cast<const NamedDecl *
>(Records.front()));
119 Annotations Source(R
"cpp(
131 auto AST = TU.build();
133 for (Position Pt : Source.points()) {
141TEST(TypeParents, SimpleInheritance) {
142 Annotations Source(R
"cpp(
147struct Child1 : Parent {
151struct Child2 : Child1 {
157 auto AST = TU.build();
159 const CXXRecordDecl *
Parent =
161 const CXXRecordDecl *Child1 =
163 const CXXRecordDecl *Child2 =
168 EXPECT_THAT(
typeParents(Child2), ElementsAre(Child1));
171TEST(TypeParents, MultipleInheritance) {
172 Annotations Source(R
"cpp(
181struct Parent3 : Parent2 {
185struct Child : Parent1, Parent3 {
191 auto AST = TU.build();
193 const CXXRecordDecl *Parent1 =
194 dyn_cast<CXXRecordDecl>(&
findDecl(
AST,
"Parent1"));
195 const CXXRecordDecl *Parent2 =
196 dyn_cast<CXXRecordDecl>(&
findDecl(
AST,
"Parent2"));
197 const CXXRecordDecl *Parent3 =
198 dyn_cast<CXXRecordDecl>(&
findDecl(
AST,
"Parent3"));
199 const CXXRecordDecl *Child = dyn_cast<CXXRecordDecl>(&
findDecl(
AST,
"Child"));
203 EXPECT_THAT(
typeParents(Parent3), ElementsAre(Parent2));
204 EXPECT_THAT(
typeParents(Child), ElementsAre(Parent1, Parent3));
207TEST(TypeParents, ClassTemplate) {
208 Annotations Source(R
"cpp(
212struct Child : Parent {};
216 auto AST = TU.build();
218 const CXXRecordDecl *
Parent =
220 const CXXRecordDecl *Child =
221 dyn_cast<ClassTemplateDecl>(&
findDecl(
AST,
"Child"))->getTemplatedDecl();
226MATCHER_P(implicitSpecOf, ClassTemplate,
"") {
227 const ClassTemplateSpecializationDecl *CTS =
228 dyn_cast<ClassTemplateSpecializationDecl>(arg);
230 CTS->getSpecializedTemplate()->getTemplatedDecl() == ClassTemplate &&
231 CTS->getSpecializationKind() == TSK_ImplicitInstantiation;
236const NamedDecl &findDeclWithTemplateArgs(ParsedAST &
AST,
237 llvm::StringRef Query) {
238 return findDecl(
AST, [&Query](
const NamedDecl &ND) {
240 llvm::raw_string_ostream
OS(QName);
241 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
244 ND.getNameForDiagnostic(
OS, Policy,
true);
246 return QName == Query;
250TEST(TypeParents, TemplateSpec1) {
251 Annotations Source(R
"cpp(
256struct Parent<int> {};
258struct Child1 : Parent<float> {};
260struct Child2 : Parent<int> {};
264 auto AST = TU.build();
266 const CXXRecordDecl *
Parent =
267 dyn_cast<ClassTemplateDecl>(&
findDecl(
AST,
"Parent"))->getTemplatedDecl();
268 const CXXRecordDecl *ParentSpec =
269 dyn_cast<CXXRecordDecl>(&findDeclWithTemplateArgs(
AST,
"Parent<int>"));
270 const CXXRecordDecl *Child1 =
272 const CXXRecordDecl *Child2 =
276 EXPECT_THAT(
typeParents(Child2), ElementsAre(ParentSpec));
279TEST(TypeParents, TemplateSpec2) {
280 Annotations Source(R
"cpp(
287struct Child<int> : Parent {};
291 auto AST = TU.build();
293 const CXXRecordDecl *
Parent =
295 const CXXRecordDecl *Child =
296 dyn_cast<ClassTemplateDecl>(&
findDecl(
AST,
"Child"))->getTemplatedDecl();
297 const CXXRecordDecl *ChildSpec =
298 dyn_cast<CXXRecordDecl>(&findDeclWithTemplateArgs(
AST,
"Child<int>"));
304TEST(TypeParents, DependentBase) {
305 Annotations Source(R
"cpp(
310struct Child1 : Parent<T> {};
313struct Child2 : Parent<T>::Type {};
320 auto AST = TU.build();
322 const CXXRecordDecl *
Parent =
323 dyn_cast<ClassTemplateDecl>(&
findDecl(
AST,
"Parent"))->getTemplatedDecl();
324 const CXXRecordDecl *Child1 =
325 dyn_cast<ClassTemplateDecl>(&
findDecl(
AST,
"Child1"))->getTemplatedDecl();
326 const CXXRecordDecl *Child2 =
327 dyn_cast<ClassTemplateDecl>(&
findDecl(
AST,
"Child2"))->getTemplatedDecl();
328 const CXXRecordDecl *Child3 =
329 dyn_cast<ClassTemplateDecl>(&
findDecl(
AST,
"Child3"))->getTemplatedDecl();
339TEST(TypeParents, IncompleteClass) {
340 Annotations Source(R
"cpp(
344 auto AST = TU.build();
346 const CXXRecordDecl *Incomplete =
347 dyn_cast<CXXRecordDecl>(&
findDecl(
AST,
"Incomplete"));
355 Annotations Source(R
"cpp(
356struct $Parent1Def[[Parent1]] {
360struct $Parent2Def[[Parent2]] {
364struct $Parent3Def[[Parent3]] : Parent2 {
368struct Ch^ild : Parent1, Parent3 {
380 auto AST = TU.build();
382 for (Position Pt : Source.points()) {
387 ASSERT_THAT(Result, SizeIs(1));
391 withName(
"Child"), withKind(SymbolKind::Struct),
392 parents(AllOf(withName(
"Parent1"), withKind(SymbolKind::Struct),
393 selectionRangeIs(Source.range(
"Parent1Def")),
395 AllOf(withName(
"Parent3"), withKind(SymbolKind::Struct),
396 selectionRangeIs(Source.range(
"Parent3Def")),
398 withName(
"Parent2"), withKind(SymbolKind::Struct),
399 selectionRangeIs(Source.range(
"Parent2Def")),
404TEST(TypeHierarchy, RecursiveHierarchyUnbounded) {
405 Annotations Source(R
"cpp(
407 struct $SDef[[S]] : S<N + 1> {};
413 TU.ExtraArgs.push_back("-ftemplate-depth=10");
414 auto AST = TU.build();
418 ASSERT_FALSE(
AST.getDiagnostics().empty());
426 ASSERT_THAT(Result, SizeIs(1));
429 AllOf(withName(
"S<0>"), withKind(SymbolKind::Struct),
431 AllOf(withName(
"S"), withKind(SymbolKind::Struct),
432 selectionRangeIs(Source.range(
"SDef")),
433 parents(AllOf(withName(
"S"), withKind(SymbolKind::Struct),
434 selectionRangeIs(Source.range(
"SDef")),
438TEST(TypeHierarchy, RecursiveHierarchyBounded) {
439 Annotations Source(R
"cpp(
441 struct $SDef[[S]] : S<N - 1> {};
446 S$SRefConcrete^<2> s;
450 S$SRefDependent^<N> s;
454 auto AST = TU.build();
460 ASSERT_THAT(Result, SizeIs(1));
463 AllOf(withName(
"S<2>"), withKind(SymbolKind::Struct),
465 withName(
"S<1>"), withKind(SymbolKind::Struct),
466 selectionRangeIs(Source.range(
"SDef")),
467 parents(AllOf(withName(
"S<0>"), withKind(SymbolKind::Struct),
471 ASSERT_THAT(Result, SizeIs(1));
474 AllOf(withName(
"S"), withKind(SymbolKind::Struct),
475 parents(AllOf(withName(
"S"), withKind(SymbolKind::Struct),
476 selectionRangeIs(Source.range(
"SDef")), parents()))));
479TEST(TypeHierarchy, DeriveFromImplicitSpec) {
480 Annotations Source(R
"cpp(
481 template <typename T>
484 struct Child1 : Parent<int> {};
486 struct Child2 : Parent<char> {};
492 auto AST = TU.build();
493 auto Index = TU.index();
498 ASSERT_THAT(Result, SizeIs(1));
499 EXPECT_THAT(Result.front(),
500 AllOf(withName(
"Parent"), withKind(SymbolKind::Struct),
501 children(AllOf(withName(
"Child1"),
502 withKind(SymbolKind::Struct), children()),
503 AllOf(withName(
"Child2"),
504 withKind(SymbolKind::Struct), children()))));
507TEST(TypeHierarchy, DeriveFromPartialSpec) {
508 Annotations Source(R
"cpp(
509 template <typename T> struct Parent {};
510 template <typename T> struct Parent<T*> {};
512 struct Child : Parent<int*> {};
518 auto AST = TU.build();
519 auto Index = TU.index();
524 ASSERT_THAT(Result, SizeIs(1));
525 EXPECT_THAT(Result.front(), AllOf(withName(
"Parent"),
526 withKind(SymbolKind::Struct), children()));
529TEST(TypeHierarchy, DeriveFromTemplate) {
530 Annotations Source(R
"cpp(
531 template <typename T>
534 template <typename T>
535 struct Child : Parent<T> {};
541 auto AST = TU.build();
542 auto Index = TU.index();
550 ASSERT_THAT(Result, SizeIs(1));
551 EXPECT_THAT(Result.front(),
552 AllOf(withName(
"Parent"), withKind(SymbolKind::Struct),
553 children(AllOf(withName(
"Child"),
554 withKind(SymbolKind::Struct), children()))));
558 Annotations SourceAnnotations(R
"cpp(
559struct Ch^ild : Parent {
563 Annotations HeaderInPreambleAnnotations(R"cpp(
569 TU.HeaderCode = HeaderInPreambleAnnotations.code().str();
570 auto AST = TU.build();
575 ASSERT_THAT(Result, SizeIs(1));
578 AllOf(withName(
"Child"),
579 parents(AllOf(withName(
"Parent"),
580 selectionRangeIs(HeaderInPreambleAnnotations.range()),
584SymbolID findSymbolIDByName(SymbolIndex *Index, llvm::StringRef
Name,
585 llvm::StringRef TemplateArgs =
"") {
587 FuzzyFindRequest Request;
588 Request.Query = std::string(
Name);
589 Request.AnyScope =
true;
590 bool GotResult =
false;
591 Index->fuzzyFind(Request, [&](
const Symbol &S) {
592 if (TemplateArgs == S.TemplateSpecializationArgs) {
593 EXPECT_FALSE(GotResult);
598 EXPECT_TRUE(GotResult);
602std::vector<SymbolID> collectSubtypes(SymbolID Subject, SymbolIndex *Index) {
603 std::vector<SymbolID> Result;
604 RelationsRequest Req;
605 Req.Subjects.insert(Subject);
607 Index->relations(Req,
608 [&Result](
const SymbolID &Subject,
const Symbol &
Object) {
609 Result.push_back(
Object.ID);
614TEST(Subtypes, SimpleInheritance) {
615 Annotations Source(R
"cpp(
617struct Child1a : Parent {};
618struct Child1b : Parent {};
619struct Child2 : Child1a {};
623 auto Index = TU.index();
626 SymbolID Child1a = findSymbolIDByName(Index.get(),
"Child1a");
627 SymbolID Child1b = findSymbolIDByName(Index.get(),
"Child1b");
628 SymbolID Child2 = findSymbolIDByName(Index.get(),
"Child2");
630 EXPECT_THAT(collectSubtypes(
Parent, Index.get()),
631 UnorderedElementsAre(Child1a, Child1b));
632 EXPECT_THAT(collectSubtypes(Child1a, Index.get()), ElementsAre(Child2));
635TEST(Subtypes, MultipleInheritance) {
636 Annotations Source(R
"cpp(
639struct Parent3 : Parent2 {};
640struct Child : Parent1, Parent3 {};
644 auto Index = TU.index();
646 SymbolID Parent1 = findSymbolIDByName(Index.get(),
"Parent1");
647 SymbolID Parent2 = findSymbolIDByName(Index.get(),
"Parent2");
648 SymbolID Parent3 = findSymbolIDByName(Index.get(),
"Parent3");
649 SymbolID Child = findSymbolIDByName(Index.get(),
"Child");
651 EXPECT_THAT(collectSubtypes(Parent1, Index.get()), ElementsAre(Child));
652 EXPECT_THAT(collectSubtypes(Parent2, Index.get()), ElementsAre(Parent3));
653 EXPECT_THAT(collectSubtypes(Parent3, Index.get()), ElementsAre(Child));
656TEST(Subtypes, ClassTemplate) {
657 Annotations Source(R
"cpp(
661struct Child : Parent {};
665 auto Index = TU.index();
668 SymbolID Child = findSymbolIDByName(Index.get(),
"Child");
670 EXPECT_THAT(collectSubtypes(
Parent, Index.get()), ElementsAre(Child));
673TEST(Subtypes, TemplateSpec1) {
674 Annotations Source(R
"cpp(
679struct Parent<int> {};
681struct Child1 : Parent<float> {};
683struct Child2 : Parent<int> {};
687 auto Index = TU.index();
690 SymbolID ParentSpec = findSymbolIDByName(Index.get(),
"Parent",
"<int>");
691 SymbolID Child1 = findSymbolIDByName(Index.get(),
"Child1");
692 SymbolID Child2 = findSymbolIDByName(Index.get(),
"Child2");
694 EXPECT_THAT(collectSubtypes(
Parent, Index.get()), ElementsAre(Child1));
695 EXPECT_THAT(collectSubtypes(ParentSpec, Index.get()), ElementsAre(Child2));
698TEST(Subtypes, TemplateSpec2) {
699 Annotations Source(R
"cpp(
706struct Child<int> : Parent {};
710 auto Index = TU.index();
713 SymbolID ChildSpec = findSymbolIDByName(Index.get(),
"Child",
"<int>");
715 EXPECT_THAT(collectSubtypes(
Parent, Index.get()), ElementsAre(ChildSpec));
718TEST(Subtypes, DependentBase) {
719 Annotations Source(R
"cpp(
724struct Child : Parent<T> {};
728 auto Index = TU.index();
731 SymbolID Child = findSymbolIDByName(Index.get(),
"Child");
733 EXPECT_THAT(collectSubtypes(
Parent, Index.get()), ElementsAre(Child));
736TEST(Subtypes, LazyResolution) {
737 Annotations Source(R
"cpp(
739struct Child1 : Parent {};
740struct Child2a : Child1 {};
741struct Child2b : Child1 {};
745 auto AST = TU.build();
746 auto Index = TU.index();
751 ASSERT_THAT(Result, SizeIs(1));
754 AllOf(withName(
"Parent"), withKind(SymbolKind::Struct), parents(),
755 children(AllOf(withName(
"Child1"), withKind(SymbolKind::Struct),
756 parentsNotResolved(), childrenNotResolved()))));
762 (*Result.front().children)[0],
763 AllOf(withName(
"Child1"), withKind(SymbolKind::Struct),
764 parentsNotResolved(),
765 children(AllOf(withName(
"Child2a"), withKind(SymbolKind::Struct),
766 parentsNotResolved(), childrenNotResolved()),
767 AllOf(withName(
"Child2b"), withKind(SymbolKind::Struct),
768 parentsNotResolved(), childrenNotResolved()))));
772 Annotations Source(R
"cpp(
775struct Child : Parent1, Parent2 {};
779 auto AST = TU.build();
780 auto Index = TU.index();
785 ASSERT_THAT(Result, SizeIs(1));
792 UnorderedElementsAre(
793 AllOf(withName(
"Child"),
794 withResolveParents(
HasValue(UnorderedElementsAre(withResolveID(
799 Annotations Source(R
"cpp(
801struct Chil^d : Parent {};
805 auto AST = TU.build();
806 auto Index = TU.index();
811 ASSERT_THAT(Result, SizeIs(1));
815 AllOf(withName(
"Parent"),
816 withResolveParents(
HasValue(IsEmpty()))))));
llvm::SmallString< 256U > Name
const google::protobuf::Message & M
llvm::raw_string_ostream OS
std::vector< TypeHierarchyItem > subTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct children of a TypeHierarchyItem.
std::optional< std::vector< TypeHierarchyItem > > superTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index)
Returns direct parents of a TypeHierarchyItem using SymbolIDs stored inside the item.
SymbolID getSymbolID(const Decl *D)
Gets the symbol ID for a declaration. Returned SymbolID might be null.
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
OptionalMatcher< InnerMatcher > HasValue(const InnerMatcher &inner_matcher)
std::vector< TypeHierarchyItem > getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index, PathRef TUPath)
Get type hierarchy information at Pos.
std::string testPath(PathRef File, llvm::sys::path::Style Style)
TEST(BackgroundQueueTest, Priority)
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
std::vector< const CXXRecordDecl * > findRecordTypeAt(ParsedAST &AST, Position Pos)
Find the record types referenced at Pos.
std::vector< const CXXRecordDecl * > typeParents(const CXXRecordDecl *CXXRD)
Given a record type declaration, find its base (parent) types.
std::array< uint8_t, 20 > SymbolID
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static TestTU withCode(llvm::StringRef Code)
std::optional< std::vector< TypeHierarchyItem > > children
If this type hierarchy item is resolved, it contains the direct children of the current item.
std::optional< std::vector< TypeHierarchyItem > > parents
This is a clangd exntesion.