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!");
46 return DenseMapInfo<clang::SourceLocation>::getHashValue(Val.first) +
47 DenseMapInfo<StringRef>::getHashValue(Val.second);
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 const 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);
147 if (
const NamedDecl *InClassRef =
findDecl(Parent, DeclName))
148 return NameLookup(InClassRef);
149 const NamedDecl *Found =
nullptr;
151 for (
const 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);
176 return NameLookup(Found);
182class RenamerClangTidyCheckPPCallbacks :
public PPCallbacks {
184 RenamerClangTidyCheckPPCallbacks(
const SourceManager &SM,
185 RenamerClangTidyCheck *Check)
186 : SM(SM), Check(Check) {}
189 void MacroDefined(
const Token &MacroNameTok,
190 const MacroDirective *MD)
override {
191 const MacroInfo *Info = MD->getMacroInfo();
192 if (Info->isBuiltinMacro())
194 if (SM.isWrittenInBuiltinFile(MacroNameTok.getLocation()))
196 if (SM.isWrittenInCommandLineFile(MacroNameTok.getLocation()))
198 if (SM.isInSystemHeader(MacroNameTok.getLocation()))
200 Check->checkMacro(MacroNameTok, Info, SM);
204 void MacroExpands(
const Token &MacroNameTok,
const MacroDefinition &MD,
206 const MacroArgs * )
override {
207 Check->expandMacro(MacroNameTok, MD.getMacroInfo(), SM);
211 const SourceManager &SM;
212 RenamerClangTidyCheck *Check;
215class RenamerClangTidyVisitor
216 :
public RecursiveASTVisitor<RenamerClangTidyVisitor> {
218 RenamerClangTidyVisitor(RenamerClangTidyCheck *Check,
const SourceManager &SM,
219 bool AggressiveDependentMemberLookup)
220 : Check(Check), SM(SM),
221 AggressiveDependentMemberLookup(AggressiveDependentMemberLookup) {}
223 bool shouldVisitTemplateInstantiations()
const {
return true; }
225 bool shouldVisitImplicitCode()
const {
return false; }
227 bool VisitCXXConstructorDecl(CXXConstructorDecl *Decl) {
228 if (Decl->isImplicit())
230 Check->addUsage(Decl->getParent(), Decl->getNameInfo().getSourceRange(),
233 for (
const auto *Init : Decl->inits()) {
234 if (!Init->isWritten() || Init->isInClassMemberInitializer())
236 if (
const FieldDecl *FD = Init->getAnyMember())
237 Check->addUsage(FD, SourceRange(Init->getMemberLocation()), SM);
245 bool VisitCXXDestructorDecl(CXXDestructorDecl *Decl) {
246 if (Decl->isImplicit())
248 SourceRange Range = Decl->getNameInfo().getSourceRange();
249 if (Range.getBegin().isInvalid())
254 Range.setBegin(CharSourceRange::getTokenRange(Range).getEnd());
255 Check->addUsage(Decl->getParent(), Range, SM);
259 bool VisitUsingDecl(UsingDecl *Decl) {
260 for (
const auto *Shadow : Decl->shadows())
261 Check->addUsage(Shadow->getTargetDecl(),
262 Decl->getNameInfo().getSourceRange(), SM);
266 bool VisitUsingDirectiveDecl(UsingDirectiveDecl *Decl) {
267 Check->addUsage(Decl->getNominatedNamespaceAsWritten(),
268 Decl->getIdentLocation(), SM);
272 bool VisitNamedDecl(NamedDecl *Decl) {
273 const SourceRange UsageRange =
274 DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
276 Check->addUsage(Decl, UsageRange, SM);
280 bool VisitDeclRefExpr(DeclRefExpr *DeclRef) {
281 const SourceRange Range = DeclRef->getNameInfo().getSourceRange();
282 Check->addUsage(DeclRef->getDecl(), Range, SM);
286 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Loc) {
287 if (
const NestedNameSpecifier Spec = Loc.getNestedNameSpecifier();
288 Spec.getKind() == NestedNameSpecifier::Kind::Namespace) {
289 if (
const auto *Decl =
290 dyn_cast<NamespaceDecl>(Spec.getAsNamespaceAndPrefix().Namespace))
291 Check->addUsage(Decl, Loc.getLocalSourceRange(), SM);
294 using Base = RecursiveASTVisitor<RenamerClangTidyVisitor>;
295 return Base::TraverseNestedNameSpecifierLoc(Loc);
298 bool VisitMemberExpr(MemberExpr *MemberRef) {
299 const SourceRange Range = MemberRef->getMemberNameInfo().getSourceRange();
300 Check->addUsage(MemberRef->getMemberDecl(), Range, SM);
305 VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *DepMemberRef) {
306 const QualType BaseType =
307 DepMemberRef->isArrow() ? DepMemberRef->getBaseType()->getPointeeType()
308 : DepMemberRef->getBaseType();
309 if (BaseType.isNull())
311 const CXXRecordDecl *Base = BaseType.getTypePtr()->getAsCXXRecordDecl();
314 const DeclarationName DeclName =
315 DepMemberRef->getMemberNameInfo().getName();
316 if (!DeclName.isIdentifier())
318 const StringRef
DependentName = DeclName.getAsIdentifierInfo()->getName();
321 *Base, DependentName, AggressiveDependentMemberLookup)) {
323 Check->addUsage(*Resolved,
324 DepMemberRef->getMemberNameInfo().getSourceRange(), SM);
330 bool VisitTypedefTypeLoc(
const TypedefTypeLoc &Loc) {
331 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
335 bool VisitTagTypeLoc(
const TagTypeLoc &Loc) {
336 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
340 bool VisitUnresolvedUsingTypeLoc(
const UnresolvedUsingTypeLoc &Loc) {
341 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
345 bool VisitTemplateTypeParmTypeLoc(
const TemplateTypeParmTypeLoc &Loc) {
346 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
351 VisitTemplateSpecializationTypeLoc(
const TemplateSpecializationTypeLoc &Loc) {
352 const TemplateDecl *Decl =
353 Loc.getTypePtr()->getTemplateName().getAsTemplateDecl(
358 if (
const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl))
359 if (
const NamedDecl *TemplDecl = ClassDecl->getTemplatedDecl())
360 Check->addUsage(TemplDecl, Loc.getTemplateNameLoc(), SM);
365 bool VisitDesignatedInitExpr(DesignatedInitExpr *Expr) {
366 for (
const DesignatedInitExpr::Designator &D : Expr->designators()) {
367 if (!
D.isFieldDesignator())
369 const FieldDecl *FD =
D.getFieldDecl();
372 const IdentifierInfo *II = FD->getIdentifier();
375 const SourceRange FixLocation{
D.getFieldLoc(),
D.getFieldLoc()};
376 Check->addUsage(FD, FixLocation, SM);
383 RenamerClangTidyCheck *Check;
384 const SourceManager &SM;
385 const bool AggressiveDependentMemberLookup;
393 AggressiveDependentMemberLookup(
394 Options.get(
"AggressiveDependentMemberLookup", false)) {}
398 Options.store(Opts,
"AggressiveDependentMemberLookup",
399 AggressiveDependentMemberLookup);
403 Finder->addMatcher(translationUnitDecl(),
this);
407 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
408 ModuleExpanderPP->addPPCallbacks(
409 std::make_unique<RenamerClangTidyCheckPPCallbacks>(SM,
this));
412std::pair<RenamerClangTidyCheck::NamingCheckFailureMap::iterator, bool>
415 SourceRange UsageRange,
const SourceManager &SourceMgr) {
417 if (UsageRange.isInvalid())
418 return {NamingCheckFailures.end(),
false};
423 SourceLocation FixLocation = UsageRange.getBegin();
424 FixLocation = SourceMgr.getSpellingLoc(FixLocation);
425 if (FixLocation.isInvalid())
426 return {NamingCheckFailures.end(),
false};
429 if (SourceMgr.isInSystemHeader(FixLocation))
430 return {NamingCheckFailures.end(),
false};
432 auto EmplaceResult = NamingCheckFailures.try_emplace(FailureId);
437 if (!Failure.RawUsageLocs.insert(FixLocation).second)
438 return EmplaceResult;
441 return EmplaceResult;
443 if (SourceMgr.isWrittenInScratchSpace(FixLocation))
449 return EmplaceResult;
453 SourceRange UsageRange,
454 const SourceManager &SourceMgr) {
455 if (SourceMgr.isInSystemHeader(Decl->getLocation()))
463 if (isa<ClassTemplateSpecializationDecl>(Decl))
473 std::optional<FailureInfo> MaybeFailure =
479 FailureDecl->getName());
481 auto [FailureIter, NewFailure] =
addUsage(FailureId, UsageRange, SourceMgr);
483 if (FailureIter == NamingCheckFailures.end()) {
494 Failure.
Info = std::move(*MaybeFailure);
499 const IdentifierTable &Idents = FailureDecl->getASTContext().Idents;
500 auto CheckNewIdentifier = Idents.find(Failure.
Info.
Fixup);
501 if (CheckNewIdentifier != Idents.end()) {
502 const IdentifierInfo *Ident = CheckNewIdentifier->second;
503 if (Ident->isKeyword(getLangOpts()))
505 else if (Ident->hasMacroDefinition())
507 }
else if (!isValidAsciiIdentifier(Failure.
Info.
Fixup)) {
513 if (!Result.SourceManager) {
519 RenamerClangTidyVisitor Visitor(
this, *Result.SourceManager,
520 AggressiveDependentMemberLookup);
521 Visitor.TraverseAST(*Result.Context);
526 const SourceManager &SourceMgr) {
527 std::optional<FailureInfo> MaybeFailure =
532 const StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
535 const SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
537 if (!isValidAsciiIdentifier(Info.Fixup))
540 Failure.
Info = std::move(Info);
546 const SourceManager &SourceMgr) {
547 const StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
550 auto Failure = NamingCheckFailures.find(ID);
551 if (Failure == NamingCheckFailures.end())
554 const SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
560 const std::string &Fixup) {
563 return "; cannot be fixed automatically";
570 return "; cannot be fixed because '" + Fixup +
571 "' would conflict with a keyword";
574 return "; cannot be fixed because '" + Fixup +
575 "' would conflict with a macro definition";
576 llvm_unreachable(
"invalid ShouldFixStatus");
580 for (
const auto &Pair : NamingCheckFailures) {
589 auto Diag = diag(Decl.first,
606 Diag << FixItHint::CreateReplacement(SourceRange(Loc),
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
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.
~RenamerClangTidyCheck() override
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 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.
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