[clang-tools-extra] 1b962fd - [clangd] Heuristic resolution for dependent type and template names
Nathan Ridge via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 12 10:37:42 PDT 2020
Author: Nathan Ridge
Date: 2020-10-12T13:37:22-04:00
New Revision: 1b962fdd5f365a10684d9f70d703ae101c20d37a
URL: https://github.com/llvm/llvm-project/commit/1b962fdd5f365a10684d9f70d703ae101c20d37a
DIFF: https://github.com/llvm/llvm-project/commit/1b962fdd5f365a10684d9f70d703ae101c20d37a.diff
LOG: [clangd] Heuristic resolution for dependent type and template names
Fixes https://github.com/clangd/clangd/issues/543
Differential Revision: https://reviews.llvm.org/D88469
Added:
Modified:
clang-tools-extra/clangd/FindTarget.cpp
clang-tools-extra/clangd/unittests/FindTargetTests.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp
index 4cf62d3d1539..19ffdbb7c7ea 100644
--- a/clang-tools-extra/clangd/FindTarget.cpp
+++ b/clang-tools-extra/clangd/FindTarget.cpp
@@ -125,6 +125,10 @@ const auto StaticFilter = [](const NamedDecl *D) {
return !D->isCXXInstanceMember();
};
const auto ValueFilter = [](const NamedDecl *D) { return isa<ValueDecl>(D); };
+const auto TypeFilter = [](const NamedDecl *D) { return isa<TypeDecl>(D); };
+const auto TemplateFilter = [](const NamedDecl *D) {
+ return isa<TemplateDecl>(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 @@ std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E) {
return {};
}
-// Try to heuristically resolve the type of a possibly-dependent expression `E`.
-const Type *resolveExprToType(const Expr *E) {
- std::vector<const NamedDecl *> Decls = resolveExprToDecls(E);
+const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls) {
if (Decls.size() != 1) // Names an overload set -- just bail.
return nullptr;
if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) {
return TD->getTypeForDecl();
- } else if (const auto *VD = dyn_cast<ValueDecl>(Decls[0])) {
+ }
+ if (const auto *VD = dyn_cast<ValueDecl>(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<CXXRecordDecl>(D)) {
if (const auto *Result = CRD->getTemplateInstantiationPattern())
@@ -291,10 +321,8 @@ const NamedDecl *getTemplatePattern(const NamedDecl *D) {
// 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 @@ struct TargetFinder {
if (auto *TD = DTST->getTemplateName().getAsTemplateDecl())
Outer.add(TD->getTemplatedDecl(), Flags | Rel::TemplatePattern);
}
+ void VisitDependentNameType(const DependentNameType *DNT) {
+ for (const NamedDecl *ND : getMembersReferencedViaDependentName(
+ resolveNestedNameSpecifierToType(DNT->getQualifier()),
+ [DNT](ASTContext &) { return DNT->getIdentifier(); },
+ TypeFilter)) {
+ Outer.add(ND, Flags);
+ }
+ }
+ void VisitDependentTemplateSpecializationType(
+ const DependentTemplateSpecializationType *DTST) {
+ for (const NamedDecl *ND : getMembersReferencedViaDependentName(
+ resolveNestedNameSpecifierToType(DTST->getQualifier()),
+ [DTST](ASTContext &) { return DTST->getIdentifier(); },
+ TemplateFilter)) {
+ Outer.add(ND, Flags);
+ }
+ }
void VisitTypedefType(const TypedefType *TT) {
Outer.add(TT->getDecl(), Flags);
}
@@ -591,17 +636,16 @@ struct TargetFinder {
return;
debug(*NNS, Flags);
switch (NNS->getKind()) {
- case NestedNameSpecifier::Identifier:
- return;
case NestedNameSpecifier::Namespace:
add(NNS->getAsNamespace(), Flags);
return;
case NestedNameSpecifier::NamespaceAlias:
add(NNS->getAsNamespaceAlias(), Flags);
return;
+ case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
- add(QualType(NNS->getAsType(), 0), Flags);
+ add(QualType(resolveNestedNameSpecifierToType(NNS), 0), Flags);
return;
case NestedNameSpecifier::Global:
// This should be TUDecl, but we can't get a pointer to it!
diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
index e4f584bea01f..1ea2aa34f289 100644
--- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -728,6 +728,54 @@ TEST_F(TargetDeclTest, DependentExprs) {
"template <typename T> T convert() const");
}
+TEST_F(TargetDeclTest, DependentTypes) {
+ Flags = {"-fno-delayed-template-parsing"};
+
+ // Heuristic resolution of dependent type name
+ Code = R"cpp(
+ template <typename>
+ struct A { struct B {}; };
+
+ template <typename T>
+ void foo(typename A<T>::[[B]]);
+ )cpp";
+ EXPECT_DECLS("DependentNameTypeLoc", "struct B");
+
+ // Heuristic resolution of dependent type name which doesn't get a TypeLoc
+ Code = R"cpp(
+ template <typename>
+ struct A { struct B { struct C {}; }; };
+
+ template <typename T>
+ void foo(typename A<T>::[[B]]::C);
+ )cpp";
+ EXPECT_DECLS("NestedNameSpecifierLoc", "struct B");
+
+ // Heuristic resolution of dependent type name whose qualifier is also
+ // dependent
+ Code = R"cpp(
+ template <typename>
+ struct A { struct B { struct C {}; }; };
+
+ template <typename T>
+ void foo(typename A<T>::B::[[C]]);
+ )cpp";
+ EXPECT_DECLS("DependentNameTypeLoc", "struct C");
+
+ // Heuristic resolution of dependent template name
+ Code = R"cpp(
+ template <typename>
+ struct A {
+ template <typename> struct B {};
+ };
+
+ template <typename T>
+ void foo(typename A<T>::template [[B]]<int>);
+ )cpp";
+ EXPECT_DECLS("DependentTemplateSpecializationTypeLoc",
+ "template <typename> struct B");
+}
+
TEST_F(TargetDeclTest, ObjC) {
Flags = {"-xobjective-c"};
Code = R"cpp(
More information about the cfe-commits
mailing list