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"
22#define DEBUG_TYPE "clang-tidy"
34 return {DenseMapInfo<clang::SourceLocation>::getEmptyKey(),
"EMPTY"};
38 return {DenseMapInfo<clang::SourceLocation>::getTombstoneKey(),
43 assert(Val != getEmptyKey() &&
"Cannot hash the empty key!");
44 assert(Val != getTombstoneKey() &&
"Cannot hash the tombstone key!");
46 return DenseMapInfo<clang::SourceLocation>::getHashValue(Val.first) +
47 DenseMapInfo<StringRef>::getHashValue(Val.second);
51 if (RHS == getEmptyKey())
52 return LHS == getEmptyKey();
53 if (RHS == getTombstoneKey())
54 return LHS == getTombstoneKey();
66 llvm::PointerIntPair<const NamedDecl *, 1, bool> Data;
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) {}
74 bool hasMultipleResolutions()
const {
return Data.getInt(); }
75 const NamedDecl *getDecl()
const {
76 assert(!hasMultipleResolutions() &&
"Found multiple decls");
77 return Data.getPointer();
79 operator bool()
const {
return !hasMultipleResolutions(); }
80 const NamedDecl *operator*()
const {
return getDecl(); }
85static const NamedDecl *
findDecl(
const RecordDecl &RecDecl,
87 for (
const Decl *D : RecDecl.decls()) {
88 if (
const auto *ND = dyn_cast<NamedDecl>(D)) {
89 if (ND->getDeclName().isIdentifier() && ND->getName() == DeclName)
100 if (Method->size_overridden_methods() != 1)
104 Method = *Method->begin_overridden_methods();
105 assert(Method &&
"Overridden method shouldn't be null");
106 unsigned NumOverrides = Method->size_overridden_methods();
107 if (NumOverrides == 0)
109 if (NumOverrides > 1)
115 return !
Decl->getIdentifier() ||
Decl->getName().empty();
119 const auto *Canonical = cast<NamedDecl>(ND->getCanonicalDecl());
123 if (
const auto *Method = dyn_cast<CXXMethodDecl>(ND)) {
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());
144 bool AggressiveTemplateLookup) {
145 if (!
Parent.hasDefinition())
146 return NameLookup(
nullptr);
148 return NameLookup(InClassRef);
149 const NamedDecl *Found =
nullptr;
151 for (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();
173 return NameLookup(std::nullopt);
175 return NameLookup(Found);
181class RenamerClangTidyCheckPPCallbacks :
public PPCallbacks {
183 RenamerClangTidyCheckPPCallbacks(
const SourceManager &SM,
184 RenamerClangTidyCheck *Check)
185 : SM(SM), Check(Check) {}
188 void MacroDefined(
const Token &MacroNameTok,
189 const MacroDirective *MD)
override {
190 const MacroInfo *
Info = MD->getMacroInfo();
191 if (
Info->isBuiltinMacro())
193 if (SM.isWrittenInBuiltinFile(MacroNameTok.getLocation()))
195 if (SM.isWrittenInCommandLineFile(MacroNameTok.getLocation()))
197 Check->checkMacro(MacroNameTok,
Info, SM);
201 void MacroExpands(
const Token &MacroNameTok,
const MacroDefinition &MD,
203 const MacroArgs * )
override {
204 Check->expandMacro(MacroNameTok, MD.getMacroInfo(), SM);
208 const SourceManager &SM;
209 RenamerClangTidyCheck *Check;
212class RenamerClangTidyVisitor
215 RenamerClangTidyVisitor(RenamerClangTidyCheck *Check,
const SourceManager &SM,
216 bool AggressiveDependentMemberLookup)
217 : Check(Check), SM(SM),
218 AggressiveDependentMemberLookup(AggressiveDependentMemberLookup) {}
220 bool shouldVisitTemplateInstantiations()
const {
return true; }
222 bool shouldVisitImplicitCode()
const {
return false; }
224 bool VisitCXXConstructorDecl(CXXConstructorDecl *
Decl) {
225 if (
Decl->isImplicit())
227 Check->addUsage(
Decl->getParent(),
Decl->getNameInfo().getSourceRange(),
230 for (
const auto *Init :
Decl->inits()) {
231 if (!Init->isWritten() || Init->isInClassMemberInitializer())
233 if (
const FieldDecl *FD = Init->getAnyMember())
234 Check->addUsage(FD, SourceRange(Init->getMemberLocation()), SM);
242 bool VisitCXXDestructorDecl(CXXDestructorDecl *
Decl) {
243 if (
Decl->isImplicit())
245 SourceRange
Range =
Decl->getNameInfo().getSourceRange();
246 if (
Range.getBegin().isInvalid())
251 Range.setBegin(CharSourceRange::getTokenRange(Range).getEnd());
252 Check->addUsage(
Decl->getParent(), Range, SM);
256 bool VisitUsingDecl(UsingDecl *
Decl) {
257 for (
const auto *Shadow :
Decl->shadows())
258 Check->addUsage(Shadow->getTargetDecl(),
259 Decl->getNameInfo().getSourceRange(), SM);
263 bool VisitUsingDirectiveDecl(UsingDirectiveDecl *
Decl) {
264 Check->addUsage(
Decl->getNominatedNamespaceAsWritten(),
265 Decl->getIdentLocation(), SM);
269 bool VisitNamedDecl(NamedDecl *
Decl) {
270 SourceRange UsageRange =
271 DeclarationNameInfo(
Decl->getDeclName(),
Decl->getLocation())
273 Check->addUsage(
Decl, UsageRange, SM);
277 bool VisitDeclRefExpr(DeclRefExpr *
DeclRef) {
278 SourceRange
Range =
DeclRef->getNameInfo().getSourceRange();
279 Check->addUsage(
DeclRef->getDecl(), Range, SM);
283 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc
Loc) {
284 if (
const NestedNameSpecifier *Spec =
Loc.getNestedNameSpecifier()) {
285 if (
const NamespaceDecl *
Decl = Spec->getAsNamespace())
286 Check->addUsage(
Decl,
Loc.getLocalSourceRange(), SM);
290 return Base::TraverseNestedNameSpecifierLoc(
Loc);
293 bool VisitMemberExpr(MemberExpr *MemberRef) {
294 SourceRange
Range = MemberRef->getMemberNameInfo().getSourceRange();
295 Check->addUsage(MemberRef->getMemberDecl(), Range, SM);
300 VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *DepMemberRef) {
301 QualType BaseType = DepMemberRef->isArrow()
302 ? DepMemberRef->getBaseType()->getPointeeType()
303 : DepMemberRef->getBaseType();
304 if (BaseType.isNull())
306 const CXXRecordDecl *Base = BaseType.getTypePtr()->getAsCXXRecordDecl();
309 DeclarationName DeclName = DepMemberRef->getMemberNameInfo().getName();
310 if (!DeclName.isIdentifier())
312 StringRef
DependentName = DeclName.getAsIdentifierInfo()->getName();
315 *Base, DependentName, AggressiveDependentMemberLookup)) {
317 Check->addUsage(*Resolved,
318 DepMemberRef->getMemberNameInfo().getSourceRange(), SM);
324 bool VisitTypedefTypeLoc(
const TypedefTypeLoc &
Loc) {
325 Check->addUsage(
Loc.getTypedefNameDecl(),
Loc.getSourceRange(), SM);
329 bool VisitTagTypeLoc(
const TagTypeLoc &
Loc) {
330 Check->addUsage(
Loc.getDecl(),
Loc.getSourceRange(), SM);
334 bool VisitInjectedClassNameTypeLoc(
const InjectedClassNameTypeLoc &
Loc) {
335 Check->addUsage(
Loc.getDecl(),
Loc.getSourceRange(), SM);
339 bool VisitUnresolvedUsingTypeLoc(
const UnresolvedUsingTypeLoc &
Loc) {
340 Check->addUsage(
Loc.getDecl(),
Loc.getSourceRange(), SM);
344 bool VisitTemplateTypeParmTypeLoc(
const TemplateTypeParmTypeLoc &
Loc) {
345 Check->addUsage(
Loc.getDecl(),
Loc.getSourceRange(), SM);
350 VisitTemplateSpecializationTypeLoc(
const TemplateSpecializationTypeLoc &
Loc) {
351 const TemplateDecl *
Decl =
352 Loc.getTypePtr()->getTemplateName().getAsTemplateDecl();
354 SourceRange
Range(
Loc.getTemplateNameLoc(),
Loc.getTemplateNameLoc());
355 if (
const auto *ClassDecl = dyn_cast<TemplateDecl>(
Decl)) {
356 if (
const NamedDecl *TemplDecl = ClassDecl->getTemplatedDecl())
357 Check->addUsage(TemplDecl, Range, SM);
363 bool VisitDependentTemplateSpecializationTypeLoc(
364 const DependentTemplateSpecializationTypeLoc &
Loc) {
365 if (
const TagDecl *
Decl =
Loc.getTypePtr()->getAsTagDecl())
366 Check->addUsage(
Decl,
Loc.getSourceRange(), SM);
371 bool VisitDesignatedInitExpr(DesignatedInitExpr *Expr) {
372 for (
const DesignatedInitExpr::Designator &D : Expr->designators()) {
373 if (!D.isFieldDesignator())
375 const FieldDecl *FD = D.getFieldDecl();
378 const IdentifierInfo *II = FD->getIdentifier();
381 SourceRange FixLocation{D.getFieldLoc(), D.getFieldLoc()};
382 Check->addUsage(FD, FixLocation, SM);
389 RenamerClangTidyCheck *Check;
390 const SourceManager &SM;
391 const bool AggressiveDependentMemberLookup;
399 AggressiveDependentMemberLookup(
400 Options.getLocalOrGlobal(
"AggressiveDependentMemberLookup", false)) {}
405 AggressiveDependentMemberLookup);
409 Finder->addMatcher(translationUnitDecl(),
this);
413 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
414 ModuleExpanderPP->addPPCallbacks(
415 std::make_unique<RenamerClangTidyCheckPPCallbacks>(SM,
this));
418std::pair<RenamerClangTidyCheck::NamingCheckFailureMap::iterator, bool>
421 SourceRange UsageRange,
const SourceManager &SourceMgr) {
423 if (UsageRange.isInvalid())
424 return {NamingCheckFailures.end(),
false};
429 SourceLocation FixLocation = UsageRange.getBegin();
430 FixLocation = SourceMgr.getSpellingLoc(FixLocation);
431 if (FixLocation.isInvalid())
432 return {NamingCheckFailures.end(),
false};
434 auto EmplaceResult = NamingCheckFailures.try_emplace(FailureId);
435 NamingCheckFailure &Failure = EmplaceResult.first->second;
439 if (!Failure.RawUsageLocs.insert(FixLocation).second)
440 return EmplaceResult;
443 return EmplaceResult;
445 if (SourceMgr.isWrittenInScratchSpace(FixLocation))
451 return EmplaceResult;
455 SourceRange UsageRange,
456 const SourceManager &SourceMgr) {
462 if (isa<ClassTemplateSpecializationDecl>(
Decl))
472 std::optional<FailureInfo> MaybeFailure =
477 NamingCheckId FailureId(FailureDecl->getLocation(), FailureDecl->getName());
479 auto [FailureIter, NewFailure] =
addUsage(FailureId, UsageRange, SourceMgr);
481 if (FailureIter == NamingCheckFailures.end()) {
492 Failure.
Info = std::move(*MaybeFailure);
498 const IdentifierTable &Idents = FailureDecl->getASTContext().Idents;
499 auto CheckNewIdentifier = Idents.find(Failure.
Info.
Fixup);
500 if (CheckNewIdentifier != Idents.end()) {
501 const IdentifierInfo *Ident = CheckNewIdentifier->second;
504 else if (Ident->hasMacroDefinition())
506 }
else if (!isValidAsciiIdentifier(Failure.
Info.
Fixup)) {
512 if (!Result.SourceManager) {
518 RenamerClangTidyVisitor Visitor(
this, *Result.SourceManager,
519 AggressiveDependentMemberLookup);
520 Visitor.TraverseAST(*Result.Context);
525 const SourceManager &SourceMgr) {
526 std::optional<FailureInfo> MaybeFailure =
531 StringRef
Name = MacroNameTok.getIdentifierInfo()->getName();
534 SourceRange
Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
536 if (!isValidAsciiIdentifier(
Info.Fixup))
545 const SourceManager &SourceMgr) {
546 StringRef
Name = MacroNameTok.getIdentifierInfo()->getName();
549 auto Failure = NamingCheckFailures.find(
ID);
550 if (Failure == NamingCheckFailures.end())
553 SourceRange
Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
559 const std::string &Fixup) {
562 return "; cannot be fixed automatically";
569 return "; cannot be fixed because '" + Fixup +
570 "' would conflict with a keyword";
573 return "; cannot be fixed because '" + Fixup +
574 "' would conflict with a macro definition";
575 llvm_unreachable(
"invalid ShouldFixStatus");
579 for (
const auto &Pair : NamingCheckFailures) {
605 Diag << FixItHint::CreateReplacement(SourceRange(
Loc),
const FunctionDecl * Decl
llvm::SmallString< 256U > Name
CharSourceRange Range
SourceRange for the file 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.
std::pair< SourceLocation, StringRef > NamingCheckId
void onEndOfTranslationUnit() final
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)
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 overridding.
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.
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...
ShouldFixStatus FixStatus
llvm::DenseSet< SourceLocation > RawUsageLocs
A set of all the identifier usages starting SourceLocation.
bool shouldNotify() const
bool shouldFix() const
Whether the failure should be fixed or not.
static NamingCheckId getTombstoneKey()
static NamingCheckId getEmptyKey()
static bool isEqual(const NamingCheckId &LHS, const NamingCheckId &RHS)
static unsigned getHashValue(NamingCheckId Val)
clang::tidy::RenamerClangTidyCheck::NamingCheckId NamingCheckId