From ca842c825a1caf10aacb1dc63664d565b1f2f4eb Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Mon, 31 Aug 2020 03:00:58 -0400 Subject: [PATCH] [clangd] Handle templates more consistently in type hierarchy If the tree includes types derived from all specializations of a template, do not misleadingly label the root node with the name of a single specialization. Fixes https://github.com/clangd/clangd/issues/507 Differential Revision: https://reviews.llvm.org/D86861 --- clang-tools-extra/clangd/XRefs.cpp | 29 ++++++++++++++-------- .../clangd/unittests/TypeHierarchyTests.cpp | 22 +++++++++------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp index 031a9c7..67c857c 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -1479,30 +1479,39 @@ getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels, 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 index 8e615e2..9f021ad 100644 --- a/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp +++ b/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp @@ -454,7 +454,9 @@ TEST(TypeHierarchy, DeriveFromImplicitSpec) { template struct Parent {}; - struct Child : Parent {}; + struct Child1 : Parent {}; + + struct Child2 : Parent {}; Parent Fo^o; )cpp"); @@ -468,8 +470,10 @@ TEST(TypeHierarchy, DeriveFromImplicitSpec) { 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 @@ TEST(TypeHierarchy, DeriveFromPartialSpec) { 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 @@ TEST(TypeHierarchy, DeriveFromTemplate) { 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())))); } -- 2.7.4