[PATCH] D59083: [clangd] Store explicit template specializations in index for code navigation purposes

2019-03-14 Thread Kadir Cetinkaya via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL356125: [clangd] Store explicit template specializations in 
index for code navigation… (authored by kadircet, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59083/new/

https://reviews.llvm.org/D59083

Files:
  clang-tools-extra/trunk/clangd/CodeComplete.cpp
  clang-tools-extra/trunk/clangd/index/MemIndex.cpp
  clang-tools-extra/trunk/clangd/index/SymbolCollector.cpp
  clang-tools-extra/trunk/clangd/index/dex/Dex.cpp
  clang-tools-extra/trunk/unittests/clangd/DexTests.cpp
  clang-tools-extra/trunk/unittests/clangd/IndexTests.cpp
  clang-tools-extra/trunk/unittests/clangd/SymbolCollectorTests.cpp

Index: clang-tools-extra/trunk/clangd/CodeComplete.cpp
===
--- clang-tools-extra/trunk/clangd/CodeComplete.cpp
+++ clang-tools-extra/trunk/clangd/CodeComplete.cpp
@@ -1510,6 +1510,13 @@
   }
 };
 
+template  bool isExplicitTemplateSpecialization(const NamedDecl ) {
+  if (const auto *TD = dyn_cast())
+if (TD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+  return true;
+  return false;
+}
+
 } // namespace
 
 clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const {
@@ -1603,6 +1610,13 @@
 };
 return false;
   };
+  // We only complete symbol's name, which is the same as the name of the
+  // *primary* template in case of template specializations.
+  if (isExplicitTemplateSpecialization(ND) ||
+  isExplicitTemplateSpecialization(ND) ||
+  isExplicitTemplateSpecialization(ND))
+return false;
+
   if (InTopLevelScope(ND))
 return true;
 
Index: clang-tools-extra/trunk/clangd/index/SymbolCollector.cpp
===
--- clang-tools-extra/trunk/clangd/index/SymbolCollector.cpp
+++ clang-tools-extra/trunk/clangd/index/SymbolCollector.cpp
@@ -221,13 +221,6 @@
   return static_cast(static_cast(RefKind::All) & Roles);
 }
 
-template  bool explicitTemplateSpecialization(const NamedDecl ) {
-  if (const auto *TD = dyn_cast())
-if (TD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
-  return true;
-  return false;
-}
-
 } // namespace
 
 SymbolCollector::SymbolCollector(Options Opts) : Opts(std::move(Opts)) {}
@@ -279,10 +272,6 @@
 if (!isa(DeclCtx))
   return false;
   }
-  if (explicitTemplateSpecialization(ND) ||
-  explicitTemplateSpecialization(ND) ||
-  explicitTemplateSpecialization(ND))
-return false;
 
   // Avoid indexing internal symbols in protobuf generated headers.
   if (isPrivateProtoDecl(ND))
Index: clang-tools-extra/trunk/clangd/index/MemIndex.cpp
===
--- clang-tools-extra/trunk/clangd/index/MemIndex.cpp
+++ clang-tools-extra/trunk/clangd/index/MemIndex.cpp
@@ -11,6 +11,7 @@
 #include "Logger.h"
 #include "Quality.h"
 #include "Trace.h"
+#include "clang/Index/IndexSymbol.h"
 
 namespace clang {
 namespace clangd {
@@ -37,6 +38,15 @@
   for (const auto Pair : Index) {
 const Symbol *Sym = Pair.second;
 
+// FIXME: Enable fuzzy find on template specializations once we start
+// storing template arguments in the name. Currently we only store name for
+// class template, which would cause duplication in the results.
+if (Sym->SymInfo.Properties &
+(static_cast(
+ index::SymbolProperty::TemplateSpecialization) |
+ static_cast(
+ index::SymbolProperty::TemplatePartialSpecialization)))
+  continue;
 // Exact match against all possible scopes.
 if (!Req.AnyScope && !llvm::is_contained(Req.Scopes, Sym->Scope))
   continue;
Index: clang-tools-extra/trunk/clangd/index/dex/Dex.cpp
===
--- clang-tools-extra/trunk/clangd/index/dex/Dex.cpp
+++ clang-tools-extra/trunk/clangd/index/dex/Dex.cpp
@@ -86,6 +86,15 @@
   llvm::DenseMap> TempInvertedIndex;
   for (DocID SymbolRank = 0; SymbolRank < Symbols.size(); ++SymbolRank) {
 const auto *Sym = Symbols[SymbolRank];
+// FIXME: Enable fuzzy find on template specializations once we start
+// storing template arguments in the name. Currently we only store name for
+// class template, which would cause duplication in the results.
+if (Sym->SymInfo.Properties &
+(static_cast(
+ index::SymbolProperty::TemplateSpecialization) |
+ static_cast(
+ index::SymbolProperty::TemplatePartialSpecialization)))
+  continue;
 for (const auto  : generateSearchTokens(*Sym))
   TempInvertedIndex[Token].push_back(SymbolRank);
   }
Index: clang-tools-extra/trunk/unittests/clangd/SymbolCollectorTests.cpp
===
--- 

[PATCH] D59083: [clangd] Store explicit template specializations in index for code navigation purposes

2019-03-13 Thread Kadir Cetinkaya via Phabricator via cfe-commits
kadircet added a comment.

In D59083#1426105 , @ilya-biryukov 
wrote:

> To split this into multiple independent changes, we could start with storing 
> the symbols for template specializations, but only showing the primary 
> template in the results of workspaceSymbols.
>  This would enable other features (xrefs, etc), and we could re-add 
> specializations to workspaceSymbols after we improve the presentation.


SGTM, moving forward with that approach.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59083/new/

https://reviews.llvm.org/D59083



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59083: [clangd] Store explicit template specializations in index for code navigation purposes

2019-03-13 Thread Kadir Cetinkaya via Phabricator via cfe-commits
kadircet updated this revision to Diff 190382.
kadircet marked an inline comment as done.
kadircet added a comment.

- Agree on ilya-biryukov@'s suggestion, changing fuzzyfind to skip template 
(partial) specializations for now.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59083/new/

https://reviews.llvm.org/D59083

Files:
  clangd/CodeComplete.cpp
  clangd/index/MemIndex.cpp
  clangd/index/SymbolCollector.cpp
  clangd/index/dex/Dex.cpp
  unittests/clangd/DexTests.cpp
  unittests/clangd/IndexTests.cpp
  unittests/clangd/SymbolCollectorTests.cpp

Index: unittests/clangd/SymbolCollectorTests.cpp
===
--- unittests/clangd/SymbolCollectorTests.cpp
+++ unittests/clangd/SymbolCollectorTests.cpp
@@ -392,17 +392,25 @@
 
 TEST_F(SymbolCollectorTest, Template) {
   Annotations Header(R"(
-// Template is indexed, specialization and instantiation is not.
-template  struct [[Tmpl]] {T $xdecl[[x]] = 0;};
-template <> struct Tmpl {};
-extern template struct Tmpl;
-template struct Tmpl;
+// Primary template and explicit specialization are indexed, instantiation
+// is not.
+template  struct [[Tmpl]] {T $xdecl[[x]] = 0;};
+template <> struct $specdecl[[Tmpl]] {};
+template  struct $partspecdecl[[Tmpl]] {};
+extern template struct Tmpl;
+template struct Tmpl;
   )");
   runSymbolCollector(Header.code(), /*Main=*/"");
   EXPECT_THAT(Symbols,
-  UnorderedElementsAreArray(
-  {AllOf(QName("Tmpl"), DeclRange(Header.range())),
-   AllOf(QName("Tmpl::x"), DeclRange(Header.range("xdecl")))}));
+  UnorderedElementsAre(
+  AllOf(QName("Tmpl"), DeclRange(Header.range()),
+ForCodeCompletion(true)),
+  AllOf(QName("Tmpl"), DeclRange(Header.range("specdecl")),
+ForCodeCompletion(false)),
+  AllOf(QName("Tmpl"), DeclRange(Header.range("partspecdecl")),
+ForCodeCompletion(false)),
+  AllOf(QName("Tmpl::x"), DeclRange(Header.range("xdecl")),
+ForCodeCompletion(false;
 }
 
 TEST_F(SymbolCollectorTest, ObjCSymbols) {
Index: unittests/clangd/IndexTests.cpp
===
--- unittests/clangd/IndexTests.cpp
+++ unittests/clangd/IndexTests.cpp
@@ -13,6 +13,8 @@
 #include "index/Index.h"
 #include "index/MemIndex.h"
 #include "index/Merge.h"
+#include "index/Symbol.h"
+#include "clang/Index/IndexSymbol.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
@@ -181,6 +183,41 @@
   EXPECT_THAT(lookup(*I, SymbolID("ns::nonono")), UnorderedElementsAre());
 }
 
+TEST(MemIndexTest, TemplateSpecialization) {
+  SymbolSlab::Builder B;
+
+  Symbol S = symbol("TempSpec");
+  S.ID = SymbolID("0");
+  B.insert(S);
+
+  S = symbol("TempSpec");
+  S.ID = SymbolID("1");
+  S.SymInfo.Properties = static_cast(
+  index::SymbolProperty::TemplateSpecialization);
+  B.insert(S);
+
+  S = symbol("TempSpec");
+  S.ID = SymbolID("2");
+  S.SymInfo.Properties = static_cast(
+  index::SymbolProperty::TemplatePartialSpecialization);
+  B.insert(S);
+
+  auto I = MemIndex::build(std::move(B).build(), RefSlab());
+  FuzzyFindRequest Req;
+  Req.Query = "TempSpec";
+  Req.AnyScope = true;
+
+  std::vector Symbols;
+  I->fuzzyFind(Req, [](const Symbol ) { Symbols.push_back(Sym); });
+  EXPECT_EQ(Symbols.size(), 1U);
+  EXPECT_FALSE(Symbols.front().SymInfo.Properties &
+   static_cast(
+   index::SymbolProperty::TemplateSpecialization));
+  EXPECT_FALSE(Symbols.front().SymInfo.Properties &
+   static_cast(
+   index::SymbolProperty::TemplatePartialSpecialization));
+}
+
 TEST(MergeIndexTest, Lookup) {
   auto I = MemIndex::build(generateSymbols({"ns::A", "ns::B"}), RefSlab()),
J = MemIndex::build(generateSymbols({"ns::B", "ns::C"}), RefSlab());
Index: unittests/clangd/DexTests.cpp
===
--- unittests/clangd/DexTests.cpp
+++ unittests/clangd/DexTests.cpp
@@ -710,6 +710,41 @@
   EXPECT_THAT(match(I, Req), ElementsAre("t2"));
 }
 
+TEST(DexTest, TemplateSpecialization) {
+  SymbolSlab::Builder B;
+
+  Symbol S = symbol("TempSpec");
+  S.ID = SymbolID("0");
+  B.insert(S);
+
+  S = symbol("TempSpec");
+  S.ID = SymbolID("1");
+  S.SymInfo.Properties = static_cast(
+  index::SymbolProperty::TemplateSpecialization);
+  B.insert(S);
+
+  S = symbol("TempSpec");
+  S.ID = SymbolID("2");
+  S.SymInfo.Properties = static_cast(
+  index::SymbolProperty::TemplatePartialSpecialization);
+  B.insert(S);
+
+  auto I = dex::Dex::build(std::move(B).build(), RefSlab());
+  FuzzyFindRequest Req;
+  Req.Query = "TempSpec";
+  Req.AnyScope = true;
+
+  std::vector Symbols;
+  I->fuzzyFind(Req, [](const Symbol ) { 

[PATCH] D59083: [clangd] Store explicit template specializations in index for code navigation purposes

2019-03-12 Thread Ilya Biryukov via Phabricator via cfe-commits
ilya-biryukov added a comment.

To split this into multiple independent changes, we could start with storing 
the symbols for template specializations, but only showing the primary template 
in the results of workspaceSymbols.
This would enable other features (xrefs, etc), and we could re-add 
specializations to workspaceSymbols after we improve the presentation.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59083/new/

https://reviews.llvm.org/D59083



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59083: [clangd] Store explicit template specializations in index for code navigation purposes

2019-03-11 Thread Nathan Ridge via Phabricator via cfe-commits
nridge added a comment.

One of the use cases I imagined for this (unrelated to D58880 
) is that if the user searches for `vector` 
(using `workspace/symbols`), they get a separate search result for the `vector` 
primary template, and a separate one for `vector`. For this to be useful, 
the server needs to print the `` as part of the search result.

(For D58880 , I would find it useful for be 
able to look up an explicit spec. by template-id in the tests, but that can 
probably be worked around.)


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59083/new/

https://reviews.llvm.org/D59083



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59083: [clangd] Store explicit template specializations in index for code navigation purposes

2019-03-11 Thread Kadir Cetinkaya via Phabricator via cfe-commits
kadircet added a comment.

In D59083#1424509 , @nridge wrote:

> Is any representation of the template arguments stored in the index?


No we only have, class name if you want to do a "name based" search/lookup. But 
symbol IDs for template specializations are different, so you can query them by 
ID.
Do you have any use case that needs names?


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59083/new/

https://reviews.llvm.org/D59083



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59083: [clangd] Store explicit template specializations in index for code navigation purposes

2019-03-11 Thread Nathan Ridge via Phabricator via cfe-commits
nridge added a comment.

Is any representation of the template arguments stored in the index?


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59083/new/

https://reviews.llvm.org/D59083



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59083: [clangd] Store explicit template specializations in index for code navigation purposes

2019-03-08 Thread Dmitri Gribenko via Phabricator via cfe-commits
gribozavr accepted this revision.
gribozavr added inline comments.



Comment at: clangd/CodeComplete.cpp:1613
   };
+  // We only complete symbol's name, which is same as the class template in the
+  // case of template specializations.

which is the same as the name of the *primary* template in case of template 
specializations.


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59083/new/

https://reviews.llvm.org/D59083



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59083: [clangd] Store explicit template specializations in index for code navigation purposes

2019-03-08 Thread Kadir Cetinkaya via Phabricator via cfe-commits
kadircet updated this revision to Diff 189817.
kadircet marked 3 inline comments as done.
kadircet added a comment.

- Address comments


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59083/new/

https://reviews.llvm.org/D59083

Files:
  clangd/CodeComplete.cpp
  clangd/index/SymbolCollector.cpp
  unittests/clangd/SymbolCollectorTests.cpp


Index: unittests/clangd/SymbolCollectorTests.cpp
===
--- unittests/clangd/SymbolCollectorTests.cpp
+++ unittests/clangd/SymbolCollectorTests.cpp
@@ -392,17 +392,25 @@
 
 TEST_F(SymbolCollectorTest, Template) {
   Annotations Header(R"(
-// Template is indexed, specialization and instantiation is not.
-template  struct [[Tmpl]] {T $xdecl[[x]] = 0;};
-template <> struct Tmpl {};
-extern template struct Tmpl;
-template struct Tmpl;
+// Primary template and explicit specialization are indexed, instantiation
+// is not.
+template  struct [[Tmpl]] {T $xdecl[[x]] = 0;};
+template <> struct $specdecl[[Tmpl]] {};
+template  struct $partspecdecl[[Tmpl]] {};
+extern template struct Tmpl;
+template struct Tmpl;
   )");
   runSymbolCollector(Header.code(), /*Main=*/"");
   EXPECT_THAT(Symbols,
-  UnorderedElementsAreArray(
-  {AllOf(QName("Tmpl"), DeclRange(Header.range())),
-   AllOf(QName("Tmpl::x"), 
DeclRange(Header.range("xdecl")))}));
+  UnorderedElementsAre(
+  AllOf(QName("Tmpl"), DeclRange(Header.range()),
+ForCodeCompletion(true)),
+  AllOf(QName("Tmpl"), DeclRange(Header.range("specdecl")),
+ForCodeCompletion(false)),
+  AllOf(QName("Tmpl"), DeclRange(Header.range("partspecdecl")),
+ForCodeCompletion(false)),
+  AllOf(QName("Tmpl::x"), DeclRange(Header.range("xdecl")),
+ForCodeCompletion(false;
 }
 
 TEST_F(SymbolCollectorTest, ObjCSymbols) {
Index: clangd/index/SymbolCollector.cpp
===
--- clangd/index/SymbolCollector.cpp
+++ clangd/index/SymbolCollector.cpp
@@ -221,13 +221,6 @@
   return static_cast(static_cast(RefKind::All) & Roles);
 }
 
-template  bool explicitTemplateSpecialization(const NamedDecl ) {
-  if (const auto *TD = dyn_cast())
-if (TD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
-  return true;
-  return false;
-}
-
 } // namespace
 
 SymbolCollector::SymbolCollector(Options Opts) : Opts(std::move(Opts)) {}
@@ -279,10 +272,6 @@
 if (!isa(DeclCtx))
   return false;
   }
-  if (explicitTemplateSpecialization(ND) ||
-  explicitTemplateSpecialization(ND) ||
-  explicitTemplateSpecialization(ND))
-return false;
 
   // Avoid indexing internal symbols in protobuf generated headers.
   if (isPrivateProtoDecl(ND))
Index: clangd/CodeComplete.cpp
===
--- clangd/CodeComplete.cpp
+++ clangd/CodeComplete.cpp
@@ -1510,6 +1510,13 @@
   }
 };
 
+template  bool isExplicitTemplateSpecialization(const NamedDecl ) {
+  if (const auto *TD = dyn_cast())
+if (TD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+  return true;
+  return false;
+}
+
 } // namespace
 
 clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const {
@@ -1603,6 +1610,13 @@
 };
 return false;
   };
+  // We only complete symbol's name, which is same as the class template in the
+  // case of template specializations.
+  if (isExplicitTemplateSpecialization(ND) ||
+  isExplicitTemplateSpecialization(ND) ||
+  isExplicitTemplateSpecialization(ND))
+return false;
+
   if (InTopLevelScope(ND))
 return true;
 


Index: unittests/clangd/SymbolCollectorTests.cpp
===
--- unittests/clangd/SymbolCollectorTests.cpp
+++ unittests/clangd/SymbolCollectorTests.cpp
@@ -392,17 +392,25 @@
 
 TEST_F(SymbolCollectorTest, Template) {
   Annotations Header(R"(
-// Template is indexed, specialization and instantiation is not.
-template  struct [[Tmpl]] {T $xdecl[[x]] = 0;};
-template <> struct Tmpl {};
-extern template struct Tmpl;
-template struct Tmpl;
+// Primary template and explicit specialization are indexed, instantiation
+// is not.
+template  struct [[Tmpl]] {T $xdecl[[x]] = 0;};
+template <> struct $specdecl[[Tmpl]] {};
+template  struct $partspecdecl[[Tmpl]] {};
+extern template struct Tmpl;
+template struct Tmpl;
   )");
   runSymbolCollector(Header.code(), /*Main=*/"");
   EXPECT_THAT(Symbols,
-  UnorderedElementsAreArray(
-  {AllOf(QName("Tmpl"), DeclRange(Header.range())),
-   AllOf(QName("Tmpl::x"), DeclRange(Header.range("xdecl")))}));
+  

[PATCH] D59083: [clangd] Store explicit template specializations in index for code navigation purposes

2019-03-07 Thread Eric Liu via Phabricator via cfe-commits
ioeric added a comment.

> We need that information for providing better code navigation support, like 
> find references, children/base classes etc.

It's not trivial how they make code navigation better. Can you explain and 
provide examples in the summary? Thanks!




Comment at: clangd/CodeComplete.cpp:1613
   };
+  // We index explicit template specializations merely for code navigation
+  // support.

nit: the context here is code completion. Maybe explain why they are not 
interesting for completion rather than why we index them?


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59083/new/

https://reviews.llvm.org/D59083



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59083: [clangd] Store explicit template specializations in index for code navigation purposes

2019-03-07 Thread Dmitri Gribenko via Phabricator via cfe-commits
gribozavr accepted this revision.
gribozavr added inline comments.
This revision is now accepted and ready to land.



Comment at: clangd/CodeComplete.cpp:1513
 
+template  bool explicitTemplateSpecialization(const NamedDecl ) {
+  if (const auto *TD = dyn_cast())

isExplicitTemplateSpecialization?



Comment at: unittests/clangd/SymbolCollectorTests.cpp:395
   Annotations Header(R"(
-// Template is indexed, specialization and instantiation is not.
-template  struct [[Tmpl]] {T $xdecl[[x]] = 0;};
-template <> struct Tmpl {};
-extern template struct Tmpl;
-template struct Tmpl;
+// Template and explicit specialization is indexed, instantiation is not.
+template  struct [[Tmpl]] {T $xdecl[[x]] = 0;};

"Template" -> "Primary template"

"is indexed" -> "are indexed"


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59083/new/

https://reviews.llvm.org/D59083



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D59083: [clangd] Store explicit template specializations in index for code navigation purposes

2019-03-07 Thread Kadir Cetinkaya via Phabricator via cfe-commits
kadircet created this revision.
kadircet added reviewers: hokein, gribozavr.
Herald added subscribers: cfe-commits, jdoerfert, arphaman, jkorous, MaskRay, 
ioeric, ilya-biryukov.
Herald added a project: clang.

This introduces ~4k new symbols, and ~10k refs for LLVM. We need that
information for providing better code navigation support, like find references,
children/base classes etc.

Number of symbols: 378574 -> 382784
Number of refs: 5098857 -> 5110689


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D59083

Files:
  clangd/CodeComplete.cpp
  clangd/index/SymbolCollector.cpp
  unittests/clangd/SymbolCollectorTests.cpp


Index: unittests/clangd/SymbolCollectorTests.cpp
===
--- unittests/clangd/SymbolCollectorTests.cpp
+++ unittests/clangd/SymbolCollectorTests.cpp
@@ -392,17 +392,24 @@
 
 TEST_F(SymbolCollectorTest, Template) {
   Annotations Header(R"(
-// Template is indexed, specialization and instantiation is not.
-template  struct [[Tmpl]] {T $xdecl[[x]] = 0;};
-template <> struct Tmpl {};
-extern template struct Tmpl;
-template struct Tmpl;
+// Template and explicit specialization is indexed, instantiation is not.
+template  struct [[Tmpl]] {T $xdecl[[x]] = 0;};
+template <> struct $specdecl[[Tmpl]] {};
+template  struct $partspecdecl[[Tmpl]] {};
+extern template struct Tmpl;
+template struct Tmpl;
   )");
   runSymbolCollector(Header.code(), /*Main=*/"");
   EXPECT_THAT(Symbols,
-  UnorderedElementsAreArray(
-  {AllOf(QName("Tmpl"), DeclRange(Header.range())),
-   AllOf(QName("Tmpl::x"), 
DeclRange(Header.range("xdecl")))}));
+  UnorderedElementsAre(
+  AllOf(QName("Tmpl"), DeclRange(Header.range()),
+ForCodeCompletion(true)),
+  AllOf(QName("Tmpl"), DeclRange(Header.range("specdecl")),
+ForCodeCompletion(false)),
+  AllOf(QName("Tmpl"), DeclRange(Header.range("partspecdecl")),
+ForCodeCompletion(false)),
+  AllOf(QName("Tmpl::x"), DeclRange(Header.range("xdecl")),
+ForCodeCompletion(false;
 }
 
 TEST_F(SymbolCollectorTest, ObjCSymbols) {
Index: clangd/index/SymbolCollector.cpp
===
--- clangd/index/SymbolCollector.cpp
+++ clangd/index/SymbolCollector.cpp
@@ -221,13 +221,6 @@
   return static_cast(static_cast(RefKind::All) & Roles);
 }
 
-template  bool explicitTemplateSpecialization(const NamedDecl ) {
-  if (const auto *TD = dyn_cast())
-if (TD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
-  return true;
-  return false;
-}
-
 } // namespace
 
 SymbolCollector::SymbolCollector(Options Opts) : Opts(std::move(Opts)) {}
@@ -279,10 +272,6 @@
 if (!isa(DeclCtx))
   return false;
   }
-  if (explicitTemplateSpecialization(ND) ||
-  explicitTemplateSpecialization(ND) ||
-  explicitTemplateSpecialization(ND))
-return false;
 
   // Avoid indexing internal symbols in protobuf generated headers.
   if (isPrivateProtoDecl(ND))
Index: clangd/CodeComplete.cpp
===
--- clangd/CodeComplete.cpp
+++ clangd/CodeComplete.cpp
@@ -1510,6 +1510,13 @@
   }
 };
 
+template  bool explicitTemplateSpecialization(const NamedDecl ) {
+  if (const auto *TD = dyn_cast())
+if (TD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+  return true;
+  return false;
+}
+
 } // namespace
 
 clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const {
@@ -1603,6 +1610,13 @@
 };
 return false;
   };
+  // We index explicit template specializations merely for code navigation
+  // support.
+  if (explicitTemplateSpecialization(ND) ||
+  explicitTemplateSpecialization(ND) ||
+  explicitTemplateSpecialization(ND))
+return false;
+
   if (InTopLevelScope(ND))
 return true;
 


Index: unittests/clangd/SymbolCollectorTests.cpp
===
--- unittests/clangd/SymbolCollectorTests.cpp
+++ unittests/clangd/SymbolCollectorTests.cpp
@@ -392,17 +392,24 @@
 
 TEST_F(SymbolCollectorTest, Template) {
   Annotations Header(R"(
-// Template is indexed, specialization and instantiation is not.
-template  struct [[Tmpl]] {T $xdecl[[x]] = 0;};
-template <> struct Tmpl {};
-extern template struct Tmpl;
-template struct Tmpl;
+// Template and explicit specialization is indexed, instantiation is not.
+template  struct [[Tmpl]] {T $xdecl[[x]] = 0;};
+template <> struct $specdecl[[Tmpl]] {};
+template  struct $partspecdecl[[Tmpl]] {};
+extern template struct Tmpl;
+template struct Tmpl;
   )");
   runSymbolCollector(Header.code(), /*Main=*/"");
   EXPECT_THAT(Symbols,
-