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( 70 auto AST = TU.
build();
72 ASSERT_TRUE(AST.getDiagnostics().empty());
74 for (Position Pt : Source.points()) {
76 EXPECT_EQ(&
findDecl(AST,
"Child2"), static_cast<const NamedDecl *>(RD));
80 TEST(FindRecordTypeAt, Method) {
81 Annotations Source(R
"cpp( 94 auto AST = TU.
build();
96 ASSERT_TRUE(AST.getDiagnostics().empty());
98 for (Position Pt : Source.points()) {
100 EXPECT_EQ(&
findDecl(AST,
"Child2"), static_cast<const NamedDecl *>(RD));
104 TEST(FindRecordTypeAt, Field) {
105 Annotations Source(R
"cpp( 117 auto AST = TU.
build();
119 ASSERT_TRUE(AST.getDiagnostics().empty());
121 for (Position Pt : Source.points()) {
126 EXPECT_EQ(
nullptr, RD);
130 TEST(TypeParents, SimpleInheritance) {
131 Annotations Source(R
"cpp( 136 struct Child1 : Parent { 140 struct Child2 : Child1 { 146 auto AST = TU.
build();
148 ASSERT_TRUE(AST.getDiagnostics().empty());
150 const CXXRecordDecl *Parent =
151 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Parent"));
152 const CXXRecordDecl *Child1 =
153 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Child1"));
154 const CXXRecordDecl *Child2 =
155 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Child2"));
158 EXPECT_THAT(
typeParents(Child1), ElementsAre(Parent));
159 EXPECT_THAT(
typeParents(Child2), ElementsAre(Child1));
162 TEST(TypeParents, MultipleInheritance) {
163 Annotations Source(R
"cpp( 172 struct Parent3 : Parent2 { 176 struct Child : Parent1, Parent3 { 182 auto AST = TU.
build();
184 ASSERT_TRUE(AST.getDiagnostics().empty());
186 const CXXRecordDecl *Parent1 =
187 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Parent1"));
188 const CXXRecordDecl *Parent2 =
189 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Parent2"));
190 const CXXRecordDecl *Parent3 =
191 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Parent3"));
192 const CXXRecordDecl *Child = dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Child"));
196 EXPECT_THAT(
typeParents(Parent3), ElementsAre(Parent2));
197 EXPECT_THAT(
typeParents(Child), ElementsAre(Parent1, Parent3));
200 TEST(TypeParents, ClassTemplate) {
201 Annotations Source(R
"cpp( 204 template <typename T> 205 struct Child : Parent {}; 209 auto AST = TU.
build();
211 ASSERT_TRUE(AST.getDiagnostics().empty());
213 const CXXRecordDecl *Parent =
214 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Parent"));
215 const CXXRecordDecl *Child =
216 dyn_cast<ClassTemplateDecl>(&
findDecl(AST,
"Child"))->getTemplatedDecl();
218 EXPECT_THAT(
typeParents(Child), ElementsAre(Parent));
221 MATCHER_P(ImplicitSpecOf, ClassTemplate,
"") {
222 const ClassTemplateSpecializationDecl *CTS =
223 dyn_cast<ClassTemplateSpecializationDecl>(arg);
225 CTS->getSpecializedTemplate()->getTemplatedDecl() == ClassTemplate &&
226 CTS->getSpecializationKind() == TSK_ImplicitInstantiation;
231 const NamedDecl &findDeclWithTemplateArgs(ParsedAST &AST,
232 llvm::StringRef Query) {
233 return findDecl(AST, [&Query](
const NamedDecl &ND) {
235 llvm::raw_string_ostream OS(QName);
236 PrintingPolicy Policy(ND.getASTContext().getLangOpts());
239 ND.getNameForDiagnostic(OS, Policy,
true);
241 return QName == Query;
245 TEST(TypeParents, TemplateSpec1) {
246 Annotations Source(R
"cpp( 247 template <typename T> 251 struct Parent<int> {}; 253 struct Child1 : Parent<float> {}; 255 struct Child2 : Parent<int> {}; 259 auto AST = TU.
build();
261 ASSERT_TRUE(AST.getDiagnostics().empty());
263 const CXXRecordDecl *Parent =
264 dyn_cast<ClassTemplateDecl>(&
findDecl(AST,
"Parent"))->getTemplatedDecl();
265 const CXXRecordDecl *ParentSpec =
266 dyn_cast<CXXRecordDecl>(&findDeclWithTemplateArgs(AST,
"Parent<int>"));
267 const CXXRecordDecl *Child1 =
268 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Child1"));
269 const CXXRecordDecl *Child2 =
270 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Child2"));
272 EXPECT_THAT(
typeParents(Child1), ElementsAre(ImplicitSpecOf(Parent)));
273 EXPECT_THAT(
typeParents(Child2), ElementsAre(ParentSpec));
276 TEST(TypeParents, TemplateSpec2) {
277 Annotations Source(R
"cpp( 280 template <typename T> 284 struct Child<int> : Parent {}; 288 auto AST = TU.
build();
290 ASSERT_TRUE(AST.getDiagnostics().empty());
292 const CXXRecordDecl *Parent =
293 dyn_cast<CXXRecordDecl>(&
findDecl(AST,
"Parent"));
294 const CXXRecordDecl *Child =
295 dyn_cast<ClassTemplateDecl>(&
findDecl(AST,
"Child"))->getTemplatedDecl();
296 const CXXRecordDecl *ChildSpec =
297 dyn_cast<CXXRecordDecl>(&findDeclWithTemplateArgs(AST,
"Child<int>"));
300 EXPECT_THAT(
typeParents(ChildSpec), ElementsAre(Parent));
303 TEST(TypeParents, DependentBase) {
304 Annotations Source(R
"cpp( 305 template <typename T> 308 template <typename T> 309 struct Child1 : Parent<T> {}; 311 template <typename T> 312 struct Child2 : Parent<T>::Type {}; 314 template <typename T> 315 struct Child3 : T {}; 319 auto AST = TU.
build();
321 ASSERT_TRUE(AST.getDiagnostics().empty());
323 const CXXRecordDecl *Parent =
324 dyn_cast<ClassTemplateDecl>(&
findDecl(AST,
"Parent"))->getTemplatedDecl();
325 const CXXRecordDecl *Child1 =
326 dyn_cast<ClassTemplateDecl>(&
findDecl(AST,
"Child1"))->getTemplatedDecl();
327 const CXXRecordDecl *Child2 =
328 dyn_cast<ClassTemplateDecl>(&
findDecl(AST,
"Child2"))->getTemplatedDecl();
329 const CXXRecordDecl *Child3 =
330 dyn_cast<ClassTemplateDecl>(&
findDecl(AST,
"Child3"))->getTemplatedDecl();
333 EXPECT_THAT(
typeParents(Child1), ElementsAre(Parent));
343 TEST(TypeHierarchy, Parents) {
344 Annotations Source(R
"cpp( 345 struct $Parent1Def[[Parent1]] { 349 struct $Parent2Def[[Parent2]] { 353 struct $Parent3Def[[Parent3]] : Parent2 { 357 struct Ch^ild : Parent1, Parent3 { 369 auto AST = TU.
build();
371 for (Position Pt : Source.points()) {
376 ASSERT_TRUE(
bool(Result));
382 SelectionRangeIs(Source.range(
"Parent1Def")),
385 SelectionRangeIs(Source.range(
"Parent3Def")),
388 SelectionRangeIs(Source.range(
"Parent2Def")),
393 TEST(TypeHierarchy, RecursiveHierarchyUnbounded) {
394 Annotations Source(R
"cpp( 396 struct $SDef[[S]] : S<N + 1> {}; 402 TU.ExtraArgs.push_back("-ftemplate-depth=10");
403 auto AST = TU.build();
407 ASSERT_TRUE(!AST.getDiagnostics().empty());
415 ASSERT_TRUE(
bool(Result));
420 SelectionRangeIs(Source.range(
"SDef")),
Parents()))));
423 TEST(TypeHierarchy, RecursiveHierarchyBounded) {
424 Annotations Source(R
"cpp( 426 struct $SDef[[S]] : S<N - 1> {}; 431 S$SRefConcrete^<2> s; 435 S$SRefDependent^<N> s; 439 auto AST = TU.
build();
441 ASSERT_TRUE(AST.getDiagnostics().empty());
447 ASSERT_TRUE(
bool(Result));
452 SelectionRangeIs(Source.range(
"SDef")),
Parents()))));
455 ASSERT_TRUE(
bool(Result));
460 SelectionRangeIs(Source.range(
"SDef")),
Parents()))));
464 llvm::StringRef TemplateArgs =
"") {
466 FuzzyFindRequest Request;
467 Request.Query =
Name;
468 Request.AnyScope =
true;
469 bool GotResult =
false;
470 Index->fuzzyFind(Request, [&](
const Symbol &S) {
471 if (TemplateArgs == S.TemplateSpecializationArgs) {
472 EXPECT_FALSE(GotResult);
477 EXPECT_TRUE(GotResult);
481 std::vector<SymbolID> collectSubtypes(
SymbolID Subject, SymbolIndex *Index) {
482 std::vector<SymbolID>
Result;
483 RelationsRequest Req;
484 Req.Subjects.insert(Subject);
485 Req.Predicate = index::SymbolRole::RelationBaseOf;
486 Index->relations(Req,
487 [&Result](
const SymbolID &Subject,
const Symbol &Object) {
488 Result.push_back(Object.ID);
493 TEST(Subtypes, SimpleInheritance) {
494 Annotations Source(R
"cpp( 496 struct Child1a : Parent {}; 497 struct Child1b : Parent {}; 498 struct Child2 : Child1a {}; 502 auto Index = TU.
index();
504 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
505 SymbolID Child1a = findSymbolIDByName(Index.get(),
"Child1a");
506 SymbolID Child1b = findSymbolIDByName(Index.get(),
"Child1b");
507 SymbolID Child2 = findSymbolIDByName(Index.get(),
"Child2");
509 EXPECT_THAT(collectSubtypes(Parent, Index.get()),
510 UnorderedElementsAre(Child1a, Child1b));
511 EXPECT_THAT(collectSubtypes(Child1a, Index.get()), ElementsAre(Child2));
514 TEST(Subtypes, MultipleInheritance) {
515 Annotations Source(R
"cpp( 518 struct Parent3 : Parent2 {}; 519 struct Child : Parent1, Parent3 {}; 523 auto Index = TU.
index();
525 SymbolID Parent1 = findSymbolIDByName(Index.get(),
"Parent1");
526 SymbolID Parent2 = findSymbolIDByName(Index.get(),
"Parent2");
527 SymbolID Parent3 = findSymbolIDByName(Index.get(),
"Parent3");
528 SymbolID Child = findSymbolIDByName(Index.get(),
"Child");
530 EXPECT_THAT(collectSubtypes(Parent1, Index.get()), ElementsAre(Child));
531 EXPECT_THAT(collectSubtypes(Parent2, Index.get()), ElementsAre(Parent3));
532 EXPECT_THAT(collectSubtypes(Parent3, Index.get()), ElementsAre(Child));
535 TEST(Subtypes, ClassTemplate) {
536 Annotations Source(R
"cpp( 539 template <typename T> 540 struct Child : Parent {}; 544 auto Index = TU.
index();
546 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
547 SymbolID Child = findSymbolIDByName(Index.get(),
"Child");
549 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child));
552 TEST(Subtypes, TemplateSpec1) {
553 Annotations Source(R
"cpp( 554 template <typename T> 558 struct Parent<int> {}; 560 struct Child1 : Parent<float> {}; 562 struct Child2 : Parent<int> {}; 566 auto Index = TU.
index();
568 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
569 SymbolID ParentSpec = findSymbolIDByName(Index.get(),
"Parent",
"<int>");
570 SymbolID Child1 = findSymbolIDByName(Index.get(),
"Child1");
571 SymbolID Child2 = findSymbolIDByName(Index.get(),
"Child2");
573 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child1));
574 EXPECT_THAT(collectSubtypes(ParentSpec, Index.get()), ElementsAre(Child2));
577 TEST(Subtypes, TemplateSpec2) {
578 Annotations Source(R
"cpp( 581 template <typename T> 585 struct Child<int> : Parent {}; 589 auto Index = TU.
index();
591 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
592 SymbolID ChildSpec = findSymbolIDByName(Index.get(),
"Child",
"<int>");
594 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(ChildSpec));
597 TEST(Subtypes, DependentBase) {
598 Annotations Source(R
"cpp( 599 template <typename T> 602 template <typename T> 603 struct Child : Parent<T> {}; 607 auto Index = TU.
index();
609 SymbolID Parent = findSymbolIDByName(Index.get(),
"Parent");
610 SymbolID Child = findSymbolIDByName(Index.get(),
"Child");
612 EXPECT_THAT(collectSubtypes(Parent, Index.get()), ElementsAre(Child));
615 TEST(Subtypes, LazyResolution) {
616 Annotations Source(R
"cpp( 618 struct Child1 : Parent {}; 619 struct Child2a : Child1 {}; 620 struct Child2b : Child1 {}; 624 auto AST = TU.
build();
625 auto Index = TU.index();
628 AST, Source.point(), 1,
630 ASSERT_TRUE(
bool(Result));
634 ParentsNotResolved(),
636 ParentsNotResolved(), ChildrenNotResolved()))));
642 (*Result->children)[0],
644 ParentsNotResolved(),
646 ParentsNotResolved(), ChildrenNotResolved()),
648 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)
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< 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< llvm::Expected< tooling::AtomicChanges > > Result
llvm::Optional< std::vector< TypeHierarchyItem > > parents
If this type hierarchy item is resolved, it contains the direct parents.
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