18 #include "clang/AST/DeclCXX.h" 19 #include "clang/AST/DeclTemplate.h" 20 #include "clang/Index/IndexingAction.h" 21 #include "llvm/Support/Path.h" 22 #include "llvm/Support/ScopedPrinter.h" 23 #include "gmock/gmock.h" 24 #include "gtest/gtest.h" 30 using ::testing::AllOf;
31 using ::testing::ElementsAre;
33 using ::testing::Field;
34 using ::testing::IsEmpty;
35 using ::testing::Matcher;
36 using ::testing::Pointee;
37 using ::testing::UnorderedElementsAre;
40 MATCHER_P(WithName, N,
"") {
return arg.name == N; }
42 MATCHER_P(SelectionRangeIs, R,
"") {
return arg.selectionRange == R; }
43 template <
class... ParentMatchers>
44 ::testing::Matcher<TypeHierarchyItem>
Parents(ParentMatchers... ParentsM) {
46 HasValue(UnorderedElementsAre(ParentsM...)));
48 template <
class... ChildMatchers>
49 ::testing::Matcher<TypeHierarchyItem>
Children(ChildMatchers... ChildrenM) {
51 HasValue(UnorderedElementsAre(ChildrenM...)));
54 MATCHER(ParentsNotResolved,
"") {
return !arg.parents; }
55 MATCHER(ChildrenNotResolved,
"") {
return !arg.children; }
57 TEST(FindRecordTypeAt, TypeOrVariable) {
58 Annotations Source(R
"cpp( 63 using A^lias = Child2; 72 auto AST = TU.
build();
74 ASSERT_TRUE(AST.getDiagnostics().empty());
76 for (Position Pt : Source.points()) {
78 EXPECT_EQ(&
findDecl(AST,
"Child2"), static_cast<const NamedDecl *>(RD));
82 TEST(FindRecordTypeAt, Method) {
83 Annotations Source(R
"cpp( 96 auto AST = TU.
build();
98 ASSERT_TRUE(AST.getDiagnostics().empty());
100 for (Position Pt : Source.points()) {
102 EXPECT_EQ(&
findDecl(AST,
"Child2"), static_cast<const NamedDecl *>(RD));
106 TEST(FindRecordTypeAt, Field) {
107 Annotations Source(R
"cpp( 119 auto AST = TU.
build();
121 ASSERT_TRUE(AST.getDiagnostics().empty());
123 for (Position Pt : Source.points()) {
128 EXPECT_EQ(
nullptr, RD);
132 TEST(TypeParents, SimpleInheritance) {
133 Annotations Source(R
"cpp( 138 struct Child1 : Parent { 142 struct Child2 : Child1 { 148 auto AST = TU.
build();
150 ASSERT_TRUE(AST.getDiagnostics().empty());
152 const CXXRecordDecl *
Parent =
153 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Parent"));
154 const CXXRecordDecl *Child1 =
155 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Child1"));
156 const CXXRecordDecl *Child2 =
157 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Child2"));
160 EXPECT_THAT(
typeParents(Child1), ElementsAre(Parent));
161 EXPECT_THAT(
typeParents(Child2), ElementsAre(Child1));
164 TEST(TypeParents, MultipleInheritance) {
165 Annotations Source(R
"cpp( 174 struct Parent3 : Parent2 { 178 struct Child : Parent1, Parent3 { 184 auto AST = TU.
build();
186 ASSERT_TRUE(AST.getDiagnostics().empty());
188 const CXXRecordDecl *Parent1 =
189 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Parent1"));
190 const CXXRecordDecl *Parent2 =
191 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Parent2"));
192 const CXXRecordDecl *Parent3 =
193 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Parent3"));
194 const CXXRecordDecl *Child = dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Child"));
198 EXPECT_THAT(
typeParents(Parent3), ElementsAre(Parent2));
199 EXPECT_THAT(
typeParents(Child), ElementsAre(Parent1, Parent3));
202 TEST(TypeParents, ClassTemplate) {
203 Annotations Source(R
"cpp( 206 template <typename T> 207 struct Child : Parent {}; 211 auto AST = TU.
build();
213 ASSERT_TRUE(AST.getDiagnostics().empty());
215 const CXXRecordDecl *Parent =
216 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Parent"));
217 const CXXRecordDecl *Child =
218 dyn_cast<ClassTemplateDecl>(&
findDecl(AST,
"Child"))->getTemplatedDecl();
220 EXPECT_THAT(
typeParents(Child), ElementsAre(Parent));
223 MATCHER_P(ImplicitSpecOf, ClassTemplate,
"") {
224 const ClassTemplateSpecializationDecl *CTS =
225 dyn_cast<ClassTemplateSpecializationDecl>(arg);
227 CTS->getSpecializedTemplate()->getTemplatedDecl() == ClassTemplate &&
228 CTS->getSpecializationKind() == TSK_ImplicitInstantiation;
233 const NamedDecl &findDeclWithTemplateArgs(ParsedAST &AST,
234 llvm::StringRef Query) {
235 return findDecl(AST, [&Query](
const NamedDecl &ND) {
237 llvm::raw_string_ostream OS(QName);
238 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
241 ND.getNameForDiagnostic(OS, Policy,
true);
243 return QName == Query;
247 TEST(TypeParents, TemplateSpec1) {
248 Annotations Source(R
"cpp( 249 template <typename T> 253 struct Parent<int> {}; 255 struct Child1 : Parent<float> {}; 257 struct Child2 : Parent<int> {}; 261 auto AST = TU.
build();
263 ASSERT_TRUE(AST.getDiagnostics().empty());
265 const CXXRecordDecl *Parent =
266 dyn_cast<ClassTemplateDecl>(&
findDecl(AST,
"Parent"))->getTemplatedDecl();
267 const CXXRecordDecl *ParentSpec =
268 dyn_cast<CXXRecordDecl>(&findDeclWithTemplateArgs(AST,
"Parent<int>"));
269 const CXXRecordDecl *Child1 =
270 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Child1"));
271 const CXXRecordDecl *Child2 =
272 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Child2"));
274 EXPECT_THAT(
typeParents(Child1), ElementsAre(ImplicitSpecOf(Parent)));
275 EXPECT_THAT(
typeParents(Child2), ElementsAre(ParentSpec));
278 TEST(TypeParents, TemplateSpec2) {
279 Annotations Source(R
"cpp( 282 template <typename T> 286 struct Child<int> : Parent {}; 290 auto AST = TU.
build();
292 ASSERT_TRUE(AST.getDiagnostics().empty());
294 const CXXRecordDecl *Parent =
295 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Parent"));
296 const CXXRecordDecl *Child =
297 dyn_cast<ClassTemplateDecl>(&
findDecl(AST,
"Child"))->getTemplatedDecl();
298 const CXXRecordDecl *ChildSpec =
299 dyn_cast<CXXRecordDecl>(&findDeclWithTemplateArgs(AST,
"Child<int>"));
302 EXPECT_THAT(
typeParents(ChildSpec), ElementsAre(Parent));
305 TEST(TypeParents, DependentBase) {
306 Annotations Source(R
"cpp( 307 template <typename T> 310 template <typename T> 311 struct Child1 : Parent<T> {}; 313 template <typename T> 314 struct Child2 : Parent<T>::Type {}; 316 template <typename T> 317 struct Child3 : T {}; 321 auto AST = TU.
build();
323 ASSERT_TRUE(AST.getDiagnostics().empty());
325 const CXXRecordDecl *Parent =
326 dyn_cast<ClassTemplateDecl>(&
findDecl(AST,
"Parent"))->getTemplatedDecl();
327 const CXXRecordDecl *Child1 =
328 dyn_cast<ClassTemplateDecl>(&
findDecl(AST,
"Child1"))->getTemplatedDecl();
329 const CXXRecordDecl *Child2 =
330 dyn_cast<ClassTemplateDecl>(&
findDecl(AST,
"Child2"))->getTemplatedDecl();
331 const CXXRecordDecl *Child3 =
332 dyn_cast<ClassTemplateDecl>(&
findDecl(AST,
"Child3"))->getTemplatedDecl();
335 EXPECT_THAT(
typeParents(Child1), ElementsAre(Parent));
345 TEST(TypeHierarchy, Parents) {
346 Annotations Source(R
"cpp( 347 struct $Parent1Def[[Parent1]] { 351 struct $Parent2Def[[Parent2]] { 355 struct $Parent3Def[[Parent3]] : Parent2 { 359 struct Ch^ild : Parent1, Parent3 { 371 auto AST = TU.
build();
373 for (Position Pt : Source.points()) {
378 ASSERT_TRUE(
bool(Result));
384 SelectionRangeIs(Source.range(
"Parent1Def")),
387 SelectionRangeIs(Source.range(
"Parent3Def")),
390 SelectionRangeIs(Source.range(
"Parent2Def")),
395 TEST(TypeHierarchy, RecursiveHierarchyUnbounded) {
396 Annotations Source(R
"cpp( 398 struct $SDef[[S]] : S<N + 1> {}; 404 TU.ExtraArgs.push_back("-ftemplate-depth=10");
405 auto AST = TU.build();
409 ASSERT_TRUE(!AST.getDiagnostics().empty());
417 ASSERT_TRUE(
bool(Result));
423 SelectionRangeIs(Source.range(
"SDef")),
425 SelectionRangeIs(Source.range(
"SDef")),
429 TEST(TypeHierarchy, RecursiveHierarchyBounded) {
430 Annotations Source(R
"cpp( 432 struct $SDef[[S]] : S<N - 1> {}; 437 S$SRefConcrete^<2> s; 441 S$SRefDependent^<N> s; 445 auto AST = TU.
build();
447 ASSERT_TRUE(AST.getDiagnostics().empty());
453 ASSERT_TRUE(
bool(Result));
459 SelectionRangeIs(Source.range(
"SDef")),
464 ASSERT_TRUE(
bool(Result));
469 SelectionRangeIs(Source.range(
"SDef")),
Parents()))));
472 TEST(TypeHierarchy, DeriveFromImplicitSpec) {
473 Annotations Source(R
"cpp( 474 template <typename T> 477 struct Child : Parent<int> {}; 483 auto AST = TU.
build();
484 auto Index = TU.index();
485 ASSERT_TRUE(AST.getDiagnostics().empty());
490 ASSERT_TRUE(
bool(Result));
497 TEST(TypeHierarchy, DeriveFromPartialSpec) {
498 Annotations Source(R
"cpp( 499 template <typename T> struct Parent {}; 500 template <typename T> struct Parent<T*> {}; 502 struct Child : Parent<int*> {}; 508 auto AST = TU.
build();
509 auto Index = TU.index();
510 ASSERT_TRUE(AST.getDiagnostics().empty());
515 ASSERT_TRUE(
bool(Result));
516 EXPECT_THAT(*Result, AllOf(WithName(
"Parent<int>"),
520 TEST(TypeHierarchy, DeriveFromTemplate) {
521 Annotations Source(R
"cpp( 522 template <typename T> 525 template <typename T> 526 struct Child : Parent<T> {}; 532 auto AST = TU.
build();
533 auto Index = TU.index();
534 ASSERT_TRUE(AST.getDiagnostics().empty());
542 ASSERT_TRUE(
bool(Result));
550 llvm::StringRef TemplateArgs =
"") {
552 FuzzyFindRequest Request;
553 Request.Query =
Name;
554 Request.AnyScope =
true;
555 bool GotResult =
false;
556 Index->fuzzyFind(Request, [&](
const Symbol &S) {
557 if (TemplateArgs == S.TemplateSpecializationArgs) {
558 EXPECT_FALSE(GotResult);
563 EXPECT_TRUE(GotResult);
567 std::vector<SymbolID> collectSubtypes(
SymbolID Subject, SymbolIndex *Index) {
568 std::vector<SymbolID> Result;
569 RelationsRequest Req;
570 Req.Subjects.insert(Subject);
572 Index->relations(Req,
573 [&Result](
const SymbolID &Subject,
const Symbol &Object) {
574 Result.push_back(Object.ID);
579 TEST(Subtypes, SimpleInheritance) {
580 Annotations Source(R
"cpp( 582 struct Child1a : Parent {}; 583 struct Child1b : Parent {}; 584 struct Child2 : Child1a {}; 588 auto Index = TU.
index();
590 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
591 SymbolID Child1a = findSymbolIDByName(Index.get(),
"Child1a");
592 SymbolID Child1b = findSymbolIDByName(Index.get(),
"Child1b");
593 SymbolID Child2 = findSymbolIDByName(Index.get(),
"Child2");
595 EXPECT_THAT(collectSubtypes(Parent, Index.get()),
596 UnorderedElementsAre(Child1a, Child1b));
597 EXPECT_THAT(collectSubtypes(Child1a, Index.get()), ElementsAre(Child2));
600 TEST(Subtypes, MultipleInheritance) {
601 Annotations Source(R
"cpp( 604 struct Parent3 : Parent2 {}; 605 struct Child : Parent1, Parent3 {}; 609 auto Index = TU.
index();
611 SymbolID Parent1 = findSymbolIDByName(Index.get(),
"Parent1");
612 SymbolID Parent2 = findSymbolIDByName(Index.get(),
"Parent2");
613 SymbolID Parent3 = findSymbolIDByName(Index.get(),
"Parent3");
614 SymbolID Child = findSymbolIDByName(Index.get(),
"Child");
616 EXPECT_THAT(collectSubtypes(Parent1, Index.get()), ElementsAre(Child));
617 EXPECT_THAT(collectSubtypes(Parent2, Index.get()), ElementsAre(Parent3));
618 EXPECT_THAT(collectSubtypes(Parent3, Index.get()), ElementsAre(Child));
621 TEST(Subtypes, ClassTemplate) {
622 Annotations Source(R
"cpp( 625 template <typename T> 626 struct Child : Parent {}; 630 auto Index = TU.
index();
632 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
633 SymbolID Child = findSymbolIDByName(Index.get(),
"Child");
635 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child));
638 TEST(Subtypes, TemplateSpec1) {
639 Annotations Source(R
"cpp( 640 template <typename T> 644 struct Parent<int> {}; 646 struct Child1 : Parent<float> {}; 648 struct Child2 : Parent<int> {}; 652 auto Index = TU.
index();
654 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
655 SymbolID ParentSpec = findSymbolIDByName(Index.get(),
"Parent",
"<int>");
656 SymbolID Child1 = findSymbolIDByName(Index.get(),
"Child1");
657 SymbolID Child2 = findSymbolIDByName(Index.get(),
"Child2");
659 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child1));
660 EXPECT_THAT(collectSubtypes(ParentSpec, Index.get()), ElementsAre(Child2));
663 TEST(Subtypes, TemplateSpec2) {
664 Annotations Source(R
"cpp( 667 template <typename T> 671 struct Child<int> : Parent {}; 675 auto Index = TU.
index();
677 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
678 SymbolID ChildSpec = findSymbolIDByName(Index.get(),
"Child",
"<int>");
680 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(ChildSpec));
683 TEST(Subtypes, DependentBase) {
684 Annotations Source(R
"cpp( 685 template <typename T> 688 template <typename T> 689 struct Child : Parent<T> {}; 693 auto Index = TU.
index();
695 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
696 SymbolID Child = findSymbolIDByName(Index.get(),
"Child");
698 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child));
701 TEST(Subtypes, LazyResolution) {
702 Annotations Source(R
"cpp( 704 struct Child1 : Parent {}; 705 struct Child2a : Child1 {}; 706 struct Child2b : Child1 {}; 710 auto AST = TU.
build();
711 auto Index = TU.index();
714 AST, Source.point(), 1,
716 ASSERT_TRUE(
bool(Result));
720 ParentsNotResolved(),
722 ParentsNotResolved(), ChildrenNotResolved()))));
728 (*Result->children)[0],
730 ParentsNotResolved(),
732 ParentsNotResolved(), ChildrenNotResolved()),
734 ParentsNotResolved(), ChildrenNotResolved()))));
llvm::Optional< std::vector< TypeHierarchyItem > > children
If this type hierarchy item is resolved, it contains the direct children of the current item...
OptionalMatcher< InnerMatcher > HasValue(const InnerMatcher &inner_matcher)
void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index)
std::vector< const char * > ExtraArgs
TEST(BackgroundQueueTest, Priority)
std::string testPath(PathRef File)
static constexpr llvm::StringLiteral Name
static TestTU withCode(llvm::StringRef Code)
std::vector< std::unique_ptr< HTMLNode > > Children
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
const CXXRecordDecl * findRecordTypeAt(ParsedAST &AST, Position Pos)
Find the record type references at Pos.
llvm::Optional< TypeHierarchyItem > getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels, TypeHierarchyDirection Direction, const SymbolIndex *Index, PathRef TUPath)
Get type hierarchy information at Pos.
std::unique_ptr< SymbolIndex > index() const
llvm::Optional< std::vector< TypeHierarchyItem > > parents
If this type hierarchy item is resolved, it contains the direct parents.
static llvm::Optional< ParsedAST > build(std::unique_ptr< clang::CompilerInvocation > CI, llvm::ArrayRef< Diag > CompilerInvocationDiags, std::shared_ptr< const PreambleData > Preamble, std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, const SymbolIndex *Index, const ParseOptions &Opts)
Attempts to run Clang and store parsed AST.
std::array< uint8_t, 20 > SymbolID
std::vector< const CXXRecordDecl * > typeParents(const CXXRecordDecl *CXXRD)
Given a record type declaration, find its base (parent) types.
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
const SymbolIndex * Index