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