@@ -61,6 +61,44 @@ struct DenseMapInfo<clang::tidy::RenamerClangTidyCheck::NamingCheckId> {
61
61
namespace clang ::tidy {
62
62
63
63
namespace {
64
+ // / Returns the function that \p Method is overridding. If There are none or
65
+ // / multiple overrides it returns nullptr. If the overridden function itself is
66
+ // / overridding then it will recurse up to find the first decl of the function.
67
+ const CXXMethodDecl *getOverrideMethod (const CXXMethodDecl *Method) {
68
+ if (Method->size_overridden_methods () != 1 )
69
+ return nullptr ;
70
+
71
+ while (true ) {
72
+ Method = *Method->begin_overridden_methods ();
73
+ assert (Method && " Overridden method shouldn't be null" );
74
+ unsigned NumOverrides = Method->size_overridden_methods ();
75
+ if (NumOverrides == 0 )
76
+ return Method;
77
+ if (NumOverrides > 1 )
78
+ return nullptr ;
79
+ }
80
+ }
81
+
82
+ bool hasNoName (const NamedDecl *Decl) {
83
+ return !Decl->getIdentifier () || Decl->getName ().empty ();
84
+ }
85
+
86
+ const NamedDecl *getFailureForNamedDecl (const NamedDecl *ND) {
87
+ const auto *Canonical = cast<NamedDecl>(ND->getCanonicalDecl ());
88
+ if (Canonical != ND)
89
+ return Canonical;
90
+
91
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(ND)) {
92
+ if (const CXXMethodDecl *Overridden = getOverrideMethod (Method))
93
+ Canonical = cast<NamedDecl>(Overridden->getCanonicalDecl ());
94
+
95
+ if (Canonical != ND)
96
+ return Canonical;
97
+ }
98
+
99
+ return ND;
100
+ }
101
+
64
102
class NameLookup {
65
103
llvm::PointerIntPair<const NamedDecl *, 1 , bool > Data;
66
104
@@ -132,24 +170,6 @@ static NameLookup findDeclInBases(const CXXRecordDecl &Parent,
132
170
return NameLookup (Found); // If nullptr, decl wasn't found.
133
171
}
134
172
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
173
namespace {
154
174
155
175
// / Callback supplies macros to RenamerClangTidyCheck::checkMacro
@@ -192,10 +212,6 @@ class RenamerClangTidyVisitor
192
212
: Check(Check), SM(SM),
193
213
AggressiveDependentMemberLookup (AggressiveDependentMemberLookup) {}
194
214
195
- static bool hasNoName (const NamedDecl *Decl) {
196
- return !Decl->getIdentifier () || Decl->getName ().empty ();
197
- }
198
-
199
215
bool shouldVisitTemplateInstantiations () const { return true ; }
200
216
201
217
bool shouldVisitImplicitCode () const { return false ; }
@@ -246,29 +262,10 @@ class RenamerClangTidyVisitor
246
262
}
247
263
248
264
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);
265
+ SourceRange UsageRange =
266
+ DeclarationNameInfo (Decl->getDeclName (), Decl->getLocation ())
267
+ .getSourceRange ();
268
+ Check->addUsage (Decl, UsageRange, SM);
272
269
return true ;
273
270
}
274
271
@@ -413,82 +410,97 @@ void RenamerClangTidyCheck::registerPPCallbacks(
413
410
std::make_unique<RenamerClangTidyCheckPPCallbacks>(SM, this ));
414
411
}
415
412
416
- void RenamerClangTidyCheck::addUsage (
417
- const RenamerClangTidyCheck::NamingCheckId &Decl, SourceRange Range,
418
- const SourceManager &SourceMgr) {
413
+ std::pair<RenamerClangTidyCheck::NamingCheckFailureMap::iterator, bool >
414
+ RenamerClangTidyCheck::addUsage (
415
+ const RenamerClangTidyCheck::NamingCheckId &FailureId,
416
+ SourceRange UsageRange, const SourceManager &SourceMgr) {
419
417
// Do nothing if the provided range is invalid.
420
- if (Range .isInvalid ())
421
- return ;
418
+ if (UsageRange .isInvalid ())
419
+ return {NamingCheckFailures. end (), false } ;
422
420
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 ();
421
+ // Get the spelling location for performing the fix. This is necessary because
422
+ // macros can map the same spelling location to different source locations,
423
+ // and we only want to fix the token once, before it is expanded by the macro.
424
+ SourceLocation FixLocation = UsageRange.getBegin ();
428
425
FixLocation = SourceMgr.getSpellingLoc (FixLocation);
429
426
if (FixLocation.isInvalid ())
430
- return ;
427
+ return {NamingCheckFailures.end (), false };
428
+
429
+ auto EmplaceResult = NamingCheckFailures.try_emplace (FailureId);
430
+ NamingCheckFailure &Failure = EmplaceResult.first ->second ;
431
431
432
432
// Try to insert the identifier location in the Usages map, and bail out if it
433
433
// is already in there
434
- RenamerClangTidyCheck::NamingCheckFailure &Failure =
435
- NamingCheckFailures[Decl];
436
434
if (!Failure.RawUsageLocs .insert (FixLocation).second )
437
- return ;
435
+ return EmplaceResult ;
438
436
439
- if (! Failure.shouldFix () )
440
- return ;
437
+ if (Failure.FixStatus != RenamerClangTidyCheck::ShouldFixStatus::ShouldFix )
438
+ return EmplaceResult ;
441
439
442
440
if (SourceMgr.isWrittenInScratchSpace (FixLocation))
443
441
Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro;
444
442
445
- if (!utils::rangeCanBeFixed (Range , &SourceMgr))
443
+ if (!utils::rangeCanBeFixed (UsageRange , &SourceMgr))
446
444
Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro;
445
+
446
+ return EmplaceResult;
447
447
}
448
448
449
- void RenamerClangTidyCheck::addUsage (const NamedDecl *Decl, SourceRange Range,
449
+ void RenamerClangTidyCheck::addUsage (const NamedDecl *Decl,
450
+ SourceRange UsageRange,
450
451
const SourceManager &SourceMgr) {
451
- // Don't keep track for non-identifier names.
452
- auto *II = Decl->getIdentifier ();
453
- if (!II)
452
+ if (hasNoName (Decl))
453
+ return ;
454
+
455
+ // Ignore ClassTemplateSpecializationDecl which are creating duplicate
456
+ // replacements with CXXRecordDecl.
457
+ if (isa<ClassTemplateSpecializationDecl>(Decl))
454
458
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
459
465
- void RenamerClangTidyCheck::checkNamedDecl (const NamedDecl *Decl,
466
- const SourceManager &SourceMgr) {
467
- std::optional<FailureInfo> MaybeFailure = getDeclFailureInfo (Decl, SourceMgr);
460
+ // We don't want to create a failure for every NamedDecl we find. Ideally
461
+ // there is just one NamedDecl in every group of "related" NamedDecls that
462
+ // becomes the failure. This NamedDecl and all of its related NamedDecls
463
+ // become usages. E.g. Since NamedDecls are Redeclarable, only the canonical
464
+ // NamedDecl becomes the failure and all redeclarations become usages.
465
+ const NamedDecl *FailureDecl = getFailureForNamedDecl (Decl);
466
+
467
+ std::optional<FailureInfo> MaybeFailure =
468
+ getDeclFailureInfo (FailureDecl, SourceMgr);
468
469
if (!MaybeFailure)
469
470
return ;
470
471
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 );
472
+ NamingCheckId FailureId (FailureDecl->getLocation (), FailureDecl->getName ());
473
+
474
+ auto [FailureIter, NewFailure] = addUsage (FailureId, UsageRange, SourceMgr);
475
+
476
+ if (FailureIter == NamingCheckFailures.end ()) {
477
+ // Nothing to do if the usage wasn't accepted.
478
+ return ;
479
+ }
480
+ if (!NewFailure) {
481
+ // FailureInfo has already been provided.
482
+ return ;
483
+ }
484
+
485
+ // Update the stored failure with info regarding the FailureDecl.
486
+ NamingCheckFailure &Failure = FailureIter->second ;
487
+ Failure.Info = std::move (*MaybeFailure);
488
+
489
+ // Don't overwritte the failure status if it was already set.
490
+ if (!Failure.shouldFix ()) {
491
+ return ;
492
+ }
493
+ const IdentifierTable &Idents = FailureDecl->getASTContext ().Idents ;
494
+ auto CheckNewIdentifier = Idents.find (Failure.Info .Fixup );
480
495
if (CheckNewIdentifier != Idents.end ()) {
481
496
const IdentifierInfo *Ident = CheckNewIdentifier->second ;
482
497
if (Ident->isKeyword (getLangOpts ()))
483
498
Failure.FixStatus = ShouldFixStatus::ConflictsWithKeyword;
484
499
else if (Ident->hasMacroDefinition ())
485
500
Failure.FixStatus = ShouldFixStatus::ConflictsWithMacroDefinition;
486
- } else if (!isValidAsciiIdentifier (Info.Fixup )) {
501
+ } else if (!isValidAsciiIdentifier (Failure. Info .Fixup )) {
487
502
Failure.FixStatus = ShouldFixStatus::FixInvalidIdentifier;
488
503
}
489
-
490
- Failure.Info = std::move (Info);
491
- addUsage (Decl, Range, SourceMgr);
492
504
}
493
505
494
506
void RenamerClangTidyCheck::check (const MatchFinder::MatchResult &Result) {
0 commit comments