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 @@ -137,7 +137,7 @@ SelectionTree Selection(AST.getASTContext(), AST.getTokens(), Offset); std::vector Result; if (const SelectionTree::Node *N = Selection.commonAncestor()) { - auto Decls = targetDecl(N->ASTNode, Relations); + auto Decls = explicitReferenceTargets(N->ASTNode, Relations); Result.assign(Decls.begin(), Decls.end()); } return Result; @@ -229,8 +229,7 @@ } // Emit all symbol locations (declaration or definition) from AST. - DeclRelationSet Relations = - DeclRelation::TemplatePattern | DeclRelation::Alias; + DeclRelationSet Relations = DeclRelation::Alias; for (const Decl *D : getDeclAtPosition(AST, SourceLoc, Relations)) { const Decl *Def = getDefinition(D); const Decl *Preferred = Def ? Def : D; @@ -371,8 +370,7 @@ Position Pos) { const SourceManager &SM = AST.getSourceManager(); // FIXME: show references to macro within file? - DeclRelationSet Relations = - DeclRelation::TemplatePattern | DeclRelation::Alias; + DeclRelationSet Relations = DeclRelation::Alias; auto References = findRefs( getDeclAtPosition(AST, SM.getMacroArgExpandedLocation(getBeginningOfIdentifier( @@ -417,8 +415,7 @@ // TODO: should we handle macros, too? // We also show references to the targets of using-decls, so we include // DeclRelation::Underlying. - DeclRelationSet Relations = DeclRelation::TemplatePattern | - DeclRelation::Alias | DeclRelation::Underlying; + DeclRelationSet Relations = DeclRelation::Alias | DeclRelation::Underlying; auto Decls = getDeclAtPosition(AST, Loc, Relations); // We traverse the AST to find references in the main file. @@ -484,8 +481,7 @@ // We also want the targets of using-decls, so we include // DeclRelation::Underlying. - DeclRelationSet Relations = DeclRelation::TemplatePattern | - DeclRelation::Alias | DeclRelation::Underlying; + DeclRelationSet Relations = DeclRelation::Alias | DeclRelation::Underlying; for (const Decl *D : getDeclAtPosition(AST, Loc, Relations)) { SymbolDetails NewSymbol; if (const NamedDecl *ND = dyn_cast(D)) { @@ -654,8 +650,10 @@ const SourceManager &SM = AST.getSourceManager(); SourceLocation SourceLocationBeg = SM.getMacroArgExpandedLocation( getBeginningOfIdentifier(Pos, SM, AST.getLangOpts())); - DeclRelationSet Relations = - DeclRelation::TemplatePattern | DeclRelation::Underlying; + // Search for both template instantiations and template patterns. + // We prefer the former, if available (generally, one will be + // available for non-dependent specializations of a class template). + DeclRelationSet Relations = DeclRelation::Underlying; auto Decls = getDeclAtPosition(AST, SourceLocationBeg, Relations); if (Decls.empty()) return nullptr; @@ -736,6 +734,11 @@ 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 @@ -409,17 +409,13 @@ ASSERT_TRUE(!AST.getDiagnostics().empty()); // Make sure getTypeHierarchy() doesn't get into an infinite recursion. - // FIXME(nridge): It would be preferable if the type hierarchy gave us type - // names (e.g. "S<0>" for the child and "S<1>" for the parent) rather than - // template names (e.g. "S"). + // Here, we actually don't get any parents, because the unbounded hierarchy + // causes instantiation of the base specifier to fail. llvm::Optional Result = getTypeHierarchy( AST, Source.points()[0], 0, TypeHierarchyDirection::Parents); ASSERT_TRUE(bool(Result)); - EXPECT_THAT( - *Result, - AllOf(WithName("S"), WithKind(SymbolKind::Struct), - Parents(AllOf(WithName("S"), WithKind(SymbolKind::Struct), - SelectionRangeIs(Source.range("SDef")), Parents())))); + EXPECT_THAT(*Result, + AllOf(WithName("S<0>"), WithKind(SymbolKind::Struct), Parents())); } TEST(TypeHierarchy, RecursiveHierarchyBounded) { @@ -449,9 +445,12 @@ ASSERT_TRUE(bool(Result)); EXPECT_THAT( *Result, - AllOf(WithName("S"), WithKind(SymbolKind::Struct), - Parents(AllOf(WithName("S"), WithKind(SymbolKind::Struct), - SelectionRangeIs(Source.range("SDef")), Parents())))); + AllOf(WithName("S<2>"), WithKind(SymbolKind::Struct), + Parents(AllOf( + WithName("S<1>"), WithKind(SymbolKind::Struct), + SelectionRangeIs(Source.range("SDef")), + Parents(AllOf(WithName("S<0>"), WithKind(SymbolKind::Struct), + Parents())))))); Result = getTypeHierarchy(AST, Source.point("SRefDependent"), 0, TypeHierarchyDirection::Parents); ASSERT_TRUE(bool(Result)); @@ -462,6 +461,83 @@ SelectionRangeIs(Source.range("SDef")), Parents())))); } +TEST(TypeHierarchy, DeriveFromImplicitSpec) { + Annotations Source(R"cpp( + template + struct Parent {}; + + struct Child : Parent {}; + + Parent Fo^o; + )cpp"); + + TestTU TU = TestTU::withCode(Source.code()); + auto AST = TU.build(); + auto Index = TU.index(); + ASSERT_TRUE(AST.getDiagnostics().empty()); + + 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), + Children(AllOf(WithName("Child"), + WithKind(SymbolKind::Struct), Children())))); +} + +TEST(TypeHierarchy, DeriveFromPartialSpec) { + Annotations Source(R"cpp( + template struct Parent {}; + template struct Parent {}; + + struct Child : Parent {}; + + Parent Fo^o; + )cpp"); + + TestTU TU = TestTU::withCode(Source.code()); + auto AST = TU.build(); + auto Index = TU.index(); + ASSERT_TRUE(AST.getDiagnostics().empty()); + + 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), Children())); +} + +TEST(TypeHierarchy, DeriveFromTemplate) { + Annotations Source(R"cpp( + template + struct Parent {}; + + template + struct Child : Parent {}; + + Parent Fo^o; + )cpp"); + + TestTU TU = TestTU::withCode(Source.code()); + auto AST = TU.build(); + auto Index = TU.index(); + ASSERT_TRUE(AST.getDiagnostics().empty()); + + // FIXME: We'd like this to return the implicit specialization 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), + Children(AllOf(WithName("Child"), + WithKind(SymbolKind::Struct), Children())))); +} + SymbolID findSymbolIDByName(SymbolIndex *Index, llvm::StringRef Name, llvm::StringRef TemplateArgs = "") { SymbolID Result;