diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -1479,30 +1479,39 @@ if (!CXXRD) return llvm::None; + bool WantParents = Direction == TypeHierarchyDirection::Parents || + Direction == TypeHierarchyDirection::Both; + bool WantChildren = Direction == TypeHierarchyDirection::Children || + Direction == TypeHierarchyDirection::Both; + + // If we're looking for children, we're doing the lookup in the index. + // The index does not store relationships between implicit + // specializations, so if we have one, use the template pattern instead. + // Note that this needs to be done before the declToTypeHierarchyItem(), + // otherwise the type hierarchy item would misleadingly contain the + // specialization parameters, while the children would involve classes + // that derive from other specializations of the template. + if (WantChildren) { + if (auto *CTSD = dyn_cast(CXXRD)) + CXXRD = CTSD->getTemplateInstantiationPattern(); + } + Optional Result = declToTypeHierarchyItem(AST.getASTContext(), *CXXRD); if (!Result) return Result; - if (Direction == TypeHierarchyDirection::Parents || - Direction == TypeHierarchyDirection::Both) { + if (WantParents) { Result->parents.emplace(); RecursionProtectionSet RPSet; fillSuperTypes(*CXXRD, AST.getASTContext(), *Result->parents, RPSet); } - if ((Direction == TypeHierarchyDirection::Children || - Direction == TypeHierarchyDirection::Both) && - ResolveLevels > 0) { + if (WantChildren && ResolveLevels > 0) { Result->children.emplace(); if (Index) { - // The index does not store relationships between implicit - // specializations, so if we have one, use the template pattern instead. - if (auto *CTSD = dyn_cast(CXXRD)) - CXXRD = CTSD->getTemplateInstantiationPattern(); - if (Optional ID = getSymbolID(CXXRD)) fillSubTypes(*ID, *Result->children, Index, ResolveLevels, TUPath); } diff --git a/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp b/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp --- a/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp +++ b/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp @@ -454,7 +454,9 @@ template struct Parent {}; - struct Child : Parent {}; + struct Child1 : Parent {}; + + struct Child2 : Parent {}; Parent Fo^o; )cpp"); @@ -468,8 +470,10 @@ testPath(TU.Filename)); ASSERT_TRUE(bool(Result)); EXPECT_THAT(*Result, - AllOf(WithName("Parent"), WithKind(SymbolKind::Struct), - Children(AllOf(WithName("Child"), + AllOf(WithName("Parent"), WithKind(SymbolKind::Struct), + Children(AllOf(WithName("Child1"), + WithKind(SymbolKind::Struct), Children()), + AllOf(WithName("Child2"), WithKind(SymbolKind::Struct), Children())))); } @@ -491,8 +495,8 @@ AST, Source.points()[0], 2, TypeHierarchyDirection::Children, Index.get(), testPath(TU.Filename)); ASSERT_TRUE(bool(Result)); - EXPECT_THAT(*Result, AllOf(WithName("Parent"), - WithKind(SymbolKind::Struct), Children())); + EXPECT_THAT(*Result, AllOf(WithName("Parent"), WithKind(SymbolKind::Struct), + Children())); } TEST(TypeHierarchy, DeriveFromTemplate) { @@ -510,15 +514,15 @@ auto AST = TU.build(); auto Index = TU.index(); - // FIXME: We'd like this to return the implicit specialization Child, - // but currently libIndex does not expose relationships between - // implicit specializations. + // FIXME: We'd like this to show the implicit specializations Parent + // and Child, but currently libIndex does not expose relationships + // between implicit specializations. llvm::Optional Result = getTypeHierarchy( AST, Source.points()[0], 2, TypeHierarchyDirection::Children, Index.get(), testPath(TU.Filename)); ASSERT_TRUE(bool(Result)); EXPECT_THAT(*Result, - AllOf(WithName("Parent"), WithKind(SymbolKind::Struct), + AllOf(WithName("Parent"), WithKind(SymbolKind::Struct), Children(AllOf(WithName("Child"), WithKind(SymbolKind::Struct), Children())))); }