1 //===--- RenamerClangTidyCheck.cpp - clang-tidy ---------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "RenamerClangTidyCheck.h"
10 #include "ASTUtils.h"
11 #include "clang/AST/CXXInheritance.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Frontend/CompilerInstance.h"
14 #include "clang/Lex/PPCallbacks.h"
15 #include "clang/Lex/Preprocessor.h"
16 #include "llvm/ADT/DenseMapInfo.h"
17 #include "llvm/ADT/PointerIntPair.h"
18 
19 #define DEBUG_TYPE "clang-tidy"
20 
21 using namespace clang::ast_matchers;
22 
23 namespace llvm {
24 
25 /// Specialisation of DenseMapInfo to allow NamingCheckId objects in DenseMaps
26 template <>
27 struct DenseMapInfo<clang::tidy::RenamerClangTidyCheck::NamingCheckId> {
28   using NamingCheckId = clang::tidy::RenamerClangTidyCheck::NamingCheckId;
29 
getEmptyKeyllvm::DenseMapInfo30   static inline NamingCheckId getEmptyKey() {
31     return NamingCheckId(DenseMapInfo<clang::SourceLocation>::getEmptyKey(),
32                          "EMPTY");
33   }
34 
getTombstoneKeyllvm::DenseMapInfo35   static inline NamingCheckId getTombstoneKey() {
36     return NamingCheckId(DenseMapInfo<clang::SourceLocation>::getTombstoneKey(),
37                          "TOMBSTONE");
38   }
39 
getHashValuellvm::DenseMapInfo40   static unsigned getHashValue(NamingCheckId Val) {
41     assert(Val != getEmptyKey() && "Cannot hash the empty key!");
42     assert(Val != getTombstoneKey() && "Cannot hash the tombstone key!");
43 
44     std::hash<NamingCheckId::second_type> SecondHash;
45     return DenseMapInfo<clang::SourceLocation>::getHashValue(Val.first) +
46            SecondHash(Val.second);
47   }
48 
isEqualllvm::DenseMapInfo49   static bool isEqual(const NamingCheckId &LHS, const NamingCheckId &RHS) {
50     if (RHS == getEmptyKey())
51       return LHS == getEmptyKey();
52     if (RHS == getTombstoneKey())
53       return LHS == getTombstoneKey();
54     return LHS == RHS;
55   }
56 };
57 
58 } // namespace llvm
59 
60 namespace clang {
61 namespace tidy {
62 
63 namespace {
64 
65 /// Callback supplies macros to RenamerClangTidyCheck::checkMacro
66 class RenamerClangTidyCheckPPCallbacks : public PPCallbacks {
67 public:
RenamerClangTidyCheckPPCallbacks(Preprocessor * PP,RenamerClangTidyCheck * Check)68   RenamerClangTidyCheckPPCallbacks(Preprocessor *PP,
69                                    RenamerClangTidyCheck *Check)
70       : PP(PP), Check(Check) {}
71 
72   /// MacroDefined calls checkMacro for macros in the main file
MacroDefined(const Token & MacroNameTok,const MacroDirective * MD)73   void MacroDefined(const Token &MacroNameTok,
74                     const MacroDirective *MD) override {
75     if (MD->getMacroInfo()->isBuiltinMacro())
76       return;
77     if (PP->getSourceManager().isWrittenInBuiltinFile(
78             MacroNameTok.getLocation()))
79       return;
80     if (PP->getSourceManager().isWrittenInCommandLineFile(
81             MacroNameTok.getLocation()))
82       return;
83     Check->checkMacro(PP->getSourceManager(), MacroNameTok, MD->getMacroInfo());
84   }
85 
86   /// MacroExpands calls expandMacro for macros in the main file
MacroExpands(const Token & MacroNameTok,const MacroDefinition & MD,SourceRange,const MacroArgs *)87   void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
88                     SourceRange /*Range*/,
89                     const MacroArgs * /*Args*/) override {
90     Check->expandMacro(MacroNameTok, MD.getMacroInfo());
91   }
92 
93 private:
94   Preprocessor *PP;
95   RenamerClangTidyCheck *Check;
96 };
97 
98 } // namespace
99 
RenamerClangTidyCheck(StringRef CheckName,ClangTidyContext * Context)100 RenamerClangTidyCheck::RenamerClangTidyCheck(StringRef CheckName,
101                                              ClangTidyContext *Context)
102     : ClangTidyCheck(CheckName, Context),
103       AggressiveDependentMemberLookup(
104           Options.getLocalOrGlobal("AggressiveDependentMemberLookup", false)) {}
105 RenamerClangTidyCheck::~RenamerClangTidyCheck() = default;
106 
storeOptions(ClangTidyOptions::OptionMap & Opts)107 void RenamerClangTidyCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
108   Options.store(Opts, "AggressiveDependentMemberLookup",
109                 AggressiveDependentMemberLookup);
110 }
111 
registerMatchers(MatchFinder * Finder)112 void RenamerClangTidyCheck::registerMatchers(MatchFinder *Finder) {
113   Finder->addMatcher(namedDecl().bind("decl"), this);
114   Finder->addMatcher(usingDecl().bind("using"), this);
115   Finder->addMatcher(declRefExpr().bind("declRef"), this);
116   Finder->addMatcher(cxxConstructorDecl(unless(isImplicit())).bind("classRef"),
117                      this);
118   Finder->addMatcher(cxxDestructorDecl(unless(isImplicit())).bind("classRef"),
119                      this);
120   Finder->addMatcher(typeLoc().bind("typeLoc"), this);
121   Finder->addMatcher(nestedNameSpecifierLoc().bind("nestedNameLoc"), this);
122   auto MemberRestrictions =
123       unless(forFunction(anyOf(isDefaulted(), isImplicit())));
124   Finder->addMatcher(memberExpr(MemberRestrictions).bind("memberExpr"), this);
125   Finder->addMatcher(
126       cxxDependentScopeMemberExpr(MemberRestrictions).bind("depMemberExpr"),
127       this);
128 }
129 
registerPPCallbacks(const SourceManager & SM,Preprocessor * PP,Preprocessor * ModuleExpanderPP)130 void RenamerClangTidyCheck::registerPPCallbacks(
131     const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
132   ModuleExpanderPP->addPPCallbacks(
133       std::make_unique<RenamerClangTidyCheckPPCallbacks>(ModuleExpanderPP,
134                                                          this));
135 }
136 
137 /// Returns the function that \p Method is overridding. If There are none or
138 /// multiple overrides it returns nullptr. If the overridden function itself is
139 /// overridding then it will recurse up to find the first decl of the function.
getOverrideMethod(const CXXMethodDecl * Method)140 static const CXXMethodDecl *getOverrideMethod(const CXXMethodDecl *Method) {
141   if (Method->size_overridden_methods() != 1)
142     return nullptr;
143   while (true) {
144     Method = *Method->begin_overridden_methods();
145     assert(Method && "Overridden method shouldn't be null");
146     unsigned NumOverrides = Method->size_overridden_methods();
147     if (NumOverrides == 0)
148       return Method;
149     if (NumOverrides > 1)
150       return nullptr;
151   }
152 }
153 
addUsage(const RenamerClangTidyCheck::NamingCheckId & Decl,SourceRange Range,SourceManager * SourceMgr)154 void RenamerClangTidyCheck::addUsage(
155     const RenamerClangTidyCheck::NamingCheckId &Decl, SourceRange Range,
156     SourceManager *SourceMgr) {
157   // Do nothing if the provided range is invalid.
158   if (Range.isInvalid())
159     return;
160 
161   // If we have a source manager, use it to convert to the spelling location for
162   // performing the fix. This is necessary because macros can map the same
163   // spelling location to different source locations, and we only want to fix
164   // the token once, before it is expanded by the macro.
165   SourceLocation FixLocation = Range.getBegin();
166   if (SourceMgr)
167     FixLocation = SourceMgr->getSpellingLoc(FixLocation);
168   if (FixLocation.isInvalid())
169     return;
170 
171   // Try to insert the identifier location in the Usages map, and bail out if it
172   // is already in there
173   RenamerClangTidyCheck::NamingCheckFailure &Failure =
174       NamingCheckFailures[Decl];
175   if (!Failure.RawUsageLocs.insert(FixLocation).second)
176     return;
177 
178   if (!Failure.ShouldFix())
179     return;
180 
181   if (SourceMgr && SourceMgr->isWrittenInScratchSpace(FixLocation))
182     Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro;
183 
184   if (!utils::rangeCanBeFixed(Range, SourceMgr))
185     Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro;
186 }
187 
addUsage(const NamedDecl * Decl,SourceRange Range,SourceManager * SourceMgr)188 void RenamerClangTidyCheck::addUsage(const NamedDecl *Decl, SourceRange Range,
189                                      SourceManager *SourceMgr) {
190   if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
191     if (const CXXMethodDecl *Overridden = getOverrideMethod(Method))
192       Decl = Overridden;
193   }
194   Decl = cast<NamedDecl>(Decl->getCanonicalDecl());
195   return addUsage(RenamerClangTidyCheck::NamingCheckId(Decl->getLocation(),
196                                                        Decl->getNameAsString()),
197                   Range, SourceMgr);
198 }
199 
findDecl(const RecordDecl & RecDecl,StringRef DeclName)200 const NamedDecl *findDecl(const RecordDecl &RecDecl, StringRef DeclName) {
201   for (const Decl *D : RecDecl.decls()) {
202     if (const auto *ND = dyn_cast<NamedDecl>(D)) {
203       if (ND->getDeclName().isIdentifier() && ND->getName().equals(DeclName))
204         return ND;
205     }
206   }
207   return nullptr;
208 }
209 
210 namespace {
211 class NameLookup {
212   llvm::PointerIntPair<const NamedDecl *, 1, bool> Data;
213 
214 public:
NameLookup(const NamedDecl * ND)215   explicit NameLookup(const NamedDecl *ND) : Data(ND, false) {}
NameLookup(llvm::NoneType)216   explicit NameLookup(llvm::NoneType) : Data(nullptr, true) {}
NameLookup(std::nullptr_t)217   explicit NameLookup(std::nullptr_t) : Data(nullptr, false) {}
NameLookup()218   NameLookup() : NameLookup(nullptr) {}
219 
hasMultipleResolutions() const220   bool hasMultipleResolutions() const { return Data.getInt(); }
getDecl() const221   const NamedDecl *getDecl() const {
222     assert(!hasMultipleResolutions() && "Found multiple decls");
223     return Data.getPointer();
224   }
operator bool() const225   operator bool() const { return !hasMultipleResolutions(); }
operator *() const226   const NamedDecl *operator*() const { return getDecl(); }
227 };
228 } // namespace
229 
230 /// Returns a decl matching the \p DeclName in \p Parent or one of its base
231 /// classes. If \p AggressiveTemplateLookup is `true` then it will check
232 /// template dependent base classes as well.
233 /// If a matching decl is found in multiple base classes then it will return a
234 /// flag indicating the multiple resolutions.
findDeclInBases(const CXXRecordDecl & Parent,StringRef DeclName,bool AggressiveTemplateLookup)235 NameLookup findDeclInBases(const CXXRecordDecl &Parent, StringRef DeclName,
236                            bool AggressiveTemplateLookup) {
237   if (!Parent.hasDefinition())
238     return NameLookup(nullptr);
239   if (const NamedDecl *InClassRef = findDecl(Parent, DeclName))
240     return NameLookup(InClassRef);
241   const NamedDecl *Found = nullptr;
242 
243   for (CXXBaseSpecifier Base : Parent.bases()) {
244     const auto *Record = Base.getType()->getAsCXXRecordDecl();
245     if (!Record && AggressiveTemplateLookup) {
246       if (const auto *TST =
247               Base.getType()->getAs<TemplateSpecializationType>()) {
248         if (const auto *TD = llvm::dyn_cast_or_null<ClassTemplateDecl>(
249                 TST->getTemplateName().getAsTemplateDecl()))
250           Record = TD->getTemplatedDecl();
251       }
252     }
253     if (!Record)
254       continue;
255     if (auto Search =
256             findDeclInBases(*Record, DeclName, AggressiveTemplateLookup)) {
257       if (*Search) {
258         if (Found)
259           return NameLookup(
260               llvm::None); // Multiple decls found in different base classes.
261         Found = *Search;
262         continue;
263       }
264     } else
265       return NameLookup(llvm::None); // Propagate multiple resolution back up.
266   }
267   return NameLookup(Found); // If nullptr, decl wasnt found.
268 }
269 
check(const MatchFinder::MatchResult & Result)270 void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) {
271   if (const auto *Decl =
272           Result.Nodes.getNodeAs<CXXConstructorDecl>("classRef")) {
273 
274     addUsage(Decl->getParent(), Decl->getNameInfo().getSourceRange(),
275              Result.SourceManager);
276 
277     for (const auto *Init : Decl->inits()) {
278       if (!Init->isWritten() || Init->isInClassMemberInitializer())
279         continue;
280       if (const FieldDecl *FD = Init->getAnyMember())
281         addUsage(FD, SourceRange(Init->getMemberLocation()),
282                  Result.SourceManager);
283       // Note: delegating constructors and base class initializers are handled
284       // via the "typeLoc" matcher.
285     }
286     return;
287   }
288 
289   if (const auto *Decl =
290           Result.Nodes.getNodeAs<CXXDestructorDecl>("classRef")) {
291 
292     SourceRange Range = Decl->getNameInfo().getSourceRange();
293     if (Range.getBegin().isInvalid())
294       return;
295     // The first token that will be found is the ~ (or the equivalent trigraph),
296     // we want instead to replace the next token, that will be the identifier.
297     Range.setBegin(CharSourceRange::getTokenRange(Range).getEnd());
298 
299     addUsage(Decl->getParent(), Range, Result.SourceManager);
300     return;
301   }
302 
303   if (const auto *Loc = Result.Nodes.getNodeAs<TypeLoc>("typeLoc")) {
304     UnqualTypeLoc Unqual = Loc->getUnqualifiedLoc();
305     NamedDecl *Decl = nullptr;
306     if (const auto &Ref = Unqual.getAs<TagTypeLoc>())
307       Decl = Ref.getDecl();
308     else if (const auto &Ref = Unqual.getAs<InjectedClassNameTypeLoc>())
309       Decl = Ref.getDecl();
310     else if (const auto &Ref = Unqual.getAs<UnresolvedUsingTypeLoc>())
311       Decl = Ref.getDecl();
312     else if (const auto &Ref = Unqual.getAs<TemplateTypeParmTypeLoc>())
313       Decl = Ref.getDecl();
314     // further TypeLocs handled below
315 
316     if (Decl) {
317       addUsage(Decl, Loc->getSourceRange(), Result.SourceManager);
318       return;
319     }
320 
321     if (const auto &Ref = Loc->getAs<TemplateSpecializationTypeLoc>()) {
322       const TemplateDecl *Decl =
323           Ref.getTypePtr()->getTemplateName().getAsTemplateDecl();
324 
325       SourceRange Range(Ref.getTemplateNameLoc(), Ref.getTemplateNameLoc());
326       if (const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl)) {
327         if (const NamedDecl *TemplDecl = ClassDecl->getTemplatedDecl())
328           addUsage(TemplDecl, Range, Result.SourceManager);
329         return;
330       }
331     }
332 
333     if (const auto &Ref =
334             Loc->getAs<DependentTemplateSpecializationTypeLoc>()) {
335       if (const TagDecl *Decl = Ref.getTypePtr()->getAsTagDecl())
336         addUsage(Decl, Loc->getSourceRange(), Result.SourceManager);
337       return;
338     }
339   }
340 
341   if (const auto *Loc =
342           Result.Nodes.getNodeAs<NestedNameSpecifierLoc>("nestedNameLoc")) {
343     if (const NestedNameSpecifier *Spec = Loc->getNestedNameSpecifier()) {
344       if (const NamespaceDecl *Decl = Spec->getAsNamespace()) {
345         addUsage(Decl, Loc->getLocalSourceRange(), Result.SourceManager);
346         return;
347       }
348     }
349   }
350 
351   if (const auto *Decl = Result.Nodes.getNodeAs<UsingDecl>("using")) {
352     for (const auto *Shadow : Decl->shadows())
353       addUsage(Shadow->getTargetDecl(), Decl->getNameInfo().getSourceRange(),
354                Result.SourceManager);
355     return;
356   }
357 
358   if (const auto *DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>("declRef")) {
359     SourceRange Range = DeclRef->getNameInfo().getSourceRange();
360     addUsage(DeclRef->getDecl(), Range, Result.SourceManager);
361     return;
362   }
363 
364   if (const auto *MemberRef =
365           Result.Nodes.getNodeAs<MemberExpr>("memberExpr")) {
366     SourceRange Range = MemberRef->getMemberNameInfo().getSourceRange();
367     addUsage(MemberRef->getMemberDecl(), Range, Result.SourceManager);
368     return;
369   }
370 
371   if (const auto *DepMemberRef =
372           Result.Nodes.getNodeAs<CXXDependentScopeMemberExpr>(
373               "depMemberExpr")) {
374     QualType BaseType = DepMemberRef->isArrow()
375                             ? DepMemberRef->getBaseType()->getPointeeType()
376                             : DepMemberRef->getBaseType();
377     if (BaseType.isNull())
378       return;
379     const CXXRecordDecl *Base = BaseType.getTypePtr()->getAsCXXRecordDecl();
380     if (!Base)
381       return;
382     DeclarationName DeclName = DepMemberRef->getMemberNameInfo().getName();
383     if (!DeclName.isIdentifier())
384       return;
385     StringRef DependentName = DeclName.getAsIdentifierInfo()->getName();
386 
387     if (NameLookup Resolved = findDeclInBases(
388             *Base, DependentName, AggressiveDependentMemberLookup)) {
389       if (*Resolved)
390         addUsage(*Resolved, DepMemberRef->getMemberNameInfo().getSourceRange(),
391                  Result.SourceManager);
392     }
393     return;
394   }
395 
396   if (const auto *Decl = Result.Nodes.getNodeAs<NamedDecl>("decl")) {
397     // Fix using namespace declarations.
398     if (const auto *UsingNS = dyn_cast<UsingDirectiveDecl>(Decl))
399       addUsage(UsingNS->getNominatedNamespaceAsWritten(),
400                UsingNS->getIdentLocation(), Result.SourceManager);
401 
402     if (!Decl->getIdentifier() || Decl->getName().empty() || Decl->isImplicit())
403       return;
404 
405     const auto *Canonical = cast<NamedDecl>(Decl->getCanonicalDecl());
406     if (Canonical != Decl) {
407       addUsage(Canonical, Decl->getLocation(), Result.SourceManager);
408       return;
409     }
410 
411     // Fix type aliases in value declarations.
412     if (const auto *Value = Result.Nodes.getNodeAs<ValueDecl>("decl")) {
413       if (const Type *TypePtr = Value->getType().getTypePtrOrNull()) {
414         if (const auto *Typedef = TypePtr->getAs<TypedefType>())
415           addUsage(Typedef->getDecl(), Value->getSourceRange(),
416                    Result.SourceManager);
417       }
418     }
419 
420     // Fix type aliases in function declarations.
421     if (const auto *Value = Result.Nodes.getNodeAs<FunctionDecl>("decl")) {
422       if (const auto *Typedef =
423               Value->getReturnType().getTypePtr()->getAs<TypedefType>())
424         addUsage(Typedef->getDecl(), Value->getSourceRange(),
425                  Result.SourceManager);
426       for (const ParmVarDecl *Param : Value->parameters()) {
427         if (const TypedefType *Typedef =
428                 Param->getType().getTypePtr()->getAs<TypedefType>())
429           addUsage(Typedef->getDecl(), Value->getSourceRange(),
430                    Result.SourceManager);
431       }
432     }
433 
434     // Fix overridden methods
435     if (const auto *Method = Result.Nodes.getNodeAs<CXXMethodDecl>("decl")) {
436       if (const CXXMethodDecl *Overridden = getOverrideMethod(Method)) {
437         addUsage(Overridden, Method->getLocation());
438         return; // Don't try to add the actual decl as a Failure.
439       }
440     }
441 
442     // Ignore ClassTemplateSpecializationDecl which are creating duplicate
443     // replacements with CXXRecordDecl.
444     if (isa<ClassTemplateSpecializationDecl>(Decl))
445       return;
446 
447     Optional<FailureInfo> MaybeFailure =
448         GetDeclFailureInfo(Decl, *Result.SourceManager);
449     if (!MaybeFailure)
450       return;
451     FailureInfo &Info = *MaybeFailure;
452     NamingCheckFailure &Failure = NamingCheckFailures[NamingCheckId(
453         Decl->getLocation(), Decl->getNameAsString())];
454     SourceRange Range =
455         DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
456             .getSourceRange();
457 
458     const IdentifierTable &Idents = Decl->getASTContext().Idents;
459     auto CheckNewIdentifier = Idents.find(Info.Fixup);
460     if (CheckNewIdentifier != Idents.end()) {
461       const IdentifierInfo *Ident = CheckNewIdentifier->second;
462       if (Ident->isKeyword(getLangOpts()))
463         Failure.FixStatus = ShouldFixStatus::ConflictsWithKeyword;
464       else if (Ident->hasMacroDefinition())
465         Failure.FixStatus = ShouldFixStatus::ConflictsWithMacroDefinition;
466     }
467 
468     Failure.Info = std::move(Info);
469     addUsage(Decl, Range);
470   }
471 }
472 
checkMacro(SourceManager & SourceMgr,const Token & MacroNameTok,const MacroInfo * MI)473 void RenamerClangTidyCheck::checkMacro(SourceManager &SourceMgr,
474                                        const Token &MacroNameTok,
475                                        const MacroInfo *MI) {
476   Optional<FailureInfo> MaybeFailure =
477       GetMacroFailureInfo(MacroNameTok, SourceMgr);
478   if (!MaybeFailure)
479     return;
480   FailureInfo &Info = *MaybeFailure;
481   StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
482   NamingCheckId ID(MI->getDefinitionLoc(), std::string(Name));
483   NamingCheckFailure &Failure = NamingCheckFailures[ID];
484   SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
485 
486   Failure.Info = std::move(Info);
487   addUsage(ID, Range);
488 }
489 
expandMacro(const Token & MacroNameTok,const MacroInfo * MI)490 void RenamerClangTidyCheck::expandMacro(const Token &MacroNameTok,
491                                         const MacroInfo *MI) {
492   StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
493   NamingCheckId ID(MI->getDefinitionLoc(), std::string(Name));
494 
495   auto Failure = NamingCheckFailures.find(ID);
496   if (Failure == NamingCheckFailures.end())
497     return;
498 
499   SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
500   addUsage(ID, Range);
501 }
502 
503 static std::string
getDiagnosticSuffix(const RenamerClangTidyCheck::ShouldFixStatus FixStatus,const std::string & Fixup)504 getDiagnosticSuffix(const RenamerClangTidyCheck::ShouldFixStatus FixStatus,
505                     const std::string &Fixup) {
506   if (Fixup.empty())
507     return "; cannot be fixed automatically";
508   if (FixStatus == RenamerClangTidyCheck::ShouldFixStatus::ShouldFix)
509     return {};
510   if (FixStatus >=
511       RenamerClangTidyCheck::ShouldFixStatus::IgnoreFailureThreshold)
512     return {};
513   if (FixStatus == RenamerClangTidyCheck::ShouldFixStatus::ConflictsWithKeyword)
514     return "; cannot be fixed because '" + Fixup +
515            "' would conflict with a keyword";
516   if (FixStatus ==
517       RenamerClangTidyCheck::ShouldFixStatus::ConflictsWithMacroDefinition)
518     return "; cannot be fixed because '" + Fixup +
519            "' would conflict with a macro definition";
520 
521   llvm_unreachable("invalid ShouldFixStatus");
522 }
523 
onEndOfTranslationUnit()524 void RenamerClangTidyCheck::onEndOfTranslationUnit() {
525   for (const auto &Pair : NamingCheckFailures) {
526     const NamingCheckId &Decl = Pair.first;
527     const NamingCheckFailure &Failure = Pair.second;
528 
529     if (Failure.Info.KindName.empty())
530       continue;
531 
532     if (Failure.ShouldNotify()) {
533       auto DiagInfo = GetDiagInfo(Decl, Failure);
534       auto Diag = diag(Decl.first,
535                        DiagInfo.Text + getDiagnosticSuffix(Failure.FixStatus,
536                                                            Failure.Info.Fixup));
537       DiagInfo.ApplyArgs(Diag);
538 
539       if (Failure.ShouldFix()) {
540         for (const auto &Loc : Failure.RawUsageLocs) {
541           // We assume that the identifier name is made of one token only. This
542           // is always the case as we ignore usages in macros that could build
543           // identifier names by combining multiple tokens.
544           //
545           // For destructors, we already take care of it by remembering the
546           // location of the start of the identifier and not the start of the
547           // tilde.
548           //
549           // Other multi-token identifiers, such as operators are not checked at
550           // all.
551           Diag << FixItHint::CreateReplacement(SourceRange(Loc),
552                                                Failure.Info.Fixup);
553         }
554       }
555     }
556   }
557 }
558 
559 } // namespace tidy
560 } // namespace clang
561