14
14
#include " clang/Lex/PPCallbacks.h"
15
15
#include " clang/Lex/Preprocessor.h"
16
16
#include " llvm/ADT/DenseMapInfo.h"
17
- #include " llvm/Support/Debug.h"
18
- #include " llvm/Support/Format.h"
17
+ #include " llvm/ADT/PointerIntPair.h"
19
18
20
19
#define DEBUG_TYPE " clang-tidy"
21
20
@@ -93,9 +92,16 @@ class RenamerClangTidyCheckPPCallbacks : public PPCallbacks {
93
92
94
93
RenamerClangTidyCheck::RenamerClangTidyCheck (StringRef CheckName,
95
94
ClangTidyContext *Context)
96
- : ClangTidyCheck(CheckName, Context) {}
95
+ : ClangTidyCheck(CheckName, Context),
96
+ AggressiveDependentMemberLookup (
97
+ Options.getLocalOrGlobal(" AggressiveDependentMemberLookup" , false )) {}
97
98
RenamerClangTidyCheck::~RenamerClangTidyCheck () = default ;
98
99
100
+ void RenamerClangTidyCheck::storeOptions (ClangTidyOptions::OptionMap &Opts) {
101
+ Options.store (Opts, " AggressiveDependentMemberLookup" ,
102
+ AggressiveDependentMemberLookup);
103
+ }
104
+
99
105
void RenamerClangTidyCheck::registerMatchers (MatchFinder *Finder) {
100
106
Finder->addMatcher (namedDecl ().bind (" decl" ), this );
101
107
Finder->addMatcher (usingDecl ().bind (" using" ), this );
@@ -106,20 +112,12 @@ void RenamerClangTidyCheck::registerMatchers(MatchFinder *Finder) {
106
112
this );
107
113
Finder->addMatcher (typeLoc ().bind (" typeLoc" ), this );
108
114
Finder->addMatcher (nestedNameSpecifierLoc ().bind (" nestedNameLoc" ), this );
115
+ auto MemberRestrictions =
116
+ unless (forFunction (anyOf (isDefaulted (), isImplicit ())));
117
+ Finder->addMatcher (memberExpr (MemberRestrictions).bind (" memberExpr" ), this );
109
118
Finder->addMatcher (
110
- functionDecl (unless (cxxMethodDecl (isImplicit ())),
111
- hasBody (forEachDescendant (memberExpr ().bind (" memberExpr" )))),
119
+ cxxDependentScopeMemberExpr (MemberRestrictions).bind (" depMemberExpr" ),
112
120
this );
113
- Finder->addMatcher (
114
- cxxConstructorDecl (
115
- unless (isImplicit ()),
116
- forEachConstructorInitializer (
117
- allOf (isWritten (), withInitializer (forEachDescendant (
118
- memberExpr ().bind (" memberExpr" )))))),
119
- this );
120
- Finder->addMatcher (fieldDecl (hasInClassInitializer (
121
- forEachDescendant (memberExpr ().bind (" memberExpr" )))),
122
- this );
123
121
}
124
122
125
123
void RenamerClangTidyCheck::registerPPCallbacks (
@@ -129,9 +127,9 @@ void RenamerClangTidyCheck::registerPPCallbacks(
129
127
this ));
130
128
}
131
129
132
- static void addUsage ( RenamerClangTidyCheck::NamingCheckFailureMap &Failures,
133
- const RenamerClangTidyCheck::NamingCheckId &Decl,
134
- SourceRange Range, SourceManager *SourceMgr = nullptr ) {
130
+ void RenamerClangTidyCheck::addUsage (
131
+ const RenamerClangTidyCheck::NamingCheckId &Decl, SourceRange Range ,
132
+ SourceManager *SourceMgr) {
135
133
// Do nothing if the provided range is invalid.
136
134
if (Range.isInvalid ())
137
135
return ;
@@ -148,7 +146,8 @@ static void addUsage(RenamerClangTidyCheck::NamingCheckFailureMap &Failures,
148
146
149
147
// Try to insert the identifier location in the Usages map, and bail out if it
150
148
// is already in there
151
- RenamerClangTidyCheck::NamingCheckFailure &Failure = Failures[Decl];
149
+ RenamerClangTidyCheck::NamingCheckFailure &Failure =
150
+ NamingCheckFailures[Decl];
152
151
if (!Failure.RawUsageLocs .insert (FixLocation.getRawEncoding ()).second )
153
152
return ;
154
153
@@ -159,29 +158,97 @@ static void addUsage(RenamerClangTidyCheck::NamingCheckFailureMap &Failures,
159
158
Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro;
160
159
}
161
160
162
- // / Convenience method when the usage to be added is a NamedDecl
163
- static void addUsage (RenamerClangTidyCheck::NamingCheckFailureMap &Failures,
164
- const NamedDecl *Decl, SourceRange Range,
165
- SourceManager *SourceMgr = nullptr ) {
166
- return addUsage (Failures,
167
- RenamerClangTidyCheck::NamingCheckId (Decl->getLocation (),
161
+ void RenamerClangTidyCheck::addUsage (const NamedDecl *Decl, SourceRange Range,
162
+ SourceManager *SourceMgr) {
163
+
164
+ return addUsage (RenamerClangTidyCheck::NamingCheckId (Decl->getLocation (),
168
165
Decl->getNameAsString ()),
169
166
Range, SourceMgr);
170
167
}
171
168
169
+ const NamedDecl *findDecl (const RecordDecl &RecDecl, StringRef DeclName) {
170
+ for (const Decl *D : RecDecl.decls ()) {
171
+ if (const auto *ND = dyn_cast<NamedDecl>(D)) {
172
+ if (ND->getDeclName ().isIdentifier () && ND->getName ().equals (DeclName))
173
+ return ND;
174
+ }
175
+ }
176
+ return nullptr ;
177
+ }
178
+
179
+ namespace {
180
+ class NameLookup {
181
+ llvm::PointerIntPair<const NamedDecl *, 1 , bool > Data;
182
+
183
+ public:
184
+ explicit NameLookup (const NamedDecl *ND) : Data(ND, false ) {}
185
+ explicit NameLookup (llvm::NoneType) : Data(nullptr , true ) {}
186
+ explicit NameLookup (std::nullptr_t ) : Data(nullptr , false ) {}
187
+ NameLookup () : NameLookup(nullptr ) {}
188
+
189
+ bool hasMultipleResolutions () const { return Data.getInt (); }
190
+ bool hasDecl () const {
191
+ assert (!hasMultipleResolutions () && " Found multiple decls" );
192
+ return Data.getPointer () != nullptr ;
193
+ }
194
+ const NamedDecl *getDecl () const {
195
+ assert (!hasMultipleResolutions () && " Found multiple decls" );
196
+ return Data.getPointer ();
197
+ }
198
+ operator bool () const { return !hasMultipleResolutions (); }
199
+ const NamedDecl *operator *() const { return getDecl (); }
200
+ };
201
+ } // namespace
202
+
203
+ // / Returns a decl matching the \p DeclName in \p Parent or one of its base
204
+ // / classes. If \p AggressiveTemplateLookup is `true` then it will check
205
+ // / template dependent base classes as well.
206
+ // / If a matching decl is found in multiple base classes then it will return a
207
+ // / flag indicating the multiple resolutions.
208
+ NameLookup findDeclInBases (const CXXRecordDecl &Parent, StringRef DeclName,
209
+ bool AggressiveTemplateLookup) {
210
+ if (const NamedDecl *InClassRef = findDecl (Parent, DeclName))
211
+ return NameLookup (InClassRef);
212
+ const NamedDecl *Found = nullptr ;
213
+
214
+ for (CXXBaseSpecifier Base : Parent.bases ()) {
215
+ const auto *Record = Base.getType ()->getAsCXXRecordDecl ();
216
+ if (!Record && AggressiveTemplateLookup) {
217
+ if (const auto *TST =
218
+ Base.getType ()->getAs <TemplateSpecializationType>()) {
219
+ if (const auto *TD = llvm::dyn_cast_or_null<ClassTemplateDecl>(
220
+ TST->getTemplateName ().getAsTemplateDecl ()))
221
+ Record = TD->getTemplatedDecl ();
222
+ }
223
+ }
224
+ if (!Record)
225
+ continue ;
226
+ if (auto Search =
227
+ findDeclInBases (*Record, DeclName, AggressiveTemplateLookup)) {
228
+ if (*Search) {
229
+ if (Found)
230
+ return NameLookup (
231
+ llvm::None); // Multiple decls found in different base classes.
232
+ Found = *Search;
233
+ continue ;
234
+ }
235
+ } else
236
+ return NameLookup (llvm::None); // Propagate multiple resolution back up.
237
+ }
238
+ return NameLookup (Found); // If nullptr, decl wasnt found.
239
+ }
240
+
172
241
void RenamerClangTidyCheck::check (const MatchFinder::MatchResult &Result) {
173
242
if (const auto *Decl =
174
243
Result.Nodes .getNodeAs <CXXConstructorDecl>(" classRef" )) {
175
244
176
- addUsage (NamingCheckFailures, Decl->getParent (),
177
- Decl->getNameInfo ().getSourceRange ());
245
+ addUsage (Decl->getParent (), Decl->getNameInfo ().getSourceRange ());
178
246
179
247
for (const auto *Init : Decl->inits ()) {
180
248
if (!Init->isWritten () || Init->isInClassMemberInitializer ())
181
249
continue ;
182
250
if (const FieldDecl *FD = Init->getAnyMember ())
183
- addUsage (NamingCheckFailures, FD,
184
- SourceRange (Init->getMemberLocation ()));
251
+ addUsage (FD, SourceRange (Init->getMemberLocation ()));
185
252
// Note: delegating constructors and base class initializers are handled
186
253
// via the "typeLoc" matcher.
187
254
}
@@ -198,7 +265,7 @@ void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) {
198
265
// we want instead to replace the next token, that will be the identifier.
199
266
Range.setBegin (CharSourceRange::getTokenRange (Range).getEnd ());
200
267
201
- addUsage (NamingCheckFailures, Decl->getParent (), Range);
268
+ addUsage (Decl->getParent (), Range);
202
269
return ;
203
270
}
204
271
@@ -216,7 +283,7 @@ void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) {
216
283
// further TypeLocs handled below
217
284
218
285
if (Decl) {
219
- addUsage (NamingCheckFailures, Decl, Loc->getSourceRange ());
286
+ addUsage (Decl, Loc->getSourceRange ());
220
287
return ;
221
288
}
222
289
@@ -227,15 +294,15 @@ void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) {
227
294
SourceRange Range (Ref.getTemplateNameLoc (), Ref.getTemplateNameLoc ());
228
295
if (const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl)) {
229
296
if (const NamedDecl *TemplDecl = ClassDecl->getTemplatedDecl ())
230
- addUsage (NamingCheckFailures, TemplDecl, Range);
297
+ addUsage (TemplDecl, Range);
231
298
return ;
232
299
}
233
300
}
234
301
235
302
if (const auto &Ref =
236
303
Loc->getAs <DependentTemplateSpecializationTypeLoc>()) {
237
304
if (const TagDecl *Decl = Ref.getTypePtr ()->getAsTagDecl ())
238
- addUsage (NamingCheckFailures, Decl, Loc->getSourceRange ());
305
+ addUsage (Decl, Loc->getSourceRange ());
239
306
return ;
240
307
}
241
308
}
@@ -244,38 +311,60 @@ void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) {
244
311
Result.Nodes .getNodeAs <NestedNameSpecifierLoc>(" nestedNameLoc" )) {
245
312
if (const NestedNameSpecifier *Spec = Loc->getNestedNameSpecifier ()) {
246
313
if (const NamespaceDecl *Decl = Spec->getAsNamespace ()) {
247
- addUsage (NamingCheckFailures, Decl, Loc->getLocalSourceRange ());
314
+ addUsage (Decl, Loc->getLocalSourceRange ());
248
315
return ;
249
316
}
250
317
}
251
318
}
252
319
253
320
if (const auto *Decl = Result.Nodes .getNodeAs <UsingDecl>(" using" )) {
254
321
for (const auto *Shadow : Decl->shadows ())
255
- addUsage (NamingCheckFailures, Shadow->getTargetDecl (),
256
- Decl->getNameInfo ().getSourceRange ());
322
+ addUsage (Shadow->getTargetDecl (), Decl->getNameInfo ().getSourceRange ());
257
323
return ;
258
324
}
259
325
260
326
if (const auto *DeclRef = Result.Nodes .getNodeAs <DeclRefExpr>(" declRef" )) {
261
327
SourceRange Range = DeclRef->getNameInfo ().getSourceRange ();
262
- addUsage (NamingCheckFailures, DeclRef->getDecl (), Range,
263
- Result.SourceManager );
328
+ addUsage (DeclRef->getDecl (), Range, Result.SourceManager );
264
329
return ;
265
330
}
266
331
267
332
if (const auto *MemberRef =
268
333
Result.Nodes .getNodeAs <MemberExpr>(" memberExpr" )) {
269
334
SourceRange Range = MemberRef->getMemberNameInfo ().getSourceRange ();
270
- addUsage (NamingCheckFailures, MemberRef->getMemberDecl (), Range,
271
- Result.SourceManager );
335
+ addUsage (MemberRef->getMemberDecl (), Range, Result.SourceManager );
336
+ return ;
337
+ }
338
+
339
+ if (const auto *DepMemberRef =
340
+ Result.Nodes .getNodeAs <CXXDependentScopeMemberExpr>(
341
+ " depMemberExpr" )) {
342
+ QualType BaseType = DepMemberRef->isArrow ()
343
+ ? DepMemberRef->getBaseType ()->getPointeeType ()
344
+ : DepMemberRef->getBaseType ();
345
+ if (BaseType.isNull ())
346
+ return ;
347
+ const CXXRecordDecl *Base = BaseType.getTypePtr ()->getAsCXXRecordDecl ();
348
+ if (!Base)
349
+ return ;
350
+ DeclarationName DeclName = DepMemberRef->getMemberNameInfo ().getName ();
351
+ if (!DeclName.isIdentifier ())
352
+ return ;
353
+ StringRef DependentName = DeclName.getAsIdentifierInfo ()->getName ();
354
+
355
+ if (NameLookup Resolved = findDeclInBases (
356
+ *Base, DependentName, AggressiveDependentMemberLookup)) {
357
+ if (*Resolved)
358
+ addUsage (*Resolved, DepMemberRef->getMemberNameInfo ().getSourceRange (),
359
+ Result.SourceManager );
360
+ }
272
361
return ;
273
362
}
274
363
275
364
if (const auto *Decl = Result.Nodes .getNodeAs <NamedDecl>(" decl" )) {
276
365
// Fix using namespace declarations.
277
366
if (const auto *UsingNS = dyn_cast<UsingDirectiveDecl>(Decl))
278
- addUsage (NamingCheckFailures, UsingNS->getNominatedNamespaceAsWritten (),
367
+ addUsage (UsingNS->getNominatedNamespaceAsWritten (),
279
368
UsingNS->getIdentLocation ());
280
369
281
370
if (!Decl->getIdentifier () || Decl->getName ().empty () || Decl->isImplicit ())
@@ -285,22 +374,19 @@ void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) {
285
374
if (const auto *Value = Result.Nodes .getNodeAs <ValueDecl>(" decl" )) {
286
375
if (const Type *TypePtr = Value->getType ().getTypePtrOrNull ()) {
287
376
if (const auto *Typedef = TypePtr->getAs <TypedefType>())
288
- addUsage (NamingCheckFailures, Typedef->getDecl (),
289
- Value->getSourceRange ());
377
+ addUsage (Typedef->getDecl (), Value->getSourceRange ());
290
378
}
291
379
}
292
380
293
381
// Fix type aliases in function declarations.
294
382
if (const auto *Value = Result.Nodes .getNodeAs <FunctionDecl>(" decl" )) {
295
383
if (const auto *Typedef =
296
384
Value->getReturnType ().getTypePtr ()->getAs <TypedefType>())
297
- addUsage (NamingCheckFailures, Typedef->getDecl (),
298
- Value->getSourceRange ());
385
+ addUsage (Typedef->getDecl (), Value->getSourceRange ());
299
386
for (const ParmVarDecl *Param : Value->parameters ()) {
300
387
if (const TypedefType *Typedef =
301
388
Param->getType ().getTypePtr ()->getAs <TypedefType>())
302
- addUsage (NamingCheckFailures, Typedef->getDecl (),
303
- Value->getSourceRange ());
389
+ addUsage (Typedef->getDecl (), Value->getSourceRange ());
304
390
}
305
391
}
306
392
@@ -331,7 +417,7 @@ void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) {
331
417
}
332
418
333
419
Failure.Info = std::move (Info);
334
- addUsage (NamingCheckFailures, Decl, Range);
420
+ addUsage (Decl, Range);
335
421
}
336
422
}
337
423
@@ -349,7 +435,7 @@ void RenamerClangTidyCheck::checkMacro(SourceManager &SourceMgr,
349
435
SourceRange Range (MacroNameTok.getLocation (), MacroNameTok.getEndLoc ());
350
436
351
437
Failure.Info = std::move (Info);
352
- addUsage (NamingCheckFailures, ID, Range);
438
+ addUsage (ID, Range);
353
439
}
354
440
355
441
void RenamerClangTidyCheck::expandMacro (const Token &MacroNameTok,
@@ -362,7 +448,7 @@ void RenamerClangTidyCheck::expandMacro(const Token &MacroNameTok,
362
448
return ;
363
449
364
450
SourceRange Range (MacroNameTok.getLocation (), MacroNameTok.getEndLoc ());
365
- addUsage (NamingCheckFailures, ID, Range);
451
+ addUsage (ID, Range);
366
452
}
367
453
368
454
static std::string
0 commit comments