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::Optional;
32using ::testing::SizeIs;
33using ::testing::UnorderedElementsAre;
36MATCHER_P(withName, N,
"") {
return arg.name == N; }
37MATCHER_P(withKind, Kind,
"") {
return arg.kind == Kind; }
38MATCHER_P(selectionRangeIs, R,
"") {
return arg.selectionRange == R; }
39template <
class... ParentMatchers>
40::testing::Matcher<TypeHierarchyItem> parents(ParentMatchers... ParentsM) {
42 Optional(UnorderedElementsAre(ParentsM...)));
44template <
class... ChildMatchers>
45::testing::Matcher<TypeHierarchyItem> children(ChildMatchers... ChildrenM) {
47 Optional(UnorderedElementsAre(ChildrenM...)));
50MATCHER(parentsNotResolved,
"") {
return !arg.parents; }
51MATCHER(childrenNotResolved,
"") {
return !arg.children; }
52MATCHER_P(withResolveID, SID,
"") {
return arg.symbolID.str() == SID; }
54 return testing::ExplainMatchResult(M, arg.data.parents, result_listener);
57template <
typename... Tags>
58::testing::Matcher<TypeHierarchyItem> withSymbolTags(Tags... tags) {
63TEST(FindRecordTypeAt, TypeOrVariable) {
78 auto AST = TU.build();
80 for (
Position Pt : Source.points()) {
82 ASSERT_THAT(Records, SizeIs(1));
84 static_cast<const NamedDecl *
>(Records.front()));
88TEST(FindRecordTypeAt, Nonexistent) {
93 auto AST = TU.build();
95 for (
Position Pt : Source.points()) {
97 ASSERT_THAT(Records, SizeIs(0));
105 void met^hod (int x);
115 auto AST = TU.build();
117 for (
Position Pt : Source.points()) {
119 ASSERT_THAT(Records, SizeIs(1));
121 static_cast<const NamedDecl *
>(Records.front()));
138 auto AST = TU.build();
140 for (
Position Pt : Source.points()) {
148TEST(TypeParents, SimpleInheritance) {
154struct Child1 : Parent {
158struct Child2 : Child1 {
164 auto AST = TU.build();
166 const CXXRecordDecl *Parent =
168 const CXXRecordDecl *Child1 =
170 const CXXRecordDecl *Child2 =
174 EXPECT_THAT(
typeParents(Child1), ElementsAre(Parent));
175 EXPECT_THAT(
typeParents(Child2), ElementsAre(Child1));
178TEST(TypeParents, MultipleInheritance) {
188struct Parent3 : Parent2 {
192struct Child : Parent1, Parent3 {
198 auto AST = TU.build();
200 const CXXRecordDecl *Parent1 =
201 dyn_cast<CXXRecordDecl>(&
findDecl(
AST,
"Parent1"));
202 const CXXRecordDecl *Parent2 =
203 dyn_cast<CXXRecordDecl>(&
findDecl(
AST,
"Parent2"));
204 const CXXRecordDecl *Parent3 =
205 dyn_cast<CXXRecordDecl>(&
findDecl(
AST,
"Parent3"));
206 const CXXRecordDecl *Child = dyn_cast<CXXRecordDecl>(&
findDecl(
AST,
"Child"));
210 EXPECT_THAT(
typeParents(Parent3), ElementsAre(Parent2));
211 EXPECT_THAT(
typeParents(Child), ElementsAre(Parent1, Parent3));
214TEST(TypeParents, ClassTemplate) {
219struct Child : Parent {};
223 auto AST = TU.build();
225 const CXXRecordDecl *Parent =
227 const CXXRecordDecl *Child =
228 dyn_cast<ClassTemplateDecl>(&
findDecl(
AST,
"Child"))->getTemplatedDecl();
230 EXPECT_THAT(
typeParents(Child), ElementsAre(Parent));
233MATCHER_P(implicitSpecOf, ClassTemplate,
"") {
234 const ClassTemplateSpecializationDecl *CTS =
235 dyn_cast<ClassTemplateSpecializationDecl>(arg);
237 CTS->getSpecializedTemplate()->getTemplatedDecl() == ClassTemplate &&
238 CTS->getSpecializationKind() == TSK_ImplicitInstantiation;
243const NamedDecl &findDeclWithTemplateArgs(
ParsedAST &
AST,
244 llvm::StringRef Query) {
245 return findDecl(
AST, [&Query](
const NamedDecl &ND) {
247 llvm::raw_string_ostream OS(QName);
248 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
251 ND.getNameForDiagnostic(OS, Policy,
true);
252 return QName == Query;
256TEST(TypeParents, TemplateSpec1) {
262struct Parent<int> {};
264struct Child1 : Parent<float> {};
266struct Child2 : Parent<int> {};
270 auto AST = TU.build();
272 const CXXRecordDecl *Parent =
273 dyn_cast<ClassTemplateDecl>(&
findDecl(
AST,
"Parent"))->getTemplatedDecl();
274 const CXXRecordDecl *ParentSpec =
275 dyn_cast<CXXRecordDecl>(&findDeclWithTemplateArgs(
AST,
"Parent<int>"));
276 const CXXRecordDecl *Child1 =
278 const CXXRecordDecl *Child2 =
281 EXPECT_THAT(
typeParents(Child1), ElementsAre(implicitSpecOf(Parent)));
282 EXPECT_THAT(
typeParents(Child2), ElementsAre(ParentSpec));
285TEST(TypeParents, TemplateSpec2) {
293struct Child<int> : Parent {};
297 auto AST = TU.build();
299 const CXXRecordDecl *Parent =
301 const CXXRecordDecl *Child =
302 dyn_cast<ClassTemplateDecl>(&
findDecl(
AST,
"Child"))->getTemplatedDecl();
303 const CXXRecordDecl *ChildSpec =
304 dyn_cast<CXXRecordDecl>(&findDeclWithTemplateArgs(
AST,
"Child<int>"));
307 EXPECT_THAT(
typeParents(ChildSpec), ElementsAre(Parent));
310TEST(TypeParents, DependentBase) {
316struct Child1 : Parent<T> {};
319struct Child2 : Parent<T>::Type {};
326 auto AST = TU.build();
328 const CXXRecordDecl *Parent =
329 dyn_cast<ClassTemplateDecl>(&
findDecl(
AST,
"Parent"))->getTemplatedDecl();
330 const CXXRecordDecl *Child1 =
331 dyn_cast<ClassTemplateDecl>(&
findDecl(
AST,
"Child1"))->getTemplatedDecl();
332 const CXXRecordDecl *Child2 =
333 dyn_cast<ClassTemplateDecl>(&
findDecl(
AST,
"Child2"))->getTemplatedDecl();
334 const CXXRecordDecl *Child3 =
335 dyn_cast<ClassTemplateDecl>(&
findDecl(
AST,
"Child3"))->getTemplatedDecl();
338 EXPECT_THAT(
typeParents(Child1), ElementsAre(Parent));
345TEST(TypeParents, IncompleteClass) {
350 auto AST = TU.build();
352 const CXXRecordDecl *Incomplete =
353 dyn_cast<CXXRecordDecl>(&
findDecl(
AST,
"Incomplete"));
362struct $Parent1Def[[Parent1]] {
366struct $Parent2Def[[Parent2]] {
370struct $Parent3Def[[Parent3]] : Parent2 {
374struct Ch^ild : Parent1, Parent3 {
386 auto AST = TU.build();
388 for (
Position Pt : Source.points()) {
393 ASSERT_THAT(Result, SizeIs(1));
397 withName(
"Child"), withKind(SymbolKind::Struct),
398 parents(AllOf(withName(
"Parent1"), withKind(SymbolKind::Struct),
399 selectionRangeIs(Source.range(
"Parent1Def")),
401 AllOf(withName(
"Parent3"), withKind(SymbolKind::Struct),
402 selectionRangeIs(Source.range(
"Parent3Def")),
404 withName(
"Parent2"), withKind(SymbolKind::Struct),
405 selectionRangeIs(Source.range(
"Parent2Def")),
410TEST(TypeHierarchy, RecursiveHierarchyUnbounded) {
413 struct $SDef[[S]] : S<N + 1> {};
419 TU.ExtraArgs.push_back("-ftemplate-depth=10");
420 auto AST = TU.build();
424 ASSERT_FALSE(
AST.getDiagnostics().empty());
432 ASSERT_THAT(Result, SizeIs(1));
435 AllOf(withName(
"S<0>"), withKind(SymbolKind::Struct),
437 AllOf(withName(
"S"), withKind(SymbolKind::Struct),
438 selectionRangeIs(Source.range(
"SDef")),
439 parents(AllOf(withName(
"S"), withKind(SymbolKind::Struct),
440 selectionRangeIs(Source.range(
"SDef")),
444TEST(TypeHierarchy, RecursiveHierarchyBounded) {
447 struct $SDef[[S]] : S<N - 1> {};
452 S$SRefConcrete^<2> s;
456 S$SRefDependent^<N> s;
460 auto AST = TU.build();
466 ASSERT_THAT(Result, SizeIs(1));
469 AllOf(withName(
"S<2>"), withKind(SymbolKind::Struct),
471 withName(
"S<1>"), withKind(SymbolKind::Struct),
472 selectionRangeIs(Source.range(
"SDef")),
473 parents(AllOf(withName(
"S<0>"), withKind(SymbolKind::Struct),
477 ASSERT_THAT(Result, SizeIs(1));
480 AllOf(withName(
"S"), withKind(SymbolKind::Struct),
481 parents(AllOf(withName(
"S"), withKind(SymbolKind::Struct),
482 selectionRangeIs(Source.range(
"SDef")), parents()))));
485TEST(TypeHierarchy, DeriveFromImplicitSpec) {
487 template <typename T>
490 struct Child1 : Parent<int> {};
492 struct Child2 : Parent<char> {};
498 auto AST = TU.build();
499 auto Index = TU.index();
504 ASSERT_THAT(Result, SizeIs(1));
505 EXPECT_THAT(Result.front(),
506 AllOf(withName(
"Parent"), withKind(SymbolKind::Struct),
507 children(AllOf(withName(
"Child1"),
508 withKind(SymbolKind::Struct), children()),
509 AllOf(withName(
"Child2"),
510 withKind(SymbolKind::Struct), children()))));
513TEST(TypeHierarchy, DeriveFromPartialSpec) {
515 template <typename T> struct Parent {};
516 template <typename T> struct Parent<T*> {};
518 struct Child : Parent<int*> {};
524 auto AST = TU.build();
525 auto Index = TU.index();
530 ASSERT_THAT(Result, SizeIs(1));
531 EXPECT_THAT(Result.front(), AllOf(withName(
"Parent"),
532 withKind(SymbolKind::Struct), children()));
535TEST(TypeHierarchy, DeriveFromTemplate) {
537 template <typename T>
540 template <typename T>
541 struct Child : Parent<T> {};
547 auto AST = TU.build();
548 auto Index = TU.index();
556 ASSERT_THAT(Result, SizeIs(1));
557 EXPECT_THAT(Result.front(),
558 AllOf(withName(
"Parent"), withKind(SymbolKind::Struct),
559 children(AllOf(withName(
"Child"),
560 withKind(SymbolKind::Struct), children()))));
565struct Ch^ild : Parent {
575 TU.HeaderCode = HeaderInPreambleAnnotations.code().str();
576 auto AST = TU.build();
581 ASSERT_THAT(Result, SizeIs(1));
584 AllOf(withName(
"Child"),
585 parents(AllOf(withName(
"Parent"),
586 selectionRangeIs(HeaderInPreambleAnnotations.range()),
591 llvm::StringRef TemplateArgs =
"") {
594 Request.
Query = std::string(Name);
595 Request.AnyScope =
true;
596 bool GotResult =
false;
597 Index->fuzzyFind(Request, [&](
const Symbol &S) {
598 if (TemplateArgs == S.TemplateSpecializationArgs) {
599 EXPECT_FALSE(GotResult);
604 EXPECT_TRUE(GotResult);
609 std::vector<SymbolID> Result;
613 Index->relations(Req,
615 Result.push_back(
Object.ID);
620TEST(Subtypes, SimpleInheritance) {
623struct Child1a : Parent {};
624struct Child1b : Parent {};
625struct Child2 : Child1a {};
629 auto Index = TU.index();
631 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
632 SymbolID Child1a = findSymbolIDByName(Index.get(),
"Child1a");
633 SymbolID Child1b = findSymbolIDByName(Index.get(),
"Child1b");
634 SymbolID Child2 = findSymbolIDByName(Index.get(),
"Child2");
636 EXPECT_THAT(collectSubtypes(Parent, Index.get()),
637 UnorderedElementsAre(Child1a, Child1b));
638 EXPECT_THAT(collectSubtypes(Child1a, Index.get()), ElementsAre(Child2));
641TEST(Subtypes, MultipleInheritance) {
645struct Parent3 : Parent2 {};
646struct Child : Parent1, Parent3 {};
650 auto Index = TU.index();
652 SymbolID Parent1 = findSymbolIDByName(Index.get(),
"Parent1");
653 SymbolID Parent2 = findSymbolIDByName(Index.get(),
"Parent2");
654 SymbolID Parent3 = findSymbolIDByName(Index.get(),
"Parent3");
655 SymbolID Child = findSymbolIDByName(Index.get(),
"Child");
657 EXPECT_THAT(collectSubtypes(Parent1, Index.get()), ElementsAre(Child));
658 EXPECT_THAT(collectSubtypes(Parent2, Index.get()), ElementsAre(Parent3));
659 EXPECT_THAT(collectSubtypes(Parent3, Index.get()), ElementsAre(Child));
662TEST(Subtypes, ClassTemplate) {
667struct Child : Parent {};
671 auto Index = TU.index();
673 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
674 SymbolID Child = findSymbolIDByName(Index.get(),
"Child");
676 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child));
679TEST(Subtypes, TemplateSpec1) {
685struct Parent<int> {};
687struct Child1 : Parent<float> {};
689struct Child2 : Parent<int> {};
693 auto Index = TU.index();
695 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
696 SymbolID ParentSpec = findSymbolIDByName(Index.get(),
"Parent",
"<int>");
697 SymbolID Child1 = findSymbolIDByName(Index.get(),
"Child1");
698 SymbolID Child2 = findSymbolIDByName(Index.get(),
"Child2");
700 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child1));
701 EXPECT_THAT(collectSubtypes(ParentSpec, Index.get()), ElementsAre(Child2));
704TEST(Subtypes, TemplateSpec2) {
712struct Child<int> : Parent {};
716 auto Index = TU.index();
718 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
719 SymbolID ChildSpec = findSymbolIDByName(Index.get(),
"Child",
"<int>");
721 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(ChildSpec));
724TEST(Subtypes, DependentBase) {
730struct Child : Parent<T> {};
734 auto Index = TU.index();
736 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
737 SymbolID Child = findSymbolIDByName(Index.get(),
"Child");
739 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child));
742TEST(Subtypes, LazyResolution) {
745struct Child1 : Parent {};
746struct Child2a : Child1 {};
747struct Child2b : Child1 {};
751 auto AST = TU.build();
752 auto Index = TU.index();
757 ASSERT_THAT(Result, SizeIs(1));
760 AllOf(withName(
"Parent"), withKind(SymbolKind::Struct), parents(),
761 children(AllOf(withName(
"Child1"), withKind(SymbolKind::Struct),
762 parentsNotResolved(), childrenNotResolved()))));
768 (*Result.front().children)[0],
769 AllOf(withName(
"Child1"), withKind(SymbolKind::Struct),
770 parentsNotResolved(),
771 children(AllOf(withName(
"Child2a"), withKind(SymbolKind::Struct),
772 parentsNotResolved(), childrenNotResolved()),
773 AllOf(withName(
"Child2b"), withKind(SymbolKind::Struct),
774 parentsNotResolved(), childrenNotResolved()))));
781struct Child final: Parent1, Parent2 {};
785 auto AST = TU.build();
786 auto Index = TU.index();
791 ASSERT_THAT(Result, SizeIs(1));
798 UnorderedElementsAre(
799 AllOf(withName(
"Child"),
802 withResolveParents(Optional(UnorderedElementsAre(withResolveID(
809struct Chil^d : Parent {};
813 auto AST = TU.build();
814 auto Index = TU.index();
819 ASSERT_THAT(Result, SizeIs(1));
823 Optional(UnorderedElementsAre(AllOf(
826 withResolveParents(Optional(IsEmpty()))))));
Same as llvm::Annotations, but adjusts functions to LSP-specific types for positions and ranges.
Stores and provides access to parsed AST.
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
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)
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.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::string Query
A query string for the fuzzy find.
llvm::DenseSet< SymbolID > Subjects
Ensure we have enough bits to represent all SymbolTag values.
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.
std::vector< SymbolTag > tags
The symbol tags for this item.