692 lines · cpp
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-exception6//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 17namespace clang {18 19namespace {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 external24// call into a HeuristicResolver operation. That allows this25// class to store state that's local to such a top-level call,26// particularly "recursion protection sets" that keep track of27// nodes that have already been seen to avoid infinite recursion.28class HeuristicResolverImpl {29public:30 HeuristicResolverImpl(ASTContext &Ctx) : Ctx(Ctx) {}31 32 // These functions match the public interface of HeuristicResolver33 // (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 *> resolveCalleeOfCallExpr(const CallExpr *CE);39 std::vector<const NamedDecl *>40 resolveUsingValueDecl(const UnresolvedUsingValueDecl *UUVD);41 std::vector<const NamedDecl *>42 resolveDependentNameType(const DependentNameType *DNT);43 std::vector<const NamedDecl *>44 resolveTemplateSpecializationType(const TemplateSpecializationType *TST);45 QualType resolveNestedNameSpecifierToType(NestedNameSpecifier NNS);46 QualType getPointeeType(QualType T);47 std::vector<const NamedDecl *>48 lookupDependentName(CXXRecordDecl *RD, DeclarationName Name,49 llvm::function_ref<bool(const NamedDecl *ND)> Filter);50 TagDecl *resolveTypeToTagDecl(QualType T);51 QualType simplifyType(QualType Type, const Expr *E, bool UnwrapPointer);52 QualType resolveExprToType(const Expr *E);53 FunctionProtoTypeLoc getFunctionProtoTypeLoc(const Expr *Fn);54 55private:56 ASTContext &Ctx;57 58 // Recursion protection sets59 llvm::SmallPtrSet<const DependentNameType *, 4> SeenDependentNameTypes;60 61 // Given a tag-decl type and a member name, heuristically resolve the62 // name to one or more declarations.63 // The current heuristic is simply to look up the name in the primary64 // template. This is a heuristic because the template could potentially65 // have specializations that declare different members.66 // Multiple declarations could be returned if the name is overloaded67 // (e.g. an overloaded method in the primary template).68 // This heuristic will give the desired answer in many cases, e.g.69 // for a call to vector<T>::size().70 std::vector<const NamedDecl *>71 resolveDependentMember(QualType T, DeclarationName Name,72 llvm::function_ref<bool(const NamedDecl *ND)> Filter);73 74 std::vector<const NamedDecl *> resolveExprToDecls(const Expr *E);75 QualType resolveTypeOfCallExpr(const CallExpr *CE);76 77 bool findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,78 CXXBasePath &Path,79 DeclarationName Name);80};81 82// Convenience lambdas for use as the 'Filter' parameter of83// HeuristicResolver::resolveDependentMember().84const auto NoFilter = [](const NamedDecl *D) { return true; };85const auto NonStaticFilter = [](const NamedDecl *D) {86 return D->isCXXInstanceMember();87};88const auto StaticFilter = [](const NamedDecl *D) {89 return !D->isCXXInstanceMember();90};91const auto ValueFilter = [](const NamedDecl *D) { return isa<ValueDecl>(D); };92const auto TypeFilter = [](const NamedDecl *D) { return isa<TypeDecl>(D); };93const auto TemplateFilter = [](const NamedDecl *D) {94 return isa<TemplateDecl>(D);95};96 97QualType resolveDeclToType(const NamedDecl *D, ASTContext &Ctx) {98 if (const auto *TempD = dyn_cast<TemplateDecl>(D)) {99 D = TempD->getTemplatedDecl();100 }101 if (const auto *TD = dyn_cast<TypeDecl>(D))102 return Ctx.getCanonicalTypeDeclType(TD);103 if (const auto *VD = dyn_cast<ValueDecl>(D)) {104 return VD->getType();105 }106 return QualType();107}108 109QualType resolveDeclsToType(const std::vector<const NamedDecl *> &Decls,110 ASTContext &Ctx) {111 if (Decls.size() != 1) // Names an overload set -- just bail.112 return QualType();113 return resolveDeclToType(Decls[0], Ctx);114}115 116TemplateName getReferencedTemplateName(const Type *T) {117 if (const auto *TST = T->getAs<TemplateSpecializationType>()) {118 return TST->getTemplateName();119 }120 if (const auto *DTST = T->getAs<DeducedTemplateSpecializationType>()) {121 return DTST->getTemplateName();122 }123 return TemplateName();124}125 126// Helper function for HeuristicResolver::resolveDependentMember()127// which takes a possibly-dependent type `T` and heuristically128// resolves it to a CXXRecordDecl in which we can try name lookup.129TagDecl *HeuristicResolverImpl::resolveTypeToTagDecl(QualType QT) {130 const Type *T = QT.getTypePtrOrNull();131 if (!T)132 return nullptr;133 134 // Unwrap type sugar such as type aliases.135 T = T->getCanonicalTypeInternal().getTypePtr();136 137 if (const auto *DNT = T->getAs<DependentNameType>()) {138 T = resolveDeclsToType(resolveDependentNameType(DNT), Ctx)139 .getTypePtrOrNull();140 if (!T)141 return nullptr;142 T = T->getCanonicalTypeInternal().getTypePtr();143 }144 145 if (auto *TD = T->getAsTagDecl()) {146 // Template might not be instantiated yet, fall back to primary template147 // in such cases.148 if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(TD)) {149 if (CTSD->getTemplateSpecializationKind() == TSK_Undeclared) {150 return CTSD->getSpecializedTemplate()->getTemplatedDecl();151 }152 }153 return TD;154 }155 156 TemplateName TN = getReferencedTemplateName(T);157 if (TN.isNull())158 return nullptr;159 160 const ClassTemplateDecl *TD =161 dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());162 if (!TD)163 return nullptr;164 165 return TD->getTemplatedDecl();166}167 168QualType HeuristicResolverImpl::getPointeeType(QualType T) {169 if (T.isNull())170 return QualType();171 172 if (T->isPointerType())173 return T->castAs<PointerType>()->getPointeeType();174 175 // Try to handle smart pointer types.176 177 // Look up operator-> in the primary template. If we find one, it's probably a178 // smart pointer type.179 auto ArrowOps = resolveDependentMember(180 T, Ctx.DeclarationNames.getCXXOperatorName(OO_Arrow), NonStaticFilter);181 if (ArrowOps.empty())182 return QualType();183 184 // Getting the return type of the found operator-> method decl isn't useful,185 // because we discarded template arguments to perform lookup in the primary186 // template scope, so the return type would just have the form U* where U is a187 // template parameter type.188 // Instead, just handle the common case where the smart pointer type has the189 // form of SmartPtr<X, ...>, and assume X is the pointee type.190 auto *TST = T->getAs<TemplateSpecializationType>();191 if (!TST)192 return QualType();193 if (TST->template_arguments().size() == 0)194 return QualType();195 const TemplateArgument &FirstArg = TST->template_arguments()[0];196 if (FirstArg.getKind() != TemplateArgument::Type)197 return QualType();198 return FirstArg.getAsType();199}200 201QualType HeuristicResolverImpl::simplifyType(QualType Type, const Expr *E,202 bool UnwrapPointer) {203 bool DidUnwrapPointer = false;204 // A type, together with an optional expression whose type it represents205 // which may have additional information about the expression's type206 // not stored in the QualType itself.207 struct TypeExprPair {208 QualType Type;209 const Expr *E = nullptr;210 };211 TypeExprPair Current{Type, E};212 auto SimplifyOneStep = [UnwrapPointer, &DidUnwrapPointer,213 this](TypeExprPair T) -> TypeExprPair {214 if (UnwrapPointer) {215 if (QualType Pointee = getPointeeType(T.Type); !Pointee.isNull()) {216 DidUnwrapPointer = true;217 return {Pointee};218 }219 }220 if (const auto *RT = T.Type->getAs<ReferenceType>()) {221 // Does not count as "unwrap pointer".222 return {RT->getPointeeType()};223 }224 if (const auto *BT = T.Type->getAs<BuiltinType>()) {225 // If BaseType is the type of a dependent expression, it's just226 // represented as BuiltinType::Dependent which gives us no information. We227 // can get further by analyzing the dependent expression.228 if (T.E && BT->getKind() == BuiltinType::Dependent) {229 return {resolveExprToType(T.E), T.E};230 }231 }232 if (const auto *AT = T.Type->getContainedAutoType()) {233 // If T contains a dependent `auto` type, deduction will not have234 // been performed on it yet. In simple cases (e.g. `auto` variable with235 // initializer), get the approximate type that would result from236 // deduction.237 // FIXME: A more accurate implementation would propagate things like the238 // `const` in `const auto`.239 if (T.E && AT->isUndeducedAutoType()) {240 if (const auto *DRE = dyn_cast<DeclRefExpr>(T.E)) {241 if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {242 if (auto *Init = VD->getInit())243 return {resolveExprToType(Init), Init};244 }245 }246 }247 }248 if (const auto *TTPT = dyn_cast_if_present<TemplateTypeParmType>(T.Type)) {249 // We can't do much useful with a template parameter (e.g. we cannot look250 // up member names inside it). However, if the template parameter has a251 // default argument, as a heuristic we can replace T with the default252 // argument type.253 if (const auto *TTPD = TTPT->getDecl()) {254 if (TTPD->hasDefaultArgument()) {255 const auto &DefaultArg = TTPD->getDefaultArgument().getArgument();256 if (DefaultArg.getKind() == TemplateArgument::Type) {257 return {DefaultArg.getAsType()};258 }259 }260 }261 }262 263 // Similarly, heuristically replace a template template parameter with its264 // default argument if it has one.265 if (const auto *TST =266 dyn_cast_if_present<TemplateSpecializationType>(T.Type)) {267 if (const auto *TTPD = dyn_cast_if_present<TemplateTemplateParmDecl>(268 TST->getTemplateName().getAsTemplateDecl())) {269 if (TTPD->hasDefaultArgument()) {270 const auto &DefaultArg = TTPD->getDefaultArgument().getArgument();271 if (DefaultArg.getKind() == TemplateArgument::Template) {272 if (const auto *CTD = dyn_cast_if_present<ClassTemplateDecl>(273 DefaultArg.getAsTemplate().getAsTemplateDecl())) {274 return {Ctx.getCanonicalTagType(CTD->getTemplatedDecl())};275 }276 }277 }278 }279 }280 281 // Check if the expression refers to an explicit object parameter of282 // templated type. If so, heuristically treat it as having the type of the283 // enclosing class.284 if (!T.Type.isNull() &&285 (T.Type->isUndeducedAutoType() || T.Type->isTemplateTypeParmType())) {286 if (auto *DRE = dyn_cast_if_present<DeclRefExpr>(T.E)) {287 auto *PrDecl = dyn_cast<ParmVarDecl>(DRE->getDecl());288 if (PrDecl && PrDecl->isExplicitObjectParameter()) {289 const auto *Parent =290 dyn_cast<TagDecl>(PrDecl->getDeclContext()->getParent());291 return {Ctx.getCanonicalTagType(Parent)};292 }293 }294 }295 296 return T;297 };298 // As an additional protection against infinite loops, bound the number of299 // simplification steps.300 size_t StepCount = 0;301 const size_t MaxSteps = 64;302 while (!Current.Type.isNull() && StepCount++ < MaxSteps) {303 TypeExprPair New = SimplifyOneStep(Current);304 if (New.Type == Current.Type)305 break;306 Current = New;307 }308 if (UnwrapPointer && !DidUnwrapPointer)309 return QualType();310 return Current.Type;311}312 313std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr(314 const CXXDependentScopeMemberExpr *ME) {315 // If the expression has a qualifier, try resolving the member inside the316 // qualifier's type.317 // Note that we cannot use a NonStaticFilter in either case, for a couple318 // of reasons:319 // 1. It's valid to access a static member using instance member syntax,320 // e.g. `instance.static_member`.321 // 2. We can sometimes get a CXXDependentScopeMemberExpr for static322 // member syntax too, e.g. if `X::static_member` occurs inside323 // an instance method, it's represented as a CXXDependentScopeMemberExpr324 // with `this` as the base expression as `X` as the qualifier325 // (which could be valid if `X` names a base class after instantiation).326 if (NestedNameSpecifier NNS = ME->getQualifier()) {327 if (QualType QualifierType = resolveNestedNameSpecifierToType(NNS);328 !QualifierType.isNull()) {329 auto Decls =330 resolveDependentMember(QualifierType, ME->getMember(), NoFilter);331 if (!Decls.empty())332 return Decls;333 }334 335 // Do not proceed to try resolving the member in the expression's base type336 // without regard to the qualifier, as that could produce incorrect results.337 // For example, `void foo() { this->Base::foo(); }` shouldn't resolve to338 // foo() itself!339 return {};340 }341 342 // Try resolving the member inside the expression's base type.343 Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase();344 QualType BaseType = ME->getBaseType();345 BaseType = simplifyType(BaseType, Base, ME->isArrow());346 return resolveDependentMember(BaseType, ME->getMember(), NoFilter);347}348 349std::vector<const NamedDecl *>350HeuristicResolverImpl::resolveDeclRefExpr(const DependentScopeDeclRefExpr *RE) {351 QualType Qualifier = resolveNestedNameSpecifierToType(RE->getQualifier());352 Qualifier = simplifyType(Qualifier, nullptr, /*UnwrapPointer=*/false);353 return resolveDependentMember(Qualifier, RE->getDeclName(), StaticFilter);354}355 356QualType HeuristicResolverImpl::resolveTypeOfCallExpr(const CallExpr *CE) {357 // resolveExprToType(CE->getCallee()) would bail in the case of multiple358 // overloads, as it can't produce a single type for them. We can be more359 // permissive here, and allow multiple overloads with a common return type.360 std::vector<const NamedDecl *> CalleeDecls =361 resolveExprToDecls(CE->getCallee());362 QualType CommonReturnType;363 for (const NamedDecl *CalleeDecl : CalleeDecls) {364 QualType CalleeType = resolveDeclToType(CalleeDecl, Ctx);365 if (CalleeType.isNull())366 continue;367 if (const auto *FnTypePtr = CalleeType->getAs<PointerType>())368 CalleeType = FnTypePtr->getPointeeType();369 if (const FunctionType *FnType = CalleeType->getAs<FunctionType>()) {370 QualType ReturnType =371 simplifyType(FnType->getReturnType(), nullptr, false);372 if (!CommonReturnType.isNull() && CommonReturnType != ReturnType) {373 return {}; // conflicting return types374 }375 CommonReturnType = ReturnType;376 }377 }378 return CommonReturnType;379}380 381std::vector<const NamedDecl *>382HeuristicResolverImpl::resolveCalleeOfCallExpr(const CallExpr *CE) {383 if (const auto *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {384 return {ND};385 }386 387 return resolveExprToDecls(CE->getCallee());388}389 390std::vector<const NamedDecl *> HeuristicResolverImpl::resolveUsingValueDecl(391 const UnresolvedUsingValueDecl *UUVD) {392 NestedNameSpecifier Qualifier = UUVD->getQualifier();393 if (Qualifier.getKind() != NestedNameSpecifier::Kind::Type)394 return {};395 return resolveDependentMember(QualType(Qualifier.getAsType(), 0),396 UUVD->getNameInfo().getName(), ValueFilter);397}398 399std::vector<const NamedDecl *>400HeuristicResolverImpl::resolveDependentNameType(const DependentNameType *DNT) {401 if (auto [_, inserted] = SeenDependentNameTypes.insert(DNT); !inserted)402 return {};403 return resolveDependentMember(404 resolveNestedNameSpecifierToType(DNT->getQualifier()),405 DNT->getIdentifier(), TypeFilter);406}407 408std::vector<const NamedDecl *>409HeuristicResolverImpl::resolveTemplateSpecializationType(410 const TemplateSpecializationType *TST) {411 const DependentTemplateStorage &DTN =412 *TST->getTemplateName().getAsDependentTemplateName();413 return resolveDependentMember(414 resolveNestedNameSpecifierToType(DTN.getQualifier()),415 DTN.getName().getIdentifier(), TemplateFilter);416}417 418std::vector<const NamedDecl *>419HeuristicResolverImpl::resolveExprToDecls(const Expr *E) {420 if (const auto *ME = dyn_cast<CXXDependentScopeMemberExpr>(E)) {421 return resolveMemberExpr(ME);422 }423 if (const auto *RE = dyn_cast<DependentScopeDeclRefExpr>(E)) {424 return resolveDeclRefExpr(RE);425 }426 if (const auto *OE = dyn_cast<OverloadExpr>(E)) {427 return {OE->decls_begin(), OE->decls_end()};428 }429 if (const auto *CE = dyn_cast<CallExpr>(E)) {430 QualType T = resolveTypeOfCallExpr(CE);431 if (const auto *D = resolveTypeToTagDecl(T)) {432 return {D};433 }434 return {};435 }436 if (const auto *ME = dyn_cast<MemberExpr>(E))437 return {ME->getMemberDecl()};438 if (const auto *DRE = dyn_cast<DeclRefExpr>(E))439 return {DRE->getDecl()};440 441 return {};442}443 444QualType HeuristicResolverImpl::resolveExprToType(const Expr *E) {445 // resolveExprToDecls on a CallExpr only succeeds if the return type is446 // a TagDecl, but we may want the type of a call in other cases as well.447 // (FIXME: There are probably other cases where we can do something more448 // flexible than resoveExprToDecls + resolveDeclsToType, e.g. in the case449 // of OverloadExpr we can probably accept overloads with a common type).450 if (const auto *CE = dyn_cast<CallExpr>(E)) {451 if (QualType Resolved = resolveTypeOfCallExpr(CE); !Resolved.isNull())452 return Resolved;453 454 // Don't proceed to try resolveExprToDecls(), it would just call455 // resolveTypeOfCallExpr() again.456 return E->getType();457 }458 459 // Similarly, unwrapping a unary dereference operation does not work via460 // resolveExprToDecls.461 if (const auto *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts())) {462 if (UO->getOpcode() == UnaryOperatorKind::UO_Deref) {463 if (auto Pointee = getPointeeType(resolveExprToType(UO->getSubExpr()));464 !Pointee.isNull()) {465 return Pointee;466 }467 }468 }469 470 std::vector<const NamedDecl *> Decls = resolveExprToDecls(E);471 if (!Decls.empty())472 return resolveDeclsToType(Decls, Ctx);473 474 return E->getType();475}476 477QualType HeuristicResolverImpl::resolveNestedNameSpecifierToType(478 NestedNameSpecifier NNS) {479 // The purpose of this function is to handle the dependent (Kind ==480 // Identifier) case, but we need to recurse on the prefix because481 // that may be dependent as well, so for convenience handle482 // the TypeSpec cases too.483 switch (NNS.getKind()) {484 case NestedNameSpecifier::Kind::Type: {485 const auto *T = NNS.getAsType();486 // FIXME: Should this handle the DependentTemplateSpecializationType as487 // well?488 if (const auto *DTN = dyn_cast<DependentNameType>(T))489 return resolveDeclsToType(490 resolveDependentMember(491 resolveNestedNameSpecifierToType(DTN->getQualifier()),492 DTN->getIdentifier(), TypeFilter),493 Ctx);494 return QualType(T, 0);495 }496 default:497 break;498 }499 return QualType();500}501 502bool isOrdinaryMember(const NamedDecl *ND) {503 return ND->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_Tag |504 Decl::IDNS_Member);505}506 507bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,508 DeclarationName Name) {509 Path.Decls = RD->lookup(Name).begin();510 for (DeclContext::lookup_iterator I = Path.Decls, E = I.end(); I != E; ++I)511 if (isOrdinaryMember(*I))512 return true;513 514 return false;515}516 517bool HeuristicResolverImpl::findOrdinaryMemberInDependentClasses(518 const CXXBaseSpecifier *Specifier, CXXBasePath &Path,519 DeclarationName Name) {520 TagDecl *TD = resolveTypeToTagDecl(Specifier->getType());521 if (const auto *RD = dyn_cast_if_present<CXXRecordDecl>(TD)) {522 return findOrdinaryMember(RD, Path, Name);523 }524 return false;525}526 527std::vector<const NamedDecl *> HeuristicResolverImpl::lookupDependentName(528 CXXRecordDecl *RD, DeclarationName Name,529 llvm::function_ref<bool(const NamedDecl *ND)> Filter) {530 std::vector<const NamedDecl *> Results;531 532 // Lookup in the class.533 bool AnyOrdinaryMembers = false;534 for (const NamedDecl *ND : RD->lookup(Name)) {535 if (isOrdinaryMember(ND))536 AnyOrdinaryMembers = true;537 if (Filter(ND))538 Results.push_back(ND);539 }540 if (AnyOrdinaryMembers)541 return Results;542 543 // Perform lookup into our base classes.544 CXXBasePaths Paths;545 Paths.setOrigin(RD);546 if (!RD->lookupInBases(547 [&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {548 return findOrdinaryMemberInDependentClasses(Specifier, Path, Name);549 },550 Paths, /*LookupInDependent=*/true))551 return Results;552 for (DeclContext::lookup_iterator I = Paths.front().Decls, E = I.end();553 I != E; ++I) {554 if (isOrdinaryMember(*I) && Filter(*I))555 Results.push_back(*I);556 }557 return Results;558}559 560std::vector<const NamedDecl *> HeuristicResolverImpl::resolveDependentMember(561 QualType QT, DeclarationName Name,562 llvm::function_ref<bool(const NamedDecl *ND)> Filter) {563 TagDecl *TD = resolveTypeToTagDecl(QT);564 if (!TD)565 return {};566 if (auto *ED = dyn_cast<EnumDecl>(TD)) {567 auto Result = ED->lookup(Name);568 return {Result.begin(), Result.end()};569 }570 if (auto *RD = dyn_cast<CXXRecordDecl>(TD)) {571 if (!RD->hasDefinition())572 return {};573 RD = RD->getDefinition();574 return lookupDependentName(RD, Name, [&](const NamedDecl *ND) {575 if (!Filter(ND))576 return false;577 if (const auto *MD = dyn_cast<CXXMethodDecl>(ND)) {578 return !MD->isInstance() ||579 MD->getMethodQualifiers().compatiblyIncludes(QT.getQualifiers(),580 Ctx);581 }582 return true;583 });584 }585 return {};586}587 588FunctionProtoTypeLoc589HeuristicResolverImpl::getFunctionProtoTypeLoc(const Expr *Fn) {590 TypeLoc Target;591 const Expr *NakedFn = Fn->IgnoreParenCasts();592 if (const auto *T = NakedFn->getType().getTypePtr()->getAs<TypedefType>()) {593 Target = T->getDecl()->getTypeSourceInfo()->getTypeLoc();594 } else if (const auto *DR = dyn_cast<DeclRefExpr>(NakedFn)) {595 const auto *D = DR->getDecl();596 if (const auto *const VD = dyn_cast<VarDecl>(D)) {597 Target = VD->getTypeSourceInfo()->getTypeLoc();598 }599 } else if (const auto *ME = dyn_cast<MemberExpr>(NakedFn)) {600 const auto *MD = ME->getMemberDecl();601 if (const auto *FD = dyn_cast<FieldDecl>(MD)) {602 Target = FD->getTypeSourceInfo()->getTypeLoc();603 }604 }605 606 if (!Target)607 return {};608 609 // Unwrap types that may be wrapping the function type610 while (true) {611 if (auto P = Target.getAs<PointerTypeLoc>()) {612 Target = P.getPointeeLoc();613 continue;614 }615 if (auto A = Target.getAs<AttributedTypeLoc>()) {616 Target = A.getModifiedLoc();617 continue;618 }619 if (auto P = Target.getAs<ParenTypeLoc>()) {620 Target = P.getInnerLoc();621 continue;622 }623 break;624 }625 626 if (auto F = Target.getAs<FunctionProtoTypeLoc>()) {627 // In some edge cases the AST can contain a "trivial" FunctionProtoTypeLoc628 // which has null parameters. Avoid these as they don't contain useful629 // information.630 if (!llvm::is_contained(F.getParams(), nullptr))631 return F;632 }633 634 return {};635}636 637} // namespace638 639std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(640 const CXXDependentScopeMemberExpr *ME) const {641 return HeuristicResolverImpl(Ctx).resolveMemberExpr(ME);642}643std::vector<const NamedDecl *> HeuristicResolver::resolveDeclRefExpr(644 const DependentScopeDeclRefExpr *RE) const {645 return HeuristicResolverImpl(Ctx).resolveDeclRefExpr(RE);646}647std::vector<const NamedDecl *>648HeuristicResolver::resolveCalleeOfCallExpr(const CallExpr *CE) const {649 return HeuristicResolverImpl(Ctx).resolveCalleeOfCallExpr(CE);650}651std::vector<const NamedDecl *> HeuristicResolver::resolveUsingValueDecl(652 const UnresolvedUsingValueDecl *UUVD) const {653 return HeuristicResolverImpl(Ctx).resolveUsingValueDecl(UUVD);654}655std::vector<const NamedDecl *> HeuristicResolver::resolveDependentNameType(656 const DependentNameType *DNT) const {657 return HeuristicResolverImpl(Ctx).resolveDependentNameType(DNT);658}659std::vector<const NamedDecl *>660HeuristicResolver::resolveTemplateSpecializationType(661 const TemplateSpecializationType *TST) const {662 return HeuristicResolverImpl(Ctx).resolveTemplateSpecializationType(TST);663}664QualType HeuristicResolver::resolveNestedNameSpecifierToType(665 NestedNameSpecifier NNS) const {666 return HeuristicResolverImpl(Ctx).resolveNestedNameSpecifierToType(NNS);667}668std::vector<const NamedDecl *> HeuristicResolver::lookupDependentName(669 CXXRecordDecl *RD, DeclarationName Name,670 llvm::function_ref<bool(const NamedDecl *ND)> Filter) {671 return HeuristicResolverImpl(Ctx).lookupDependentName(RD, Name, Filter);672}673const QualType HeuristicResolver::getPointeeType(QualType T) const {674 return HeuristicResolverImpl(Ctx).getPointeeType(T);675}676TagDecl *HeuristicResolver::resolveTypeToTagDecl(QualType T) const {677 return HeuristicResolverImpl(Ctx).resolveTypeToTagDecl(T);678}679QualType HeuristicResolver::simplifyType(QualType Type, const Expr *E,680 bool UnwrapPointer) {681 return HeuristicResolverImpl(Ctx).simplifyType(Type, E, UnwrapPointer);682}683QualType HeuristicResolver::resolveExprToType(const Expr *E) const {684 return HeuristicResolverImpl(Ctx).resolveExprToType(E);685}686FunctionProtoTypeLoc687HeuristicResolver::getFunctionProtoTypeLoc(const Expr *Fn) const {688 return HeuristicResolverImpl(Ctx).getFunctionProtoTypeLoc(Fn);689}690 691} // namespace clang692