[PATCH] D88469: [clangd] Heuristic resolution for dependent type and template names

2020-10-12 Thread Nathan Ridge via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG1b962fdd5f36: [clangd] Heuristic resolution for dependent 
type and template names (authored by nridge).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D88469

Files:
  clang-tools-extra/clangd/FindTarget.cpp
  clang-tools-extra/clangd/unittests/FindTargetTests.cpp

Index: clang-tools-extra/clangd/unittests/FindTargetTests.cpp
===
--- clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -728,6 +728,54 @@
"template  T convert() const");
 }
 
+TEST_F(TargetDeclTest, DependentTypes) {
+  Flags = {"-fno-delayed-template-parsing"};
+
+  // Heuristic resolution of dependent type name
+  Code = R"cpp(
+template 
+struct A { struct B {}; };
+
+template 
+void foo(typename A::[[B]]);
+  )cpp";
+  EXPECT_DECLS("DependentNameTypeLoc", "struct B");
+
+  // Heuristic resolution of dependent type name which doesn't get a TypeLoc
+  Code = R"cpp(
+template 
+struct A { struct B { struct C {}; }; };
+
+template 
+void foo(typename A::[[B]]::C);
+  )cpp";
+  EXPECT_DECLS("NestedNameSpecifierLoc", "struct B");
+
+  // Heuristic resolution of dependent type name whose qualifier is also
+  // dependent
+  Code = R"cpp(
+template 
+struct A { struct B { struct C {}; }; };
+
+template 
+void foo(typename A::B::[[C]]);
+  )cpp";
+  EXPECT_DECLS("DependentNameTypeLoc", "struct C");
+
+  // Heuristic resolution of dependent template name
+  Code = R"cpp(
+template 
+struct A {
+  template  struct B {};
+};
+
+template 
+void foo(typename A::template [[B]]);
+  )cpp";
+  EXPECT_DECLS("DependentTemplateSpecializationTypeLoc",
+   "template  struct B");
+}
+
 TEST_F(TargetDeclTest, ObjC) {
   Flags = {"-xobjective-c"};
   Code = R"cpp(
Index: clang-tools-extra/clangd/FindTarget.cpp
===
--- clang-tools-extra/clangd/FindTarget.cpp
+++ clang-tools-extra/clangd/FindTarget.cpp
@@ -125,6 +125,10 @@
   return !D->isCXXInstanceMember();
 };
 const auto ValueFilter = [](const NamedDecl *D) { return isa(D); };
+const auto TypeFilter = [](const NamedDecl *D) { return isa(D); };
+const auto TemplateFilter = [](const NamedDecl *D) {
+  return isa(D);
+};
 
 // Given the type T of a dependent expression that appears of the LHS of a
 // "->", heuristically find a corresponding pointee type in whose scope we
@@ -219,19 +223,45 @@
   return {};
 }
 
-// Try to heuristically resolve the type of a possibly-dependent expression `E`.
-const Type *resolveExprToType(const Expr *E) {
-  std::vector Decls = resolveExprToDecls(E);
+const Type *resolveDeclsToType(const std::vector &Decls) {
   if (Decls.size() != 1) // Names an overload set -- just bail.
 return nullptr;
   if (const auto *TD = dyn_cast(Decls[0])) {
 return TD->getTypeForDecl();
-  } else if (const auto *VD = dyn_cast(Decls[0])) {
+  }
+  if (const auto *VD = dyn_cast(Decls[0])) {
 return VD->getType().getTypePtrOrNull();
   }
   return nullptr;
 }
 
+// Try to heuristically resolve the type of a possibly-dependent expression `E`.
+const Type *resolveExprToType(const Expr *E) {
+  return resolveDeclsToType(resolveExprToDecls(E));
+}
+
+// Try to heuristically resolve the type of a possibly-dependent nested name
+// specifier.
+const Type *resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS) {
+  if (!NNS)
+return nullptr;
+
+  switch (NNS->getKind()) {
+  case NestedNameSpecifier::TypeSpec:
+  case NestedNameSpecifier::TypeSpecWithTemplate:
+return NNS->getAsType();
+  case NestedNameSpecifier::Identifier: {
+return resolveDeclsToType(getMembersReferencedViaDependentName(
+resolveNestedNameSpecifierToType(NNS->getPrefix()),
+[&](const ASTContext &) { return NNS->getAsIdentifier(); },
+TypeFilter));
+  }
+  default:
+break;
+  }
+  return nullptr;
+}
+
 const NamedDecl *getTemplatePattern(const NamedDecl *D) {
   if (const CXXRecordDecl *CRD = dyn_cast(D)) {
 if (const auto *Result = CRD->getTemplateInstantiationPattern())
@@ -291,10 +321,8 @@
 //and both are lossy. We must know upfront what the caller ultimately wants.
 //
 // FIXME: improve common dependent scope using name lookup in primary templates.
-// We currently handle DependentScopeDeclRefExpr and
-// CXXDependentScopeMemberExpr, but some other constructs remain to be handled:
-//  - DependentTemplateSpecializationType,
-//  - DependentNameType
+// We currently handle several dependent constructs, but some others remain to
+// be handled:
 //  - UnresolvedUsingTypenameDecl
 struct TargetFinder {
   using RelSet = Decl

[PATCH] D88469: [clangd] Heuristic resolution for dependent type and template names

2020-10-12 Thread Haojian Wu via Phabricator via cfe-commits
hokein accepted this revision.
hokein added a comment.
This revision is now accepted and ready to land.

thanks.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D88469

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


[PATCH] D88469: [clangd] Heuristic resolution for dependent type and template names

2020-10-10 Thread Nathan Ridge via Phabricator via cfe-commits
nridge updated this revision to Diff 297445.
nridge marked an inline comment as done.
nridge added a comment.

Address review comment


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D88469

Files:
  clang-tools-extra/clangd/FindTarget.cpp
  clang-tools-extra/clangd/unittests/FindTargetTests.cpp

Index: clang-tools-extra/clangd/unittests/FindTargetTests.cpp
===
--- clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -731,6 +731,54 @@
"template  T convert() const");
 }
 
+TEST_F(TargetDeclTest, DependentTypes) {
+  Flags = {"-fno-delayed-template-parsing"};
+
+  // Heuristic resolution of dependent type name
+  Code = R"cpp(
+template 
+struct A { struct B {}; };
+
+template 
+void foo(typename A::[[B]]);
+  )cpp";
+  EXPECT_DECLS("DependentNameTypeLoc", "struct B");
+
+  // Heuristic resolution of dependent type name which doesn't get a TypeLoc
+  Code = R"cpp(
+template 
+struct A { struct B { struct C {}; }; };
+
+template 
+void foo(typename A::[[B]]::C);
+  )cpp";
+  EXPECT_DECLS("NestedNameSpecifierLoc", "struct B");
+
+  // Heuristic resolution of dependent type name whose qualifier is also
+  // dependent
+  Code = R"cpp(
+template 
+struct A { struct B { struct C {}; }; };
+
+template 
+void foo(typename A::B::[[C]]);
+  )cpp";
+  EXPECT_DECLS("DependentNameTypeLoc", "struct C");
+
+  // Heuristic resolution of dependent template name
+  Code = R"cpp(
+template 
+struct A {
+  template  struct B {};
+};
+
+template 
+void foo(typename A::template [[B]]);
+  )cpp";
+  EXPECT_DECLS("DependentTemplateSpecializationTypeLoc",
+   "template  struct B");
+}
+
 TEST_F(TargetDeclTest, ObjC) {
   Flags = {"-xobjective-c"};
   Code = R"cpp(
Index: clang-tools-extra/clangd/FindTarget.cpp
===
--- clang-tools-extra/clangd/FindTarget.cpp
+++ clang-tools-extra/clangd/FindTarget.cpp
@@ -125,6 +125,10 @@
   return !D->isCXXInstanceMember();
 };
 const auto ValueFilter = [](const NamedDecl *D) { return isa(D); };
+const auto TypeFilter = [](const NamedDecl *D) { return isa(D); };
+const auto TemplateFilter = [](const NamedDecl *D) {
+  return isa(D);
+};
 
 // Given the type T of a dependent expression that appears of the LHS of a
 // "->", heuristically find a corresponding pointee type in whose scope we
@@ -219,19 +223,45 @@
   return {};
 }
 
-// Try to heuristically resolve the type of a possibly-dependent expression `E`.
-const Type *resolveExprToType(const Expr *E) {
-  std::vector Decls = resolveExprToDecls(E);
+const Type *resolveDeclsToType(const std::vector &Decls) {
   if (Decls.size() != 1) // Names an overload set -- just bail.
 return nullptr;
   if (const auto *TD = dyn_cast(Decls[0])) {
 return TD->getTypeForDecl();
-  } else if (const auto *VD = dyn_cast(Decls[0])) {
+  }
+  if (const auto *VD = dyn_cast(Decls[0])) {
 return VD->getType().getTypePtrOrNull();
   }
   return nullptr;
 }
 
+// Try to heuristically resolve the type of a possibly-dependent expression `E`.
+const Type *resolveExprToType(const Expr *E) {
+  return resolveDeclsToType(resolveExprToDecls(E));
+}
+
+// Try to heuristically resolve the type of a possibly-dependent nested name
+// specifier.
+const Type *resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS) {
+  if (!NNS)
+return nullptr;
+
+  switch (NNS->getKind()) {
+  case NestedNameSpecifier::TypeSpec:
+  case NestedNameSpecifier::TypeSpecWithTemplate:
+return NNS->getAsType();
+  case NestedNameSpecifier::Identifier: {
+return resolveDeclsToType(getMembersReferencedViaDependentName(
+resolveNestedNameSpecifierToType(NNS->getPrefix()),
+[&](const ASTContext &) { return NNS->getAsIdentifier(); },
+TypeFilter));
+  }
+  default:
+break;
+  }
+  return nullptr;
+}
+
 const NamedDecl *getTemplatePattern(const NamedDecl *D) {
   if (const CXXRecordDecl *CRD = dyn_cast(D)) {
 if (const auto *Result = CRD->getTemplateInstantiationPattern())
@@ -291,10 +321,8 @@
 //and both are lossy. We must know upfront what the caller ultimately wants.
 //
 // FIXME: improve common dependent scope using name lookup in primary templates.
-// We currently handle DependentScopeDeclRefExpr and
-// CXXDependentScopeMemberExpr, but some other constructs remain to be handled:
-//  - DependentTemplateSpecializationType,
-//  - DependentNameType
+// We currently handle several dependent constructs, but some others remain to
+// be handled:
 //  - UnresolvedUsingTypenameDecl
 struct TargetFinder {
   using RelSet = DeclRelationSet;
@@ -536,6 +564,23 @@
 if (auto *TD = DTST-

[PATCH] D88469: [clangd] Heuristic resolution for dependent type and template names

2020-10-05 Thread Haojian Wu via Phabricator via cfe-commits
hokein added inline comments.



Comment at: clang-tools-extra/clangd/FindTarget.cpp:578
+for (const NamedDecl *ND : getMembersReferencedViaDependentName(
+ resolveNestedNameSpecifierToType(DTST->getQualifier()),
+ [DTST](ASTContext &) { return DTST->getIdentifier(); },

we need to be robust in `resolveNestedNameSpecifierToType` -- we may get a null 
qualifier for DependentTemplateSpecializationType, see 
https://reviews.llvm.org/D76320.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D88469

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


[PATCH] D88469: [clangd] Heuristic resolution for dependent type and template names

2020-10-03 Thread Nathan Ridge via Phabricator via cfe-commits
nridge updated this revision to Diff 296019.
nridge added a comment.

Address review comments


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D88469

Files:
  clang-tools-extra/clangd/FindTarget.cpp
  clang-tools-extra/clangd/unittests/FindTargetTests.cpp

Index: clang-tools-extra/clangd/unittests/FindTargetTests.cpp
===
--- clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -731,6 +731,54 @@
"template  T convert() const");
 }
 
+TEST_F(TargetDeclTest, DependentTypes) {
+  Flags = {"-fno-delayed-template-parsing"};
+
+  // Heuristic resolution of dependent type name
+  Code = R"cpp(
+template 
+struct A { struct B {}; };
+
+template 
+void foo(typename A::[[B]]);
+  )cpp";
+  EXPECT_DECLS("DependentNameTypeLoc", "struct B");
+
+  // Heuristic resolution of dependent type name which doesn't get a TypeLoc
+  Code = R"cpp(
+template 
+struct A { struct B { struct C {}; }; };
+
+template 
+void foo(typename A::[[B]]::C);
+  )cpp";
+  EXPECT_DECLS("NestedNameSpecifierLoc", "struct B");
+
+  // Heuristic resolution of dependent type name whose qualifier is also
+  // dependent
+  Code = R"cpp(
+template 
+struct A { struct B { struct C {}; }; };
+
+template 
+void foo(typename A::B::[[C]]);
+  )cpp";
+  EXPECT_DECLS("DependentNameTypeLoc", "struct C");
+
+  // Heuristic resolution of dependent template name
+  Code = R"cpp(
+template 
+struct A {
+  template  struct B {};
+};
+
+template 
+void foo(typename A::template [[B]]);
+  )cpp";
+  EXPECT_DECLS("DependentTemplateSpecializationTypeLoc",
+   "template  struct B");
+}
+
 TEST_F(TargetDeclTest, ObjC) {
   Flags = {"-xobjective-c"};
   Code = R"cpp(
Index: clang-tools-extra/clangd/FindTarget.cpp
===
--- clang-tools-extra/clangd/FindTarget.cpp
+++ clang-tools-extra/clangd/FindTarget.cpp
@@ -125,6 +125,10 @@
   return !D->isCXXInstanceMember();
 };
 const auto ValueFilter = [](const NamedDecl *D) { return isa(D); };
+const auto TypeFilter = [](const NamedDecl *D) { return isa(D); };
+const auto TemplateFilter = [](const NamedDecl *D) {
+  return isa(D);
+};
 
 // Given the type T of a dependent expression that appears of the LHS of a
 // "->", heuristically find a corresponding pointee type in whose scope we
@@ -219,19 +223,45 @@
   return {};
 }
 
-// Try to heuristically resolve the type of a possibly-dependent expression `E`.
-const Type *resolveExprToType(const Expr *E) {
-  std::vector Decls = resolveExprToDecls(E);
+const Type *resolveDeclsToType(const std::vector &Decls) {
   if (Decls.size() != 1) // Names an overload set -- just bail.
 return nullptr;
   if (const auto *TD = dyn_cast(Decls[0])) {
 return TD->getTypeForDecl();
-  } else if (const auto *VD = dyn_cast(Decls[0])) {
+  }
+  if (const auto *VD = dyn_cast(Decls[0])) {
 return VD->getType().getTypePtrOrNull();
   }
   return nullptr;
 }
 
+// Try to heuristically resolve the type of a possibly-dependent expression `E`.
+const Type *resolveExprToType(const Expr *E) {
+  return resolveDeclsToType(resolveExprToDecls(E));
+}
+
+// Try to heuristically resolve the type of a possibly-dependent nested name
+// specifier.
+const Type *resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS) {
+  switch (NNS->getKind()) {
+  case NestedNameSpecifier::TypeSpec:
+  case NestedNameSpecifier::TypeSpecWithTemplate:
+return NNS->getAsType();
+  case NestedNameSpecifier::Identifier: {
+if (const NestedNameSpecifier *Prefix = NNS->getPrefix()) {
+  return resolveDeclsToType(getMembersReferencedViaDependentName(
+  resolveNestedNameSpecifierToType(Prefix),
+  [&](const ASTContext &) { return NNS->getAsIdentifier(); },
+  TypeFilter));
+}
+break;
+  }
+  default:
+break;
+  }
+  return nullptr;
+}
+
 const NamedDecl *getTemplatePattern(const NamedDecl *D) {
   if (const CXXRecordDecl *CRD = dyn_cast(D)) {
 if (const auto *Result = CRD->getTemplateInstantiationPattern())
@@ -291,10 +321,8 @@
 //and both are lossy. We must know upfront what the caller ultimately wants.
 //
 // FIXME: improve common dependent scope using name lookup in primary templates.
-// We currently handle DependentScopeDeclRefExpr and
-// CXXDependentScopeMemberExpr, but some other constructs remain to be handled:
-//  - DependentTemplateSpecializationType,
-//  - DependentNameType
+// We currently handle several dependent constructs, but some others remain to
+// be handled:
 //  - UnresolvedUsingTypenameDecl
 struct TargetFinder {
   using RelSet = DeclRelationSet;
@@ -536,6 +564,23 @@
 if (auto *TD =

[PATCH] D88469: [clangd] Heuristic resolution for dependent type and template names

2020-09-29 Thread Haojian Wu via Phabricator via cfe-commits
hokein added inline comments.



Comment at: clang-tools-extra/clangd/FindTarget.cpp:128
 const auto ValueFilter = [](const NamedDecl *D) { return isa(D); };
+const auto TypeFilter = [](const NamedDecl *D) { return !isa(D); };
 

nridge wrote:
> hokein wrote:
> > why not using `isa(D)`?
> Heh. When I wrote this, I searched for `TypeDecl` via `workspaceSymbols`, did 
> not see it in the first few results, and concluded that there is no such type.
> 
> Now I see it is there, just further down (and below **partial** matches like 
> `CFConstantStringTypeDecl`). Maybe I should file a `workspaceSymbols` bug 
> about this :)
yeah, I reproduced that, I think it is probably a ranking bug -- but if you 
type `clang::TypeDecl`, you will get it from the first result. 


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D88469

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


[PATCH] D88469: [clangd] Heuristic resolution for dependent type and template names

2020-09-29 Thread Nathan Ridge via Phabricator via cfe-commits
nridge added inline comments.



Comment at: clang-tools-extra/clangd/FindTarget.cpp:128
 const auto ValueFilter = [](const NamedDecl *D) { return isa(D); };
+const auto TypeFilter = [](const NamedDecl *D) { return !isa(D); };
 

hokein wrote:
> why not using `isa(D)`?
Heh. When I wrote this, I searched for `TypeDecl` via `workspaceSymbols`, did 
not see it in the first few results, and concluded that there is no such type.

Now I see it is there, just further down (and below **partial** matches like 
`CFConstantStringTypeDecl`). Maybe I should file a `workspaceSymbols` bug about 
this :)



Comment at: clang-tools-extra/clangd/unittests/FindTargetTests.cpp:743
+template 
+void foo(typename A::[[B]]);
+  )cpp";

hokein wrote:
> can you try to add a nested struct C in B, and verify `typename 
> A::B::[[C]])` still works?
Thank you for the example; this does not currently work.

Also, `typename A::[[B]]::C` does not work either, because only the leaf 
type gets a `DependentNameType`.

I will try to get these to work.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D88469

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


[PATCH] D88469: [clangd] Heuristic resolution for dependent type and template names

2020-09-29 Thread Haojian Wu via Phabricator via cfe-commits
hokein added inline comments.



Comment at: clang-tools-extra/clangd/FindTarget.cpp:128
 const auto ValueFilter = [](const NamedDecl *D) { return isa(D); };
+const auto TypeFilter = [](const NamedDecl *D) { return !isa(D); };
 

why not using `isa(D)`?



Comment at: clang-tools-extra/clangd/unittests/FindTargetTests.cpp:743
+template 
+void foo(typename A::[[B]]);
+  )cpp";

can you try to add a nested struct C in B, and verify `typename 
A::B::[[C]])` still works?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D88469

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


[PATCH] D88469: [clangd] Heuristic resolution for dependent type and template names

2020-09-29 Thread Nathan Ridge via Phabricator via cfe-commits
nridge created this revision.
Herald added subscribers: cfe-commits, usaxena95, kadircet, arphaman.
Herald added a project: clang.
nridge requested review of this revision.
Herald added subscribers: MaskRay, ilya-biryukov.

Fixes https://github.com/clangd/clangd/issues/543


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D88469

Files:
  clang-tools-extra/clangd/FindTarget.cpp
  clang-tools-extra/clangd/unittests/FindTargetTests.cpp


Index: clang-tools-extra/clangd/unittests/FindTargetTests.cpp
===
--- clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -731,6 +731,33 @@
"template  T convert() const");
 }
 
+TEST_F(TargetDeclTest, DependentTypes) {
+  Flags = {"-fno-delayed-template-parsing"};
+
+  // Heuristic resolution of dependent type name
+  Code = R"cpp(
+template 
+struct A { struct B {}; };
+
+template 
+void foo(typename A::[[B]]);
+  )cpp";
+  EXPECT_DECLS("DependentNameTypeLoc", "struct B");
+
+  // Heuristic resolution of dependent template name
+  Code = R"cpp(
+template 
+struct A { 
+  template  struct B {};
+};
+
+template 
+void foo(typename A::template [[B]]);
+  )cpp";
+  EXPECT_DECLS("DependentTemplateSpecializationTypeLoc",
+   "template  struct B");
+}
+
 TEST_F(TargetDeclTest, ObjC) {
   Flags = {"-xobjective-c"};
   Code = R"cpp(
Index: clang-tools-extra/clangd/FindTarget.cpp
===
--- clang-tools-extra/clangd/FindTarget.cpp
+++ clang-tools-extra/clangd/FindTarget.cpp
@@ -125,6 +125,7 @@
   return !D->isCXXInstanceMember();
 };
 const auto ValueFilter = [](const NamedDecl *D) { return isa(D); };
+const auto TypeFilter = [](const NamedDecl *D) { return !isa(D); };
 
 // Given the type T of a dependent expression that appears of the LHS of a
 // "->", heuristically find a corresponding pointee type in whose scope we
@@ -291,10 +292,8 @@
 //and both are lossy. We must know upfront what the caller ultimately 
wants.
 //
 // FIXME: improve common dependent scope using name lookup in primary 
templates.
-// We currently handle DependentScopeDeclRefExpr and
-// CXXDependentScopeMemberExpr, but some other constructs remain to be handled:
-//  - DependentTemplateSpecializationType,
-//  - DependentNameType
+// We currently handle several dependent constructs, but some others remain to
+// be handled:
 //  - UnresolvedUsingTypenameDecl
 struct TargetFinder {
   using RelSet = DeclRelationSet;
@@ -536,6 +535,23 @@
 if (auto *TD = DTST->getTemplateName().getAsTemplateDecl())
   Outer.add(TD->getTemplatedDecl(), Flags | Rel::TemplatePattern);
   }
+  void VisitDependentNameType(const DependentNameType *DNT) {
+for (const NamedDecl *ND : getMembersReferencedViaDependentName(
+ DNT->getQualifier()->getAsType(),
+ [DNT](ASTContext &) { return DNT->getIdentifier(); },
+ TypeFilter)) {
+  Outer.add(ND, Flags);
+}
+  }
+  void VisitDependentTemplateSpecializationType(
+  const DependentTemplateSpecializationType *DTST) {
+for (const NamedDecl *ND : getMembersReferencedViaDependentName(
+ DTST->getQualifier()->getAsType(),
+ [DTST](ASTContext &) { return DTST->getIdentifier(); },
+ TypeFilter)) {
+  Outer.add(ND, Flags);
+}
+  }
   void VisitTypedefType(const TypedefType *TT) {
 Outer.add(TT->getDecl(), Flags);
   }


Index: clang-tools-extra/clangd/unittests/FindTargetTests.cpp
===
--- clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -731,6 +731,33 @@
"template  T convert() const");
 }
 
+TEST_F(TargetDeclTest, DependentTypes) {
+  Flags = {"-fno-delayed-template-parsing"};
+
+  // Heuristic resolution of dependent type name
+  Code = R"cpp(
+template 
+struct A { struct B {}; };
+
+template 
+void foo(typename A::[[B]]);
+  )cpp";
+  EXPECT_DECLS("DependentNameTypeLoc", "struct B");
+
+  // Heuristic resolution of dependent template name
+  Code = R"cpp(
+template 
+struct A { 
+  template  struct B {};
+};
+
+template 
+void foo(typename A::template [[B]]);
+  )cpp";
+  EXPECT_DECLS("DependentTemplateSpecializationTypeLoc",
+   "template  struct B");
+}
+
 TEST_F(TargetDeclTest, ObjC) {
   Flags = {"-xobjective-c"};
   Code = R"cpp(
Index: clang-tools-extra/clangd/FindTarget.cpp
===
--- clang-tools-extra/clangd/FindTarget.cpp
+++ clang-tools-extra/clangd/FindTarget.cpp