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"
20#include "llvm/ADT/ScopeExit.h"
23#define DEBUG_TYPE "clang-tidy"
35 return DenseMapInfo<clang::SourceLocation>::getHashValue(Val.first) +
36 DenseMapInfo<StringRef>::getHashValue(Val.second);
51 llvm::PointerIntPair<const NamedDecl *, 1, bool> Data;
54 explicit NameLookup(
const NamedDecl *ND) : Data(ND, false) {}
55 explicit NameLookup(std::nullopt_t) : Data(nullptr, true) {}
56 explicit NameLookup(std::nullptr_t) : Data(nullptr, false) {}
57 NameLookup() : NameLookup(nullptr) {}
59 bool hasMultipleResolutions()
const {
return Data.getInt(); }
60 const NamedDecl *getDecl()
const {
61 assert(!hasMultipleResolutions() &&
"Found multiple decls");
62 return Data.getPointer();
64 operator bool()
const {
return !hasMultipleResolutions(); }
65 const NamedDecl *operator*()
const {
return getDecl(); }
70static const NamedDecl *
findDecl(
const RecordDecl &RecDecl,
72 for (
const Decl *D : RecDecl.decls())
73 if (
const auto *ND = dyn_cast<NamedDecl>(D);
74 ND && ND->getDeclName().isIdentifier() && ND->getName() == DeclName)
83 if (Method->size_overridden_methods() != 1)
87 Method = *Method->begin_overridden_methods();
88 assert(Method &&
"Overridden method shouldn't be null");
89 const unsigned NumOverrides = Method->size_overridden_methods();
90 if (NumOverrides == 0)
98 return !Decl->getIdentifier() || Decl->getName().empty();
102 const auto *Canonical = cast<NamedDecl>(ND->getCanonicalDecl());
106 if (
const auto *Method = dyn_cast<CXXMethodDecl>(ND)) {
108 Canonical = Overridden->getCanonicalDecl();
109 else if (
const FunctionTemplateDecl *Primary = Method->getPrimaryTemplate())
110 if (
const FunctionDecl *TemplatedDecl = Primary->getTemplatedDecl())
111 Canonical = TemplatedDecl->getCanonicalDecl();
129 bool AggressiveTemplateLookup,
131 if (!Parent.hasDefinition())
132 return NameLookup(
nullptr);
134 const auto *Definition = Parent.getDefinition();
135 if (!Visited.insert(Definition).second)
136 return NameLookup(
nullptr);
137 const auto RemoveFromVisited =
138 llvm::scope_exit([&Visited, Definition] { Visited.erase(Definition); });
140 if (
const NamedDecl *InClassRef =
findDecl(Parent, DeclName))
141 return NameLookup(InClassRef);
142 const NamedDecl *Found =
nullptr;
144 for (
const CXXBaseSpecifier Base : Parent.bases()) {
145 const auto *Record = Base.getType()->getAsCXXRecordDecl();
146 if (!Record && AggressiveTemplateLookup) {
147 if (
const auto *TST =
148 Base.getType()->getAs<TemplateSpecializationType>()) {
149 if (
const auto *TD = dyn_cast_or_null<ClassTemplateDecl>(
150 TST->getTemplateName().getAsTemplateDecl()))
151 Record = TD->getTemplatedDecl();
157 *Record, DeclName, AggressiveTemplateLookup, Visited)) {
166 return NameLookup(std::nullopt);
169 return NameLookup(Found);
175class RenamerClangTidyCheckPPCallbacks :
public PPCallbacks {
177 RenamerClangTidyCheckPPCallbacks(
const SourceManager &SM,
178 RenamerClangTidyCheck *Check)
179 : SM(SM), Check(Check) {}
182 void MacroDefined(
const Token &MacroNameTok,
183 const MacroDirective *
MD)
override {
184 const MacroInfo *Info =
MD->getMacroInfo();
185 if (Info->isBuiltinMacro())
187 if (SM.isWrittenInBuiltinFile(MacroNameTok.getLocation()))
189 if (SM.isWrittenInCommandLineFile(MacroNameTok.getLocation()))
191 if (SM.isInSystemHeader(MacroNameTok.getLocation()))
193 Check->checkMacro(MacroNameTok, Info, SM);
197 void MacroExpands(
const Token &MacroNameTok,
const MacroDefinition &
MD,
199 const MacroArgs * )
override {
200 Check->expandMacro(MacroNameTok,
MD.getMacroInfo(), SM);
204 const SourceManager &SM;
205 RenamerClangTidyCheck *Check;
208class RenamerClangTidyVisitor
209 :
public RecursiveASTVisitor<RenamerClangTidyVisitor> {
211 RenamerClangTidyVisitor(RenamerClangTidyCheck *Check,
const SourceManager &SM,
212 bool AggressiveDependentMemberLookup)
213 : Check(Check), SM(SM),
214 AggressiveDependentMemberLookup(AggressiveDependentMemberLookup) {}
216 bool shouldVisitTemplateInstantiations()
const {
return true; }
218 bool shouldVisitImplicitCode()
const {
return false; }
220 bool VisitCXXConstructorDecl(CXXConstructorDecl *Decl) {
221 if (Decl->isImplicit())
223 Check->addUsage(Decl->getParent(), Decl->getNameInfo().getSourceRange(),
226 for (
const auto *Init : Decl->inits()) {
227 if (!Init->isWritten() || Init->isInClassMemberInitializer())
229 if (
const FieldDecl *FD = Init->getAnyMember())
230 Check->addUsage(FD, SourceRange(Init->getMemberLocation()), SM);
238 bool VisitCXXDestructorDecl(CXXDestructorDecl *Decl) {
239 if (Decl->isImplicit())
241 SourceRange Range = Decl->getNameInfo().getSourceRange();
242 if (Range.getBegin().isInvalid())
247 Range.setBegin(CharSourceRange::getTokenRange(Range).getEnd());
248 Check->addUsage(Decl->getParent(), Range, SM);
252 bool VisitUsingDecl(UsingDecl *Decl) {
253 for (
const auto *Shadow : Decl->shadows())
254 Check->addUsage(Shadow->getTargetDecl(),
255 Decl->getNameInfo().getSourceRange(), SM);
259 bool VisitUsingDirectiveDecl(UsingDirectiveDecl *Decl) {
260 Check->addUsage(Decl->getNominatedNamespaceAsWritten(),
261 Decl->getIdentLocation(), SM);
265 bool VisitNamedDecl(NamedDecl *Decl) {
266 const SourceRange UsageRange =
267 DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
269 Check->addUsage(Decl, UsageRange, SM);
273 bool VisitDeclRefExpr(DeclRefExpr *DeclRef) {
274 const SourceRange Range = DeclRef->getNameInfo().getSourceRange();
275 Check->addUsage(DeclRef->getDecl(), Range, SM);
279 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Loc) {
280 if (
const NestedNameSpecifier Spec = Loc.getNestedNameSpecifier();
281 Spec.getKind() == NestedNameSpecifier::Kind::Namespace) {
282 if (
const auto *Decl =
283 dyn_cast<NamespaceDecl>(Spec.getAsNamespaceAndPrefix().Namespace))
284 Check->addUsage(Decl, Loc.getLocalSourceRange(), SM);
287 using Base = RecursiveASTVisitor<RenamerClangTidyVisitor>;
288 return Base::TraverseNestedNameSpecifierLoc(Loc);
291 bool VisitMemberExpr(MemberExpr *MemberRef) {
292 const SourceRange Range = MemberRef->getMemberNameInfo().getSourceRange();
293 Check->addUsage(MemberRef->getMemberDecl(), Range, SM);
298 VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *DepMemberRef) {
299 const QualType BaseType =
300 DepMemberRef->isArrow() ? DepMemberRef->getBaseType()->getPointeeType()
301 : DepMemberRef->getBaseType();
302 if (BaseType.isNull())
304 const CXXRecordDecl *Base = BaseType.getTypePtr()->getAsCXXRecordDecl();
307 const DeclarationName DeclName =
308 DepMemberRef->getMemberNameInfo().getName();
309 if (!DeclName.isIdentifier())
311 const StringRef
DependentName = DeclName.getAsIdentifierInfo()->getName();
315 *Base, DependentName, AggressiveDependentMemberLookup, Visited)) {
317 Check->addUsage(*Resolved,
318 DepMemberRef->getMemberNameInfo().getSourceRange(), SM);
324 bool VisitTypedefTypeLoc(
const TypedefTypeLoc &Loc) {
325 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
329 bool VisitTagTypeLoc(
const TagTypeLoc &Loc) {
330 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
334 bool VisitUnresolvedUsingTypeLoc(
const UnresolvedUsingTypeLoc &Loc) {
335 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
339 bool VisitTemplateTypeParmTypeLoc(
const TemplateTypeParmTypeLoc &Loc) {
340 Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
345 VisitTemplateSpecializationTypeLoc(
const TemplateSpecializationTypeLoc &Loc) {
346 const TemplateDecl *Decl =
347 Loc.getTypePtr()->getTemplateName().getAsTemplateDecl(
352 if (
const NamedDecl *TemplDecl = Decl->getTemplatedDecl())
353 Check->addUsage(TemplDecl, Loc.getTemplateNameLoc(), SM);
358 bool VisitDesignatedInitExpr(DesignatedInitExpr *Expr) {
359 for (
const DesignatedInitExpr::Designator &D : Expr->designators()) {
360 if (!
D.isFieldDesignator())
362 const FieldDecl *FD =
D.getFieldDecl();
365 const IdentifierInfo *II = FD->getIdentifier();
368 const SourceRange FixLocation{
D.getFieldLoc(),
D.getFieldLoc()};
369 Check->addUsage(FD, FixLocation, SM);
376 RenamerClangTidyCheck *Check;
377 const SourceManager &SM;
378 const bool AggressiveDependentMemberLookup;
386 AggressiveDependentMemberLookup(
387 Options.get(
"AggressiveDependentMemberLookup", false)) {}
391 Options.store(Opts,
"AggressiveDependentMemberLookup",
392 AggressiveDependentMemberLookup);
396 Finder->addMatcher(translationUnitDecl(),
this);
400 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
401 ModuleExpanderPP->addPPCallbacks(
402 std::make_unique<RenamerClangTidyCheckPPCallbacks>(SM,
this));
405std::pair<RenamerClangTidyCheck::NamingCheckFailureMap::iterator, bool>
408 SourceRange UsageRange,
const SourceManager &SourceMgr) {
410 if (UsageRange.isInvalid())
411 return {NamingCheckFailures.end(),
false};
416 SourceLocation FixLocation = UsageRange.getBegin();
417 FixLocation = SourceMgr.getSpellingLoc(FixLocation);
418 if (FixLocation.isInvalid())
419 return {NamingCheckFailures.end(),
false};
422 if (SourceMgr.isInSystemHeader(FixLocation))
423 return {NamingCheckFailures.end(),
false};
425 auto EmplaceResult = NamingCheckFailures.try_emplace(FailureId);
430 if (!Failure.RawUsageLocs.insert(FixLocation).second)
431 return EmplaceResult;
434 return EmplaceResult;
436 if (SourceMgr.isWrittenInScratchSpace(FixLocation))
442 return EmplaceResult;
446 SourceRange UsageRange,
447 const SourceManager &SourceMgr) {
448 if (SourceMgr.isInSystemHeader(Decl->getLocation()))
456 if (isa<ClassTemplateSpecializationDecl>(Decl))
466 std::optional<FailureInfo> MaybeFailure =
472 FailureDecl->getName());
474 auto [FailureIter, NewFailure] =
addUsage(FailureId, UsageRange, SourceMgr);
476 if (FailureIter == NamingCheckFailures.end()) {
487 Failure.Info = std::move(*MaybeFailure);
490 if (!Failure.shouldFix())
492 const IdentifierTable &Idents = FailureDecl->getASTContext().Idents;
493 const auto CheckNewIdentifier = Idents.find(Failure.Info.Fixup);
494 if (CheckNewIdentifier != Idents.end()) {
495 const IdentifierInfo *Ident = CheckNewIdentifier->second;
496 if (Ident->isKeyword(getLangOpts()))
498 else if (Ident->hasMacroDefinition())
500 }
else if (!isValidAsciiIdentifier(Failure.Info.Fixup)) {
506 if (!Result.SourceManager) {
512 RenamerClangTidyVisitor Visitor(
this, *Result.SourceManager,
513 AggressiveDependentMemberLookup);
514 Visitor.TraverseAST(*Result.Context);
519 const SourceManager &SourceMgr) {
520 std::optional<FailureInfo> MaybeFailure =
525 const StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
528 const SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
530 if (!isValidAsciiIdentifier(Info.Fixup))
533 Failure.Info = std::move(Info);
539 const SourceManager &SourceMgr) {
540 const StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
543 const auto Failure = NamingCheckFailures.find(ID);
544 if (Failure == NamingCheckFailures.end())
547 const SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
553 const std::string &Fixup) {
556 return "; cannot be fixed automatically";
563 return "; cannot be fixed because '" + Fixup +
564 "' would conflict with a keyword";
567 return "; cannot be fixed because '" + Fixup +
568 "' would conflict with a macro definition";
569 llvm_unreachable(
"invalid ShouldFixStatus");
573 for (
const auto &[Decl, Failure] : NamingCheckFailures) {
574 if (Failure.Info.KindName.empty())
577 if (Failure.shouldNotify()) {
579 auto Diag = diag(Decl.first,
581 Failure.Info.Fixup));
584 if (Failure.shouldFix()) {
585 for (
const auto &Loc : Failure.RawUsageLocs) {
596 Diag << FixItHint::CreateReplacement(SourceRange(Loc),
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for Markdown output.")
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 std::string getDiagnosticSuffix(const RenamerClangTidyCheck::ShouldFixStatus FixStatus, const std::string &Fixup)
llvm::SmallPtrSet< const CXXRecordDecl *, 4 > RecursionProtectionSet
static const CXXMethodDecl * getOverrideMethod(const CXXMethodDecl *Method)
Returns the function that Method is overriding.
static NameLookup findDeclInBases(const CXXRecordDecl &Parent, StringRef DeclName, bool AggressiveTemplateLookup, RecursionProtectionSet &Visited)
Returns a decl matching the DeclName in Parent or one of its base classes.
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...
static bool isEqual(const NamingCheckId &LHS, const NamingCheckId &RHS)
static unsigned getHashValue(NamingCheckId Val)
clang::tidy::RenamerClangTidyCheck::NamingCheckId NamingCheckId