summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd/FindTarget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clangd/FindTarget.cpp')
-rw-r--r--clang-tools-extra/clangd/FindTarget.cpp64
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);
}
OpenPOWER on IntegriCloud