nridge created this revision. nridge added a reviewer: hokein. Herald added subscribers: kadircet, arphaman. Herald added a project: All. nridge requested review of this revision. Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov. Herald added a project: clang-tools-extra.
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 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D153248 Files: clang-tools-extra/clangd/HeuristicResolver.cpp clang-tools-extra/clangd/HeuristicResolver.h 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 @@ -893,6 +893,19 @@ } )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) { Index: clang-tools-extra/clangd/HeuristicResolver.h =================================================================== --- clang-tools-extra/clangd/HeuristicResolver.h +++ clang-tools-extra/clangd/HeuristicResolver.h @@ -16,6 +16,7 @@ class ASTContext; class CallExpr; +class CXXBasePath; class CXXDependentScopeMemberExpr; class DeclarationName; class DependentScopeDeclRefExpr; @@ -99,6 +100,20 @@ // 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 Index: clang-tools-extra/clangd/HeuristicResolver.cpp =================================================================== --- clang-tools-extra/clangd/HeuristicResolver.cpp +++ clang-tools-extra/clangd/HeuristicResolver.cpp @@ -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 @@ 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 @@ if (!RD->hasDefinition()) return {}; RD = RD->getDefinition(); - return RD->lookupDependentName(Name, Filter); + return lookupDependentName(RD, Name, Filter); } return {}; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits