16
16
namespace clang {
17
17
namespace clangd {
18
18
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
+
19
93
// Convenience lambdas for use as the 'Filter' parameter of
20
94
// HeuristicResolver::resolveDependentMember().
21
95
const auto NoFilter = [](const NamedDecl *D) { return true ; };
@@ -31,8 +105,6 @@ const auto TemplateFilter = [](const NamedDecl *D) {
31
105
return isa<TemplateDecl>(D);
32
106
};
33
107
34
- namespace {
35
-
36
108
const Type *resolveDeclsToType (const std::vector<const NamedDecl *> &Decls,
37
109
ASTContext &Ctx) {
38
110
if (Decls.size () != 1 ) // Names an overload set -- just bail.
@@ -46,12 +118,10 @@ const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls,
46
118
return nullptr ;
47
119
}
48
120
49
- } // namespace
50
-
51
121
// Helper function for HeuristicResolver::resolveDependentMember()
52
122
// which takes a possibly-dependent type `T` and heuristically
53
123
// 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) {
55
125
assert (T);
56
126
57
127
// Unwrap type sugar such as type aliases.
@@ -84,7 +154,7 @@ CXXRecordDecl *HeuristicResolver::resolveTypeToRecordDecl(const Type *T) const {
84
154
return TD->getTemplatedDecl ();
85
155
}
86
156
87
- const Type *HeuristicResolver ::getPointeeType (const Type *T) const {
157
+ const Type *HeuristicResolverImpl ::getPointeeType (const Type *T) {
88
158
if (!T)
89
159
return nullptr ;
90
160
@@ -117,8 +187,8 @@ const Type *HeuristicResolver::getPointeeType(const Type *T) const {
117
187
return FirstArg.getAsType ().getTypePtrOrNull ();
118
188
}
119
189
120
- std::vector<const NamedDecl *> HeuristicResolver ::resolveMemberExpr (
121
- const CXXDependentScopeMemberExpr *ME) const {
190
+ std::vector<const NamedDecl *> HeuristicResolverImpl ::resolveMemberExpr (
191
+ const CXXDependentScopeMemberExpr *ME) {
122
192
// If the expression has a qualifier, try resolving the member inside the
123
193
// qualifier's type.
124
194
// Note that we cannot use a NonStaticFilter in either case, for a couple
@@ -164,14 +234,14 @@ std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(
164
234
return resolveDependentMember (BaseType, ME->getMember (), NoFilter);
165
235
}
166
236
167
- std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr (
168
- const DependentScopeDeclRefExpr *RE) const {
237
+ std::vector<const NamedDecl *>
238
+ HeuristicResolverImpl::resolveDeclRefExpr ( const DependentScopeDeclRefExpr *RE) {
169
239
return resolveDependentMember (RE->getQualifier ()->getAsType (),
170
240
RE->getDeclName (), StaticFilter);
171
241
}
172
242
173
243
std::vector<const NamedDecl *>
174
- HeuristicResolver ::resolveTypeOfCallExpr (const CallExpr *CE) const {
244
+ HeuristicResolverImpl ::resolveTypeOfCallExpr (const CallExpr *CE) {
175
245
const auto *CalleeType = resolveExprToType (CE->getCallee ());
176
246
if (!CalleeType)
177
247
return {};
@@ -187,37 +257,39 @@ HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const {
187
257
}
188
258
189
259
std::vector<const NamedDecl *>
190
- HeuristicResolver ::resolveCalleeOfCallExpr (const CallExpr *CE) const {
260
+ HeuristicResolverImpl ::resolveCalleeOfCallExpr (const CallExpr *CE) {
191
261
if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl ())) {
192
262
return {ND};
193
263
}
194
264
195
265
return resolveExprToDecls (CE->getCallee ());
196
266
}
197
267
198
- std::vector<const NamedDecl *> HeuristicResolver ::resolveUsingValueDecl (
199
- const UnresolvedUsingValueDecl *UUVD) const {
268
+ std::vector<const NamedDecl *> HeuristicResolverImpl ::resolveUsingValueDecl (
269
+ const UnresolvedUsingValueDecl *UUVD) {
200
270
return resolveDependentMember (UUVD->getQualifier ()->getAsType (),
201
271
UUVD->getNameInfo ().getName (), ValueFilter);
202
272
}
203
273
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 {};
206
278
return resolveDependentMember (
207
279
resolveNestedNameSpecifierToType (DNT->getQualifier ()),
208
280
DNT->getIdentifier (), TypeFilter);
209
281
}
210
282
211
283
std::vector<const NamedDecl *>
212
- HeuristicResolver ::resolveTemplateSpecializationType (
213
- const DependentTemplateSpecializationType *DTST) const {
284
+ HeuristicResolverImpl ::resolveTemplateSpecializationType (
285
+ const DependentTemplateSpecializationType *DTST) {
214
286
return resolveDependentMember (
215
287
resolveNestedNameSpecifierToType (DTST->getQualifier ()),
216
288
DTST->getIdentifier (), TemplateFilter);
217
289
}
218
290
219
291
std::vector<const NamedDecl *>
220
- HeuristicResolver ::resolveExprToDecls (const Expr *E) const {
292
+ HeuristicResolverImpl ::resolveExprToDecls (const Expr *E) {
221
293
if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) {
222
294
return resolveMemberExpr (ME);
223
295
}
@@ -236,16 +308,16 @@ HeuristicResolver::resolveExprToDecls(const Expr *E) const {
236
308
return {};
237
309
}
238
310
239
- const Type *HeuristicResolver ::resolveExprToType (const Expr *E) const {
311
+ const Type *HeuristicResolverImpl ::resolveExprToType (const Expr *E) {
240
312
std::vector<const NamedDecl *> Decls = resolveExprToDecls (E);
241
313
if (!Decls.empty ())
242
314
return resolveDeclsToType (Decls, Ctx);
243
315
244
316
return E->getType ().getTypePtr ();
245
317
}
246
318
247
- const Type *HeuristicResolver ::resolveNestedNameSpecifierToType (
248
- const NestedNameSpecifier *NNS) const {
319
+ const Type *HeuristicResolverImpl ::resolveNestedNameSpecifierToType (
320
+ const NestedNameSpecifier *NNS) {
249
321
if (!NNS)
250
322
return nullptr ;
251
323
@@ -270,8 +342,6 @@ const Type *HeuristicResolver::resolveNestedNameSpecifierToType(
270
342
return nullptr ;
271
343
}
272
344
273
- namespace {
274
-
275
345
bool isOrdinaryMember (const NamedDecl *ND) {
276
346
return ND->isInIdentifierNamespace (Decl::IDNS_Ordinary | Decl::IDNS_Tag |
277
347
Decl::IDNS_Member);
@@ -287,21 +357,19 @@ bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,
287
357
return false ;
288
358
}
289
359
290
- } // namespace
291
-
292
- bool HeuristicResolver::findOrdinaryMemberInDependentClasses (
360
+ bool HeuristicResolverImpl::findOrdinaryMemberInDependentClasses (
293
361
const CXXBaseSpecifier *Specifier, CXXBasePath &Path,
294
- DeclarationName Name) const {
362
+ DeclarationName Name) {
295
363
CXXRecordDecl *RD =
296
364
resolveTypeToRecordDecl (Specifier->getType ().getTypePtr ());
297
365
if (!RD)
298
366
return false ;
299
367
return findOrdinaryMember (RD, Path, Name);
300
368
}
301
369
302
- std::vector<const NamedDecl *> HeuristicResolver ::lookupDependentName (
370
+ std::vector<const NamedDecl *> HeuristicResolverImpl ::lookupDependentName (
303
371
CXXRecordDecl *RD, DeclarationName Name,
304
- llvm::function_ref<bool (const NamedDecl *ND)> Filter) const {
372
+ llvm::function_ref<bool (const NamedDecl *ND)> Filter) {
305
373
std::vector<const NamedDecl *> Results;
306
374
307
375
// Lookup in the class.
@@ -332,9 +400,9 @@ std::vector<const NamedDecl *> HeuristicResolver::lookupDependentName(
332
400
return Results;
333
401
}
334
402
335
- std::vector<const NamedDecl *> HeuristicResolver ::resolveDependentMember (
403
+ std::vector<const NamedDecl *> HeuristicResolverImpl ::resolveDependentMember (
336
404
const Type *T, DeclarationName Name,
337
- llvm::function_ref<bool (const NamedDecl *ND)> Filter) const {
405
+ llvm::function_ref<bool (const NamedDecl *ND)> Filter) {
338
406
if (!T)
339
407
return {};
340
408
if (auto *ET = T->getAs <EnumType>()) {
@@ -349,6 +417,44 @@ std::vector<const NamedDecl *> HeuristicResolver::resolveDependentMember(
349
417
}
350
418
return {};
351
419
}
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
+ }
352
458
353
459
} // namespace clangd
354
460
} // namespace clang
0 commit comments