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