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();
65 llvm::PointerIntPair<const NamedDecl *, 1, bool> Data;
68 explicit NameLookup(
const NamedDecl *ND) : Data(ND, false) {}
69 explicit NameLookup(std::nullopt_t) : Data(nullptr, true) {}
70 explicit NameLookup(std::nullptr_t) : Data(nullptr, false) {}
71 NameLookup() : NameLookup(nullptr) {}
73 bool hasMultipleResolutions()
const {
return Data.getInt(); }
74 const NamedDecl *getDecl()
const {
75 assert(!hasMultipleResolutions() &&
"Found multiple decls");
76 return Data.getPointer();
78 operator bool()
const {
return !hasMultipleResolutions(); }
79 const NamedDecl *operator*()
const {
return getDecl(); }
83static const NamedDecl *
findDecl(
const RecordDecl &RecDecl,
85 for (
const Decl *D : RecDecl.decls()) {
86 if (
const auto *ND = dyn_cast<NamedDecl>(D)) {
87 if (ND->getDeclName().isIdentifier() && ND->getName().equals(DeclName))
101 bool AggressiveTemplateLookup) {
102 if (!
Parent.hasDefinition())
103 return NameLookup(
nullptr);
105 return NameLookup(InClassRef);
106 const NamedDecl *Found =
nullptr;
108 for (CXXBaseSpecifier Base :
Parent.bases()) {
109 const auto *Record = Base.getType()->getAsCXXRecordDecl();
110 if (!Record && AggressiveTemplateLookup) {
111 if (
const auto *TST =
112 Base.getType()->getAs<TemplateSpecializationType>()) {
113 if (
const auto *TD = llvm::dyn_cast_or_null<ClassTemplateDecl>(
114 TST->getTemplateName().getAsTemplateDecl()))
115 Record = TD->getTemplatedDecl();
130 return NameLookup(std::nullopt);
132 return NameLookup(Found);
139 if (Method->size_overridden_methods() != 1)
143 Method = *Method->begin_overridden_methods();
144 assert(Method &&
"Overridden method shouldn't be null");
145 unsigned NumOverrides = Method->size_overridden_methods();
146 if (NumOverrides == 0)
148 if (NumOverrides > 1)
156class RenamerClangTidyCheckPPCallbacks :
public PPCallbacks {
158 RenamerClangTidyCheckPPCallbacks(
const SourceManager &SM,
159 RenamerClangTidyCheck *Check)
160 : SM(SM), Check(Check) {}
163 void MacroDefined(
const Token &MacroNameTok,
164 const MacroDirective *MD)
override {
165 const MacroInfo *
Info = MD->getMacroInfo();
166 if (
Info->isBuiltinMacro())
168 if (SM.isWrittenInBuiltinFile(MacroNameTok.getLocation()))
170 if (SM.isWrittenInCommandLineFile(MacroNameTok.getLocation()))
172 Check->checkMacro(MacroNameTok,
Info, SM);
176 void MacroExpands(
const Token &MacroNameTok,
const MacroDefinition &MD,
178 const MacroArgs * )
override {
179 Check->expandMacro(MacroNameTok, MD.getMacroInfo(), SM);
183 const SourceManager &SM;
184 RenamerClangTidyCheck *Check;
187class RenamerClangTidyVisitor
190 RenamerClangTidyVisitor(RenamerClangTidyCheck *Check,
const SourceManager &SM,
191 bool AggressiveDependentMemberLookup)
192 : Check(Check), SM(SM),
193 AggressiveDependentMemberLookup(AggressiveDependentMemberLookup) {}
195 static bool hasNoName(
const NamedDecl *
Decl) {
196 return !
Decl->getIdentifier() ||
Decl->getName().empty();
199 bool shouldVisitTemplateInstantiations()
const {
return true; }
201 bool shouldVisitImplicitCode()
const {
return false; }
203 bool VisitCXXConstructorDecl(CXXConstructorDecl *
Decl) {
204 if (
Decl->isImplicit())
206 Check->addUsage(
Decl->getParent(),
Decl->getNameInfo().getSourceRange(),
209 for (
const auto *Init :
Decl->inits()) {
210 if (!Init->isWritten() || Init->isInClassMemberInitializer())
212 if (
const FieldDecl *FD = Init->getAnyMember())
213 Check->addUsage(FD, SourceRange(Init->getMemberLocation()), SM);
221 bool VisitCXXDestructorDecl(CXXDestructorDecl *
Decl) {
222 if (
Decl->isImplicit())
224 SourceRange
Range =
Decl->getNameInfo().getSourceRange();
225 if (
Range.getBegin().isInvalid())
230 Range.setBegin(CharSourceRange::getTokenRange(Range).getEnd());
231 Check->addUsage(
Decl->getParent(), Range, SM);
235 bool VisitUsingDecl(UsingDecl *
Decl) {
236 for (
const auto *Shadow :
Decl->shadows())
237 Check->addUsage(Shadow->getTargetDecl(),
238 Decl->getNameInfo().getSourceRange(), SM);
242 bool VisitUsingDirectiveDecl(UsingDirectiveDecl *
Decl) {
243 Check->addUsage(
Decl->getNominatedNamespaceAsWritten(),
244 Decl->getIdentLocation(), SM);
248 bool VisitNamedDecl(NamedDecl *
Decl) {
252 const auto *
Canonical = cast<NamedDecl>(
Decl->getCanonicalDecl());
253 if (Canonical !=
Decl) {
254 Check->addUsage(Canonical,
Decl->getLocation(), SM);
259 if (
const auto *Method = dyn_cast<CXXMethodDecl>(
Decl)) {
261 Check->addUsage(Overridden,
Method->getLocation(), SM);
268 if (isa<ClassTemplateSpecializationDecl>(
Decl))
271 Check->checkNamedDecl(
Decl, SM);
275 bool VisitDeclRefExpr(DeclRefExpr *
DeclRef) {
276 SourceRange
Range =
DeclRef->getNameInfo().getSourceRange();
277 Check->addUsage(
DeclRef->getDecl(), Range, SM);
281 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc
Loc) {
282 if (
const NestedNameSpecifier *Spec =
Loc.getNestedNameSpecifier()) {
283 if (
const NamespaceDecl *
Decl = Spec->getAsNamespace())
284 Check->addUsage(
Decl,
Loc.getLocalSourceRange(), SM);
288 return Base::TraverseNestedNameSpecifierLoc(
Loc);
291 bool VisitMemberExpr(MemberExpr *MemberRef) {
292 SourceRange
Range = MemberRef->getMemberNameInfo().getSourceRange();
293 Check->addUsage(MemberRef->getMemberDecl(), Range, SM);
298 VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *DepMemberRef) {
299 QualType BaseType = DepMemberRef->isArrow()
300 ? DepMemberRef->getBaseType()->getPointeeType()
301 : DepMemberRef->getBaseType();
302 if (BaseType.isNull())
304 const CXXRecordDecl *Base = BaseType.getTypePtr()->getAsCXXRecordDecl();
307 DeclarationName DeclName = DepMemberRef->getMemberNameInfo().getName();
308 if (!DeclName.isIdentifier())
310 StringRef
DependentName = DeclName.getAsIdentifierInfo()->getName();
313 *Base, DependentName, AggressiveDependentMemberLookup)) {
315 Check->addUsage(*Resolved,
316 DepMemberRef->getMemberNameInfo().getSourceRange(), SM);
322 bool VisitTypedefTypeLoc(
const TypedefTypeLoc &
Loc) {
323 Check->addUsage(
Loc.getTypedefNameDecl(),
Loc.getSourceRange(), SM);
327 bool VisitTagTypeLoc(
const TagTypeLoc &
Loc) {
328 Check->addUsage(
Loc.getDecl(),
Loc.getSourceRange(), SM);
332 bool VisitInjectedClassNameTypeLoc(
const InjectedClassNameTypeLoc &
Loc) {
333 Check->addUsage(
Loc.getDecl(),
Loc.getSourceRange(), SM);
337 bool VisitUnresolvedUsingTypeLoc(
const UnresolvedUsingTypeLoc &
Loc) {
338 Check->addUsage(
Loc.getDecl(),
Loc.getSourceRange(), SM);
342 bool VisitTemplateTypeParmTypeLoc(
const TemplateTypeParmTypeLoc &
Loc) {
343 Check->addUsage(
Loc.getDecl(),
Loc.getSourceRange(), SM);
348 VisitTemplateSpecializationTypeLoc(
const TemplateSpecializationTypeLoc &
Loc) {
349 const TemplateDecl *
Decl =
350 Loc.getTypePtr()->getTemplateName().getAsTemplateDecl();
352 SourceRange
Range(
Loc.getTemplateNameLoc(),
Loc.getTemplateNameLoc());
353 if (
const auto *ClassDecl = dyn_cast<TemplateDecl>(
Decl)) {
354 if (
const NamedDecl *TemplDecl = ClassDecl->getTemplatedDecl())
355 Check->addUsage(TemplDecl, Range, SM);
361 bool VisitDependentTemplateSpecializationTypeLoc(
362 const DependentTemplateSpecializationTypeLoc &
Loc) {
363 if (
const TagDecl *
Decl =
Loc.getTypePtr()->getAsTagDecl())
364 Check->addUsage(
Decl,
Loc.getSourceRange(), SM);
369 bool VisitDesignatedInitExpr(DesignatedInitExpr *Expr) {
370 for (
const DesignatedInitExpr::Designator &D : Expr->designators()) {
371 if (!D.isFieldDesignator())
373 const FieldDecl *FD = D.getFieldDecl();
376 const IdentifierInfo *II = FD->getIdentifier();
379 SourceRange FixLocation{D.getFieldLoc(), D.getFieldLoc()};
380 Check->addUsage(FD, FixLocation, SM);
387 RenamerClangTidyCheck *Check;
388 const SourceManager &SM;
389 const bool AggressiveDependentMemberLookup;
397 AggressiveDependentMemberLookup(
398 Options.getLocalOrGlobal(
"AggressiveDependentMemberLookup", false)) {}
403 AggressiveDependentMemberLookup);
407 Finder->addMatcher(translationUnitDecl(),
this);
411 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
412 ModuleExpanderPP->addPPCallbacks(
413 std::make_unique<RenamerClangTidyCheckPPCallbacks>(SM,
this));
418 const SourceManager &SourceMgr) {
420 if (
Range.isInvalid())
427 SourceLocation FixLocation =
Range.getBegin();
428 FixLocation = SourceMgr.getSpellingLoc(FixLocation);
429 if (FixLocation.isInvalid())
435 NamingCheckFailures[
Decl];
442 if (SourceMgr.isWrittenInScratchSpace(FixLocation))
450 const SourceManager &SourceMgr) {
452 auto *II =
Decl->getIdentifier();
455 if (
const auto *Method = dyn_cast<CXXMethodDecl>(
Decl)) {
459 Decl = cast<NamedDecl>(
Decl->getCanonicalDecl());
466 const SourceManager &SourceMgr) {
475 DeclarationNameInfo(
Decl->getDeclName(),
Decl->getLocation())
478 const IdentifierTable &Idents =
Decl->getASTContext().Idents;
479 auto CheckNewIdentifier = Idents.find(
Info.Fixup);
480 if (CheckNewIdentifier != Idents.end()) {
481 const IdentifierInfo *Ident = CheckNewIdentifier->second;
484 else if (Ident->hasMacroDefinition())
486 }
else if (!isValidAsciiIdentifier(
Info.Fixup)) {
495 if (!Result.SourceManager) {
501 RenamerClangTidyVisitor Visitor(
this, *Result.SourceManager,
502 AggressiveDependentMemberLookup);
503 Visitor.TraverseAST(*Result.Context);
508 const SourceManager &SourceMgr) {
509 std::optional<FailureInfo> MaybeFailure =
514 StringRef
Name = MacroNameTok.getIdentifierInfo()->getName();
517 SourceRange
Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
519 if (!isValidAsciiIdentifier(
Info.Fixup))
528 const SourceManager &SourceMgr) {
529 StringRef
Name = MacroNameTok.getIdentifierInfo()->getName();
532 auto Failure = NamingCheckFailures.find(
ID);
533 if (Failure == NamingCheckFailures.end())
536 SourceRange
Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
542 const std::string &Fixup) {
545 return "; cannot be fixed automatically";
552 return "; cannot be fixed because '" + Fixup +
553 "' would conflict with a keyword";
556 return "; cannot be fixed because '" + Fixup +
557 "' would conflict with a macro definition";
558 llvm_unreachable(
"invalid ShouldFixStatus");
562 for (
const auto &Pair : NamingCheckFailures) {
588 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.
void checkNamedDecl(const NamedDecl *Decl, const SourceManager &SourceMgr)
std::pair< SourceLocation, StringRef > NamingCheckId
void addUsage(const RenamerClangTidyCheck::NamingCheckId &Decl, SourceRange Range, const SourceManager &SourceMgr)
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.
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.
@ Canonical
The two mix because the types refer to the same CanonicalType, but we do not elaborate as to how.
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 * 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...
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