RenamerClangTidyCheck.cpp 21 KB

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