|
7 | 7 | //===----------------------------------------------------------------------===//
|
8 | 8 |
|
9 | 9 | #include "HeuristicResolver.h"
|
| 10 | +#include "AST.h" |
10 | 11 | #include "clang/AST/ASTContext.h"
|
11 | 12 | #include "clang/AST/CXXInheritance.h"
|
| 13 | +#include "clang/AST/Decl.h" |
| 14 | +#include "clang/AST/DeclCXX.h" |
12 | 15 | #include "clang/AST/DeclTemplate.h"
|
13 | 16 | #include "clang/AST/ExprCXX.h"
|
| 17 | +#include "clang/AST/RecursiveASTVisitor.h" |
14 | 18 | #include "clang/AST/Type.h"
|
15 | 19 |
|
16 | 20 | namespace clang {
|
@@ -46,6 +50,98 @@ const Type *resolveDeclsToType(const std::vector<const NamedDecl *> &Decls,
|
46 | 50 | return nullptr;
|
47 | 51 | }
|
48 | 52 |
|
| 53 | +// Visitor that helps to extract deduced type from instantiated entities. |
| 54 | +// This merely performs the source location comparison against each Decl |
| 55 | +// until it finds a Decl with the same location as the |
| 56 | +// dependent one. Its associated type will then be extracted. |
| 57 | +struct InstantiatedDeclVisitor : RecursiveASTVisitor<InstantiatedDeclVisitor> { |
| 58 | + |
| 59 | + InstantiatedDeclVisitor(NamedDecl *DependentDecl) : DependentDecl(DependentDecl) {} |
| 60 | + |
| 61 | + bool shouldVisitTemplateInstantiations() const { return true; } |
| 62 | + |
| 63 | + bool shouldVisitLambdaBody() const { return true; } |
| 64 | + |
| 65 | + bool shouldVisitImplicitCode() const { return true; } |
| 66 | + |
| 67 | + template <typename D> |
| 68 | + bool onDeclVisited(D *MaybeInstantiated) { |
| 69 | + if (MaybeInstantiated->getDeclContext()->isDependentContext()) |
| 70 | + return true; |
| 71 | + auto *Dependent = dyn_cast<D>(DependentDecl); |
| 72 | + if (!Dependent) |
| 73 | + return true; |
| 74 | + auto LHS = MaybeInstantiated->getTypeSourceInfo(), |
| 75 | + RHS = Dependent->getTypeSourceInfo(); |
| 76 | + if (!LHS || !RHS) |
| 77 | + return true; |
| 78 | + if (LHS->getTypeLoc().getSourceRange() != |
| 79 | + RHS->getTypeLoc().getSourceRange()) |
| 80 | + return true; |
| 81 | + DeducedType = MaybeInstantiated->getType(); |
| 82 | + return false; |
| 83 | + } |
| 84 | + |
| 85 | + bool VisitFieldDecl(FieldDecl *FD) { |
| 86 | + return onDeclVisited(FD); |
| 87 | + } |
| 88 | + |
| 89 | + bool VisitVarDecl(VarDecl *VD) { |
| 90 | + return onDeclVisited(VD); |
| 91 | + } |
| 92 | + |
| 93 | + NamedDecl *DependentDecl; |
| 94 | + QualType DeducedType; |
| 95 | +}; |
| 96 | + |
| 97 | +/// Attempt to resolve the dependent type from the surrounding context for which |
| 98 | +/// a single instantiation is available. |
| 99 | +const Type * |
| 100 | +resolveTypeFromInstantiatedTemplate(const CXXDependentScopeMemberExpr *Expr) { |
| 101 | + if (Expr->isImplicitAccess()) |
| 102 | + return nullptr; |
| 103 | + |
| 104 | + auto *Base = Expr->getBase(); |
| 105 | + NamedDecl *ND = nullptr; |
| 106 | + if (auto *CXXMember = dyn_cast<MemberExpr>(Base)) |
| 107 | + ND = CXXMember->getMemberDecl(); |
| 108 | + |
| 109 | + if (auto *DRExpr = dyn_cast<DeclRefExpr>(Base)) |
| 110 | + ND = DRExpr->getFoundDecl(); |
| 111 | + |
| 112 | + // FIXME: Handle CXXUnresolvedConstructExpr. This kind of type doesn't have |
| 113 | + // available Decls to be matched against. Which inhibits the current heuristic |
| 114 | + // from resolving expressions such as `T().fo^o()`, where T is a |
| 115 | + // single-instantiated template parameter. |
| 116 | + if (!ND) |
| 117 | + return nullptr; |
| 118 | + |
| 119 | + NamedDecl *Instantiation = nullptr; |
| 120 | + |
| 121 | + // Find out a single instantiation that we can start with. The enclosing |
| 122 | + // context for the current Decl might not be a templated entity (e.g. a member |
| 123 | + // function inside a class template), hence we shall walk up the decl |
| 124 | + // contexts first. |
| 125 | + for (auto *EnclosingContext = ND->getDeclContext(); EnclosingContext; |
| 126 | + EnclosingContext = EnclosingContext->getParent()) { |
| 127 | + if (auto *ND = dyn_cast<NamedDecl>(EnclosingContext)) { |
| 128 | + Instantiation = getOnlyInstantiation(ND); |
| 129 | + if (Instantiation) |
| 130 | + break; |
| 131 | + } |
| 132 | + } |
| 133 | + |
| 134 | + if (!Instantiation) |
| 135 | + return nullptr; |
| 136 | + |
| 137 | + // This will traverse down the instantiation entity, visit each Decl, and |
| 138 | + // extract the deduced type for the undetermined Decl `ND`. |
| 139 | + InstantiatedDeclVisitor Visitor(ND); |
| 140 | + Visitor.TraverseDecl(Instantiation); |
| 141 | + |
| 142 | + return Visitor.DeducedType.getTypePtrOrNull(); |
| 143 | +} |
| 144 | + |
49 | 145 | } // namespace
|
50 | 146 |
|
51 | 147 | // Helper function for HeuristicResolver::resolveDependentMember()
|
@@ -150,6 +246,11 @@ std::vector<const NamedDecl *> HeuristicResolver::resolveMemberExpr(
|
150 | 246 | if (ME->isArrow()) {
|
151 | 247 | BaseType = getPointeeType(BaseType);
|
152 | 248 | }
|
| 249 | + |
| 250 | + if (BaseType->isDependentType()) |
| 251 | + if (auto *MaybeResolved = resolveTypeFromInstantiatedTemplate(ME)) |
| 252 | + BaseType = MaybeResolved; |
| 253 | + |
153 | 254 | if (!BaseType)
|
154 | 255 | return {};
|
155 | 256 | if (const auto *BT = BaseType->getAs<BuiltinType>()) {
|
|
0 commit comments