clang 23.0.0git
HeuristicResolver.cpp
Go to the documentation of this file.
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
13#include "clang/AST/ExprCXX.h"
16#include "clang/AST/Type.h"
17
18namespace clang {
19
20namespace {
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.
29class HeuristicResolverImpl {
30public:
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 *> 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 *>
45 resolveTemplateSpecializationType(const TemplateSpecializationType *TST);
46 QualType resolveNestedNameSpecifierToType(NestedNameSpecifier NNS);
47 QualType getPointeeType(QualType T);
48 std::vector<const NamedDecl *>
49 lookupDependentName(CXXRecordDecl *RD, DeclarationName Name,
50 llvm::function_ref<bool(const NamedDecl *ND)> Filter);
51 TagDecl *resolveTypeToTagDecl(QualType T);
52 QualType simplifyType(QualType Type, const Expr *E, bool UnwrapPointer);
53 QualType resolveExprToType(const Expr *E);
54 FunctionProtoTypeLoc getFunctionProtoTypeLoc(const Expr *Fn);
55
56private:
57 ASTContext &Ctx;
58
59 // Recursion protection sets
60 llvm::SmallPtrSet<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 std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E);
76 QualType resolveTypeOfCallExpr(const CallExpr *CE);
77
78 bool findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,
79 CXXBasePath &Path,
80 DeclarationName Name);
81};
82
83// Convenience lambdas for use as the 'Filter' parameter of
84// HeuristicResolver::resolveDependentMember().
85const auto NoFilter = [](const NamedDecl *D) { return true; };
86const auto NonStaticFilter = [](const NamedDecl *D) {
87 return D->isCXXInstanceMember();
88};
89const auto StaticFilter = [](const NamedDecl *D) {
90 return !D->isCXXInstanceMember();
91};
92const auto ValueFilter = [](const NamedDecl *D) { return isa<ValueDecl>(D); };
93const auto TypeFilter = [](const NamedDecl *D) { return isa<TypeDecl>(D); };
94const auto TemplateFilter = [](const NamedDecl *D) {
95 return isa<TemplateDecl>(D);
96};
97
98QualType resolveDeclToType(const NamedDecl *D, ASTContext &Ctx) {
99 if (const auto *TempD = dyn_cast<TemplateDecl>(D)) {
100 D = TempD->getTemplatedDecl();
101 }
102 if (const auto *TD = dyn_cast<TypeDecl>(D))
103 return Ctx.getCanonicalTypeDeclType(TD);
104 if (const auto *VD = dyn_cast<ValueDecl>(D)) {
105 return VD->getType();
106 }
107 return QualType();
108}
109
110QualType resolveDeclsToType(const std::vector<const NamedDecl *> &Decls,
111 ASTContext &Ctx) {
112 if (Decls.size() != 1) // Names an overload set -- just bail.
113 return QualType();
114 return resolveDeclToType(Decls[0], Ctx);
115}
116
117TemplateName getReferencedTemplateName(const Type *T) {
118 if (const auto *TST = T->getAs<TemplateSpecializationType>()) {
119 return TST->getTemplateName();
120 }
121 if (const auto *DTST = T->getAs<DeducedTemplateSpecializationType>()) {
122 return DTST->getTemplateName();
123 }
124 return TemplateName();
125}
126
127// Helper function for HeuristicResolver::resolveDependentMember()
128// which takes a possibly-dependent type `T` and heuristically
129// resolves it to a CXXRecordDecl in which we can try name lookup.
130TagDecl *HeuristicResolverImpl::resolveTypeToTagDecl(QualType QT) {
131 const Type *T = QT.getTypePtrOrNull();
132 if (!T)
133 return nullptr;
134
135 // Unwrap type sugar such as type aliases.
136 T = T->getCanonicalTypeInternal().getTypePtr();
137
138 if (const auto *DNT = T->getAs<DependentNameType>()) {
139 T = resolveDeclsToType(resolveDependentNameType(DNT), Ctx)
140 .getTypePtrOrNull();
141 if (!T)
142 return nullptr;
143 T = T->getCanonicalTypeInternal().getTypePtr();
144 }
145
146 if (auto *TD = T->getAsTagDecl()) {
147 // Template might not be instantiated yet, fall back to primary template
148 // in such cases.
149 if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(TD)) {
150 if (CTSD->getTemplateSpecializationKind() == TSK_Undeclared) {
151 return CTSD->getSpecializedTemplate()->getTemplatedDecl();
152 }
153 }
154 return TD;
155 }
156
157 TemplateName TN = getReferencedTemplateName(T);
158 if (TN.isNull())
159 return nullptr;
160
161 const ClassTemplateDecl *TD =
162 dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
163 if (!TD)
164 return nullptr;
165
166 return TD->getTemplatedDecl();
167}
168
169QualType HeuristicResolverImpl::getPointeeType(QualType T) {
170 if (T.isNull())
171 return QualType();
172
173 if (T->isPointerType())
174 return T->castAs<PointerType>()->getPointeeType();
175
176 // Try to handle smart pointer types.
177
178 // Look up operator-> in the primary template. If we find one, it's probably a
179 // smart pointer type.
180 auto ArrowOps = resolveDependentMember(
181 T, Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow), NonStaticFilter);
182 if (ArrowOps.empty())
183 return QualType();
184
185 // Getting the return type of the found operator-> method decl isn't useful,
186 // because we discarded template arguments to perform lookup in the primary
187 // template scope, so the return type would just have the form U* where U is a
188 // template parameter type.
189 // Instead, just handle the common case where the smart pointer type has the
190 // form of SmartPtr<X, ...>, and assume X is the pointee type.
191 auto *TST = T->getAs<TemplateSpecializationType>();
192 if (!TST)
193 return QualType();
194 if (TST->template_arguments().size() == 0)
195 return QualType();
196 const TemplateArgument &FirstArg = TST->template_arguments()[0];
197 if (FirstArg.getKind() != TemplateArgument::Type)
198 return QualType();
199 return FirstArg.getAsType();
200}
201
202QualType HeuristicResolverImpl::simplifyType(QualType Type, const Expr *E,
203 bool UnwrapPointer) {
204 bool DidUnwrapPointer = false;
205 // A type, together with an optional expression whose type it represents
206 // which may have additional information about the expression's type
207 // not stored in the QualType itself.
208 struct TypeExprPair {
209 QualType Type;
210 const Expr *E = nullptr;
211 };
212 TypeExprPair Current{Type, E};
213 auto SimplifyOneStep = [UnwrapPointer, &DidUnwrapPointer,
214 this](TypeExprPair T) -> TypeExprPair {
215 if (UnwrapPointer) {
216 if (QualType Pointee = getPointeeType(T.Type); !Pointee.isNull()) {
217 DidUnwrapPointer = true;
218 return {Pointee};
219 }
220 }
221 if (const auto *RT = T.Type->getAs<ReferenceType>()) {
222 // Does not count as "unwrap pointer".
223 return {RT->getPointeeType()};
224 }
225 if (const auto *BT = T.Type->getAs<BuiltinType>()) {
226 // If BaseType is the type of a dependent expression, it's just
227 // represented as BuiltinType::Dependent which gives us no information. We
228 // can get further by analyzing the dependent expression.
229 if (T.E && BT->getKind() == BuiltinType::Dependent) {
230 return {resolveExprToType(T.E), T.E};
231 }
232 }
233 if (const auto *AT = T.Type->getContainedAutoType()) {
234 // If T contains a dependent `auto` type, deduction will not have
235 // been performed on it yet. In simple cases (e.g. `auto` variable with
236 // initializer), get the approximate type that would result from
237 // deduction.
238 // FIXME: A more accurate implementation would propagate things like the
239 // `const` in `const auto`.
240 if (T.E && AT->isUndeducedAutoType()) {
241 if (const auto *DRE = dyn_cast<DeclRefExpr>(T.E)) {
242 if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
243 if (auto *Init = VD->getInit())
244 return {resolveExprToType(Init), Init};
245 }
246 }
247 }
248 }
249 if (const auto *TTPT = dyn_cast_if_present<TemplateTypeParmType>(T.Type)) {
250 // We can't do much useful with a template parameter (e.g. we cannot look
251 // up member names inside it). However, if the template parameter has a
252 // default argument, as a heuristic we can replace T with the default
253 // argument type.
254 if (const auto *TTPD = TTPT->getDecl()) {
255 if (TTPD->hasDefaultArgument()) {
256 const auto &DefaultArg = TTPD->getDefaultArgument().getArgument();
257 if (DefaultArg.getKind() == TemplateArgument::Type) {
258 return {DefaultArg.getAsType()};
259 }
260 }
261 }
262 }
263
264 // Similarly, heuristically replace a template template parameter with its
265 // default argument if it has one.
266 if (const auto *TST =
267 dyn_cast_if_present<TemplateSpecializationType>(T.Type)) {
268 if (const auto *TTPD = dyn_cast_if_present<TemplateTemplateParmDecl>(
269 TST->getTemplateName().getAsTemplateDecl())) {
270 if (TTPD->hasDefaultArgument()) {
271 const auto &DefaultArg = TTPD->getDefaultArgument().getArgument();
272 if (DefaultArg.getKind() == TemplateArgument::Template) {
273 if (const auto *CTD = dyn_cast_if_present<ClassTemplateDecl>(
274 DefaultArg.getAsTemplate().getAsTemplateDecl())) {
275 return {Ctx.getCanonicalTagType(CTD->getTemplatedDecl())};
276 }
277 }
278 }
279 }
280 }
281
282 // Check if the expression refers to an explicit object parameter of
283 // templated type. If so, heuristically treat it as having the type of the
284 // enclosing class.
285 if (!T.Type.isNull() &&
286 (T.Type->isUndeducedAutoType() || T.Type->isTemplateTypeParmType())) {
287 if (auto *DRE = dyn_cast_if_present<DeclRefExpr>(T.E)) {
288 auto *PrDecl = dyn_cast<ParmVarDecl>(DRE->getDecl());
289 if (PrDecl && PrDecl->isExplicitObjectParameter()) {
290 const auto *Parent =
291 dyn_cast<TagDecl>(PrDecl->getDeclContext()->getParent());
292 return {Ctx.getCanonicalTagType(Parent)};
293 }
294 }
295 }
296
297 return T;
298 };
299 // As an additional protection against infinite loops, bound the number of
300 // simplification steps.
301 size_t StepCount = 0;
302 const size_t MaxSteps = 64;
303 while (!Current.Type.isNull() && StepCount++ < MaxSteps) {
304 TypeExprPair New = SimplifyOneStep(Current);
305 if (New.Type == Current.Type)
306 break;
307 Current = New;
308 }
309 if (UnwrapPointer && !DidUnwrapPointer)
310 return QualType();
311 return Current.Type;
312}
313
314std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr(
315 const CXXDependentScopeMemberExpr *ME) {
316 // If the expression has a qualifier, try resolving the member inside the
317 // qualifier's type.
318 // Note that we cannot use a NonStaticFilter in either case, for a couple
319 // of reasons:
320 // 1. It's valid to access a static member using instance member syntax,
321 // e.g. `instance.static_member`.
322 // 2. We can sometimes get a CXXDependentScopeMemberExpr for static
323 // member syntax too, e.g. if `X::static_member` occurs inside
324 // an instance method, it's represented as a CXXDependentScopeMemberExpr
325 // with `this` as the base expression as `X` as the qualifier
326 // (which could be valid if `X` names a base class after instantiation).
327 if (NestedNameSpecifier NNS = ME->getQualifier()) {
328 if (QualType QualifierType = resolveNestedNameSpecifierToType(NNS);
329 !QualifierType.isNull()) {
330 auto Decls =
331 resolveDependentMember(QualifierType, ME->getMember(), NoFilter);
332 if (!Decls.empty())
333 return Decls;
334 }
335
336 // Do not proceed to try resolving the member in the expression's base type
337 // without regard to the qualifier, as that could produce incorrect results.
338 // For example, `void foo() { this->Base::foo(); }` shouldn't resolve to
339 // foo() itself!
340 return {};
341 }
342
343 // Try resolving the member inside the expression's base type.
344 Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase();
345 QualType BaseType = ME->getBaseType();
346 BaseType = simplifyType(BaseType, Base, ME->isArrow());
347 return resolveDependentMember(BaseType, ME->getMember(), NoFilter);
348}
349
350std::vector<const NamedDecl *>
351HeuristicResolverImpl::resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE) {
352 QualType Qualifier = resolveNestedNameSpecifierToType(RE->getQualifier());
353 Qualifier = simplifyType(Qualifier, nullptr, /*UnwrapPointer=*/false);
354 return resolveDependentMember(Qualifier, RE->getDeclName(), StaticFilter);
355}
356
357QualType HeuristicResolverImpl::resolveTypeOfCallExpr(const CallExpr *CE) {
358 // resolveExprToType(CE->getCallee()) would bail in the case of multiple
359 // overloads, as it can't produce a single type for them. We can be more
360 // permissive here, and allow multiple overloads with a common return type.
361 std::vector<const NamedDecl *> CalleeDecls =
362 resolveExprToDecls(CE->getCallee());
363 QualType CommonReturnType;
364 for (const NamedDecl *CalleeDecl : CalleeDecls) {
365 QualType CalleeType = resolveDeclToType(CalleeDecl, Ctx);
366 if (CalleeType.isNull())
367 continue;
368 if (const auto *FnTypePtr = CalleeType->getAs<PointerType>())
369 CalleeType = FnTypePtr->getPointeeType();
370 if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) {
371 QualType ReturnType =
372 simplifyType(FnType->getReturnType(), nullptr, false);
373 if (!CommonReturnType.isNull() && CommonReturnType != ReturnType) {
374 return {}; // conflicting return types
375 }
376 CommonReturnType = ReturnType;
377 }
378 }
379 return CommonReturnType;
380}
381
382std::vector<const NamedDecl *>
383HeuristicResolverImpl::resolveCalleeOfCallExpr(const CallExpr *CE) {
384 if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
385 return {ND};
386 }
387
388 return resolveExprToDecls(CE->getCallee());
389}
390
391std::vector<const NamedDecl *> HeuristicResolverImpl::resolveUsingValueDecl(
392 const UnresolvedUsingValueDecl *UUVD) {
393 NestedNameSpecifier Qualifier = UUVD->getQualifier();
394 if (Qualifier.getKind() != NestedNameSpecifier::Kind::Type)
395 return {};
396 return resolveDependentMember(QualType(Qualifier.getAsType(), 0),
397 UUVD->getNameInfo().getName(), ValueFilter);
398}
399
400std::vector<const NamedDecl *>
401HeuristicResolverImpl::resolveDependentNameType(const DependentNameType *DNT) {
402 if (auto [_, inserted] = SeenDependentNameTypes.insert(DNT); !inserted)
403 return {};
404 return resolveDependentMember(
405 resolveNestedNameSpecifierToType(DNT->getQualifier()),
406 DNT->getIdentifier(), TypeFilter);
407}
408
409std::vector<const NamedDecl *>
410HeuristicResolverImpl::resolveTemplateSpecializationType(
411 const TemplateSpecializationType *TST) {
412 if (TST->getTemplateName().getKind() == TemplateName::DependentTemplate) {
413 const DependentTemplateStorage &DTN =
414 *TST->getTemplateName().getAsDependentTemplateName();
415 return resolveDependentMember(
416 resolveNestedNameSpecifierToType(DTN.getQualifier()),
417 DTN.getName().getIdentifier(), TemplateFilter);
418 }
419 return {};
420}
421
422std::vector<const NamedDecl *>
423HeuristicResolverImpl::resolveExprToDecls(const Expr *E) {
424 if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) {
425 return resolveMemberExpr(ME);
426 }
427 if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) {
428 return resolveDeclRefExpr(RE);
429 }
430 if (const auto *OE = dyn_cast<OverloadExpr>(E)) {
431 return {OE->decls_begin(), OE->decls_end()};
432 }
433 if (const auto *CE = dyn_cast<CallExpr>(E)) {
434 QualType T = resolveTypeOfCallExpr(CE);
435 if (const auto *D = resolveTypeToTagDecl(T)) {
436 return {D};
437 }
438 return {};
439 }
440 if (const auto *ME = dyn_cast<MemberExpr>(E))
441 return {ME->getMemberDecl()};
442 if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
443 return {DRE->getDecl()};
444
445 return {};
446}
447
448QualType HeuristicResolverImpl::resolveExprToType(const Expr *E) {
449 // resolveExprToDecls on a CallExpr only succeeds if the return type is
450 // a TagDecl, but we may want the type of a call in other cases as well.
451 // (FIXME: There are probably other cases where we can do something more
452 // flexible than resoveExprToDecls + resolveDeclsToType, e.g. in the case
453 // of OverloadExpr we can probably accept overloads with a common type).
454 if (const auto *CE = dyn_cast<CallExpr>(E)) {
455 if (QualType Resolved = resolveTypeOfCallExpr(CE); !Resolved.isNull())
456 return Resolved;
457
458 // Don't proceed to try resolveExprToDecls(), it would just call
459 // resolveTypeOfCallExpr() again.
460 return E->getType();
461 }
462
463 // Similarly, unwrapping a unary dereference operation does not work via
464 // resolveExprToDecls.
465 if (const auto *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts())) {
466 if (UO->getOpcode() == UnaryOperatorKind::UO_Deref) {
467 if (auto Pointee = getPointeeType(resolveExprToType(UO->getSubExpr()));
468 !Pointee.isNull()) {
469 return Pointee;
470 }
471 }
472 }
473
474 std::vector<const NamedDecl *> Decls = resolveExprToDecls(E);
475 if (!Decls.empty())
476 return resolveDeclsToType(Decls, Ctx);
477
478 return E->getType();
479}
480
481QualType HeuristicResolverImpl::resolveNestedNameSpecifierToType(
482 NestedNameSpecifier NNS) {
483 // The purpose of this function is to handle the dependent (Kind ==
484 // Identifier) case, but we need to recurse on the prefix because
485 // that may be dependent as well, so for convenience handle
486 // the TypeSpec cases too.
487 switch (NNS.getKind()) {
488 case NestedNameSpecifier::Kind::Type: {
489 const auto *T = NNS.getAsType();
490 // FIXME: Should this handle the DependentTemplateSpecializationType as
491 // well?
492 if (const auto *DTN = dyn_cast<DependentNameType>(T))
493 return resolveDeclsToType(
494 resolveDependentMember(
495 resolveNestedNameSpecifierToType(DTN->getQualifier()),
496 DTN->getIdentifier(), TypeFilter),
497 Ctx);
498 return QualType(T, 0);
499 }
500 default:
501 break;
502 }
503 return QualType();
504}
505
506bool isOrdinaryMember(const NamedDecl *ND) {
507 return ND->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_Tag |
509}
510
511bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,
512 DeclarationName Name) {
513 Path.Decls = RD->lookup(Name).begin();
514 for (DeclContext::lookup_iterator I = Path.Decls, E = I.end(); I != E; ++I)
515 if (isOrdinaryMember(*I))
516 return true;
517
518 return false;
519}
520
521bool HeuristicResolverImpl::findOrdinaryMemberInDependentClasses(
522 const CXXBaseSpecifier *Specifier, CXXBasePath &Path,
523 DeclarationName Name) {
524 TagDecl *TD = resolveTypeToTagDecl(Specifier->getType());
525 if (const auto *RD = dyn_cast_if_present<CXXRecordDecl>(TD)) {
526 return findOrdinaryMember(RD, Path, Name);
527 }
528 return false;
529}
530
531std::vector<const NamedDecl *> HeuristicResolverImpl::lookupDependentName(
532 CXXRecordDecl *RD, DeclarationName Name,
533 llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
534 std::vector<const NamedDecl *> Results;
535
536 // Lookup in the class.
537 bool AnyOrdinaryMembers = false;
538 for (const NamedDecl *ND : RD->lookup(Name)) {
539 if (isOrdinaryMember(ND))
540 AnyOrdinaryMembers = true;
541 if (Filter(ND))
542 Results.push_back(ND);
543 }
544 if (AnyOrdinaryMembers)
545 return Results;
546
547 // Perform lookup into our base classes.
548 CXXBasePaths Paths;
549 Paths.setOrigin(RD);
550 if (!RD->lookupInBases(
551 [&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
552 return findOrdinaryMemberInDependentClasses(Specifier, Path, Name);
553 },
554 Paths, /*LookupInDependent=*/true))
555 return Results;
556 for (DeclContext::lookup_iterator I = Paths.front().Decls, E = I.end();
557 I != E; ++I) {
558 if (isOrdinaryMember(*I) && Filter(*I))
559 Results.push_back(*I);
560 }
561 return Results;
562}
563
564std::vector<const NamedDecl *> HeuristicResolverImpl::resolveDependentMember(
565 QualType QT, DeclarationName Name,
566 llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
567 TagDecl *TD = resolveTypeToTagDecl(QT);
568 if (!TD)
569 return {};
570 if (auto *ED = dyn_cast<EnumDecl>(TD)) {
571 auto Result = ED->lookup(Name);
572 return {Result.begin(), Result.end()};
573 }
574 if (auto *RD = dyn_cast<CXXRecordDecl>(TD)) {
575 if (!RD->hasDefinition())
576 return {};
577 RD = RD->getDefinition();
578 return lookupDependentName(RD, Name, [&](const NamedDecl *ND) {
579 if (!Filter(ND))
580 return false;
581 if (const auto *MD = dyn_cast<CXXMethodDecl>(ND)) {
582 return !MD->isInstance() ||
583 MD->getMethodQualifiers().compatiblyIncludes(QT.getQualifiers(),
584 Ctx);
585 }
586 return true;
587 });
588 }
589 return {};
590}
591
592FunctionProtoTypeLoc
593HeuristicResolverImpl::getFunctionProtoTypeLoc(const Expr *Fn) {
594 TypeLoc Target;
595 const Expr *NakedFn = Fn->IgnoreParenCasts();
596 if (const auto *T = NakedFn->getType().getTypePtr()->getAs<TypedefType>()) {
597 Target = T->getDecl()->getTypeSourceInfo()->getTypeLoc();
598 } else if (const auto *DR = dyn_cast<DeclRefExpr>(NakedFn)) {
599 const auto *D = DR->getDecl();
600 if (const auto *const VD = dyn_cast<VarDecl>(D)) {
601 Target = VD->getTypeSourceInfo()->getTypeLoc();
602 }
603 } else if (const auto *ME = dyn_cast<MemberExpr>(NakedFn)) {
604 const auto *MD = ME->getMemberDecl();
605 if (const auto *FD = dyn_cast<FieldDecl>(MD)) {
606 Target = FD->getTypeSourceInfo()->getTypeLoc();
607 }
608 }
609
610 if (!Target)
611 return {};
612
613 // Unwrap types that may be wrapping the function type
614 while (true) {
615 if (auto P = Target.getAs<PointerTypeLoc>()) {
616 Target = P.getPointeeLoc();
617 continue;
618 }
619 if (auto A = Target.getAs<AttributedTypeLoc>()) {
620 Target = A.getModifiedLoc();
621 continue;
622 }
623 if (auto P = Target.getAs<ParenTypeLoc>()) {
624 Target = P.getInnerLoc();
625 continue;
626 }
627 break;
628 }
629
630 if (auto F = Target.getAs<FunctionProtoTypeLoc>()) {
631 // In some edge cases the AST can contain a "trivial" FunctionProtoTypeLoc
632 // which has null parameters. Avoid these as they don't contain useful
633 // information.
634 if (!llvm::is_contained(F.getParams(), nullptr))
635 return F;
636 }
637
638 return {};
639}
640
641} // namespace
642
643std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(
644 const CXXDependentScopeMemberExpr *ME) const {
645 return HeuristicResolverImpl(Ctx).resolveMemberExpr(ME);
646}
647std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr(
648 const DependentScopeDeclRefExpr *RE) const {
649 return HeuristicResolverImpl(Ctx).resolveDeclRefExpr(RE);
650}
651std::vector<const NamedDecl *>
653 return HeuristicResolverImpl(Ctx).resolveCalleeOfCallExpr(CE);
654}
655std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl(
656 const UnresolvedUsingValueDecl *UUVD) const {
657 return HeuristicResolverImpl(Ctx).resolveUsingValueDecl(UUVD);
658}
659std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType(
660 const DependentNameType *DNT) const {
661 return HeuristicResolverImpl(Ctx).resolveDependentNameType(DNT);
662}
663std::vector<const NamedDecl *>
665 const TemplateSpecializationType *TST) const {
666 return HeuristicResolverImpl(Ctx).resolveTemplateSpecializationType(TST);
667}
669 NestedNameSpecifier NNS) const {
670 return HeuristicResolverImpl(Ctx).resolveNestedNameSpecifierToType(NNS);
671}
672std::vector<const NamedDecl *> HeuristicResolver::lookupDependentName(
674 llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
675 return HeuristicResolverImpl(Ctx).lookupDependentName(RD, Name, Filter);
676}
678 return HeuristicResolverImpl(Ctx).getPointeeType(T);
679}
681 return HeuristicResolverImpl(Ctx).resolveTypeToTagDecl(T);
682}
684 bool UnwrapPointer) {
685 return HeuristicResolverImpl(Ctx).simplifyType(Type, E, UnwrapPointer);
686}
688 return HeuristicResolverImpl(Ctx).resolveExprToType(E);
689}
692 return HeuristicResolverImpl(Ctx).getFunctionProtoTypeLoc(Fn);
693}
694
695} // namespace clang
Defines the clang::ASTContext interface.
static bool isOrdinaryMember(const NamedDecl *ND)
static bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path, DeclarationName Name)
Defines the C++ template declaration subclasses.
Defines the clang::Expr interface and subclasses for C++ expressions.
Result
Implement __builtin_bit_cast and related operations.
llvm::MachO::Target Target
Definition MachO.h:51
static QualType getPointeeType(const MemRegion *R)
C Language Family Type Representation.
DeclarationNameTable DeclarationNames
Definition ASTContext.h:806
CanQualType getCanonicalTypeDeclType(const TypeDecl *TD) const
CanQualType getCanonicalTagType(const TagDecl *TD) const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
Represents a C++ member access expression where the actual member referenced could not be resolved be...
Definition ExprCXX.h:3870
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2949
lookup_result::iterator lookup_iterator
Definition DeclBase.h:2591
@ IDNS_Ordinary
Ordinary names.
Definition DeclBase.h:144
@ IDNS_Member
Members, declared with object declarations within tag definitions.
Definition DeclBase.h:136
@ IDNS_Tag
Tags, declared with 'struct foo;' and referenced with 'struct foo'.
Definition DeclBase.h:125
The name of a declaration.
A qualified reference to a name whose declaration cannot yet be resolved.
Definition ExprCXX.h:3510
This represents one expression.
Definition Expr.h:112
std::vector< const NamedDecl * > resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE) const
const QualType getPointeeType(QualType T) const
QualType simplifyType(QualType Type, const Expr *E, bool UnwrapPointer)
std::vector< const NamedDecl * > resolveMemberExpr(const CXXDependentScopeMemberExpr *ME) const
FunctionProtoTypeLoc getFunctionProtoTypeLoc(const Expr *Fn) const
QualType resolveNestedNameSpecifierToType(NestedNameSpecifier NNS) const
std::vector< const NamedDecl * > resolveCalleeOfCallExpr(const CallExpr *CE) const
std::vector< const NamedDecl * > resolveTemplateSpecializationType(const TemplateSpecializationType *TST) const
TagDecl * resolveTypeToTagDecl(QualType T) const
QualType resolveExprToType(const Expr *E) const
std::vector< const NamedDecl * > resolveUsingValueDecl(const UnresolvedUsingValueDecl *UUVD) const
std::vector< const NamedDecl * > resolveDependentNameType(const DependentNameType *DNT) const
std::vector< const NamedDecl * > lookupDependentName(CXXRecordDecl *RD, DeclarationName Name, llvm::function_ref< bool(const NamedDecl *ND)> Filter)
This represents a decl that may have a name.
Definition Decl.h:274
Represents a C++ nested name specifier, such as "\::std::vector<int>::".
A (possibly-)qualified type.
Definition TypeBase.h:937
Represents the declaration of a struct/union/class/enum.
Definition Decl.h:3739
Represents a C++ template name within the type system.
The base class of the type hierarchy.
Definition TypeBase.h:1875
Represents a dependent using declaration which was not marked with typename.
Definition DeclCXX.h:3958
bool Init(InterpState &S, CodePtr OpPC)
Definition Interp.h:2373
llvm::cl::opt< std::string > Filter
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ TemplateName
The identifier is a template name. FIXME: Add an annotation for that.
Definition Parser.h:61
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
@ Type
The name was classified as a type.
Definition Sema.h:564