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);
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 if (SM.isInSystemHeader(MacroNameTok.getLocation()))
199 Check->checkMacro(MacroNameTok, Info, SM);
203 void MacroExpands(
const Token &MacroNameTok,
const MacroDefinition &MD,
205 const MacroArgs * )
override {
206 Check->expandMacro(MacroNameTok, MD.getMacroInfo(), SM);
210 const SourceManager &SM;
211 RenamerClangTidyCheck *Check;
214class RenamerClangTidyVisitor
215 :
public RecursiveASTVisitor<RenamerClangTidyVisitor> {
217 RenamerClangTidyVisitor(RenamerClangTidyCheck *Check,
const SourceManager &SM,
218 bool AggressiveDependentMemberLookup)
219 : Check(Check), SM(SM),
220 AggressiveDependentMemberLookup(AggressiveDependentMemberLookup) {}
222 bool shouldVisitTemplateInstantiations()
const {
return true; }
224 bool shouldVisitImplicitCode()
const {
return false; }
226 bool VisitCXXConstructorDecl(CXXConstructorDecl *Decl) {
227 if (Decl->isImplicit())
229 Check->addUsage(Decl->getParent(), Decl->getNameInfo().getSourceRange(),
232 for (
const auto *Init : Decl->inits()) {
233 if (!Init->isWritten() || Init->isInClassMemberInitializer())
235 if (
const FieldDecl *FD = Init->getAnyMember())
236 Check->addUsage(FD, SourceRange(Init->getMemberLocation()), SM);
244 bool VisitCXXDestructorDecl(CXXDestructorDecl *Decl) {
245 if (Decl->isImplicit())
247 SourceRange Range = Decl->getNameInfo().getSourceRange();
248 if (Range.getBegin().isInvalid())
253 Range.setBegin(CharSourceRange::getTokenRange(Range).getEnd());
254 Check->addUsage(Decl->getParent(), Range, SM);
258 bool VisitUsingDecl(UsingDecl *Decl) {
259 for (
const auto *Shadow : Decl->shadows())
260 Check->addUsage(Shadow->getTargetDecl(),
261 Decl->getNameInfo().getSourceRange(), SM);
265 bool VisitUsingDirectiveDecl(UsingDirectiveDecl *Decl) {
266 Check->addUsage(Decl->getNominatedNamespaceAsWritten(),
267 Decl->getIdentLocation(), SM);
271 bool VisitNamedDecl(NamedDecl *Decl) {
272 const SourceRange UsageRange =
273 DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
275 Check->addUsage(Decl, UsageRange, SM);
279 bool VisitDeclRefExpr(DeclRefExpr *DeclRef) {
280 const SourceRange Range = DeclRef->getNameInfo().getSourceRange();
281 Check->addUsage(DeclRef->getDecl(), Range, SM);
285 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Loc) {
286 if (
const NestedNameSpecifier Spec = Loc.getNestedNameSpecifier();
287 Spec.getKind() == NestedNameSpecifier::Kind::Namespace) {
288 if (
const auto *Decl =
289 dyn_cast<NamespaceDecl>(Spec.getAsNamespaceAndPrefix().Namespace))
290 Check->addUsage(Decl, Loc.getLocalSourceRange(), SM);
293 using Base = RecursiveASTVisitor<RenamerClangTidyVisitor>;
294 return Base::TraverseNestedNameSpecifierLoc(Loc);
297 bool VisitMemberExpr(MemberExpr *MemberRef) {
298 const SourceRange Range = MemberRef->getMemberNameInfo().getSourceRange();
299 Check->addUsage(MemberRef->getMemberDecl(), Range, SM);
304 VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *DepMemberRef) {
305 const QualType BaseType =
306 DepMemberRef->isArrow() ? DepMemberRef->getBaseType()->getPointeeType()
307 : DepMemberRef->getBaseType();
308 if (BaseType.isNull())
310 const CXXRecordDecl *Base = BaseType.getTypePtr()->getAsCXXRecordDecl();
313 const DeclarationName DeclName =
314 DepMemberRef->getMemberNameInfo().getName();
315 if (!DeclName.isIdentifier())
317 const StringRef
DependentName = DeclName.getAsIdentifierInfo()->getName();
320 *Base, DependentName, AggressiveDependentMemberLookup)) {
322 Check->addUsage(*Resolved,
323 DepMemberRef->getMemberNameInfo().getSourceRange(), SM);
329 bool VisitTypedefTypeLoc(
const TypedefTypeLoc &Loc) {
330 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
334 bool VisitTagTypeLoc(
const TagTypeLoc &Loc) {
335 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
339 bool VisitUnresolvedUsingTypeLoc(
const UnresolvedUsingTypeLoc &Loc) {
340 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
344 bool VisitTemplateTypeParmTypeLoc(
const TemplateTypeParmTypeLoc &Loc) {
345 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
350 VisitTemplateSpecializationTypeLoc(
const TemplateSpecializationTypeLoc &Loc) {
351 const TemplateDecl *Decl =
352 Loc.getTypePtr()->getTemplateName().getAsTemplateDecl(
357 if (
const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl))
358 if (
const NamedDecl *TemplDecl = ClassDecl->getTemplatedDecl())
359 Check->addUsage(TemplDecl, Loc.getTemplateNameLoc(), SM);
364 bool VisitDesignatedInitExpr(DesignatedInitExpr *Expr) {
365 for (
const DesignatedInitExpr::Designator &D : Expr->designators()) {
366 if (!
D.isFieldDesignator())
368 const FieldDecl *FD =
D.getFieldDecl();
371 const IdentifierInfo *II = FD->getIdentifier();
374 const SourceRange FixLocation{
D.getFieldLoc(),
D.getFieldLoc()};
375 Check->addUsage(FD, FixLocation, SM);
382 RenamerClangTidyCheck *Check;
383 const SourceManager &SM;
384 const bool AggressiveDependentMemberLookup;
392 AggressiveDependentMemberLookup(
393 Options.get(
"AggressiveDependentMemberLookup", false)) {}
397 Options.store(Opts,
"AggressiveDependentMemberLookup",
398 AggressiveDependentMemberLookup);
402 Finder->addMatcher(translationUnitDecl(),
this);
406 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
407 ModuleExpanderPP->addPPCallbacks(
408 std::make_unique<RenamerClangTidyCheckPPCallbacks>(SM,
this));
411std::pair<RenamerClangTidyCheck::NamingCheckFailureMap::iterator, bool>
414 SourceRange UsageRange,
const SourceManager &SourceMgr) {
416 if (UsageRange.isInvalid())
417 return {NamingCheckFailures.end(),
false};
422 SourceLocation FixLocation = UsageRange.getBegin();
423 FixLocation = SourceMgr.getSpellingLoc(FixLocation);
424 if (FixLocation.isInvalid())
425 return {NamingCheckFailures.end(),
false};
428 if (SourceMgr.isInSystemHeader(FixLocation))
429 return {NamingCheckFailures.end(),
false};
431 auto EmplaceResult = NamingCheckFailures.try_emplace(FailureId);
436 if (!Failure.RawUsageLocs.insert(FixLocation).second)
437 return EmplaceResult;
440 return EmplaceResult;
442 if (SourceMgr.isWrittenInScratchSpace(FixLocation))
448 return EmplaceResult;
452 SourceRange UsageRange,
453 const SourceManager &SourceMgr) {
454 if (SourceMgr.isInSystemHeader(Decl->getLocation()))
462 if (isa<ClassTemplateSpecializationDecl>(Decl))
472 std::optional<FailureInfo> MaybeFailure =
478 FailureDecl->getName());
480 auto [FailureIter, NewFailure] =
addUsage(FailureId, UsageRange, SourceMgr);
482 if (FailureIter == NamingCheckFailures.end()) {
493 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