forked from OSchip/llvm-project
[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
This commit is contained in:
parent
7cd6b0c3b5
commit
ca842c825a
|
@ -1479,30 +1479,39 @@ getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels,
|
||||||
if (!CXXRD)
|
if (!CXXRD)
|
||||||
return llvm::None;
|
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<ClassTemplateSpecializationDecl>(CXXRD))
|
||||||
|
CXXRD = CTSD->getTemplateInstantiationPattern();
|
||||||
|
}
|
||||||
|
|
||||||
Optional<TypeHierarchyItem> Result =
|
Optional<TypeHierarchyItem> Result =
|
||||||
declToTypeHierarchyItem(AST.getASTContext(), *CXXRD);
|
declToTypeHierarchyItem(AST.getASTContext(), *CXXRD);
|
||||||
if (!Result)
|
if (!Result)
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
if (Direction == TypeHierarchyDirection::Parents ||
|
if (WantParents) {
|
||||||
Direction == TypeHierarchyDirection::Both) {
|
|
||||||
Result->parents.emplace();
|
Result->parents.emplace();
|
||||||
|
|
||||||
RecursionProtectionSet RPSet;
|
RecursionProtectionSet RPSet;
|
||||||
fillSuperTypes(*CXXRD, AST.getASTContext(), *Result->parents, RPSet);
|
fillSuperTypes(*CXXRD, AST.getASTContext(), *Result->parents, RPSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((Direction == TypeHierarchyDirection::Children ||
|
if (WantChildren && ResolveLevels > 0) {
|
||||||
Direction == TypeHierarchyDirection::Both) &&
|
|
||||||
ResolveLevels > 0) {
|
|
||||||
Result->children.emplace();
|
Result->children.emplace();
|
||||||
|
|
||||||
if (Index) {
|
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<ClassTemplateSpecializationDecl>(CXXRD))
|
|
||||||
CXXRD = CTSD->getTemplateInstantiationPattern();
|
|
||||||
|
|
||||||
if (Optional<SymbolID> ID = getSymbolID(CXXRD))
|
if (Optional<SymbolID> ID = getSymbolID(CXXRD))
|
||||||
fillSubTypes(*ID, *Result->children, Index, ResolveLevels, TUPath);
|
fillSubTypes(*ID, *Result->children, Index, ResolveLevels, TUPath);
|
||||||
}
|
}
|
||||||
|
|
|
@ -454,7 +454,9 @@ TEST(TypeHierarchy, DeriveFromImplicitSpec) {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct Parent {};
|
struct Parent {};
|
||||||
|
|
||||||
struct Child : Parent<int> {};
|
struct Child1 : Parent<int> {};
|
||||||
|
|
||||||
|
struct Child2 : Parent<char> {};
|
||||||
|
|
||||||
Parent<int> Fo^o;
|
Parent<int> Fo^o;
|
||||||
)cpp");
|
)cpp");
|
||||||
|
@ -468,8 +470,10 @@ TEST(TypeHierarchy, DeriveFromImplicitSpec) {
|
||||||
testPath(TU.Filename));
|
testPath(TU.Filename));
|
||||||
ASSERT_TRUE(bool(Result));
|
ASSERT_TRUE(bool(Result));
|
||||||
EXPECT_THAT(*Result,
|
EXPECT_THAT(*Result,
|
||||||
AllOf(WithName("Parent<int>"), WithKind(SymbolKind::Struct),
|
AllOf(WithName("Parent"), WithKind(SymbolKind::Struct),
|
||||||
Children(AllOf(WithName("Child"),
|
Children(AllOf(WithName("Child1"),
|
||||||
|
WithKind(SymbolKind::Struct), Children()),
|
||||||
|
AllOf(WithName("Child2"),
|
||||||
WithKind(SymbolKind::Struct), Children()))));
|
WithKind(SymbolKind::Struct), Children()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,8 +495,8 @@ TEST(TypeHierarchy, DeriveFromPartialSpec) {
|
||||||
AST, Source.points()[0], 2, TypeHierarchyDirection::Children, Index.get(),
|
AST, Source.points()[0], 2, TypeHierarchyDirection::Children, Index.get(),
|
||||||
testPath(TU.Filename));
|
testPath(TU.Filename));
|
||||||
ASSERT_TRUE(bool(Result));
|
ASSERT_TRUE(bool(Result));
|
||||||
EXPECT_THAT(*Result, AllOf(WithName("Parent<int>"),
|
EXPECT_THAT(*Result, AllOf(WithName("Parent"), WithKind(SymbolKind::Struct),
|
||||||
WithKind(SymbolKind::Struct), Children()));
|
Children()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TypeHierarchy, DeriveFromTemplate) {
|
TEST(TypeHierarchy, DeriveFromTemplate) {
|
||||||
|
@ -510,15 +514,15 @@ TEST(TypeHierarchy, DeriveFromTemplate) {
|
||||||
auto AST = TU.build();
|
auto AST = TU.build();
|
||||||
auto Index = TU.index();
|
auto Index = TU.index();
|
||||||
|
|
||||||
// FIXME: We'd like this to return the implicit specialization Child<int>,
|
// FIXME: We'd like this to show the implicit specializations Parent<int>
|
||||||
// but currently libIndex does not expose relationships between
|
// and Child<int>, but currently libIndex does not expose relationships
|
||||||
// implicit specializations.
|
// between implicit specializations.
|
||||||
llvm::Optional<TypeHierarchyItem> Result = getTypeHierarchy(
|
llvm::Optional<TypeHierarchyItem> Result = getTypeHierarchy(
|
||||||
AST, Source.points()[0], 2, TypeHierarchyDirection::Children, Index.get(),
|
AST, Source.points()[0], 2, TypeHierarchyDirection::Children, Index.get(),
|
||||||
testPath(TU.Filename));
|
testPath(TU.Filename));
|
||||||
ASSERT_TRUE(bool(Result));
|
ASSERT_TRUE(bool(Result));
|
||||||
EXPECT_THAT(*Result,
|
EXPECT_THAT(*Result,
|
||||||
AllOf(WithName("Parent<int>"), WithKind(SymbolKind::Struct),
|
AllOf(WithName("Parent"), WithKind(SymbolKind::Struct),
|
||||||
Children(AllOf(WithName("Child"),
|
Children(AllOf(WithName("Child"),
|
||||||
WithKind(SymbolKind::Struct), Children()))));
|
WithKind(SymbolKind::Struct), Children()))));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue