1616namespace clang {
1717namespace clangd {
1818
19+ namespace {
20+
21+ // Helper class for implementing HeuristicResolver.
22+ // Unlike HeuristicResolver which is a long-lived class,
23+ // a new instance of this class is created for every external
24+ // call into a HeuristicResolver operation. That allows this
25+ // class to store state that's local to such a top-level call,
26+ // particularly "recursion protection sets" that keep track of
27+ // nodes that have already been seen to avoid infinite recursion.
28+ class HeuristicResolverImpl {
29+ public:
30+ HeuristicResolverImpl (ASTContext &Ctx) : Ctx(Ctx) {}
31+
32+ // These functions match the public interface of HeuristicResolver
33+ // (but aren't const since they may modify the recursion protection sets).
34+ std::vector<const NamedDecl *>
35+ resolveMemberExpr (const CXXDependentScopeMemberExpr *ME);
36+ std::vector<const NamedDecl *>
37+ resolveDeclRefExpr (const DependentScopeDeclRefExpr *RE);
38+ std::vector<const NamedDecl *> resolveTypeOfCallExpr (const CallExpr *CE);
39+ std::vector<const NamedDecl *> resolveCalleeOfCallExpr (const CallExpr *CE);
40+ std::vector<const NamedDecl *>
41+ resolveUsingValueDecl (const UnresolvedUsingValueDecl *UUVD);
42+ std::vector<const NamedDecl *>
43+ resolveDependentNameType (const DependentNameType *DNT);
44+ std::vector<const NamedDecl *> resolveTemplateSpecializationType (
45+ const DependentTemplateSpecializationType *DTST);
46+ const Type *resolveNestedNameSpecifierToType (const NestedNameSpecifier *NNS);
47+ const Type *getPointeeType (const Type *T);
48+
49+ private:
50+ ASTContext &Ctx;
51+
52+ // Recursion protection sets
53+ llvm::SmallSet<const DependentNameType *, 4 > SeenDependentNameTypes;
54+
55+ // Given a tag-decl type and a member name, heuristically resolve the
56+ // name to one or more declarations.
57+ // The current heuristic is simply to look up the name in the primary
58+ // template. This is a heuristic because the template could potentially
59+ // have specializations that declare different members.
60+ // Multiple declarations could be returned if the name is overloaded
61+ // (e.g. an overloaded method in the primary template).
62+ // This heuristic will give the desired answer in many cases, e.g.
63+ // for a call to vector<T>::size().
64+ std::vector<const NamedDecl *>
65+ resolveDependentMember (const Type *T, DeclarationName Name,
66+ llvm::function_ref<bool (const NamedDecl *ND)> Filter);
67+
68+ // Try to heuristically resolve the type of a possibly-dependent expression
69+ // `E`.
70+ const Type *resolveExprToType (const Expr *E);
71+ std::vector<const NamedDecl *> resolveExprToDecls (const Expr *E);
72+
73+ // Helper function for HeuristicResolver::resolveDependentMember()
74+ // which takes a possibly-dependent type `T` and heuristically
75+ // resolves it to a CXXRecordDecl in which we can try name lookup.
76+ CXXRecordDecl *resolveTypeToRecordDecl (const Type *T);
77+
78+ // This is a reimplementation of CXXRecordDecl::lookupDependentName()
79+ // so that the implementation can call into other HeuristicResolver helpers.
80+ // FIXME: Once HeuristicResolver is upstreamed to the clang libraries
81+ // (https://github.com/clangd/clangd/discussions/1662),
82+ // CXXRecordDecl::lookupDepenedentName() can be removed, and its call sites
83+ // can be modified to benefit from the more comprehensive heuristics offered
84+ // by HeuristicResolver instead.
85+ std::vector<const NamedDecl *>
86+ lookupDependentName (CXXRecordDecl *RD, DeclarationName Name,
87+ llvm::function_ref<bool (const NamedDecl *ND)> Filter);
88+ bool findOrdinaryMemberInDependentClasses (const CXXBaseSpecifier *Specifier,
89+ CXXBasePath &Path,
90+ DeclarationName Name);
91+ };
92+
1993// Convenience lambdas for use as the 'Filter' parameter of
2094// HeuristicResolver::resolveDependentMember().
2195const auto NoFilter = [](const NamedDecl *D) { return true ; };
@@ -31,8 +105,6 @@ const auto TemplateFilter = [](const NamedDecl *D) {
31105 return isa<TemplateDecl>(D);
32106};
33107
34- namespace {
35-
36108const Type *resolveDeclsToType (const std::vector<const NamedDecl *> &Decls,
37109 ASTContext &Ctx) {
38110 if (Decls.size () != 1 ) // Names an overload set -- just bail.
@@ -46,12 +118,10 @@ const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls,
46118 return nullptr ;
47119}
48120
49- } // namespace
50-
51121// Helper function for HeuristicResolver::resolveDependentMember()
52122// which takes a possibly-dependent type `T` and heuristically
53123// resolves it to a CXXRecordDecl in which we can try name lookup.
54- CXXRecordDecl *HeuristicResolver ::resolveTypeToRecordDecl (const Type *T) const {
124+ CXXRecordDecl *HeuristicResolverImpl ::resolveTypeToRecordDecl (const Type *T) {
55125 assert (T);
56126
57127 // Unwrap type sugar such as type aliases.
@@ -84,7 +154,7 @@ CXXRecordDecl *HeuristicResolver::resolveTypeToRecordDecl(const Type *T) const {
84154 return TD->getTemplatedDecl ();
85155}
86156
87- const Type *HeuristicResolver ::getPointeeType (const Type *T) const {
157+ const Type *HeuristicResolverImpl ::getPointeeType (const Type *T) {
88158 if (!T)
89159 return nullptr ;
90160
@@ -117,8 +187,8 @@ const Type *HeuristicResolver::getPointeeType(const Type *T) const {
117187 return FirstArg.getAsType ().getTypePtrOrNull ();
118188}
119189
120- std::vector<const NamedDecl *> HeuristicResolver ::resolveMemberExpr (
121- const CXXDependentScopeMemberExpr *ME) const {
190+ std::vector<const NamedDecl *> HeuristicResolverImpl ::resolveMemberExpr (
191+ const CXXDependentScopeMemberExpr *ME) {
122192 // If the expression has a qualifier, try resolving the member inside the
123193 // qualifier's type.
124194 // Note that we cannot use a NonStaticFilter in either case, for a couple
@@ -164,14 +234,14 @@ std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(
164234 return resolveDependentMember (BaseType, ME->getMember (), NoFilter);
165235}
166236
167- std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr (
168- const DependentScopeDeclRefExpr *RE) const {
237+ std::vector<const NamedDecl *>
238+ HeuristicResolverImpl::resolveDeclRefExpr ( const DependentScopeDeclRefExpr *RE) {
169239 return resolveDependentMember (RE->getQualifier ()->getAsType (),
170240 RE->getDeclName (), StaticFilter);
171241}
172242
173243std::vector<const NamedDecl *>
174- HeuristicResolver ::resolveTypeOfCallExpr (const CallExpr *CE) const {
244+ HeuristicResolverImpl ::resolveTypeOfCallExpr (const CallExpr *CE) {
175245 const auto *CalleeType = resolveExprToType (CE->getCallee ());
176246 if (!CalleeType)
177247 return {};
@@ -187,37 +257,39 @@ HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const {
187257}
188258
189259std::vector<const NamedDecl *>
190- HeuristicResolver ::resolveCalleeOfCallExpr (const CallExpr *CE) const {
260+ HeuristicResolverImpl ::resolveCalleeOfCallExpr (const CallExpr *CE) {
191261 if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl ())) {
192262 return {ND};
193263 }
194264
195265 return resolveExprToDecls (CE->getCallee ());
196266}
197267
198- std::vector<const NamedDecl *> HeuristicResolver ::resolveUsingValueDecl (
199- const UnresolvedUsingValueDecl *UUVD) const {
268+ std::vector<const NamedDecl *> HeuristicResolverImpl ::resolveUsingValueDecl (
269+ const UnresolvedUsingValueDecl *UUVD) {
200270 return resolveDependentMember (UUVD->getQualifier ()->getAsType (),
201271 UUVD->getNameInfo ().getName (), ValueFilter);
202272}
203273
204- std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType (
205- const DependentNameType *DNT) const {
274+ std::vector<const NamedDecl *>
275+ HeuristicResolverImpl::resolveDependentNameType (const DependentNameType *DNT) {
276+ if (auto [_, inserted] = SeenDependentNameTypes.insert (DNT); !inserted)
277+ return {};
206278 return resolveDependentMember (
207279 resolveNestedNameSpecifierToType (DNT->getQualifier ()),
208280 DNT->getIdentifier (), TypeFilter);
209281}
210282
211283std::vector<const NamedDecl *>
212- HeuristicResolver ::resolveTemplateSpecializationType (
213- const DependentTemplateSpecializationType *DTST) const {
284+ HeuristicResolverImpl ::resolveTemplateSpecializationType (
285+ const DependentTemplateSpecializationType *DTST) {
214286 return resolveDependentMember (
215287 resolveNestedNameSpecifierToType (DTST->getQualifier ()),
216288 DTST->getIdentifier (), TemplateFilter);
217289}
218290
219291std::vector<const NamedDecl *>
220- HeuristicResolver ::resolveExprToDecls (const Expr *E) const {
292+ HeuristicResolverImpl ::resolveExprToDecls (const Expr *E) {
221293 if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) {
222294 return resolveMemberExpr (ME);
223295 }
@@ -236,16 +308,16 @@ HeuristicResolver::resolveExprToDecls(const Expr *E) const {
236308 return {};
237309}
238310
239- const Type *HeuristicResolver ::resolveExprToType (const Expr *E) const {
311+ const Type *HeuristicResolverImpl ::resolveExprToType (const Expr *E) {
240312 std::vector<const NamedDecl *> Decls = resolveExprToDecls (E);
241313 if (!Decls.empty ())
242314 return resolveDeclsToType (Decls, Ctx);
243315
244316 return E->getType ().getTypePtr ();
245317}
246318
247- const Type *HeuristicResolver ::resolveNestedNameSpecifierToType (
248- const NestedNameSpecifier *NNS) const {
319+ const Type *HeuristicResolverImpl ::resolveNestedNameSpecifierToType (
320+ const NestedNameSpecifier *NNS) {
249321 if (!NNS)
250322 return nullptr ;
251323
@@ -270,8 +342,6 @@ const Type *HeuristicResolver::resolveNestedNameSpecifierToType(
270342 return nullptr ;
271343}
272344
273- namespace {
274-
275345bool isOrdinaryMember (const NamedDecl *ND) {
276346 return ND->isInIdentifierNamespace (Decl::IDNS_Ordinary | Decl::IDNS_Tag |
277347 Decl::IDNS_Member);
@@ -287,21 +357,19 @@ bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,
287357 return false ;
288358}
289359
290- } // namespace
291-
292- bool HeuristicResolver::findOrdinaryMemberInDependentClasses (
360+ bool HeuristicResolverImpl::findOrdinaryMemberInDependentClasses (
293361 const CXXBaseSpecifier *Specifier, CXXBasePath &Path,
294- DeclarationName Name) const {
362+ DeclarationName Name) {
295363 CXXRecordDecl *RD =
296364 resolveTypeToRecordDecl (Specifier->getType ().getTypePtr ());
297365 if (!RD)
298366 return false ;
299367 return findOrdinaryMember (RD, Path, Name);
300368}
301369
302- std::vector<const NamedDecl *> HeuristicResolver ::lookupDependentName (
370+ std::vector<const NamedDecl *> HeuristicResolverImpl ::lookupDependentName (
303371 CXXRecordDecl *RD, DeclarationName Name,
304- llvm::function_ref<bool (const NamedDecl *ND)> Filter) const {
372+ llvm::function_ref<bool (const NamedDecl *ND)> Filter) {
305373 std::vector<const NamedDecl *> Results;
306374
307375 // Lookup in the class.
@@ -332,9 +400,9 @@ std::vector<const NamedDecl *> HeuristicResolver::lookupDependentName(
332400 return Results;
333401}
334402
335- std::vector<const NamedDecl *> HeuristicResolver ::resolveDependentMember (
403+ std::vector<const NamedDecl *> HeuristicResolverImpl ::resolveDependentMember (
336404 const Type *T, DeclarationName Name,
337- llvm::function_ref<bool (const NamedDecl *ND)> Filter) const {
405+ llvm::function_ref<bool (const NamedDecl *ND)> Filter) {
338406 if (!T)
339407 return {};
340408 if (auto *ET = T->getAs <EnumType>()) {
@@ -349,6 +417,44 @@ std::vector<const NamedDecl *> HeuristicResolver::resolveDependentMember(
349417 }
350418 return {};
351419}
420+ } // namespace
421+
422+ std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr (
423+ const CXXDependentScopeMemberExpr *ME) const {
424+ return HeuristicResolverImpl (Ctx).resolveMemberExpr (ME);
425+ }
426+ std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr (
427+ const DependentScopeDeclRefExpr *RE) const {
428+ return HeuristicResolverImpl (Ctx).resolveDeclRefExpr (RE);
429+ }
430+ std::vector<const NamedDecl *>
431+ HeuristicResolver::resolveTypeOfCallExpr (const CallExpr *CE) const {
432+ return HeuristicResolverImpl (Ctx).resolveTypeOfCallExpr (CE);
433+ }
434+ std::vector<const NamedDecl *>
435+ HeuristicResolver::resolveCalleeOfCallExpr (const CallExpr *CE) const {
436+ return HeuristicResolverImpl (Ctx).resolveCalleeOfCallExpr (CE);
437+ }
438+ std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl (
439+ const UnresolvedUsingValueDecl *UUVD) const {
440+ return HeuristicResolverImpl (Ctx).resolveUsingValueDecl (UUVD);
441+ }
442+ std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType (
443+ const DependentNameType *DNT) const {
444+ return HeuristicResolverImpl (Ctx).resolveDependentNameType (DNT);
445+ }
446+ std::vector<const NamedDecl *>
447+ HeuristicResolver::resolveTemplateSpecializationType (
448+ const DependentTemplateSpecializationType *DTST) const {
449+ return HeuristicResolverImpl (Ctx).resolveTemplateSpecializationType (DTST);
450+ }
451+ const Type *HeuristicResolver::resolveNestedNameSpecifierToType (
452+ const NestedNameSpecifier *NNS) const {
453+ return HeuristicResolverImpl (Ctx).resolveNestedNameSpecifierToType (NNS);
454+ }
455+ const Type *HeuristicResolver::getPointeeType (const Type *T) const {
456+ return HeuristicResolverImpl (Ctx).getPointeeType (T);
457+ }
352458
353459} // namespace clangd
354460} // namespace clang
0 commit comments