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