clang-tools 23.0.0git
RenamerClangTidyCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
10#include "ASTUtils.h"
11#include "clang/AST/CXXInheritance.h"
12#include "clang/AST/RecursiveASTVisitor.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14#include "clang/Basic/CharInfo.h"
15#include "clang/Frontend/CompilerInstance.h"
16#include "clang/Lex/PPCallbacks.h"
17#include "clang/Lex/Preprocessor.h"
18#include "llvm/ADT/DenseMapInfo.h"
19#include "llvm/ADT/PointerIntPair.h"
20#include "llvm/ADT/ScopeExit.h"
21#include <optional>
22
23#define DEBUG_TYPE "clang-tidy"
24
25using namespace clang::ast_matchers;
26
27namespace llvm {
28
29/// Specialization of DenseMapInfo to allow NamingCheckId objects in DenseMaps
30template <>
33
34 static unsigned getHashValue(NamingCheckId Val) {
35 return DenseMapInfo<clang::SourceLocation>::getHashValue(Val.first) +
36 DenseMapInfo<StringRef>::getHashValue(Val.second);
37 }
38
39 static bool isEqual(const NamingCheckId &LHS, const NamingCheckId &RHS) {
40 return LHS == RHS;
41 }
42};
43
44} // namespace llvm
45
46namespace clang::tidy {
47
48namespace {
49
50class NameLookup {
51 llvm::PointerIntPair<const NamedDecl *, 1, bool> Data;
52
53public:
54 explicit NameLookup(const NamedDecl *ND) : Data(ND, false) {}
55 explicit NameLookup(std::nullopt_t) : Data(nullptr, true) {}
56 explicit NameLookup(std::nullptr_t) : Data(nullptr, false) {}
57 NameLookup() : NameLookup(nullptr) {}
58
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
68} // namespace
69
70static const NamedDecl *findDecl(const RecordDecl &RecDecl,
71 StringRef DeclName) {
72 for (const Decl *D : RecDecl.decls()) {
73 if (const auto *ND = dyn_cast<NamedDecl>(D)) {
74 if (ND->getDeclName().isIdentifier() && ND->getName() == DeclName)
75 return ND;
76 }
77 }
78 return nullptr;
79}
80
81/// Returns the function that \p Method is overriding. If There are none or
82/// multiple overrides it returns nullptr. If the overridden function itself is
83/// overriding then it will recurse up to find the first decl of the function.
84static const CXXMethodDecl *getOverrideMethod(const CXXMethodDecl *Method) {
85 if (Method->size_overridden_methods() != 1)
86 return nullptr;
87
88 while (true) {
89 Method = *Method->begin_overridden_methods();
90 assert(Method && "Overridden method shouldn't be null");
91 const unsigned NumOverrides = Method->size_overridden_methods();
92 if (NumOverrides == 0)
93 return Method;
94 if (NumOverrides > 1)
95 return nullptr;
96 }
97}
98
99static bool hasNoName(const NamedDecl *Decl) {
100 return !Decl->getIdentifier() || Decl->getName().empty();
101}
102
103static const NamedDecl *getFailureForNamedDecl(const NamedDecl *ND) {
104 const auto *Canonical = cast<NamedDecl>(ND->getCanonicalDecl());
105 if (Canonical != ND)
106 return Canonical;
107
108 if (const auto *Method = dyn_cast<CXXMethodDecl>(ND)) {
109 if (const CXXMethodDecl *Overridden = getOverrideMethod(Method))
110 Canonical = cast<NamedDecl>(Overridden->getCanonicalDecl());
111 else if (const FunctionTemplateDecl *Primary = Method->getPrimaryTemplate())
112 if (const FunctionDecl *TemplatedDecl = Primary->getTemplatedDecl())
113 Canonical = cast<NamedDecl>(TemplatedDecl->getCanonicalDecl());
114
115 if (Canonical != ND)
116 return Canonical;
117 }
118
119 return ND;
120}
121
122using RecursionProtectionSet = llvm::SmallPtrSet<const CXXRecordDecl *, 4>;
123
124/// Returns a decl matching the \p DeclName in \p Parent or one of its base
125/// classes. If \p AggressiveTemplateLookup is `true` then it will check
126/// template dependent base classes as well.
127/// If a matching decl is found in multiple base classes then it will return a
128/// flag indicating the multiple resolutions.
129static NameLookup findDeclInBases(const CXXRecordDecl &Parent,
130 StringRef DeclName,
131 bool AggressiveTemplateLookup,
132 RecursionProtectionSet &Visited) {
133 if (!Parent.hasDefinition())
134 return NameLookup(nullptr);
135
136 const auto *Definition = Parent.getDefinition();
137 if (!Visited.insert(Definition).second)
138 return NameLookup(nullptr);
139 auto RemoveFromVisited =
140 llvm::scope_exit([&Visited, Definition] { Visited.erase(Definition); });
141
142 if (const NamedDecl *InClassRef = findDecl(Parent, DeclName))
143 return NameLookup(InClassRef);
144 const NamedDecl *Found = nullptr;
145
146 for (const CXXBaseSpecifier Base : Parent.bases()) {
147 const auto *Record = Base.getType()->getAsCXXRecordDecl();
148 if (!Record && AggressiveTemplateLookup) {
149 if (const auto *TST =
150 Base.getType()->getAs<TemplateSpecializationType>()) {
151 if (const auto *TD = dyn_cast_or_null<ClassTemplateDecl>(
152 TST->getTemplateName().getAsTemplateDecl()))
153 Record = TD->getTemplatedDecl();
154 }
155 }
156 if (!Record)
157 continue;
158 if (auto Search = findDeclInBases(*Record, DeclName,
159 AggressiveTemplateLookup, Visited)) {
160 if (*Search) {
161 if (Found)
162 return NameLookup(
163 std::nullopt); // Multiple decls found in different base classes.
164 Found = *Search;
165 continue;
166 }
167 } else {
168 return NameLookup(std::nullopt); // Propagate multiple resolution back up.
169 }
170 }
171 return NameLookup(Found); // If nullptr, decl wasn't found.
172}
173
174namespace {
175
176/// Callback supplies macros to RenamerClangTidyCheck::checkMacro
177class RenamerClangTidyCheckPPCallbacks : public PPCallbacks {
178public:
179 RenamerClangTidyCheckPPCallbacks(const SourceManager &SM,
180 RenamerClangTidyCheck *Check)
181 : SM(SM), Check(Check) {}
182
183 /// MacroDefined calls checkMacro for macros in the main file
184 void MacroDefined(const Token &MacroNameTok,
185 const MacroDirective *MD) override {
186 const MacroInfo *Info = MD->getMacroInfo();
187 if (Info->isBuiltinMacro())
188 return;
189 if (SM.isWrittenInBuiltinFile(MacroNameTok.getLocation()))
190 return;
191 if (SM.isWrittenInCommandLineFile(MacroNameTok.getLocation()))
192 return;
193 if (SM.isInSystemHeader(MacroNameTok.getLocation()))
194 return;
195 Check->checkMacro(MacroNameTok, Info, SM);
196 }
197
198 /// MacroExpands calls expandMacro for macros in the main file
199 void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
200 SourceRange /*Range*/,
201 const MacroArgs * /*Args*/) override {
202 Check->expandMacro(MacroNameTok, MD.getMacroInfo(), SM);
203 }
204
205private:
206 const SourceManager &SM;
207 RenamerClangTidyCheck *Check;
208};
209
210class RenamerClangTidyVisitor
211 : public RecursiveASTVisitor<RenamerClangTidyVisitor> {
212public:
213 RenamerClangTidyVisitor(RenamerClangTidyCheck *Check, const SourceManager &SM,
214 bool AggressiveDependentMemberLookup)
215 : Check(Check), SM(SM),
216 AggressiveDependentMemberLookup(AggressiveDependentMemberLookup) {}
217
218 bool shouldVisitTemplateInstantiations() const { return true; }
219
220 bool shouldVisitImplicitCode() const { return false; }
221
222 bool VisitCXXConstructorDecl(CXXConstructorDecl *Decl) {
223 if (Decl->isImplicit())
224 return true;
225 Check->addUsage(Decl->getParent(), Decl->getNameInfo().getSourceRange(),
226 SM);
227
228 for (const auto *Init : Decl->inits()) {
229 if (!Init->isWritten() || Init->isInClassMemberInitializer())
230 continue;
231 if (const FieldDecl *FD = Init->getAnyMember())
232 Check->addUsage(FD, SourceRange(Init->getMemberLocation()), SM);
233 // Note: delegating constructors and base class initializers are handled
234 // via the "typeLoc" matcher.
235 }
236
237 return true;
238 }
239
240 bool VisitCXXDestructorDecl(CXXDestructorDecl *Decl) {
241 if (Decl->isImplicit())
242 return true;
243 SourceRange Range = Decl->getNameInfo().getSourceRange();
244 if (Range.getBegin().isInvalid())
245 return true;
246
247 // The first token that will be found is the ~ (or the equivalent trigraph),
248 // we want instead to replace the next token, that will be the identifier.
249 Range.setBegin(CharSourceRange::getTokenRange(Range).getEnd());
250 Check->addUsage(Decl->getParent(), Range, SM);
251 return true;
252 }
253
254 bool VisitUsingDecl(UsingDecl *Decl) {
255 for (const auto *Shadow : Decl->shadows())
256 Check->addUsage(Shadow->getTargetDecl(),
257 Decl->getNameInfo().getSourceRange(), SM);
258 return true;
259 }
260
261 bool VisitUsingDirectiveDecl(UsingDirectiveDecl *Decl) {
262 Check->addUsage(Decl->getNominatedNamespaceAsWritten(),
263 Decl->getIdentLocation(), SM);
264 return true;
265 }
266
267 bool VisitNamedDecl(NamedDecl *Decl) {
268 const SourceRange UsageRange =
269 DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
270 .getSourceRange();
271 Check->addUsage(Decl, UsageRange, SM);
272 return true;
273 }
274
275 bool VisitDeclRefExpr(DeclRefExpr *DeclRef) {
276 const SourceRange Range = DeclRef->getNameInfo().getSourceRange();
277 Check->addUsage(DeclRef->getDecl(), Range, SM);
278 return true;
279 }
280
281 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Loc) {
282 if (const NestedNameSpecifier Spec = Loc.getNestedNameSpecifier();
283 Spec.getKind() == NestedNameSpecifier::Kind::Namespace) {
284 if (const auto *Decl =
285 dyn_cast<NamespaceDecl>(Spec.getAsNamespaceAndPrefix().Namespace))
286 Check->addUsage(Decl, Loc.getLocalSourceRange(), SM);
287 }
288
289 using Base = RecursiveASTVisitor<RenamerClangTidyVisitor>;
290 return Base::TraverseNestedNameSpecifierLoc(Loc);
291 }
292
293 bool VisitMemberExpr(MemberExpr *MemberRef) {
294 const SourceRange Range = MemberRef->getMemberNameInfo().getSourceRange();
295 Check->addUsage(MemberRef->getMemberDecl(), Range, SM);
296 return true;
297 }
298
299 bool
300 VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *DepMemberRef) {
301 const QualType BaseType =
302 DepMemberRef->isArrow() ? DepMemberRef->getBaseType()->getPointeeType()
303 : DepMemberRef->getBaseType();
304 if (BaseType.isNull())
305 return true;
306 const CXXRecordDecl *Base = BaseType.getTypePtr()->getAsCXXRecordDecl();
307 if (!Base)
308 return true;
309 const DeclarationName DeclName =
310 DepMemberRef->getMemberNameInfo().getName();
311 if (!DeclName.isIdentifier())
312 return true;
313 const StringRef DependentName = DeclName.getAsIdentifierInfo()->getName();
314
316 if (const NameLookup Resolved = findDeclInBases(
317 *Base, DependentName, AggressiveDependentMemberLookup, Visited)) {
318 if (*Resolved)
319 Check->addUsage(*Resolved,
320 DepMemberRef->getMemberNameInfo().getSourceRange(), SM);
321 }
322
323 return true;
324 }
325
326 bool VisitTypedefTypeLoc(const TypedefTypeLoc &Loc) {
327 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
328 return true;
329 }
330
331 bool VisitTagTypeLoc(const TagTypeLoc &Loc) {
332 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
333 return true;
334 }
335
336 bool VisitUnresolvedUsingTypeLoc(const UnresolvedUsingTypeLoc &Loc) {
337 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
338 return true;
339 }
340
341 bool VisitTemplateTypeParmTypeLoc(const TemplateTypeParmTypeLoc &Loc) {
342 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
343 return true;
344 }
345
346 bool
347 VisitTemplateSpecializationTypeLoc(const TemplateSpecializationTypeLoc &Loc) {
348 const TemplateDecl *Decl =
349 Loc.getTypePtr()->getTemplateName().getAsTemplateDecl(
350 /*IgnoreDeduced=*/true);
351 if (!Decl)
352 return true;
353
354 if (const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl))
355 if (const NamedDecl *TemplDecl = ClassDecl->getTemplatedDecl())
356 Check->addUsage(TemplDecl, Loc.getTemplateNameLoc(), SM);
357
358 return true;
359 }
360
361 bool VisitDesignatedInitExpr(DesignatedInitExpr *Expr) {
362 for (const DesignatedInitExpr::Designator &D : Expr->designators()) {
363 if (!D.isFieldDesignator())
364 continue;
365 const FieldDecl *FD = D.getFieldDecl();
366 if (!FD)
367 continue;
368 const IdentifierInfo *II = FD->getIdentifier();
369 if (!II)
370 continue;
371 const SourceRange FixLocation{D.getFieldLoc(), D.getFieldLoc()};
372 Check->addUsage(FD, FixLocation, SM);
373 }
374
375 return true;
376 }
377
378private:
379 RenamerClangTidyCheck *Check;
380 const SourceManager &SM;
381 const bool AggressiveDependentMemberLookup;
382};
383
384} // namespace
385
387 ClangTidyContext *Context)
388 : ClangTidyCheck(CheckName, Context),
389 AggressiveDependentMemberLookup(
390 Options.get("AggressiveDependentMemberLookup", false)) {}
392
394 Options.store(Opts, "AggressiveDependentMemberLookup",
395 AggressiveDependentMemberLookup);
396}
397
399 Finder->addMatcher(translationUnitDecl(), this);
400}
401
403 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
404 ModuleExpanderPP->addPPCallbacks(
405 std::make_unique<RenamerClangTidyCheckPPCallbacks>(SM, this));
406}
407
408std::pair<RenamerClangTidyCheck::NamingCheckFailureMap::iterator, bool>
411 SourceRange UsageRange, const SourceManager &SourceMgr) {
412 // Do nothing if the provided range is invalid.
413 if (UsageRange.isInvalid())
414 return {NamingCheckFailures.end(), false};
415
416 // Get the spelling location for performing the fix. This is necessary because
417 // macros can map the same spelling location to different source locations,
418 // and we only want to fix the token once, before it is expanded by the macro.
419 SourceLocation FixLocation = UsageRange.getBegin();
420 FixLocation = SourceMgr.getSpellingLoc(FixLocation);
421 if (FixLocation.isInvalid())
422 return {NamingCheckFailures.end(), false};
423
424 // Skip if in system system header
425 if (SourceMgr.isInSystemHeader(FixLocation))
426 return {NamingCheckFailures.end(), false};
427
428 auto EmplaceResult = NamingCheckFailures.try_emplace(FailureId);
429 NamingCheckFailure &Failure = EmplaceResult.first->second;
430
431 // Try to insert the identifier location in the Usages map, and bail out if it
432 // is already in there
433 if (!Failure.RawUsageLocs.insert(FixLocation).second)
434 return EmplaceResult;
435
437 return EmplaceResult;
438
439 if (SourceMgr.isWrittenInScratchSpace(FixLocation))
441
442 if (!utils::rangeCanBeFixed(UsageRange, &SourceMgr))
444
445 return EmplaceResult;
446}
447
448void RenamerClangTidyCheck::addUsage(const NamedDecl *Decl,
449 SourceRange UsageRange,
450 const SourceManager &SourceMgr) {
451 if (SourceMgr.isInSystemHeader(Decl->getLocation()))
452 return;
453
454 if (hasNoName(Decl))
455 return;
456
457 // Ignore ClassTemplateSpecializationDecl which are creating duplicate
458 // replacements with CXXRecordDecl.
459 if (isa<ClassTemplateSpecializationDecl>(Decl))
460 return;
461
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);
471 if (!MaybeFailure)
472 return;
473
474 const NamingCheckId FailureId(FailureDecl->getLocation(),
475 FailureDecl->getName());
476
477 auto [FailureIter, NewFailure] = addUsage(FailureId, UsageRange, SourceMgr);
478
479 if (FailureIter == NamingCheckFailures.end()) {
480 // Nothing to do if the usage wasn't accepted.
481 return;
482 }
483 if (!NewFailure) {
484 // FailureInfo has already been provided.
485 return;
486 }
487
488 // Update the stored failure with info regarding the FailureDecl.
489 NamingCheckFailure &Failure = FailureIter->second;
490 Failure.Info = std::move(*MaybeFailure);
491
492 // Don't overwrite the failure status if it was already set.
493 if (!Failure.shouldFix())
494 return;
495 const IdentifierTable &Idents = FailureDecl->getASTContext().Idents;
496 auto CheckNewIdentifier = Idents.find(Failure.Info.Fixup);
497 if (CheckNewIdentifier != Idents.end()) {
498 const IdentifierInfo *Ident = CheckNewIdentifier->second;
499 if (Ident->isKeyword(getLangOpts()))
500 Failure.FixStatus = ShouldFixStatus::ConflictsWithKeyword;
501 else if (Ident->hasMacroDefinition())
503 } else if (!isValidAsciiIdentifier(Failure.Info.Fixup)) {
504 Failure.FixStatus = ShouldFixStatus::FixInvalidIdentifier;
505 }
506}
507
508void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) {
509 if (!Result.SourceManager) {
510 // In principle SourceManager is not null but going only by the definition
511 // of MatchResult it must be handled. Cannot rename anything without a
512 // SourceManager.
513 return;
514 }
515 RenamerClangTidyVisitor Visitor(this, *Result.SourceManager,
516 AggressiveDependentMemberLookup);
517 Visitor.TraverseAST(*Result.Context);
518}
519
520void RenamerClangTidyCheck::checkMacro(const Token &MacroNameTok,
521 const MacroInfo *MI,
522 const SourceManager &SourceMgr) {
523 std::optional<FailureInfo> MaybeFailure =
524 getMacroFailureInfo(MacroNameTok, SourceMgr);
525 if (!MaybeFailure)
526 return;
527 FailureInfo &Info = *MaybeFailure;
528 const StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
529 const NamingCheckId ID(MI->getDefinitionLoc(), Name);
530 NamingCheckFailure &Failure = NamingCheckFailures[ID];
531 const SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
532
533 if (!isValidAsciiIdentifier(Info.Fixup))
534 Failure.FixStatus = ShouldFixStatus::FixInvalidIdentifier;
535
536 Failure.Info = std::move(Info);
537 addUsage(ID, Range, SourceMgr);
538}
539
540void RenamerClangTidyCheck::expandMacro(const Token &MacroNameTok,
541 const MacroInfo *MI,
542 const SourceManager &SourceMgr) {
543 const StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
544 const NamingCheckId ID(MI->getDefinitionLoc(), Name);
545
546 auto Failure = NamingCheckFailures.find(ID);
547 if (Failure == NamingCheckFailures.end())
548 return;
549
550 const SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
551 addUsage(ID, Range, SourceMgr);
552}
553
554static std::string
556 const std::string &Fixup) {
557 if (Fixup.empty() ||
559 return "; cannot be fixed automatically";
561 return {};
562 if (FixStatus >=
564 return {};
566 return "; cannot be fixed because '" + Fixup +
567 "' would conflict with a keyword";
568 if (FixStatus ==
570 return "; cannot be fixed because '" + Fixup +
571 "' would conflict with a macro definition";
572 llvm_unreachable("invalid ShouldFixStatus");
573}
574
576 for (const auto &Pair : NamingCheckFailures) {
577 const NamingCheckId &Decl = Pair.first;
578 const NamingCheckFailure &Failure = Pair.second;
579
580 if (Failure.Info.KindName.empty())
581 continue;
582
583 if (Failure.shouldNotify()) {
584 auto DiagInfo = getDiagInfo(Decl, Failure);
585 auto Diag = diag(Decl.first,
586 DiagInfo.Text + getDiagnosticSuffix(Failure.FixStatus,
587 Failure.Info.Fixup));
588 DiagInfo.ApplyArgs(Diag);
589
590 if (Failure.shouldFix()) {
591 for (const auto &Loc : Failure.RawUsageLocs) {
592 // We assume that the identifier name is made of one token only. This
593 // is always the case as we ignore usages in macros that could build
594 // identifier names by combining multiple tokens.
595 //
596 // For destructors, we already take care of it by remembering the
597 // location of the start of the identifier and not the start of the
598 // tilde.
599 //
600 // Other multi-token identifiers, such as operators are not checked at
601 // all.
602 Diag << FixItHint::CreateReplacement(SourceRange(Loc),
603 Failure.Info.Fixup);
604 }
605 }
606 }
607 }
608}
609
610} // namespace clang::tidy
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for MD output.")
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) final
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) final
std::pair< SourceLocation, StringRef > NamingCheckId
virtual DiagInfo getDiagInfo(const NamingCheckId &ID, const NamingCheckFailure &Failure) const =0
Overridden by derived classes, returns a description of the diagnostic that should be emitted for the...
void expandMacro(const Token &MacroNameTok, const MacroInfo *MI, const SourceManager &SourceMgr)
Add a usage of a macro if it already has a violation.
void registerMatchers(ast_matchers::MatchFinder *Finder) final
Derived classes should not implement any matching logic themselves; this class will do the matching a...
RenamerClangTidyCheck(StringRef CheckName, ClangTidyContext *Context)
ShouldFixStatus
This enum will be used in select of the diagnostic message.
@ IgnoreFailureThreshold
Values pass this threshold will be ignored completely i.e no message, no fixup.
@ ConflictsWithMacroDefinition
The fixup will conflict with a macro definition, so we can't fix it automatically.
@ ConflictsWithKeyword
The fixup will conflict with a language keyword, so we can't fix it automatically.
@ InsideMacro
If the identifier was used or declared within a macro we won't offer a fixup for safety reasons.
@ FixInvalidIdentifier
The fixup results in an identifier that is not a valid c/c++ identifier.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Derived classes that override this function should call this method from the overridden method.
virtual std::optional< FailureInfo > getMacroFailureInfo(const Token &MacroNameTok, const SourceManager &SM) const =0
Overridden by derived classes, returns information about if and how a macro failed the check.
void addUsage(const NamedDecl *Decl, SourceRange Range, const SourceManager &SourceMgr)
virtual std::optional< FailureInfo > getDeclFailureInfo(const NamedDecl *Decl, const SourceManager &SM) const =0
Overridden by derived classes, returns information about if and how a Decl failed the check.
void checkMacro(const Token &MacroNameTok, const MacroInfo *MI, const SourceManager &SourceMgr)
Check Macros for style violations.
bool rangeCanBeFixed(SourceRange Range, const SourceManager *SM)
Definition ASTUtils.cpp:84
static std::string getDiagnosticSuffix(const RenamerClangTidyCheck::ShouldFixStatus FixStatus, const std::string &Fixup)
llvm::SmallPtrSet< const CXXRecordDecl *, 4 > RecursionProtectionSet
static const CXXMethodDecl * getOverrideMethod(const CXXMethodDecl *Method)
Returns the function that Method is overriding.
static NameLookup findDeclInBases(const CXXRecordDecl &Parent, StringRef DeclName, bool AggressiveTemplateLookup, RecursionProtectionSet &Visited)
Returns a decl matching the DeclName in Parent or one of its base classes.
static const NamedDecl * getFailureForNamedDecl(const NamedDecl *ND)
static const NamedDecl * findDecl(const RecordDecl &RecDecl, StringRef DeclName)
static bool hasNoName(const NamedDecl *Decl)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Some operations such as code completion produce a set of candidates.
Definition Generators.h:152
llvm::StringMap< ClangTidyValue > OptionMap
Represents customized diagnostic text and how arguments should be applied.
llvm::unique_function< void(DiagnosticBuilder &)> ApplyArgs
Information describing a failed check.
Holds an identifier name check failure, tracking the kind of the identifier, its possible fixup and t...
static bool isEqual(const NamingCheckId &LHS, const NamingCheckId &RHS)