Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Sema/HeuristicResolver.cpp
213766 views
1
//===--- HeuristicResolver.cpp ---------------------------*- C++-*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "clang/Sema/HeuristicResolver.h"
10
#include "clang/AST/ASTContext.h"
11
#include "clang/AST/CXXInheritance.h"
12
#include "clang/AST/DeclTemplate.h"
13
#include "clang/AST/ExprCXX.h"
14
#include "clang/AST/TemplateBase.h"
15
#include "clang/AST/Type.h"
16
#include "llvm/ADT/identity.h"
17
18
namespace clang {
19
20
namespace {
21
22
// Helper class for implementing HeuristicResolver.
23
// Unlike HeuristicResolver which is a long-lived class,
24
// a new instance of this class is created for every external
25
// call into a HeuristicResolver operation. That allows this
26
// class to store state that's local to such a top-level call,
27
// particularly "recursion protection sets" that keep track of
28
// nodes that have already been seen to avoid infinite recursion.
29
class HeuristicResolverImpl {
30
public:
31
HeuristicResolverImpl(ASTContext &Ctx) : Ctx(Ctx) {}
32
33
// These functions match the public interface of HeuristicResolver
34
// (but aren't const since they may modify the recursion protection sets).
35
std::vector<const NamedDecl *>
36
resolveMemberExpr(const CXXDependentScopeMemberExpr *ME);
37
std::vector<const NamedDecl *>
38
resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE);
39
std::vector<const NamedDecl *> resolveTypeOfCallExpr(const CallExpr *CE);
40
std::vector<const NamedDecl *> resolveCalleeOfCallExpr(const CallExpr *CE);
41
std::vector<const NamedDecl *>
42
resolveUsingValueDecl(const UnresolvedUsingValueDecl *UUVD);
43
std::vector<const NamedDecl *>
44
resolveDependentNameType(const DependentNameType *DNT);
45
std::vector<const NamedDecl *> resolveTemplateSpecializationType(
46
const DependentTemplateSpecializationType *DTST);
47
QualType resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS);
48
QualType getPointeeType(QualType T);
49
std::vector<const NamedDecl *>
50
lookupDependentName(CXXRecordDecl *RD, DeclarationName Name,
51
llvm::function_ref<bool(const NamedDecl *ND)> Filter);
52
TagDecl *resolveTypeToTagDecl(QualType T);
53
QualType simplifyType(QualType Type, const Expr *E, bool UnwrapPointer);
54
FunctionProtoTypeLoc getFunctionProtoTypeLoc(const Expr *Fn);
55
56
private:
57
ASTContext &Ctx;
58
59
// Recursion protection sets
60
llvm::SmallSet<const DependentNameType *, 4> SeenDependentNameTypes;
61
62
// Given a tag-decl type and a member name, heuristically resolve the
63
// name to one or more declarations.
64
// The current heuristic is simply to look up the name in the primary
65
// template. This is a heuristic because the template could potentially
66
// have specializations that declare different members.
67
// Multiple declarations could be returned if the name is overloaded
68
// (e.g. an overloaded method in the primary template).
69
// This heuristic will give the desired answer in many cases, e.g.
70
// for a call to vector<T>::size().
71
std::vector<const NamedDecl *>
72
resolveDependentMember(QualType T, DeclarationName Name,
73
llvm::function_ref<bool(const NamedDecl *ND)> Filter);
74
75
// Try to heuristically resolve the type of a possibly-dependent expression
76
// `E`.
77
QualType resolveExprToType(const Expr *E);
78
std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E);
79
80
bool findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,
81
CXXBasePath &Path,
82
DeclarationName Name);
83
};
84
85
// Convenience lambdas for use as the 'Filter' parameter of
86
// HeuristicResolver::resolveDependentMember().
87
const auto NoFilter = [](const NamedDecl *D) { return true; };
88
const auto NonStaticFilter = [](const NamedDecl *D) {
89
return D->isCXXInstanceMember();
90
};
91
const auto StaticFilter = [](const NamedDecl *D) {
92
return !D->isCXXInstanceMember();
93
};
94
const auto ValueFilter = [](const NamedDecl *D) { return isa<ValueDecl>(D); };
95
const auto TypeFilter = [](const NamedDecl *D) { return isa<TypeDecl>(D); };
96
const auto TemplateFilter = [](const NamedDecl *D) {
97
return isa<TemplateDecl>(D);
98
};
99
100
QualType resolveDeclsToType(const std::vector<const NamedDecl *> &Decls,
101
ASTContext &Ctx) {
102
if (Decls.size() != 1) // Names an overload set -- just bail.
103
return QualType();
104
if (const auto *TD = dyn_cast<TypeDecl>(Decls[0])) {
105
return Ctx.getTypeDeclType(TD);
106
}
107
if (const auto *VD = dyn_cast<ValueDecl>(Decls[0])) {
108
return VD->getType();
109
}
110
return QualType();
111
}
112
113
TemplateName getReferencedTemplateName(const Type *T) {
114
if (const auto *TST = T->getAs<TemplateSpecializationType>()) {
115
return TST->getTemplateName();
116
}
117
if (const auto *DTST = T->getAs<DeducedTemplateSpecializationType>()) {
118
return DTST->getTemplateName();
119
}
120
return TemplateName();
121
}
122
123
// Helper function for HeuristicResolver::resolveDependentMember()
124
// which takes a possibly-dependent type `T` and heuristically
125
// resolves it to a CXXRecordDecl in which we can try name lookup.
126
TagDecl *HeuristicResolverImpl::resolveTypeToTagDecl(QualType QT) {
127
const Type *T = QT.getTypePtrOrNull();
128
if (!T)
129
return nullptr;
130
131
// Unwrap type sugar such as type aliases.
132
T = T->getCanonicalTypeInternal().getTypePtr();
133
134
if (const auto *DNT = T->getAs<DependentNameType>()) {
135
T = resolveDeclsToType(resolveDependentNameType(DNT), Ctx)
136
.getTypePtrOrNull();
137
if (!T)
138
return nullptr;
139
T = T->getCanonicalTypeInternal().getTypePtr();
140
}
141
142
if (auto *TT = T->getAs<TagType>()) {
143
TagDecl *TD = TT->getDecl();
144
// Template might not be instantiated yet, fall back to primary template
145
// in such cases.
146
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(TD)) {
147
if (CTSD->getTemplateSpecializationKind() == TSK_Undeclared) {
148
return CTSD->getSpecializedTemplate()->getTemplatedDecl();
149
}
150
}
151
return TD;
152
}
153
154
if (const auto *ICNT = T->getAs<InjectedClassNameType>())
155
T = ICNT->getInjectedSpecializationType().getTypePtrOrNull();
156
if (!T)
157
return nullptr;
158
159
TemplateName TN = getReferencedTemplateName(T);
160
if (TN.isNull())
161
return nullptr;
162
163
const ClassTemplateDecl *TD =
164
dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
165
if (!TD)
166
return nullptr;
167
168
return TD->getTemplatedDecl();
169
}
170
171
QualType HeuristicResolverImpl::getPointeeType(QualType T) {
172
if (T.isNull())
173
return QualType();
174
175
if (T->isPointerType())
176
return T->castAs<PointerType>()->getPointeeType();
177
178
// Try to handle smart pointer types.
179
180
// Look up operator-> in the primary template. If we find one, it's probably a
181
// smart pointer type.
182
auto ArrowOps = resolveDependentMember(
183
T, Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow), NonStaticFilter);
184
if (ArrowOps.empty())
185
return QualType();
186
187
// Getting the return type of the found operator-> method decl isn't useful,
188
// because we discarded template arguments to perform lookup in the primary
189
// template scope, so the return type would just have the form U* where U is a
190
// template parameter type.
191
// Instead, just handle the common case where the smart pointer type has the
192
// form of SmartPtr<X, ...>, and assume X is the pointee type.
193
auto *TST = T->getAs<TemplateSpecializationType>();
194
if (!TST)
195
return QualType();
196
if (TST->template_arguments().size() == 0)
197
return QualType();
198
const TemplateArgument &FirstArg = TST->template_arguments()[0];
199
if (FirstArg.getKind() != TemplateArgument::Type)
200
return QualType();
201
return FirstArg.getAsType();
202
}
203
204
QualType HeuristicResolverImpl::simplifyType(QualType Type, const Expr *E,
205
bool UnwrapPointer) {
206
bool DidUnwrapPointer = false;
207
// A type, together with an optional expression whose type it represents
208
// which may have additional information about the expression's type
209
// not stored in the QualType itself.
210
struct TypeExprPair {
211
QualType Type;
212
const Expr *E = nullptr;
213
};
214
TypeExprPair Current{Type, E};
215
auto SimplifyOneStep = [UnwrapPointer, &DidUnwrapPointer,
216
this](TypeExprPair T) -> TypeExprPair {
217
if (UnwrapPointer) {
218
if (QualType Pointee = getPointeeType(T.Type); !Pointee.isNull()) {
219
DidUnwrapPointer = true;
220
return {Pointee};
221
}
222
}
223
if (const auto *RT = T.Type->getAs<ReferenceType>()) {
224
// Does not count as "unwrap pointer".
225
return {RT->getPointeeType()};
226
}
227
if (const auto *BT = T.Type->getAs<BuiltinType>()) {
228
// If BaseType is the type of a dependent expression, it's just
229
// represented as BuiltinType::Dependent which gives us no information. We
230
// can get further by analyzing the dependent expression.
231
if (T.E && BT->getKind() == BuiltinType::Dependent) {
232
return {resolveExprToType(T.E), T.E};
233
}
234
}
235
if (const auto *AT = T.Type->getContainedAutoType()) {
236
// If T contains a dependent `auto` type, deduction will not have
237
// been performed on it yet. In simple cases (e.g. `auto` variable with
238
// initializer), get the approximate type that would result from
239
// deduction.
240
// FIXME: A more accurate implementation would propagate things like the
241
// `const` in `const auto`.
242
if (T.E && AT->isUndeducedAutoType()) {
243
if (const auto *DRE = dyn_cast<DeclRefExpr>(T.E)) {
244
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
245
if (auto *Init = VD->getInit())
246
return {resolveExprToType(Init), Init};
247
}
248
}
249
}
250
}
251
if (const auto *TTPT = dyn_cast_if_present<TemplateTypeParmType>(T.Type)) {
252
// We can't do much useful with a template parameter (e.g. we cannot look
253
// up member names inside it). However, if the template parameter has a
254
// default argument, as a heuristic we can replace T with the default
255
// argument type.
256
if (const auto *TTPD = TTPT->getDecl()) {
257
if (TTPD->hasDefaultArgument()) {
258
const auto &DefaultArg = TTPD->getDefaultArgument().getArgument();
259
if (DefaultArg.getKind() == TemplateArgument::Type) {
260
return {DefaultArg.getAsType()};
261
}
262
}
263
}
264
}
265
return T;
266
};
267
// As an additional protection against infinite loops, bound the number of
268
// simplification steps.
269
size_t StepCount = 0;
270
const size_t MaxSteps = 64;
271
while (!Current.Type.isNull() && StepCount++ < MaxSteps) {
272
TypeExprPair New = SimplifyOneStep(Current);
273
if (New.Type == Current.Type)
274
break;
275
Current = New;
276
}
277
if (UnwrapPointer && !DidUnwrapPointer)
278
return QualType();
279
return Current.Type;
280
}
281
282
std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr(
283
const CXXDependentScopeMemberExpr *ME) {
284
// If the expression has a qualifier, try resolving the member inside the
285
// qualifier's type.
286
// Note that we cannot use a NonStaticFilter in either case, for a couple
287
// of reasons:
288
// 1. It's valid to access a static member using instance member syntax,
289
// e.g. `instance.static_member`.
290
// 2. We can sometimes get a CXXDependentScopeMemberExpr for static
291
// member syntax too, e.g. if `X::static_member` occurs inside
292
// an instance method, it's represented as a CXXDependentScopeMemberExpr
293
// with `this` as the base expression as `X` as the qualifier
294
// (which could be valid if `X` names a base class after instantiation).
295
if (NestedNameSpecifier *NNS = ME->getQualifier()) {
296
if (QualType QualifierType = resolveNestedNameSpecifierToType(NNS);
297
!QualifierType.isNull()) {
298
auto Decls =
299
resolveDependentMember(QualifierType, ME->getMember(), NoFilter);
300
if (!Decls.empty())
301
return Decls;
302
}
303
304
// Do not proceed to try resolving the member in the expression's base type
305
// without regard to the qualifier, as that could produce incorrect results.
306
// For example, `void foo() { this->Base::foo(); }` shouldn't resolve to
307
// foo() itself!
308
return {};
309
}
310
311
// Try resolving the member inside the expression's base type.
312
Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase();
313
QualType BaseType = ME->getBaseType();
314
BaseType = simplifyType(BaseType, Base, ME->isArrow());
315
return resolveDependentMember(BaseType, ME->getMember(), NoFilter);
316
}
317
318
std::vector<const NamedDecl *>
319
HeuristicResolverImpl::resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE) {
320
QualType Qualifier = resolveNestedNameSpecifierToType(RE->getQualifier());
321
Qualifier = simplifyType(Qualifier, nullptr, /*UnwrapPointer=*/false);
322
return resolveDependentMember(Qualifier, RE->getDeclName(), StaticFilter);
323
}
324
325
std::vector<const NamedDecl *>
326
HeuristicResolverImpl::resolveTypeOfCallExpr(const CallExpr *CE) {
327
QualType CalleeType = resolveExprToType(CE->getCallee());
328
if (CalleeType.isNull())
329
return {};
330
if (const auto *FnTypePtr = CalleeType->getAs<PointerType>())
331
CalleeType = FnTypePtr->getPointeeType();
332
if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) {
333
if (const auto *D = resolveTypeToTagDecl(FnType->getReturnType())) {
334
return {D};
335
}
336
}
337
return {};
338
}
339
340
std::vector<const NamedDecl *>
341
HeuristicResolverImpl::resolveCalleeOfCallExpr(const CallExpr *CE) {
342
if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
343
return {ND};
344
}
345
346
return resolveExprToDecls(CE->getCallee());
347
}
348
349
std::vector<const NamedDecl *> HeuristicResolverImpl::resolveUsingValueDecl(
350
const UnresolvedUsingValueDecl *UUVD) {
351
return resolveDependentMember(QualType(UUVD->getQualifier()->getAsType(), 0),
352
UUVD->getNameInfo().getName(), ValueFilter);
353
}
354
355
std::vector<const NamedDecl *>
356
HeuristicResolverImpl::resolveDependentNameType(const DependentNameType *DNT) {
357
if (auto [_, inserted] = SeenDependentNameTypes.insert(DNT); !inserted)
358
return {};
359
return resolveDependentMember(
360
resolveNestedNameSpecifierToType(DNT->getQualifier()),
361
DNT->getIdentifier(), TypeFilter);
362
}
363
364
std::vector<const NamedDecl *>
365
HeuristicResolverImpl::resolveTemplateSpecializationType(
366
const DependentTemplateSpecializationType *DTST) {
367
const DependentTemplateStorage &DTN = DTST->getDependentTemplateName();
368
return resolveDependentMember(
369
resolveNestedNameSpecifierToType(DTN.getQualifier()),
370
DTN.getName().getIdentifier(), TemplateFilter);
371
}
372
373
std::vector<const NamedDecl *>
374
HeuristicResolverImpl::resolveExprToDecls(const Expr *E) {
375
if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) {
376
return resolveMemberExpr(ME);
377
}
378
if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) {
379
return resolveDeclRefExpr(RE);
380
}
381
if (const auto *OE = dyn_cast<OverloadExpr>(E)) {
382
return {OE->decls_begin(), OE->decls_end()};
383
}
384
if (const auto *CE = dyn_cast<CallExpr>(E)) {
385
return resolveTypeOfCallExpr(CE);
386
}
387
if (const auto *ME = dyn_cast<MemberExpr>(E))
388
return {ME->getMemberDecl()};
389
390
return {};
391
}
392
393
QualType HeuristicResolverImpl::resolveExprToType(const Expr *E) {
394
std::vector<const NamedDecl *> Decls = resolveExprToDecls(E);
395
if (!Decls.empty())
396
return resolveDeclsToType(Decls, Ctx);
397
398
return E->getType();
399
}
400
401
QualType HeuristicResolverImpl::resolveNestedNameSpecifierToType(
402
const NestedNameSpecifier *NNS) {
403
if (!NNS)
404
return QualType();
405
406
// The purpose of this function is to handle the dependent (Kind ==
407
// Identifier) case, but we need to recurse on the prefix because
408
// that may be dependent as well, so for convenience handle
409
// the TypeSpec cases too.
410
switch (NNS->getKind()) {
411
case NestedNameSpecifier::TypeSpec:
412
return QualType(NNS->getAsType(), 0);
413
case NestedNameSpecifier::Identifier: {
414
return resolveDeclsToType(
415
resolveDependentMember(
416
resolveNestedNameSpecifierToType(NNS->getPrefix()),
417
NNS->getAsIdentifier(), TypeFilter),
418
Ctx);
419
}
420
default:
421
break;
422
}
423
return QualType();
424
}
425
426
bool isOrdinaryMember(const NamedDecl *ND) {
427
return ND->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_Tag |
428
Decl::IDNS_Member);
429
}
430
431
bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,
432
DeclarationName Name) {
433
Path.Decls = RD->lookup(Name).begin();
434
for (DeclContext::lookup_iterator I = Path.Decls, E = I.end(); I != E; ++I)
435
if (isOrdinaryMember(*I))
436
return true;
437
438
return false;
439
}
440
441
bool HeuristicResolverImpl::findOrdinaryMemberInDependentClasses(
442
const CXXBaseSpecifier *Specifier, CXXBasePath &Path,
443
DeclarationName Name) {
444
TagDecl *TD = resolveTypeToTagDecl(Specifier->getType());
445
if (const auto *RD = dyn_cast_if_present<CXXRecordDecl>(TD)) {
446
return findOrdinaryMember(RD, Path, Name);
447
}
448
return false;
449
}
450
451
std::vector<const NamedDecl *> HeuristicResolverImpl::lookupDependentName(
452
CXXRecordDecl *RD, DeclarationName Name,
453
llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
454
std::vector<const NamedDecl *> Results;
455
456
// Lookup in the class.
457
bool AnyOrdinaryMembers = false;
458
for (const NamedDecl *ND : RD->lookup(Name)) {
459
if (isOrdinaryMember(ND))
460
AnyOrdinaryMembers = true;
461
if (Filter(ND))
462
Results.push_back(ND);
463
}
464
if (AnyOrdinaryMembers)
465
return Results;
466
467
// Perform lookup into our base classes.
468
CXXBasePaths Paths;
469
Paths.setOrigin(RD);
470
if (!RD->lookupInBases(
471
[&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
472
return findOrdinaryMemberInDependentClasses(Specifier, Path, Name);
473
},
474
Paths, /*LookupInDependent=*/true))
475
return Results;
476
for (DeclContext::lookup_iterator I = Paths.front().Decls, E = I.end();
477
I != E; ++I) {
478
if (isOrdinaryMember(*I) && Filter(*I))
479
Results.push_back(*I);
480
}
481
return Results;
482
}
483
484
std::vector<const NamedDecl *> HeuristicResolverImpl::resolveDependentMember(
485
QualType QT, DeclarationName Name,
486
llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
487
TagDecl *TD = resolveTypeToTagDecl(QT);
488
if (!TD)
489
return {};
490
if (auto *ED = dyn_cast<EnumDecl>(TD)) {
491
auto Result = ED->lookup(Name);
492
return {Result.begin(), Result.end()};
493
}
494
if (auto *RD = dyn_cast<CXXRecordDecl>(TD)) {
495
if (!RD->hasDefinition())
496
return {};
497
RD = RD->getDefinition();
498
return lookupDependentName(RD, Name, [&](const NamedDecl *ND) {
499
if (!Filter(ND))
500
return false;
501
if (const auto *MD = dyn_cast<CXXMethodDecl>(ND)) {
502
return !MD->isInstance() ||
503
MD->getMethodQualifiers().compatiblyIncludes(QT.getQualifiers(),
504
Ctx);
505
}
506
return true;
507
});
508
}
509
return {};
510
}
511
512
FunctionProtoTypeLoc
513
HeuristicResolverImpl::getFunctionProtoTypeLoc(const Expr *Fn) {
514
TypeLoc Target;
515
const Expr *NakedFn = Fn->IgnoreParenCasts();
516
if (const auto *T = NakedFn->getType().getTypePtr()->getAs<TypedefType>()) {
517
Target = T->getDecl()->getTypeSourceInfo()->getTypeLoc();
518
} else if (const auto *DR = dyn_cast<DeclRefExpr>(NakedFn)) {
519
const auto *D = DR->getDecl();
520
if (const auto *const VD = dyn_cast<VarDecl>(D)) {
521
Target = VD->getTypeSourceInfo()->getTypeLoc();
522
}
523
} else if (const auto *ME = dyn_cast<MemberExpr>(NakedFn)) {
524
const auto *MD = ME->getMemberDecl();
525
if (const auto *FD = dyn_cast<FieldDecl>(MD)) {
526
Target = FD->getTypeSourceInfo()->getTypeLoc();
527
}
528
}
529
530
if (!Target)
531
return {};
532
533
// Unwrap types that may be wrapping the function type
534
while (true) {
535
if (auto P = Target.getAs<PointerTypeLoc>()) {
536
Target = P.getPointeeLoc();
537
continue;
538
}
539
if (auto A = Target.getAs<AttributedTypeLoc>()) {
540
Target = A.getModifiedLoc();
541
continue;
542
}
543
if (auto P = Target.getAs<ParenTypeLoc>()) {
544
Target = P.getInnerLoc();
545
continue;
546
}
547
break;
548
}
549
550
if (auto F = Target.getAs<FunctionProtoTypeLoc>()) {
551
// In some edge cases the AST can contain a "trivial" FunctionProtoTypeLoc
552
// which has null parameters. Avoid these as they don't contain useful
553
// information.
554
if (llvm::all_of(F.getParams(), llvm::identity<ParmVarDecl *>()))
555
return F;
556
}
557
558
return {};
559
}
560
561
} // namespace
562
563
std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(
564
const CXXDependentScopeMemberExpr *ME) const {
565
return HeuristicResolverImpl(Ctx).resolveMemberExpr(ME);
566
}
567
std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr(
568
const DependentScopeDeclRefExpr *RE) const {
569
return HeuristicResolverImpl(Ctx).resolveDeclRefExpr(RE);
570
}
571
std::vector<const NamedDecl *>
572
HeuristicResolver::resolveTypeOfCallExpr(const CallExpr *CE) const {
573
return HeuristicResolverImpl(Ctx).resolveTypeOfCallExpr(CE);
574
}
575
std::vector<const NamedDecl *>
576
HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const {
577
return HeuristicResolverImpl(Ctx).resolveCalleeOfCallExpr(CE);
578
}
579
std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl(
580
const UnresolvedUsingValueDecl *UUVD) const {
581
return HeuristicResolverImpl(Ctx).resolveUsingValueDecl(UUVD);
582
}
583
std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType(
584
const DependentNameType *DNT) const {
585
return HeuristicResolverImpl(Ctx).resolveDependentNameType(DNT);
586
}
587
std::vector<const NamedDecl *>
588
HeuristicResolver::resolveTemplateSpecializationType(
589
const DependentTemplateSpecializationType *DTST) const {
590
return HeuristicResolverImpl(Ctx).resolveTemplateSpecializationType(DTST);
591
}
592
QualType HeuristicResolver::resolveNestedNameSpecifierToType(
593
const NestedNameSpecifier *NNS) const {
594
return HeuristicResolverImpl(Ctx).resolveNestedNameSpecifierToType(NNS);
595
}
596
std::vector<const NamedDecl *> HeuristicResolver::lookupDependentName(
597
CXXRecordDecl *RD, DeclarationName Name,
598
llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
599
return HeuristicResolverImpl(Ctx).lookupDependentName(RD, Name, Filter);
600
}
601
const QualType HeuristicResolver::getPointeeType(QualType T) const {
602
return HeuristicResolverImpl(Ctx).getPointeeType(T);
603
}
604
TagDecl *HeuristicResolver::resolveTypeToTagDecl(QualType T) const {
605
return HeuristicResolverImpl(Ctx).resolveTypeToTagDecl(T);
606
}
607
QualType HeuristicResolver::simplifyType(QualType Type, const Expr *E,
608
bool UnwrapPointer) {
609
return HeuristicResolverImpl(Ctx).simplifyType(Type, E, UnwrapPointer);
610
}
611
612
FunctionProtoTypeLoc
613
HeuristicResolver::getFunctionProtoTypeLoc(const Expr *Fn) const {
614
return HeuristicResolverImpl(Ctx).getFunctionProtoTypeLoc(Fn);
615
}
616
617
} // namespace clang
618
619