@@ -61,6 +61,7 @@ struct DenseMapInfo<clang::tidy::RenamerClangTidyCheck::NamingCheckId> {
61
61
namespace clang ::tidy {
62
62
63
63
namespace {
64
+
64
65
class NameLookup {
65
66
llvm::PointerIntPair<const NamedDecl *, 1 , bool > Data;
66
67
@@ -78,6 +79,7 @@ class NameLookup {
78
79
operator bool () const { return !hasMultipleResolutions (); }
79
80
const NamedDecl *operator *() const { return getDecl (); }
80
81
};
82
+
81
83
} // namespace
82
84
83
85
static const NamedDecl *findDecl (const RecordDecl &RecDecl,
@@ -91,6 +93,44 @@ static const NamedDecl *findDecl(const RecordDecl &RecDecl,
91
93
return nullptr ;
92
94
}
93
95
96
+ // / Returns the function that \p Method is overridding. If There are none or
97
+ // / multiple overrides it returns nullptr. If the overridden function itself is
98
+ // / overridding then it will recurse up to find the first decl of the function.
99
+ static const CXXMethodDecl *getOverrideMethod (const CXXMethodDecl *Method) {
100
+ if (Method->size_overridden_methods () != 1 )
101
+ return nullptr ;
102
+
103
+ while (true ) {
104
+ Method = *Method->begin_overridden_methods ();
105
+ assert (Method && " Overridden method shouldn't be null" );
106
+ unsigned NumOverrides = Method->size_overridden_methods ();
107
+ if (NumOverrides == 0 )
108
+ return Method;
109
+ if (NumOverrides > 1 )
110
+ return nullptr ;
111
+ }
112
+ }
113
+
114
+ static bool hasNoName (const NamedDecl *Decl) {
115
+ return !Decl->getIdentifier () || Decl->getName ().empty ();
116
+ }
117
+
118
+ static const NamedDecl *getFailureForNamedDecl (const NamedDecl *ND) {
119
+ const auto *Canonical = cast<NamedDecl>(ND->getCanonicalDecl ());
120
+ if (Canonical != ND)
121
+ return Canonical;
122
+
123
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(ND)) {
124
+ if (const CXXMethodDecl *Overridden = getOverrideMethod (Method))
125
+ Canonical = cast<NamedDecl>(Overridden->getCanonicalDecl ());
126
+
127
+ if (Canonical != ND)
128
+ return Canonical;
129
+ }
130
+
131
+ return ND;
132
+ }
133
+
94
134
// / Returns a decl matching the \p DeclName in \p Parent or one of its base
95
135
// / classes. If \p AggressiveTemplateLookup is `true` then it will check
96
136
// / template dependent base classes as well.
@@ -132,24 +172,6 @@ static NameLookup findDeclInBases(const CXXRecordDecl &Parent,
132
172
return NameLookup (Found); // If nullptr, decl wasn't found.
133
173
}
134
174
135
- // / Returns the function that \p Method is overridding. If There are none or
136
- // / multiple overrides it returns nullptr. If the overridden function itself is
137
- // / overridding then it will recurse up to find the first decl of the function.
138
- static const CXXMethodDecl *getOverrideMethod (const CXXMethodDecl *Method) {
139
- if (Method->size_overridden_methods () != 1 )
140
- return nullptr ;
141
-
142
- while (true ) {
143
- Method = *Method->begin_overridden_methods ();
144
- assert (Method && " Overridden method shouldn't be null" );
145
- unsigned NumOverrides = Method->size_overridden_methods ();
146
- if (NumOverrides == 0 )
147
- return Method;
148
- if (NumOverrides > 1 )
149
- return nullptr ;
150
- }
151
- }
152
-
153
175
namespace {
154
176
155
177
// / Callback supplies macros to RenamerClangTidyCheck::checkMacro
@@ -192,10 +214,6 @@ class RenamerClangTidyVisitor
192
214
: Check(Check), SM(SM),
193
215
AggressiveDependentMemberLookup (AggressiveDependentMemberLookup) {}
194
216
195
- static bool hasNoName (const NamedDecl *Decl) {
196
- return !Decl->getIdentifier () || Decl->getName ().empty ();
197
- }
198
-
199
217
bool shouldVisitTemplateInstantiations () const { return true ; }
200
218
201
219
bool shouldVisitImplicitCode () const { return false ; }
@@ -246,29 +264,10 @@ class RenamerClangTidyVisitor
246
264
}
247
265
248
266
bool VisitNamedDecl (NamedDecl *Decl) {
249
- if (hasNoName (Decl))
250
- return true ;
251
-
252
- const auto *Canonical = cast<NamedDecl>(Decl->getCanonicalDecl ());
253
- if (Canonical != Decl) {
254
- Check->addUsage (Canonical, Decl->getLocation (), SM);
255
- return true ;
256
- }
257
-
258
- // Fix overridden methods
259
- if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
260
- if (const CXXMethodDecl *Overridden = getOverrideMethod (Method)) {
261
- Check->addUsage (Overridden, Method->getLocation (), SM);
262
- return true ; // Don't try to add the actual decl as a Failure.
263
- }
264
- }
265
-
266
- // Ignore ClassTemplateSpecializationDecl which are creating duplicate
267
- // replacements with CXXRecordDecl.
268
- if (isa<ClassTemplateSpecializationDecl>(Decl))
269
- return true ;
270
-
271
- Check->checkNamedDecl (Decl, SM);
267
+ SourceRange UsageRange =
268
+ DeclarationNameInfo (Decl->getDeclName (), Decl->getLocation ())
269
+ .getSourceRange ();
270
+ Check->addUsage (Decl, UsageRange, SM);
272
271
return true ;
273
272
}
274
273
@@ -413,82 +412,97 @@ void RenamerClangTidyCheck::registerPPCallbacks(
413
412
std::make_unique<RenamerClangTidyCheckPPCallbacks>(SM, this ));
414
413
}
415
414
416
- void RenamerClangTidyCheck::addUsage (
417
- const RenamerClangTidyCheck::NamingCheckId &Decl, SourceRange Range,
418
- const SourceManager &SourceMgr) {
415
+ std::pair<RenamerClangTidyCheck::NamingCheckFailureMap::iterator, bool >
416
+ RenamerClangTidyCheck::addUsage (
417
+ const RenamerClangTidyCheck::NamingCheckId &FailureId,
418
+ SourceRange UsageRange, const SourceManager &SourceMgr) {
419
419
// Do nothing if the provided range is invalid.
420
- if (Range .isInvalid ())
421
- return ;
420
+ if (UsageRange .isInvalid ())
421
+ return {NamingCheckFailures. end (), false } ;
422
422
423
- // If we have a source manager, use it to convert to the spelling location for
424
- // performing the fix. This is necessary because macros can map the same
425
- // spelling location to different source locations, and we only want to fix
426
- // the token once, before it is expanded by the macro.
427
- SourceLocation FixLocation = Range.getBegin ();
423
+ // Get the spelling location for performing the fix. This is necessary because
424
+ // macros can map the same spelling location to different source locations,
425
+ // and we only want to fix the token once, before it is expanded by the macro.
426
+ SourceLocation FixLocation = UsageRange.getBegin ();
428
427
FixLocation = SourceMgr.getSpellingLoc (FixLocation);
429
428
if (FixLocation.isInvalid ())
430
- return ;
429
+ return {NamingCheckFailures.end (), false };
430
+
431
+ auto EmplaceResult = NamingCheckFailures.try_emplace (FailureId);
432
+ NamingCheckFailure &Failure = EmplaceResult.first ->second ;
431
433
432
434
// Try to insert the identifier location in the Usages map, and bail out if it
433
435
// is already in there
434
- RenamerClangTidyCheck::NamingCheckFailure &Failure =
435
- NamingCheckFailures[Decl];
436
436
if (!Failure.RawUsageLocs .insert (FixLocation).second )
437
- return ;
437
+ return EmplaceResult ;
438
438
439
- if (! Failure.shouldFix () )
440
- return ;
439
+ if (Failure.FixStatus != RenamerClangTidyCheck::ShouldFixStatus::ShouldFix )
440
+ return EmplaceResult ;
441
441
442
442
if (SourceMgr.isWrittenInScratchSpace (FixLocation))
443
443
Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro;
444
444
445
- if (!utils::rangeCanBeFixed (Range , &SourceMgr))
445
+ if (!utils::rangeCanBeFixed (UsageRange , &SourceMgr))
446
446
Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro;
447
+
448
+ return EmplaceResult;
447
449
}
448
450
449
- void RenamerClangTidyCheck::addUsage (const NamedDecl *Decl, SourceRange Range,
451
+ void RenamerClangTidyCheck::addUsage (const NamedDecl *Decl,
452
+ SourceRange UsageRange,
450
453
const SourceManager &SourceMgr) {
451
- // Don't keep track for non-identifier names.
452
- auto *II = Decl->getIdentifier ();
453
- if (!II)
454
+ if (hasNoName (Decl))
455
+ return ;
456
+
457
+ // Ignore ClassTemplateSpecializationDecl which are creating duplicate
458
+ // replacements with CXXRecordDecl.
459
+ if (isa<ClassTemplateSpecializationDecl>(Decl))
454
460
return ;
455
- if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
456
- if (const CXXMethodDecl *Overridden = getOverrideMethod (Method))
457
- Decl = Overridden;
458
- }
459
- Decl = cast<NamedDecl>(Decl->getCanonicalDecl ());
460
- return addUsage (
461
- RenamerClangTidyCheck::NamingCheckId (Decl->getLocation (), II->getName ()),
462
- Range, SourceMgr);
463
- }
464
461
465
- void RenamerClangTidyCheck::checkNamedDecl (const NamedDecl *Decl,
466
- const SourceManager &SourceMgr) {
467
- std::optional<FailureInfo> MaybeFailure = getDeclFailureInfo (Decl, SourceMgr);
462
+ // We don't want to create a failure for every NamedDecl we find. Ideally
463
+ // there is just one NamedDecl in every group of "related" NamedDecls that
464
+ // becomes the failure. This NamedDecl and all of its related NamedDecls
465
+ // become usages. E.g. Since NamedDecls are Redeclarable, only the canonical
466
+ // NamedDecl becomes the failure and all redeclarations become usages.
467
+ const NamedDecl *FailureDecl = getFailureForNamedDecl (Decl);
468
+
469
+ std::optional<FailureInfo> MaybeFailure =
470
+ getDeclFailureInfo (FailureDecl, SourceMgr);
468
471
if (!MaybeFailure)
469
472
return ;
470
473
471
- FailureInfo &Info = *MaybeFailure;
472
- NamingCheckFailure &Failure =
473
- NamingCheckFailures[NamingCheckId (Decl->getLocation (), Decl->getName ())];
474
- SourceRange Range =
475
- DeclarationNameInfo (Decl->getDeclName (), Decl->getLocation ())
476
- .getSourceRange ();
477
-
478
- const IdentifierTable &Idents = Decl->getASTContext ().Idents ;
479
- auto CheckNewIdentifier = Idents.find (Info.Fixup );
474
+ NamingCheckId FailureId (FailureDecl->getLocation (), FailureDecl->getName ());
475
+
476
+ auto [FailureIter, NewFailure] = addUsage (FailureId, UsageRange, SourceMgr);
477
+
478
+ if (FailureIter == NamingCheckFailures.end ()) {
479
+ // Nothing to do if the usage wasn't accepted.
480
+ return ;
481
+ }
482
+ if (!NewFailure) {
483
+ // FailureInfo has already been provided.
484
+ return ;
485
+ }
486
+
487
+ // Update the stored failure with info regarding the FailureDecl.
488
+ NamingCheckFailure &Failure = FailureIter->second ;
489
+ Failure.Info = std::move (*MaybeFailure);
490
+
491
+ // Don't overwritte the failure status if it was already set.
492
+ if (!Failure.shouldFix ()) {
493
+ return ;
494
+ }
495
+ const IdentifierTable &Idents = FailureDecl->getASTContext ().Idents ;
496
+ auto CheckNewIdentifier = Idents.find (Failure.Info .Fixup );
480
497
if (CheckNewIdentifier != Idents.end ()) {
481
498
const IdentifierInfo *Ident = CheckNewIdentifier->second ;
482
499
if (Ident->isKeyword (getLangOpts ()))
483
500
Failure.FixStatus = ShouldFixStatus::ConflictsWithKeyword;
484
501
else if (Ident->hasMacroDefinition ())
485
502
Failure.FixStatus = ShouldFixStatus::ConflictsWithMacroDefinition;
486
- } else if (!isValidAsciiIdentifier (Info.Fixup )) {
503
+ } else if (!isValidAsciiIdentifier (Failure. Info .Fixup )) {
487
504
Failure.FixStatus = ShouldFixStatus::FixInvalidIdentifier;
488
505
}
489
-
490
- Failure.Info = std::move (Info);
491
- addUsage (Decl, Range, SourceMgr);
492
506
}
493
507
494
508
void RenamerClangTidyCheck::check (const MatchFinder::MatchResult &Result) {
0 commit comments