[AMDGPU][AsmParser][NFC] Translate parsed MIMG instructions to MCInsts automatically.
[llvm-project.git] / clang-tools-extra / clang-tidy / utils / RenamerClangTidyCheck.cpp
blobee400d88a3a7425f6e2cdfe0ecf59b17c1bc417d
1 //===--- RenamerClangTidyCheck.cpp - clang-tidy ---------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
9 #include "RenamerClangTidyCheck.h"
10 #include "ASTUtils.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"
20 #include <optional>
22 #define DEBUG_TYPE "clang-tidy"
24 using namespace clang::ast_matchers;
26 namespace llvm {
28 /// Specialization of DenseMapInfo to allow NamingCheckId objects in DenseMaps
29 template <>
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(),
35 "EMPTY");
38 static inline NamingCheckId getTombstoneKey() {
39 return NamingCheckId(DenseMapInfo<clang::SourceLocation>::getTombstoneKey(),
40 "TOMBSTONE");
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();
56 return LHS == RHS;
60 } // namespace llvm
62 namespace clang::tidy {
64 namespace {
65 class NameLookup {
66 llvm::PointerIntPair<const NamedDecl *, 1, bool> Data;
68 public:
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(); }
82 } // namespace
84 static const NamedDecl *findDecl(const RecordDecl &RecDecl,
85 StringRef DeclName) {
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))
89 return ND;
92 return nullptr;
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,
101 StringRef DeclName,
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();
119 if (!Record)
120 continue;
121 if (auto Search =
122 findDeclInBases(*Record, DeclName, AggressiveTemplateLookup)) {
123 if (*Search) {
124 if (Found)
125 return NameLookup(
126 std::nullopt); // Multiple decls found in different base classes.
127 Found = *Search;
128 continue;
130 } else
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)
141 return nullptr;
143 while (true) {
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)
148 return Method;
149 if (NumOverrides > 1)
150 return nullptr;
154 namespace {
156 /// Callback supplies macros to RenamerClangTidyCheck::checkMacro
157 class RenamerClangTidyCheckPPCallbacks : public PPCallbacks {
158 public:
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())
168 return;
169 if (SM.isWrittenInBuiltinFile(MacroNameTok.getLocation()))
170 return;
171 if (SM.isWrittenInCommandLineFile(MacroNameTok.getLocation()))
172 return;
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());
183 private:
184 const SourceManager &SM;
185 RenamerClangTidyCheck *Check;
188 class RenamerClangTidyVisitor
189 : public RecursiveASTVisitor<RenamerClangTidyVisitor> {
190 public:
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())
206 return true;
207 Check->addUsage(Decl->getParent(), Decl->getNameInfo().getSourceRange(),
208 SM);
210 for (const auto *Init : Decl->inits()) {
211 if (!Init->isWritten() || Init->isInClassMemberInitializer())
212 continue;
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.
219 return true;
222 bool VisitCXXDestructorDecl(CXXDestructorDecl *Decl) {
223 if (Decl->isImplicit())
224 return true;
225 SourceRange Range = Decl->getNameInfo().getSourceRange();
226 if (Range.getBegin().isInvalid())
227 return true;
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);
233 return true;
236 bool VisitUsingDecl(UsingDecl *Decl) {
237 for (const auto *Shadow : Decl->shadows())
238 Check->addUsage(Shadow->getTargetDecl(),
239 Decl->getNameInfo().getSourceRange(), SM);
240 return true;
243 bool VisitUsingDirectiveDecl(UsingDirectiveDecl *Decl) {
244 Check->addUsage(Decl->getNominatedNamespaceAsWritten(),
245 Decl->getIdentLocation(), SM);
246 return true;
249 bool VisitNamedDecl(NamedDecl *Decl) {
250 if (hasNoName(Decl))
251 return true;
253 const auto *Canonical = cast<NamedDecl>(Decl->getCanonicalDecl());
254 if (Canonical != Decl) {
255 Check->addUsage(Canonical, Decl->getLocation(), SM);
256 return true;
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))
290 return true;
292 Check->checkNamedDecl(Decl, *SM);
293 return true;
296 bool VisitDeclRefExpr(DeclRefExpr *DeclRef) {
297 SourceRange Range = DeclRef->getNameInfo().getSourceRange();
298 Check->addUsage(DeclRef->getDecl(), Range, SM);
299 return true;
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);
315 return true;
318 bool
319 VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *DepMemberRef) {
320 QualType BaseType = DepMemberRef->isArrow()
321 ? DepMemberRef->getBaseType()->getPointeeType()
322 : DepMemberRef->getBaseType();
323 if (BaseType.isNull())
324 return true;
325 const CXXRecordDecl *Base = BaseType.getTypePtr()->getAsCXXRecordDecl();
326 if (!Base)
327 return true;
328 DeclarationName DeclName = DepMemberRef->getMemberNameInfo().getName();
329 if (!DeclName.isIdentifier())
330 return true;
331 StringRef DependentName = DeclName.getAsIdentifierInfo()->getName();
333 if (NameLookup Resolved = findDeclInBases(
334 *Base, DependentName, AggressiveDependentMemberLookup)) {
335 if (*Resolved)
336 Check->addUsage(*Resolved,
337 DepMemberRef->getMemberNameInfo().getSourceRange(), SM);
340 return true;
343 bool VisitTagTypeLoc(const TagTypeLoc &Loc) {
344 Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM);
345 return true;
348 bool VisitInjectedClassNameTypeLoc(const InjectedClassNameTypeLoc &Loc) {
349 Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM);
350 return true;
353 bool VisitUnresolvedUsingTypeLoc(const UnresolvedUsingTypeLoc &Loc) {
354 Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM);
355 return true;
358 bool VisitTemplateTypeParmTypeLoc(const TemplateTypeParmTypeLoc &Loc) {
359 Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM);
360 return true;
363 bool
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);
374 return true;
377 bool VisitDependentTemplateSpecializationTypeLoc(
378 const DependentTemplateSpecializationTypeLoc &Loc) {
379 if (const TagDecl *Decl = Loc.getTypePtr()->getAsTagDecl())
380 Check->addUsage(Decl, Loc.getSourceRange(), SM);
382 return true;
385 private:
386 RenamerClangTidyCheck *Check;
387 const SourceManager *SM;
388 const bool AggressiveDependentMemberLookup;
391 } // namespace
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())
420 return;
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();
427 if (SourceMgr)
428 FixLocation = SourceMgr->getSpellingLoc(FixLocation);
429 if (FixLocation.isInvalid())
430 return;
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)
437 return;
439 if (!Failure.shouldFix())
440 return;
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();
453 if (!II)
454 return;
455 if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
456 if (const CXXMethodDecl *Overridden = getOverrideMethod(Method))
457 Decl = Overridden;
459 Decl = cast<NamedDecl>(Decl->getCanonicalDecl());
460 return addUsage(
461 RenamerClangTidyCheck::NamingCheckId(Decl->getLocation(), II->getName()),
462 Range, SourceMgr);
465 void RenamerClangTidyCheck::checkNamedDecl(const NamedDecl *Decl,
466 const SourceManager &SourceMgr) {
467 std::optional<FailureInfo> MaybeFailure = getDeclFailureInfo(Decl, SourceMgr);
468 if (!MaybeFailure)
469 return;
471 FailureInfo &Info = *MaybeFailure;
472 NamingCheckFailure &Failure =
473 NamingCheckFailures[NamingCheckId(Decl->getLocation(), Decl->getName())];
474 SourceRange Range =
475 DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
476 .getSourceRange();
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);
505 if (!MaybeFailure)
506 return;
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);
517 addUsage(ID, Range);
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())
527 return;
529 SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
530 addUsage(ID, Range);
533 static std::string
534 getDiagnosticSuffix(const RenamerClangTidyCheck::ShouldFixStatus FixStatus,
535 const std::string &Fixup) {
536 if (Fixup.empty() ||
537 FixStatus == RenamerClangTidyCheck::ShouldFixStatus::FixInvalidIdentifier)
538 return "; cannot be fixed automatically";
539 if (FixStatus == RenamerClangTidyCheck::ShouldFixStatus::ShouldFix)
540 return {};
541 if (FixStatus >=
542 RenamerClangTidyCheck::ShouldFixStatus::IgnoreFailureThreshold)
543 return {};
544 if (FixStatus == RenamerClangTidyCheck::ShouldFixStatus::ConflictsWithKeyword)
545 return "; cannot be fixed because '" + Fixup +
546 "' would conflict with a keyword";
547 if (FixStatus ==
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())
560 continue;
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
577 // tilde.
579 // Other multi-token identifiers, such as operators are not checked at
580 // all.
581 Diag << FixItHint::CreateReplacement(SourceRange(Loc),
582 Failure.Info.Fixup);
589 } // namespace clang::tidy