From 282ac5060f5aff2bdc39e83c4398548d2cb8fb30 Mon Sep 17 00:00:00 2001 From: Botond Ballo Date: Fri, 23 Jun 2023 01:42:55 +0000 Subject: [PATCH] Bug 1836695 - Pick up latest HeuristicResolver updates from llvm trunk. r=andi DONTBUILD Differential Revision: https://phabricator.services.mozilla.com/D181719 --- .../from-clangd/HeuristicResolver.cpp | 117 +++++++++++++++--- .../from-clangd/HeuristicResolver.h | 20 +++ .../mozsearch-plugin/from-clangd/README.md | 4 +- 3 files changed, 121 insertions(+), 20 deletions(-) diff --git a/build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.cpp b/build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.cpp index 460b9be592ba..719094dbf2b7 100644 --- a/build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.cpp +++ b/build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.cpp @@ -8,8 +8,10 @@ #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" namespace clang { namespace clangd { @@ -29,12 +31,39 @@ const auto TemplateFilter = [](const NamedDecl *D) { return isa(D); }; +namespace { + +const Type *resolveDeclsToType(const std::vector &Decls, + ASTContext &Ctx) { + if (Decls.size() != 1) // Names an overload set -- just bail. + return nullptr; + if (const auto *TD = dyn_cast(Decls[0])) { + return Ctx.getTypeDeclType(TD).getTypePtr(); + } + if (const auto *VD = dyn_cast(Decls[0])) { + return VD->getType().getTypePtrOrNull(); + } + return nullptr; +} + +} // namespace + // Helper function for HeuristicResolver::resolveDependentMember() // 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) { +CXXRecordDecl *HeuristicResolver::resolveTypeToRecordDecl(const Type *T) const { assert(T); + // Unwrap type sugar such as type aliases. + T = T->getCanonicalTypeInternal().getTypePtr(); + + if (const auto *DNT = T->getAs()) { + T = resolveDeclsToType(resolveDependentNameType(DNT), Ctx); + if (!T) + return nullptr; + T = T->getCanonicalTypeInternal().getTypePtr(); + } + if (const auto *RT = T->getAs()) return dyn_cast(RT->getDecl()); @@ -182,18 +211,6 @@ HeuristicResolver::resolveTemplateSpecializationType( DTST->getIdentifier(), TemplateFilter); } -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(); - } - if (const auto *VD = dyn_cast(Decls[0])) { - return VD->getType().getTypePtrOrNull(); - } - return nullptr; -} - std::vector HeuristicResolver::resolveExprToDecls(const Expr *E) const { if (const auto *ME = dyn_cast(E)) { @@ -217,7 +234,7 @@ HeuristicResolver::resolveExprToDecls(const Expr *E) const { const Type *HeuristicResolver::resolveExprToType(const Expr *E) const { std::vector Decls = resolveExprToDecls(E); if (!Decls.empty()) - return resolveDeclsToType(Decls); + return resolveDeclsToType(Decls, Ctx); return E->getType().getTypePtr(); } @@ -236,9 +253,11 @@ const Type *HeuristicResolver::resolveNestedNameSpecifierToType( case NestedNameSpecifier::TypeSpecWithTemplate: return NNS->getAsType(); case NestedNameSpecifier::Identifier: { - return resolveDeclsToType(resolveDependentMember( - resolveNestedNameSpecifierToType(NNS->getPrefix()), - NNS->getAsIdentifier(), TypeFilter)); + return resolveDeclsToType( + resolveDependentMember( + resolveNestedNameSpecifierToType(NNS->getPrefix()), + NNS->getAsIdentifier(), TypeFilter), + Ctx); } default: break; @@ -246,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 HeuristicResolver::lookupDependentName( + CXXRecordDecl *RD, DeclarationName Name, + llvm::function_ref Filter) const { + std::vector 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 HeuristicResolver::resolveDependentMember( const Type *T, DeclarationName Name, llvm::function_ref Filter) const { @@ -259,7 +340,7 @@ std::vector HeuristicResolver::resolveDependentMember( if (!RD->hasDefinition()) return {}; RD = RD->getDefinition(); - return RD->lookupDependentName(Name, Filter); + return lookupDependentName(RD, Name, Filter); } return {}; } diff --git a/build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.h b/build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.h index 2b66e4bd9b8f..dc04123d3759 100644 --- a/build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.h +++ b/build/clang-plugin/mozsearch-plugin/from-clangd/HeuristicResolver.h @@ -16,6 +16,7 @@ namespace clang { class ASTContext; class CallExpr; +class CXXBasePath; class CXXDependentScopeMemberExpr; class DeclarationName; class DependentScopeDeclRefExpr; @@ -94,6 +95,25 @@ private: // `E`. const Type *resolveExprToType(const Expr *E) const; std::vector resolveExprToDecls(const Expr *E) const; + + // Helper function for HeuristicResolver::resolveDependentMember() + // 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 lookupDependentName( + CXXRecordDecl *RD, DeclarationName Name, + llvm::function_ref Filter) const; + bool findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + DeclarationName Name) const; }; } // namespace clangd diff --git a/build/clang-plugin/mozsearch-plugin/from-clangd/README.md b/build/clang-plugin/mozsearch-plugin/from-clangd/README.md index 334cf4913a6a..9f39dab23186 100644 --- a/build/clang-plugin/mozsearch-plugin/from-clangd/README.md +++ b/build/clang-plugin/mozsearch-plugin/from-clangd/README.md @@ -2,8 +2,8 @@ The facilities in this subdirectory are copied over from clangd (https://clangd.llvm.org/). The files here are currently copies of the following upstream files: -https://github.com/llvm/llvm-project/blob/48bc71505e03694caac6afb2431ff1157a2382a8/clang-tools-extra/clangd/HeuristicResolver.h -https://github.com/llvm/llvm-project/blob/48bc71505e03694caac6afb2431ff1157a2382a8/clang-tools-extra/clangd/HeuristicResolver.cpp +https://github.com/llvm/llvm-project/blob/2bcbcbefcd0f7432f99cc07bb47d1e1ecb579a3f/clang-tools-extra/clangd/HeuristicResolver.h +https://github.com/llvm/llvm-project/blob/2bcbcbefcd0f7432f99cc07bb47d1e1ecb579a3f/clang-tools-extra/clangd/HeuristicResolver.cpp If, in the future, these facilities are moved from clangd to to libclangTooling and exposed in the clang API headers, we can