[clangd] Use resolveTypeToRecordDecl() to resolve the type of a base specifier during heuristic resolution

The code for resolving the type of a base specifier was inside
CXXRecordDecl::lookupDependentName(), so this patch reimplements
lookupDependentName() in HeuristicResolver.

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

Differential Revision: https://reviews.llvm.org/D153248
This commit is contained in:
Nathan Ridge 2023-06-12 04:05:10 -04:00
parent 59f266d2e2
commit 6fe9cfe413
3 changed files with 92 additions and 1 deletions

View File

@ -8,6 +8,7 @@
#include "HeuristicResolver.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/Type.h"
@ -264,6 +265,68 @@ const Type *HeuristicResolver::resolveNestedNameSpecifierToType(
return nullptr;
}
namespace {
bool isOrdinaryMember(const NamedDecl *ND) {
return ND->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_Tag |
Decl::IDNS_Member);
}
bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,
DeclarationName Name) {
Path.Decls = RD->lookup(Name).begin();
for (DeclContext::lookup_iterator I = Path.Decls, E = I.end(); I != E; ++I)
if (isOrdinaryMember(*I))
return true;
return false;
}
} // namespace
bool HeuristicResolver::findOrdinaryMemberInDependentClasses(
const CXXBaseSpecifier *Specifier, CXXBasePath &Path,
DeclarationName Name) const {
CXXRecordDecl *RD =
resolveTypeToRecordDecl(Specifier->getType().getTypePtr());
if (!RD)
return false;
return findOrdinaryMember(RD, Path, Name);
}
std::vector<const NamedDecl *> HeuristicResolver::lookupDependentName(
CXXRecordDecl *RD, DeclarationName Name,
llvm::function_ref<bool(const NamedDecl *ND)> Filter) const {
std::vector<const NamedDecl *> Results;
// Lookup in the class.
bool AnyOrdinaryMembers = false;
for (const NamedDecl *ND : RD->lookup(Name)) {
if (isOrdinaryMember(ND))
AnyOrdinaryMembers = true;
if (Filter(ND))
Results.push_back(ND);
}
if (AnyOrdinaryMembers)
return Results;
// Perform lookup into our base classes.
CXXBasePaths Paths;
Paths.setOrigin(RD);
if (!RD->lookupInBases(
[&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
return findOrdinaryMemberInDependentClasses(Specifier, Path, Name);
},
Paths, /*LookupInDependent=*/true))
return Results;
for (DeclContext::lookup_iterator I = Paths.front().Decls, E = I.end();
I != E; ++I) {
if (isOrdinaryMember(*I) && Filter(*I))
Results.push_back(*I);
}
return Results;
}
std::vector<const NamedDecl *> HeuristicResolver::resolveDependentMember(
const Type *T, DeclarationName Name,
llvm::function_ref<bool(const NamedDecl *ND)> Filter) const {
@ -277,7 +340,7 @@ std::vector<const NamedDecl *> HeuristicResolver::resolveDependentMember(
if (!RD->hasDefinition())
return {};
RD = RD->getDefinition();
return RD->lookupDependentName(Name, Filter);
return lookupDependentName(RD, Name, Filter);
}
return {};
}

View File

@ -16,6 +16,7 @@ namespace clang {
class ASTContext;
class CallExpr;
class CXXBasePath;
class CXXDependentScopeMemberExpr;
class DeclarationName;
class DependentScopeDeclRefExpr;
@ -99,6 +100,20 @@ private:
// which takes a possibly-dependent type `T` and heuristically
// resolves it to a CXXRecordDecl in which we can try name lookup.
CXXRecordDecl *resolveTypeToRecordDecl(const Type *T) const;
// This is a reimplementation of CXXRecordDecl::lookupDependentName()
// so that the implementation can call into other HeuristicResolver helpers.
// FIXME: Once HeuristicResolver is upstreamed to the clang libraries
// (https://github.com/clangd/clangd/discussions/1662),
// CXXRecordDecl::lookupDepenedentName() can be removed, and its call sites
// can be modified to benefit from the more comprehensive heuristics offered
// by HeuristicResolver instead.
std::vector<const NamedDecl *> lookupDependentName(
CXXRecordDecl *RD, DeclarationName Name,
llvm::function_ref<bool(const NamedDecl *ND)> Filter) const;
bool findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
DeclarationName Name) const;
};
} // namespace clangd

View File

@ -893,6 +893,19 @@ TEST_F(TargetDeclTest, DependentExprs) {
}
)cpp";
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void find()");
Code = R"cpp(
struct Waldo {
void find();
};
template <typename T>
using Wally = Waldo;
template <typename>
struct S : Wally<int> {
void Foo() { this->[[find]](); }
};
)cpp";
EXPECT_DECLS("CXXDependentScopeMemberExpr", "void find()");
}
TEST_F(TargetDeclTest, DependentTypes) {