clang-tools 17.0.0git
RenamerClangTidyCheck.cpp
Go to the documentation of this file.
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
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#include <optional>
20
21#define DEBUG_TYPE "clang-tidy"
22
23using namespace clang::ast_matchers;
24
25namespace llvm {
26
27/// Specialization of DenseMapInfo to allow NamingCheckId objects in DenseMaps
28template <>
31
32 static inline NamingCheckId getEmptyKey() {
33 return NamingCheckId(DenseMapInfo<clang::SourceLocation>::getEmptyKey(),
34 "EMPTY");
35 }
36
38 return NamingCheckId(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 std::hash<NamingCheckId::second_type> SecondHash;
47 return DenseMapInfo<clang::SourceLocation>::getHashValue(Val.first) +
48 SecondHash(Val.second);
49 }
50
51 static bool isEqual(const NamingCheckId &LHS, const NamingCheckId &RHS) {
52 if (RHS == getEmptyKey())
53 return LHS == getEmptyKey();
54 if (RHS == getTombstoneKey())
55 return LHS == getTombstoneKey();
56 return LHS == RHS;
57 }
58};
59
60} // namespace llvm
61
62namespace clang::tidy {
63
64namespace {
65
66/// Callback supplies macros to RenamerClangTidyCheck::checkMacro
67class RenamerClangTidyCheckPPCallbacks : public PPCallbacks {
68public:
69 RenamerClangTidyCheckPPCallbacks(Preprocessor *PP,
70 RenamerClangTidyCheck *Check)
71 : PP(PP), Check(Check) {}
72
73 /// MacroDefined calls checkMacro for macros in the main file
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
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
94private:
95 Preprocessor *PP;
96 RenamerClangTidyCheck *Check;
97};
98
99} // namespace
100
102 ClangTidyContext *Context)
103 : ClangTidyCheck(CheckName, Context),
104 AggressiveDependentMemberLookup(
105 Options.getLocalOrGlobal("AggressiveDependentMemberLookup", false)) {}
107
109 Options.store(Opts, "AggressiveDependentMemberLookup",
110 AggressiveDependentMemberLookup);
111}
112
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
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.
141static 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
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
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))
184
185 if (!utils::rangeCanBeFixed(Range, SourceMgr))
187}
188
189void 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());
197 Decl->getNameAsString()),
198 Range, SourceMgr);
199}
200
201const 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
211namespace {
212class NameLookup {
213 llvm::PointerIntPair<const NamedDecl *, 1, bool> Data;
214
215public:
216 explicit NameLookup(const NamedDecl *ND) : Data(ND, false) {}
217 explicit NameLookup(std::nullopt_t) : Data(nullptr, true) {}
218 explicit NameLookup(std::nullptr_t) : Data(nullptr, false) {}
219 NameLookup() : NameLookup(nullptr) {}
220
221 bool hasMultipleResolutions() const { return Data.getInt(); }
222 const NamedDecl *getDecl() const {
223 assert(!hasMultipleResolutions() && "Found multiple decls");
224 return Data.getPointer();
225 }
226 operator bool() const { return !hasMultipleResolutions(); }
227 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.
236NameLookup 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 std::nullopt); // Multiple decls found in different base classes.
262 Found = *Search;
263 continue;
264 }
265 } else
266 return NameLookup(std::nullopt); // Propagate multiple resolution back up.
267 }
268 return NameLookup(Found); // If nullptr, decl wasn't found.
269}
270
271void 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 std::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()))
465 else if (Ident->hasMacroDefinition())
467 } else if (!isValidAsciiIdentifier(Info.Fixup)) {
469 }
470
471 Failure.Info = std::move(Info);
473 }
474}
475
476void RenamerClangTidyCheck::checkMacro(SourceManager &SourceMgr,
477 const Token &MacroNameTok,
478 const MacroInfo *MI) {
479 std::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 if (!isValidAsciiIdentifier(Info.Fixup))
491
492 Failure.Info = std::move(Info);
493 addUsage(ID, Range);
494}
495
496void RenamerClangTidyCheck::expandMacro(const Token &MacroNameTok,
497 const MacroInfo *MI) {
498 StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
499 NamingCheckId ID(MI->getDefinitionLoc(), std::string(Name));
500
501 auto Failure = NamingCheckFailures.find(ID);
502 if (Failure == NamingCheckFailures.end())
503 return;
504
505 SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
506 addUsage(ID, Range);
507}
508
509static std::string
511 const std::string &Fixup) {
512 if (Fixup.empty() ||
514 return "; cannot be fixed automatically";
516 return {};
517 if (FixStatus >=
519 return {};
521 return "; cannot be fixed because '" + Fixup +
522 "' would conflict with a keyword";
523 if (FixStatus ==
525 return "; cannot be fixed because '" + Fixup +
526 "' would conflict with a macro definition";
527 llvm_unreachable("invalid ShouldFixStatus");
528}
529
531 for (const auto &Pair : NamingCheckFailures) {
532 const NamingCheckId &Decl = Pair.first;
533 const NamingCheckFailure &Failure = Pair.second;
534
535 if (Failure.Info.KindName.empty())
536 continue;
537
538 if (Failure.shouldNotify()) {
539 auto DiagInfo = getDiagInfo(Decl, Failure);
540 auto Diag = diag(Decl.first,
542 Failure.Info.Fixup));
543 DiagInfo.ApplyArgs(Diag);
544
545 if (Failure.shouldFix()) {
546 for (const auto &Loc : Failure.RawUsageLocs) {
547 // We assume that the identifier name is made of one token only. This
548 // is always the case as we ignore usages in macros that could build
549 // identifier names by combining multiple tokens.
550 //
551 // For destructors, we already take care of it by remembering the
552 // location of the start of the identifier and not the start of the
553 // tilde.
554 //
555 // Other multi-token identifiers, such as operators are not checked at
556 // all.
557 Diag << FixItHint::CreateReplacement(SourceRange(Loc),
558 Failure.Info.Fixup);
559 }
560 }
561 }
562 }
563}
564
565} // namespace clang::tidy
const FunctionDecl * Decl
const Node * Parent
FunctionInfo Info
NodeType Type
CharSourceRange Range
SourceRange for the file name.
SourceLocation Loc
Token Name
const DeclRefExpr * DeclRef
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
Base class for all clang-tidy checks.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
const LangOptions & getLangOpts() const
Returns the language options from the context.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) final
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) final
Override this to register PPCallbacks in the preprocessor.
void checkMacro(SourceManager &SourceMgr, const Token &MacroNameTok, const MacroInfo *MI)
Check Macros for style violations.
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 registerMatchers(ast_matchers::MatchFinder *Finder) final
Derived classes should not implement any matching logic themselves; this class will do the matching a...
std::pair< SourceLocation, std::string > NamingCheckId
RenamerClangTidyCheck(StringRef CheckName, ClangTidyContext *Context)
void expandMacro(const Token &MacroNameTok, const MacroInfo *MI)
Add a usage of a macro if it already has a violation.
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.
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 addUsage(const RenamerClangTidyCheck::NamingCheckId &Decl, SourceRange Range, SourceManager *SourceMgr=nullptr)
bool rangeCanBeFixed(SourceRange Range, const SourceManager *SM)
Definition: ASTUtils.cpp:86
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 overridding.
const NamedDecl * findDecl(const RecordDecl &RecDecl, StringRef DeclName)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Some operations such as code completion produce a set of candidates.
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)