27
27
#include " clang/AST/TypeLoc.h"
28
28
#include " clang/AST/TypeLocVisitor.h"
29
29
#include " clang/Basic/LangOptions.h"
30
+ #include " clang/Basic/OperatorKinds.h"
30
31
#include " clang/Basic/SourceLocation.h"
31
32
#include " llvm/ADT/STLExtras.h"
32
33
#include " llvm/ADT/SmallVector.h"
@@ -61,9 +62,14 @@ nodeToString(const ast_type_traits::DynTypedNode &N) {
61
62
// (e.g. an overloaded method in the primary template).
62
63
// This heuristic will give the desired answer in many cases, e.g.
63
64
// for a call to vector<T>::size().
64
- std::vector<const NamedDecl *>
65
- getMembersReferencedViaDependentName (const Type *T, const DeclarationName &Name,
66
- bool IsNonstaticMember) {
65
+ // The name to look up is provided in the form of a factory that takes
66
+ // an ASTContext, because an ASTContext may be needed to obtain the
67
+ // name (e.g. if it's an operator name), but the caller may not have
68
+ // access to an ASTContext.
69
+ std::vector<const NamedDecl *> getMembersReferencedViaDependentName (
70
+ const Type *T,
71
+ llvm::function_ref<DeclarationName(ASTContext &)> NameFactory,
72
+ bool IsNonstaticMember) {
67
73
if (!T)
68
74
return {};
69
75
if (auto *ICNT = T->getAs <InjectedClassNameType>()) {
@@ -80,12 +86,54 @@ getMembersReferencedViaDependentName(const Type *T, const DeclarationName &Name,
80
86
if (!RD->hasDefinition ())
81
87
return {};
82
88
RD = RD->getDefinition ();
89
+ DeclarationName Name = NameFactory (RD->getASTContext ());
83
90
return RD->lookupDependentName (Name, [=](const NamedDecl *D) {
84
91
return IsNonstaticMember ? D->isCXXInstanceMember ()
85
92
: !D->isCXXInstanceMember ();
86
93
});
87
94
}
88
95
96
+ // Given the type T of a dependent expression that appears of the LHS of a "->",
97
+ // heuristically find a corresponding pointee type in whose scope we could look
98
+ // up the name appearing on the RHS.
99
+ const Type *getPointeeType (const Type *T) {
100
+ if (!T)
101
+ return nullptr ;
102
+
103
+ if (T->isPointerType ()) {
104
+ return T->getAs <PointerType>()->getPointeeType ().getTypePtrOrNull ();
105
+ }
106
+
107
+ // Try to handle smart pointer types.
108
+
109
+ // Look up operator-> in the primary template. If we find one, it's probably a
110
+ // smart pointer type.
111
+ auto ArrowOps = getMembersReferencedViaDependentName (
112
+ T,
113
+ [](ASTContext &Ctx) {
114
+ return Ctx.DeclarationNames .getCXXOperatorName (OO_Arrow);
115
+ },
116
+ /* IsNonStaticMember=*/ true );
117
+ if (ArrowOps.empty ())
118
+ return nullptr ;
119
+
120
+ // Getting the return type of the found operator-> method decl isn't useful,
121
+ // because we discarded template arguments to perform lookup in the primary
122
+ // template scope, so the return type would just have the form U* where U is a
123
+ // template parameter type.
124
+ // Instead, just handle the common case where the smart pointer type has the
125
+ // form of SmartPtr<X, ...>, and assume X is the pointee type.
126
+ auto *TST = T->getAs <TemplateSpecializationType>();
127
+ if (!TST)
128
+ return nullptr ;
129
+ if (TST->getNumArgs () == 0 )
130
+ return nullptr ;
131
+ const TemplateArgument &FirstArg = TST->getArg (0 );
132
+ if (FirstArg.getKind () != TemplateArgument::Type)
133
+ return nullptr ;
134
+ return FirstArg.getAsType ().getTypePtrOrNull ();
135
+ }
136
+
89
137
// TargetFinder locates the entities that an AST node refers to.
90
138
//
91
139
// Typically this is (possibly) one declaration and (possibly) one type, but
@@ -251,24 +299,18 @@ struct TargetFinder {
251
299
VisitCXXDependentScopeMemberExpr (const CXXDependentScopeMemberExpr *E) {
252
300
const Type *BaseType = E->getBaseType ().getTypePtrOrNull ();
253
301
if (E->isArrow ()) {
254
- // FIXME: Handle smart pointer types by looking up operator->
255
- // in the primary template.
256
- if (!BaseType || !BaseType->isPointerType ()) {
257
- return ;
258
- }
259
- BaseType = BaseType->getAs <PointerType>()
260
- ->getPointeeType ()
261
- .getTypePtrOrNull ();
302
+ BaseType = getPointeeType (BaseType);
262
303
}
263
- for (const NamedDecl *D :
264
- getMembersReferencedViaDependentName ( BaseType, E ->getMember (),
265
- /* IsNonstaticMember=*/ true )) {
304
+ for (const NamedDecl *D : getMembersReferencedViaDependentName (
305
+ BaseType, [E](ASTContext &) { return E ->getMember (); } ,
306
+ /* IsNonstaticMember=*/ true )) {
266
307
Outer.add (D, Flags);
267
308
}
268
309
}
269
310
void VisitDependentScopeDeclRefExpr (const DependentScopeDeclRefExpr *E) {
270
311
for (const NamedDecl *D : getMembersReferencedViaDependentName (
271
- E->getQualifier ()->getAsType (), E->getDeclName (),
312
+ E->getQualifier ()->getAsType (),
313
+ [E](ASTContext &) { return E->getDeclName (); },
272
314
/* IsNonstaticMember=*/ false )) {
273
315
Outer.add (D, Flags);
274
316
}
0 commit comments