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(),
39 return {DenseMapInfo<clang::SourceLocation>::getTombstoneKey(),
44 assert(Val != getEmptyKey() &&
"Cannot hash the empty key!");
45 assert(Val != getTombstoneKey() &&
"Cannot hash the tombstone key!");
47 return DenseMapInfo<clang::SourceLocation>::getHashValue(Val.first) +
48 DenseMapInfo<StringRef>::getHashValue(Val.second);
52 if (RHS == getEmptyKey())
53 return LHS == getEmptyKey();
54 if (RHS == getTombstoneKey())
55 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(); }
84static const NamedDecl *
findDecl(
const RecordDecl &RecDecl,
86 for (
const Decl *D : RecDecl.decls()) {
87 if (
const auto *ND = dyn_cast<NamedDecl>(D)) {
88 if (ND->getDeclName().isIdentifier() && ND->getName().equals(DeclName))
102 bool AggressiveTemplateLookup) {
103 if (!
Parent.hasDefinition())
104 return NameLookup(
nullptr);
106 return NameLookup(InClassRef);
107 const NamedDecl *Found =
nullptr;
109 for (CXXBaseSpecifier Base :
Parent.bases()) {
110 const auto *Record = Base.getType()->getAsCXXRecordDecl();
111 if (!Record && AggressiveTemplateLookup) {
112 if (
const auto *TST =
113 Base.getType()->getAs<TemplateSpecializationType>()) {
114 if (
const auto *TD = llvm::dyn_cast_or_null<ClassTemplateDecl>(
115 TST->getTemplateName().getAsTemplateDecl()))
116 Record = TD->getTemplatedDecl();
131 return NameLookup(std::nullopt);
133 return NameLookup(Found);
140 if (Method->size_overridden_methods() != 1)
144 Method = *Method->begin_overridden_methods();
145 assert(Method &&
"Overridden method shouldn't be null");
146 unsigned NumOverrides = Method->size_overridden_methods();
147 if (NumOverrides == 0)
149 if (NumOverrides > 1)
157class RenamerClangTidyCheckPPCallbacks :
public PPCallbacks {
159 RenamerClangTidyCheckPPCallbacks(
const SourceManager &SM,
160 RenamerClangTidyCheck *Check)
161 : SM(SM), Check(Check) {}
164 void MacroDefined(
const Token &MacroNameTok,
165 const MacroDirective *MD)
override {
166 const MacroInfo *
Info = MD->getMacroInfo();
167 if (
Info->isBuiltinMacro())
169 if (SM.isWrittenInBuiltinFile(MacroNameTok.getLocation()))
171 if (SM.isWrittenInCommandLineFile(MacroNameTok.getLocation()))
173 Check->checkMacro(SM, MacroNameTok,
Info);
177 void MacroExpands(
const Token &MacroNameTok,
const MacroDefinition &MD,
179 const MacroArgs * )
override {
180 Check->expandMacro(MacroNameTok, MD.getMacroInfo());
184 const SourceManager &SM;
185 RenamerClangTidyCheck *Check;
188class RenamerClangTidyVisitor
191 RenamerClangTidyVisitor(RenamerClangTidyCheck *Check,
const SourceManager *SM,
192 bool AggressiveDependentMemberLookup)
193 : Check(Check), SM(SM),
194 AggressiveDependentMemberLookup(AggressiveDependentMemberLookup) {}
196 static bool hasNoName(
const NamedDecl *
Decl) {
197 return !
Decl->getIdentifier() ||
Decl->getName().empty();
200 bool shouldVisitTemplateInstantiations()
const {
return true; }
202 bool shouldVisitImplicitCode()
const {
return false; }
204 bool VisitCXXConstructorDecl(CXXConstructorDecl *
Decl) {
205 if (
Decl->isImplicit())
207 Check->addUsage(
Decl->getParent(),
Decl->getNameInfo().getSourceRange(),
210 for (
const auto *Init :
Decl->inits()) {
211 if (!Init->isWritten() || Init->isInClassMemberInitializer())
213 if (
const FieldDecl *FD = Init->getAnyMember())
214 Check->addUsage(FD, SourceRange(Init->getMemberLocation()), SM);
222 bool VisitCXXDestructorDecl(CXXDestructorDecl *
Decl) {
223 if (
Decl->isImplicit())
225 SourceRange
Range =
Decl->getNameInfo().getSourceRange();
226 if (
Range.getBegin().isInvalid())
231 Range.setBegin(CharSourceRange::getTokenRange(Range).getEnd());
232 Check->addUsage(
Decl->getParent(), Range, SM);
236 bool VisitUsingDecl(UsingDecl *
Decl) {
237 for (
const auto *Shadow :
Decl->shadows())
238 Check->addUsage(Shadow->getTargetDecl(),
239 Decl->getNameInfo().getSourceRange(), SM);
243 bool VisitUsingDirectiveDecl(UsingDirectiveDecl *
Decl) {
244 Check->addUsage(
Decl->getNominatedNamespaceAsWritten(),
245 Decl->getIdentLocation(), SM);
249 bool VisitNamedDecl(NamedDecl *
Decl) {
253 const auto *
Canonical = cast<NamedDecl>(
Decl->getCanonicalDecl());
254 if (Canonical !=
Decl) {
255 Check->addUsage(Canonical,
Decl->getLocation(), SM);
260 if (
const auto *Method = dyn_cast<CXXMethodDecl>(
Decl)) {
262 Check->addUsage(Overridden,
Method->getLocation());
269 if (isa<ClassTemplateSpecializationDecl>(
Decl))
272 Check->checkNamedDecl(
Decl, *SM);
276 bool VisitDeclRefExpr(DeclRefExpr *
DeclRef) {
277 SourceRange
Range =
DeclRef->getNameInfo().getSourceRange();
278 Check->addUsage(
DeclRef->getDecl(), Range, SM);
282 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc
Loc) {
283 if (
const NestedNameSpecifier *Spec =
Loc.getNestedNameSpecifier()) {
284 if (
const NamespaceDecl *
Decl = Spec->getAsNamespace())
285 Check->addUsage(
Decl,
Loc.getLocalSourceRange(), SM);
289 return Base::TraverseNestedNameSpecifierLoc(
Loc);
292 bool VisitMemberExpr(MemberExpr *MemberRef) {
293 SourceRange
Range = MemberRef->getMemberNameInfo().getSourceRange();
294 Check->addUsage(MemberRef->getMemberDecl(), Range, SM);
299 VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *DepMemberRef) {
300 QualType BaseType = DepMemberRef->isArrow()
301 ? DepMemberRef->getBaseType()->getPointeeType()
302 : DepMemberRef->getBaseType();
303 if (BaseType.isNull())
305 const CXXRecordDecl *Base = BaseType.getTypePtr()->getAsCXXRecordDecl();
308 DeclarationName DeclName = DepMemberRef->getMemberNameInfo().getName();
309 if (!DeclName.isIdentifier())
311 StringRef
DependentName = DeclName.getAsIdentifierInfo()->getName();
314 *Base, DependentName, AggressiveDependentMemberLookup)) {
316 Check->addUsage(*Resolved,
317 DepMemberRef->getMemberNameInfo().getSourceRange(), SM);
323 bool VisitTypedefTypeLoc(
const TypedefTypeLoc &
Loc) {
324 Check->addUsage(
Loc.getTypedefNameDecl(),
Loc.getSourceRange(), SM);
328 bool VisitTagTypeLoc(
const TagTypeLoc &
Loc) {
329 Check->addUsage(
Loc.getDecl(),
Loc.getSourceRange(), SM);
333 bool VisitInjectedClassNameTypeLoc(
const InjectedClassNameTypeLoc &
Loc) {
334 Check->addUsage(
Loc.getDecl(),
Loc.getSourceRange(), SM);
338 bool VisitUnresolvedUsingTypeLoc(
const UnresolvedUsingTypeLoc &
Loc) {
339 Check->addUsage(
Loc.getDecl(),
Loc.getSourceRange(), SM);
343 bool VisitTemplateTypeParmTypeLoc(
const TemplateTypeParmTypeLoc &
Loc) {
344 Check->addUsage(
Loc.getDecl(),
Loc.getSourceRange(), SM);
349 VisitTemplateSpecializationTypeLoc(
const TemplateSpecializationTypeLoc &
Loc) {
350 const TemplateDecl *
Decl =
351 Loc.getTypePtr()->getTemplateName().getAsTemplateDecl();
353 SourceRange
Range(
Loc.getTemplateNameLoc(),
Loc.getTemplateNameLoc());
354 if (
const auto *ClassDecl = dyn_cast<TemplateDecl>(
Decl)) {
355 if (
const NamedDecl *TemplDecl = ClassDecl->getTemplatedDecl())
356 Check->addUsage(TemplDecl, Range, SM);
362 bool VisitDependentTemplateSpecializationTypeLoc(
363 const DependentTemplateSpecializationTypeLoc &
Loc) {
364 if (
const TagDecl *
Decl =
Loc.getTypePtr()->getAsTagDecl())
365 Check->addUsage(
Decl,
Loc.getSourceRange(), SM);
371 RenamerClangTidyCheck *Check;
372 const SourceManager *SM;
373 const bool AggressiveDependentMemberLookup;
381 AggressiveDependentMemberLookup(
382 Options.getLocalOrGlobal(
"AggressiveDependentMemberLookup", false)) {}
387 AggressiveDependentMemberLookup);
391 Finder->addMatcher(translationUnitDecl(),
this);
395 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
396 ModuleExpanderPP->addPPCallbacks(
397 std::make_unique<RenamerClangTidyCheckPPCallbacks>(SM,
this));
402 const SourceManager *SourceMgr) {
404 if (
Range.isInvalid())
411 SourceLocation FixLocation =
Range.getBegin();
413 FixLocation = SourceMgr->getSpellingLoc(FixLocation);
414 if (FixLocation.isInvalid())
420 NamingCheckFailures[
Decl];
427 if (SourceMgr && SourceMgr->isWrittenInScratchSpace(FixLocation))
435 const SourceManager *SourceMgr) {
437 auto *II =
Decl->getIdentifier();
440 if (
const auto *Method = dyn_cast<CXXMethodDecl>(
Decl)) {
444 Decl = cast<NamedDecl>(
Decl->getCanonicalDecl());
451 const SourceManager &SourceMgr) {
460 DeclarationNameInfo(
Decl->getDeclName(),
Decl->getLocation())
463 const IdentifierTable &Idents =
Decl->getASTContext().Idents;
464 auto CheckNewIdentifier = Idents.find(
Info.Fixup);
465 if (CheckNewIdentifier != Idents.end()) {
466 const IdentifierInfo *Ident = CheckNewIdentifier->second;
469 else if (Ident->hasMacroDefinition())
471 }
else if (!isValidAsciiIdentifier(
Info.Fixup)) {
480 RenamerClangTidyVisitor Visitor(
this, Result.SourceManager,
481 AggressiveDependentMemberLookup);
482 Visitor.TraverseAST(*Result.Context);
486 const Token &MacroNameTok,
487 const MacroInfo *MI) {
488 std::optional<FailureInfo> MaybeFailure =
493 StringRef
Name = MacroNameTok.getIdentifierInfo()->getName();
496 SourceRange
Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
498 if (!isValidAsciiIdentifier(
Info.Fixup))
506 const MacroInfo *MI) {
507 StringRef
Name = MacroNameTok.getIdentifierInfo()->getName();
510 auto Failure = NamingCheckFailures.find(
ID);
511 if (Failure == NamingCheckFailures.end())
514 SourceRange
Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
520 const std::string &Fixup) {
523 return "; cannot be fixed automatically";
530 return "; cannot be fixed because '" + Fixup +
531 "' would conflict with a keyword";
534 return "; cannot be fixed because '" + Fixup +
535 "' would conflict with a macro definition";
536 llvm_unreachable(
"invalid ShouldFixStatus");
540 for (
const auto &Pair : NamingCheckFailures) {
566 Diag << FixItHint::CreateReplacement(SourceRange(
Loc),
const FunctionDecl * Decl
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 checkMacro(const SourceManager &SourceMgr, const Token &MacroNameTok, const MacroInfo *MI)
Check Macros for style violations.
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 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 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)
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.
void addUsage(const RenamerClangTidyCheck::NamingCheckId &Decl, SourceRange Range, const SourceManager *SourceMgr=nullptr)
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.
@ 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