diff options
Diffstat (limited to 'clang-tools-extra/clangd/FindTarget.cpp')
-rw-r--r-- | clang-tools-extra/clangd/FindTarget.cpp | 64 |
1 files changed, 62 insertions, 2 deletions
diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp index 69c298b6887..a4c17dbefde 100644 --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -52,6 +52,40 @@ nodeToString(const ast_type_traits::DynTypedNode &N) { return S; } +// Given a dependent type and a member name, heuristically resolve the +// name to one or more declarations. +// The current heuristic is simply to look up the name in the primary +// template. This is a heuristic because the template could potentially +// have specializations that declare different members. +// Multiple declarations could be returned if the name is overloaded +// (e.g. an overloaded method in the primary template). +// This heuristic will give the desired answer in many cases, e.g. +// for a call to vector<T>::size(). +std::vector<const NamedDecl *> +getMembersReferencedViaDependentName(const Type *T, const DeclarationName &Name, + bool IsNonstaticMember) { + if (!T) + return {}; + if (auto *ICNT = T->getAs<InjectedClassNameType>()) { + T = ICNT->getInjectedSpecializationType().getTypePtrOrNull(); + } + auto *TST = T->getAs<TemplateSpecializationType>(); + if (!TST) + return {}; + const ClassTemplateDecl *TD = dyn_cast_or_null<ClassTemplateDecl>( + TST->getTemplateName().getAsTemplateDecl()); + if (!TD) + return {}; + CXXRecordDecl *RD = TD->getTemplatedDecl(); + if (!RD->hasDefinition()) + return {}; + RD = RD->getDefinition(); + return RD->lookupDependentName(Name, [=](const NamedDecl *D) { + return IsNonstaticMember ? D->isCXXInstanceMember() + : !D->isCXXInstanceMember(); + }); +} + // TargetFinder locates the entities that an AST node refers to. // // Typically this is (possibly) one declaration and (possibly) one type, but @@ -79,9 +113,9 @@ nodeToString(const ast_type_traits::DynTypedNode &N) { // formally size() is unresolved, but the primary template is a good guess. // This affects: // - DependentTemplateSpecializationType, -// - DependentScopeMemberExpr -// - DependentScopeDeclRefExpr // - DependentNameType +// - UnresolvedUsingValueDecl +// - UnresolvedUsingTypenameDecl struct TargetFinder { using RelSet = DeclRelationSet; using Rel = DeclRelation; @@ -212,6 +246,32 @@ public: break; } } + void + VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *E) { + const Type *BaseType = E->getBaseType().getTypePtrOrNull(); + if (E->isArrow()) { + // FIXME: Handle smart pointer types by looking up operator-> + // in the primary template. + if (!BaseType || !BaseType->isPointerType()) { + return; + } + BaseType = BaseType->getAs<PointerType>() + ->getPointeeType() + .getTypePtrOrNull(); + } + for (const NamedDecl *D : + getMembersReferencedViaDependentName(BaseType, E->getMember(), + /*IsNonstaticMember=*/true)) { + Outer.add(D, Flags); + } + } + void VisitDependentScopeDeclRefExpr(const DependentScopeDeclRefExpr *E) { + for (const NamedDecl *D : getMembersReferencedViaDependentName( + E->getQualifier()->getAsType(), E->getDeclName(), + /*IsNonstaticMember=*/false)) { + Outer.add(D, Flags); + } + } void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *OIRE) { Outer.add(OIRE->getDecl(), Flags); } |