1 //===--- RenamerClangTidyCheck.cpp - clang-tidy ---------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "RenamerClangTidyCheck.h"
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"
24 using namespace clang::ast_matchers
;
28 /// Specialization of DenseMapInfo to allow NamingCheckId objects in DenseMaps
30 struct DenseMapInfo
<clang::tidy::RenamerClangTidyCheck::NamingCheckId
> {
31 using NamingCheckId
= clang::tidy::RenamerClangTidyCheck::NamingCheckId
;
33 static inline NamingCheckId
getEmptyKey() {
34 return NamingCheckId(DenseMapInfo
<clang::SourceLocation
>::getEmptyKey(),
38 static inline NamingCheckId
getTombstoneKey() {
39 return NamingCheckId(DenseMapInfo
<clang::SourceLocation
>::getTombstoneKey(),
43 static unsigned getHashValue(NamingCheckId Val
) {
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
);
51 static bool isEqual(const NamingCheckId
&LHS
, const NamingCheckId
&RHS
) {
52 if (RHS
== getEmptyKey())
53 return LHS
== getEmptyKey();
54 if (RHS
== getTombstoneKey())
55 return LHS
== getTombstoneKey();
62 namespace clang::tidy
{
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(); }
84 static 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
))
95 /// Returns a decl matching the \p DeclName in \p Parent or one of its base
96 /// classes. If \p AggressiveTemplateLookup is `true` then it will check
97 /// template dependent base classes as well.
98 /// If a matching decl is found in multiple base classes then it will return a
99 /// flag indicating the multiple resolutions.
100 static NameLookup
findDeclInBases(const CXXRecordDecl
&Parent
,
102 bool AggressiveTemplateLookup
) {
103 if (!Parent
.hasDefinition())
104 return NameLookup(nullptr);
105 if (const NamedDecl
*InClassRef
= findDecl(Parent
, DeclName
))
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();
122 findDeclInBases(*Record
, DeclName
, AggressiveTemplateLookup
)) {
126 std::nullopt
); // Multiple decls found in different base classes.
131 return NameLookup(std::nullopt
); // Propagate multiple resolution back up.
133 return NameLookup(Found
); // If nullptr, decl wasn't found.
136 /// Returns the function that \p Method is overridding. If There are none or
137 /// multiple overrides it returns nullptr. If the overridden function itself is
138 /// overridding then it will recurse up to find the first decl of the function.
139 static const CXXMethodDecl
*getOverrideMethod(const CXXMethodDecl
*Method
) {
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)
156 /// Callback supplies macros to RenamerClangTidyCheck::checkMacro
157 class RenamerClangTidyCheckPPCallbacks
: public PPCallbacks
{
159 RenamerClangTidyCheckPPCallbacks(const SourceManager
&SM
,
160 RenamerClangTidyCheck
*Check
)
161 : SM(SM
), Check(Check
) {}
163 /// MacroDefined calls checkMacro for macros in the main file
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
);
176 /// MacroExpands calls expandMacro for macros in the main file
177 void MacroExpands(const Token
&MacroNameTok
, const MacroDefinition
&MD
,
178 SourceRange
/*Range*/,
179 const MacroArgs
* /*Args*/) override
{
180 Check
->expandMacro(MacroNameTok
, MD
.getMacroInfo());
184 const SourceManager
&SM
;
185 RenamerClangTidyCheck
*Check
;
188 class RenamerClangTidyVisitor
189 : public RecursiveASTVisitor
<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
);
215 // Note: delegating constructors and base class initializers are handled
216 // via the "typeLoc" matcher.
222 bool VisitCXXDestructorDecl(CXXDestructorDecl
*Decl
) {
223 if (Decl
->isImplicit())
225 SourceRange Range
= Decl
->getNameInfo().getSourceRange();
226 if (Range
.getBegin().isInvalid())
229 // The first token that will be found is the ~ (or the equivalent trigraph),
230 // we want instead to replace the next token, that will be the identifier.
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
);
259 // Fix type aliases in value declarations.
260 if (const auto *Value
= dyn_cast
<ValueDecl
>(Decl
)) {
261 if (const Type
*TypePtr
= Value
->getType().getTypePtrOrNull()) {
262 if (const auto *Typedef
= TypePtr
->getAs
<TypedefType
>())
263 Check
->addUsage(Typedef
->getDecl(), Value
->getSourceRange(), SM
);
267 // Fix type aliases in function declarations.
268 if (const auto *Value
= dyn_cast
<FunctionDecl
>(Decl
)) {
269 if (const auto *Typedef
=
270 Value
->getReturnType().getTypePtr()->getAs
<TypedefType
>())
271 Check
->addUsage(Typedef
->getDecl(), Value
->getSourceRange(), SM
);
272 for (const ParmVarDecl
*Param
: Value
->parameters()) {
273 if (const TypedefType
*Typedef
=
274 Param
->getType().getTypePtr()->getAs
<TypedefType
>())
275 Check
->addUsage(Typedef
->getDecl(), Value
->getSourceRange(), SM
);
279 // Fix overridden methods
280 if (const auto *Method
= dyn_cast
<CXXMethodDecl
>(Decl
)) {
281 if (const CXXMethodDecl
*Overridden
= getOverrideMethod(Method
)) {
282 Check
->addUsage(Overridden
, Method
->getLocation());
283 return true; // Don't try to add the actual decl as a Failure.
287 // Ignore ClassTemplateSpecializationDecl which are creating duplicate
288 // replacements with CXXRecordDecl.
289 if (isa
<ClassTemplateSpecializationDecl
>(Decl
))
292 Check
->checkNamedDecl(Decl
, *SM
);
296 bool VisitDeclRefExpr(DeclRefExpr
*DeclRef
) {
297 SourceRange Range
= DeclRef
->getNameInfo().getSourceRange();
298 Check
->addUsage(DeclRef
->getDecl(), Range
, SM
);
302 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Loc
) {
303 if (const NestedNameSpecifier
*Spec
= Loc
.getNestedNameSpecifier()) {
304 if (const NamespaceDecl
*Decl
= Spec
->getAsNamespace())
305 Check
->addUsage(Decl
, Loc
.getLocalSourceRange(), SM
);
308 using Base
= RecursiveASTVisitor
<RenamerClangTidyVisitor
>;
309 return Base::TraverseNestedNameSpecifierLoc(Loc
);
312 bool VisitMemberExpr(MemberExpr
*MemberRef
) {
313 SourceRange Range
= MemberRef
->getMemberNameInfo().getSourceRange();
314 Check
->addUsage(MemberRef
->getMemberDecl(), Range
, SM
);
319 VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr
*DepMemberRef
) {
320 QualType BaseType
= DepMemberRef
->isArrow()
321 ? DepMemberRef
->getBaseType()->getPointeeType()
322 : DepMemberRef
->getBaseType();
323 if (BaseType
.isNull())
325 const CXXRecordDecl
*Base
= BaseType
.getTypePtr()->getAsCXXRecordDecl();
328 DeclarationName DeclName
= DepMemberRef
->getMemberNameInfo().getName();
329 if (!DeclName
.isIdentifier())
331 StringRef DependentName
= DeclName
.getAsIdentifierInfo()->getName();
333 if (NameLookup Resolved
= findDeclInBases(
334 *Base
, DependentName
, AggressiveDependentMemberLookup
)) {
336 Check
->addUsage(*Resolved
,
337 DepMemberRef
->getMemberNameInfo().getSourceRange(), SM
);
343 bool VisitTagTypeLoc(const TagTypeLoc
&Loc
) {
344 Check
->addUsage(Loc
.getDecl(), Loc
.getSourceRange(), SM
);
348 bool VisitInjectedClassNameTypeLoc(const InjectedClassNameTypeLoc
&Loc
) {
349 Check
->addUsage(Loc
.getDecl(), Loc
.getSourceRange(), SM
);
353 bool VisitUnresolvedUsingTypeLoc(const UnresolvedUsingTypeLoc
&Loc
) {
354 Check
->addUsage(Loc
.getDecl(), Loc
.getSourceRange(), SM
);
358 bool VisitTemplateTypeParmTypeLoc(const TemplateTypeParmTypeLoc
&Loc
) {
359 Check
->addUsage(Loc
.getDecl(), Loc
.getSourceRange(), SM
);
364 VisitTemplateSpecializationTypeLoc(const TemplateSpecializationTypeLoc
&Loc
) {
365 const TemplateDecl
*Decl
=
366 Loc
.getTypePtr()->getTemplateName().getAsTemplateDecl();
368 SourceRange
Range(Loc
.getTemplateNameLoc(), Loc
.getTemplateNameLoc());
369 if (const auto *ClassDecl
= dyn_cast
<TemplateDecl
>(Decl
)) {
370 if (const NamedDecl
*TemplDecl
= ClassDecl
->getTemplatedDecl())
371 Check
->addUsage(TemplDecl
, Range
, SM
);
377 bool VisitDependentTemplateSpecializationTypeLoc(
378 const DependentTemplateSpecializationTypeLoc
&Loc
) {
379 if (const TagDecl
*Decl
= Loc
.getTypePtr()->getAsTagDecl())
380 Check
->addUsage(Decl
, Loc
.getSourceRange(), SM
);
386 RenamerClangTidyCheck
*Check
;
387 const SourceManager
*SM
;
388 const bool AggressiveDependentMemberLookup
;
393 RenamerClangTidyCheck::RenamerClangTidyCheck(StringRef CheckName
,
394 ClangTidyContext
*Context
)
395 : ClangTidyCheck(CheckName
, Context
),
396 AggressiveDependentMemberLookup(
397 Options
.getLocalOrGlobal("AggressiveDependentMemberLookup", false)) {}
398 RenamerClangTidyCheck::~RenamerClangTidyCheck() = default;
400 void RenamerClangTidyCheck::storeOptions(ClangTidyOptions::OptionMap
&Opts
) {
401 Options
.store(Opts
, "AggressiveDependentMemberLookup",
402 AggressiveDependentMemberLookup
);
405 void RenamerClangTidyCheck::registerMatchers(MatchFinder
*Finder
) {
406 Finder
->addMatcher(translationUnitDecl(), this);
409 void RenamerClangTidyCheck::registerPPCallbacks(
410 const SourceManager
&SM
, Preprocessor
*PP
, Preprocessor
*ModuleExpanderPP
) {
411 ModuleExpanderPP
->addPPCallbacks(
412 std::make_unique
<RenamerClangTidyCheckPPCallbacks
>(SM
, this));
415 void RenamerClangTidyCheck::addUsage(
416 const RenamerClangTidyCheck::NamingCheckId
&Decl
, SourceRange Range
,
417 const SourceManager
*SourceMgr
) {
418 // Do nothing if the provided range is invalid.
419 if (Range
.isInvalid())
422 // If we have a source manager, use it to convert to the spelling location for
423 // performing the fix. This is necessary because macros can map the same
424 // spelling location to different source locations, and we only want to fix
425 // the token once, before it is expanded by the macro.
426 SourceLocation FixLocation
= Range
.getBegin();
428 FixLocation
= SourceMgr
->getSpellingLoc(FixLocation
);
429 if (FixLocation
.isInvalid())
432 // Try to insert the identifier location in the Usages map, and bail out if it
433 // is already in there
434 RenamerClangTidyCheck::NamingCheckFailure
&Failure
=
435 NamingCheckFailures
[Decl
];
436 if (!Failure
.RawUsageLocs
.insert(FixLocation
).second
)
439 if (!Failure
.shouldFix())
442 if (SourceMgr
&& SourceMgr
->isWrittenInScratchSpace(FixLocation
))
443 Failure
.FixStatus
= RenamerClangTidyCheck::ShouldFixStatus::InsideMacro
;
445 if (!utils::rangeCanBeFixed(Range
, SourceMgr
))
446 Failure
.FixStatus
= RenamerClangTidyCheck::ShouldFixStatus::InsideMacro
;
449 void RenamerClangTidyCheck::addUsage(const NamedDecl
*Decl
, SourceRange Range
,
450 const SourceManager
*SourceMgr
) {
451 // Don't keep track for non-identifier names.
452 auto *II
= Decl
->getIdentifier();
455 if (const auto *Method
= dyn_cast
<CXXMethodDecl
>(Decl
)) {
456 if (const CXXMethodDecl
*Overridden
= getOverrideMethod(Method
))
459 Decl
= cast
<NamedDecl
>(Decl
->getCanonicalDecl());
461 RenamerClangTidyCheck::NamingCheckId(Decl
->getLocation(), II
->getName()),
465 void RenamerClangTidyCheck::checkNamedDecl(const NamedDecl
*Decl
,
466 const SourceManager
&SourceMgr
) {
467 std::optional
<FailureInfo
> MaybeFailure
= getDeclFailureInfo(Decl
, SourceMgr
);
471 FailureInfo
&Info
= *MaybeFailure
;
472 NamingCheckFailure
&Failure
=
473 NamingCheckFailures
[NamingCheckId(Decl
->getLocation(), Decl
->getName())];
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
;
482 if (Ident
->isKeyword(getLangOpts()))
483 Failure
.FixStatus
= ShouldFixStatus::ConflictsWithKeyword
;
484 else if (Ident
->hasMacroDefinition())
485 Failure
.FixStatus
= ShouldFixStatus::ConflictsWithMacroDefinition
;
486 } else if (!isValidAsciiIdentifier(Info
.Fixup
)) {
487 Failure
.FixStatus
= ShouldFixStatus::FixInvalidIdentifier
;
490 Failure
.Info
= std::move(Info
);
491 addUsage(Decl
, Range
);
494 void RenamerClangTidyCheck::check(const MatchFinder::MatchResult
&Result
) {
495 RenamerClangTidyVisitor
Visitor(this, Result
.SourceManager
,
496 AggressiveDependentMemberLookup
);
497 Visitor
.TraverseAST(*Result
.Context
);
500 void RenamerClangTidyCheck::checkMacro(const SourceManager
&SourceMgr
,
501 const Token
&MacroNameTok
,
502 const MacroInfo
*MI
) {
503 std::optional
<FailureInfo
> MaybeFailure
=
504 getMacroFailureInfo(MacroNameTok
, SourceMgr
);
507 FailureInfo
&Info
= *MaybeFailure
;
508 StringRef Name
= MacroNameTok
.getIdentifierInfo()->getName();
509 NamingCheckId
ID(MI
->getDefinitionLoc(), Name
);
510 NamingCheckFailure
&Failure
= NamingCheckFailures
[ID
];
511 SourceRange
Range(MacroNameTok
.getLocation(), MacroNameTok
.getEndLoc());
513 if (!isValidAsciiIdentifier(Info
.Fixup
))
514 Failure
.FixStatus
= ShouldFixStatus::FixInvalidIdentifier
;
516 Failure
.Info
= std::move(Info
);
520 void RenamerClangTidyCheck::expandMacro(const Token
&MacroNameTok
,
521 const MacroInfo
*MI
) {
522 StringRef Name
= MacroNameTok
.getIdentifierInfo()->getName();
523 NamingCheckId
ID(MI
->getDefinitionLoc(), Name
);
525 auto Failure
= NamingCheckFailures
.find(ID
);
526 if (Failure
== NamingCheckFailures
.end())
529 SourceRange
Range(MacroNameTok
.getLocation(), MacroNameTok
.getEndLoc());
534 getDiagnosticSuffix(const RenamerClangTidyCheck::ShouldFixStatus FixStatus
,
535 const std::string
&Fixup
) {
537 FixStatus
== RenamerClangTidyCheck::ShouldFixStatus::FixInvalidIdentifier
)
538 return "; cannot be fixed automatically";
539 if (FixStatus
== RenamerClangTidyCheck::ShouldFixStatus::ShouldFix
)
542 RenamerClangTidyCheck::ShouldFixStatus::IgnoreFailureThreshold
)
544 if (FixStatus
== RenamerClangTidyCheck::ShouldFixStatus::ConflictsWithKeyword
)
545 return "; cannot be fixed because '" + Fixup
+
546 "' would conflict with a keyword";
548 RenamerClangTidyCheck::ShouldFixStatus::ConflictsWithMacroDefinition
)
549 return "; cannot be fixed because '" + Fixup
+
550 "' would conflict with a macro definition";
551 llvm_unreachable("invalid ShouldFixStatus");
554 void RenamerClangTidyCheck::onEndOfTranslationUnit() {
555 for (const auto &Pair
: NamingCheckFailures
) {
556 const NamingCheckId
&Decl
= Pair
.first
;
557 const NamingCheckFailure
&Failure
= Pair
.second
;
559 if (Failure
.Info
.KindName
.empty())
562 if (Failure
.shouldNotify()) {
563 auto DiagInfo
= getDiagInfo(Decl
, Failure
);
564 auto Diag
= diag(Decl
.first
,
565 DiagInfo
.Text
+ getDiagnosticSuffix(Failure
.FixStatus
,
566 Failure
.Info
.Fixup
));
567 DiagInfo
.ApplyArgs(Diag
);
569 if (Failure
.shouldFix()) {
570 for (const auto &Loc
: Failure
.RawUsageLocs
) {
571 // We assume that the identifier name is made of one token only. This
572 // is always the case as we ignore usages in macros that could build
573 // identifier names by combining multiple tokens.
575 // For destructors, we already take care of it by remembering the
576 // location of the start of the identifier and not the start of the
579 // Other multi-token identifiers, such as operators are not checked at
581 Diag
<< FixItHint::CreateReplacement(SourceRange(Loc
),
589 } // namespace clang::tidy