llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clangd

Author: Christian Kandeler (ckandeler)

<details>
<summary>Changes</summary>

## Summary
- `superTypes()` resolved each parent purely by looking up its `SymbolID` in 
the symbol index. When an immediate parent is an implicit template 
instantiation (e.g. a mixin template deriving from one of its own template 
parameters, as in `template&lt;typename Parent&gt; struct Mixin : Parent, 
MixinBase {};` used as `struct C : Mixin&lt;A&gt; {};`), that instantiation is 
never indexed, so the lookup fails. Since it was the only immediate parent, the 
whole response degraded to no supertypes at all, hiding otherwise-indexed 
ancestors further up the chain.
- `superTypes()` now falls back to the already-computed nested parent data for 
any parent whose lookup fails, skipping over the unindexed link and surfacing 
its own parents directly instead.

## Test plan
- [x] Added `Standard.SuperTypesSkipsUnindexedImplicitInstantiation` in 
`TypeHierarchyTests.cpp`, reproducing the bug and verifying the fix.
- [x] `ninja check-clangd` passes (1513 tests, 8 pre-existing unsupported, 0 
failed).

Assisted-by: Claude

---
Full diff: https://github.com/llvm/llvm-project/pull/220240.diff


2 Files Affected:

- (modified) clang-tools-extra/clangd/XRefs.cpp (+26-8) 
- (modified) clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp (+28) 


``````````diff
diff --git a/clang-tools-extra/clangd/XRefs.cpp 
b/clang-tools-extra/clangd/XRefs.cpp
index 86528d806eab3..ca20eacd5eb82 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -2335,23 +2335,41 @@ getTypeHierarchy(ParsedAST &AST, Position Pos, int 
ResolveLevels,
   return Results;
 }
 
-std::optional<std::vector<TypeHierarchyItem>>
-superTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index) {
-  if (!Index || !Item.data.parents)
-    return std::nullopt;
+// Resolves Parents against the index and appends the results to Results.
+// Parents that cannot be found in the index (e.g. because they are implicit
+// template instantiations, which clangd never indexes) are skipped over:
+// their own already-known parents are resolved instead, so a single
+// unindexed link in the chain doesn't hide everything above it.
+static void
+resolveParents(llvm::ArrayRef<TypeHierarchyItem::ResolveParams> Parents,
+               llvm::StringRef TUPath, const SymbolIndex &Index,
+               std::vector<TypeHierarchyItem> &Results) {
   LookupRequest Req;
   llvm::DenseMap<SymbolID, const TypeHierarchyItem::ResolveParams *> IDToData;
-  for (const auto &Parent : *Item.data.parents) {
+  for (const auto &Parent : Parents) {
     Req.IDs.insert(Parent.symbolID);
     IDToData[Parent.symbolID] = &Parent;
   }
-  std::vector<TypeHierarchyItem> Results;
-  Index->lookup(Req, [&Item, &Results, &IDToData](const Symbol &S) {
-    if (auto THI = symbolToTypeHierarchyItem(S, Item.uri.file())) {
+  llvm::DenseSet<SymbolID> Found;
+  Index.lookup(Req, [&](const Symbol &S) {
+    if (auto THI = symbolToTypeHierarchyItem(S, TUPath)) {
       THI->data = *IDToData.lookup(S.ID);
       Results.emplace_back(std::move(*THI));
+      Found.insert(S.ID);
     }
   });
+  for (const auto &Parent : Parents) {
+    if (!Found.contains(Parent.symbolID) && Parent.parents)
+      resolveParents(*Parent.parents, TUPath, Index, Results);
+  }
+}
+
+std::optional<std::vector<TypeHierarchyItem>>
+superTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index) {
+  if (!Index || !Item.data.parents)
+    return std::nullopt;
+  std::vector<TypeHierarchyItem> Results;
+  resolveParents(*Item.data.parents, Item.uri.file(), *Index, Results);
   return Results.empty() ? std::nullopt
                          : std::make_optional(std::move(Results));
 }
diff --git a/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp 
b/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp
index 754063ede2724..e40e0ee11a8ae 100644
--- a/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp
+++ b/clang-tools-extra/clangd/unittests/TypeHierarchyTests.cpp
@@ -825,6 +825,34 @@ struct Chil^d : Parent {};
                   withSymbolTags(SymbolTag::Declaration, 
SymbolTag::Definition),
                   withResolveParents(Optional(IsEmpty()))))));
 }
+
+// A base class that is an implicit template instantiation
+// (like Mixin<RootBase> below) is never indexed, so
+// looking it up while resolving supertypes fails. superTypes() should not
+// let that hide everything above it; it should skip over the unresolvable
+// link and surface its own already-known parents instead.
+TEST(Standard, SuperTypesSkipsUnindexedImplicitInstantiation) {
+  Annotations Source(R"cpp(
+struct RootBase {};
+struct OtherBase {};
+template <typename T>
+struct Mixin : T, OtherBase {};
+struct Deri^ved : Mixin<RootBase> {};
+)cpp");
+
+  TestTU TU = TestTU::withCode(Source.code());
+  auto AST = TU.build();
+  auto Index = TU.index();
+
+  auto Result = getTypeHierarchy(AST, Source.point(), /*ResolveLevels=*/1,
+                                 TypeHierarchyDirection::Children, Index.get(),
+                                 testPath(TU.Filename));
+  ASSERT_THAT(Result, SizeIs(1));
+  auto Parents = superTypes(Result.front(), Index.get());
+
+  EXPECT_THAT(Parents, Optional(UnorderedElementsAre(withName("RootBase"),
+                                                     withName("OtherBase"))));
+}
 } // namespace
 } // namespace clangd
 } // namespace clang

``````````

</details>


https://github.com/llvm/llvm-project/pull/220240
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to