[clang-tools-extra] d5c6b84 - Factor out renaming logic from readability-identifier-naming

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 16 13:35:09 PST 2020


Author: Logan Smith
Date: 2020-01-16T16:34:56-05:00
New Revision: d5c6b8407c12d39a78f42a216369407cb2d7b511

URL: https://github.com/llvm/llvm-project/commit/d5c6b8407c12d39a78f42a216369407cb2d7b511
DIFF: https://github.com/llvm/llvm-project/commit/d5c6b8407c12d39a78f42a216369407cb2d7b511.diff

LOG: Factor out renaming logic from readability-identifier-naming

Before this patch, readability-identifier-naming contained a significant amount
of logic for (a) checking the style of identifiers, followed by (b) renaming/
applying fix-its. This patch factors out (b) into a separate base class so that
it can be reused by other checks that want to do renaming. This also cleans up
readability-identifier-naming significantly, since now it only needs to be
concerned with the interesting details of (a).

Added: 
    clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
    clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h

Modified: 
    clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
    clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
    clang-tools-extra/clang-tidy/utils/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
index 8146cb36cf21..6a39ece09777 100644
--- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -22,44 +22,6 @@
 
 using namespace clang::ast_matchers;
 
-namespace llvm {
-/// Specialisation of DenseMapInfo to allow NamingCheckId objects in DenseMaps
-template <>
-struct DenseMapInfo<
-    clang::tidy::readability::IdentifierNamingCheck::NamingCheckId> {
-  using NamingCheckId =
-      clang::tidy::readability::IdentifierNamingCheck::NamingCheckId;
-
-  static inline NamingCheckId getEmptyKey() {
-    return NamingCheckId(
-        clang::SourceLocation::getFromRawEncoding(static_cast<unsigned>(-1)),
-        "EMPTY");
-  }
-
-  static inline NamingCheckId getTombstoneKey() {
-    return NamingCheckId(
-        clang::SourceLocation::getFromRawEncoding(static_cast<unsigned>(-2)),
-        "TOMBSTONE");
-  }
-
-  static unsigned getHashValue(NamingCheckId Val) {
-    assert(Val != getEmptyKey() && "Cannot hash the empty key!");
-    assert(Val != getTombstoneKey() && "Cannot hash the tombstone key!");
-
-    std::hash<NamingCheckId::second_type> SecondHash;
-    return Val.first.getRawEncoding() + SecondHash(Val.second);
-  }
-
-  static bool isEqual(const NamingCheckId &LHS, const NamingCheckId &RHS) {
-    if (RHS == getEmptyKey())
-      return LHS == getEmptyKey();
-    if (RHS == getTombstoneKey())
-      return LHS == getTombstoneKey();
-    return LHS == RHS;
-  }
-};
-} // namespace llvm
-
 namespace clang {
 namespace tidy {
 namespace readability {
@@ -164,7 +126,7 @@ class IdentifierNamingCheckPPCallbacks : public PPCallbacks {
 
 IdentifierNamingCheck::IdentifierNamingCheck(StringRef Name,
                                              ClangTidyContext *Context)
-    : ClangTidyCheck(Name, Context) {
+    : RenamerClangTidyCheck(Name, Context) {
   auto const fromString = [](StringRef Str) {
     return llvm::StringSwitch<llvm::Optional<CaseType>>(Str)
         .Case("aNy_CasE", CT_AnyCase)
@@ -233,39 +195,6 @@ void IdentifierNamingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "IgnoreFailedSplit", IgnoreFailedSplit);
 }
 
-void IdentifierNamingCheck::registerMatchers(MatchFinder *Finder) {
-  Finder->addMatcher(namedDecl().bind("decl"), this);
-  Finder->addMatcher(usingDecl().bind("using"), this);
-  Finder->addMatcher(declRefExpr().bind("declRef"), this);
-  Finder->addMatcher(cxxConstructorDecl(unless(isImplicit())).bind("classRef"),
-                     this);
-  Finder->addMatcher(cxxDestructorDecl(unless(isImplicit())).bind("classRef"),
-                     this);
-  Finder->addMatcher(typeLoc().bind("typeLoc"), this);
-  Finder->addMatcher(nestedNameSpecifierLoc().bind("nestedNameLoc"), this);
-  Finder->addMatcher(
-      functionDecl(unless(cxxMethodDecl(isImplicit())),
-                   hasBody(forEachDescendant(memberExpr().bind("memberExpr")))),
-      this);
-  Finder->addMatcher(
-      cxxConstructorDecl(
-          unless(isImplicit()),
-          forEachConstructorInitializer(
-              allOf(isWritten(), withInitializer(forEachDescendant(
-                                     memberExpr().bind("memberExpr")))))),
-      this);
-  Finder->addMatcher(fieldDecl(hasInClassInitializer(
-                         forEachDescendant(memberExpr().bind("memberExpr")))),
-                     this);
-}
-
-void IdentifierNamingCheck::registerPPCallbacks(
-    const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
-  ModuleExpanderPP->addPPCallbacks(
-      std::make_unique<IdentifierNamingCheckPPCallbacks>(ModuleExpanderPP,
-                                                          this));
-}
-
 static bool matchesStyle(StringRef Name,
                          IdentifierNamingCheck::NamingStyle Style) {
   static llvm::Regex Matchers[] = {
@@ -683,243 +612,47 @@ static StyleKind findStyleKind(
   return SK_Invalid;
 }
 
-static void addUsage(IdentifierNamingCheck::NamingCheckFailureMap &Failures,
-                     const IdentifierNamingCheck::NamingCheckId &Decl,
-                     SourceRange Range, SourceManager *SourceMgr = nullptr) {
-  // Do nothing if the provided range is invalid.
-  if (Range.getBegin().isInvalid() || Range.getEnd().isInvalid())
-    return;
-
-  // If we have a source manager, use it to convert to the spelling location for
-  // performing the fix. This is necessary because macros can map the same
-  // spelling location to 
diff erent source locations, and we only want to fix
-  // the token once, before it is expanded by the macro.
-  SourceLocation FixLocation = Range.getBegin();
-  if (SourceMgr)
-    FixLocation = SourceMgr->getSpellingLoc(FixLocation);
-  if (FixLocation.isInvalid())
-    return;
-
-  // Try to insert the identifier location in the Usages map, and bail out if it
-  // is already in there
-  auto &Failure = Failures[Decl];
-  if (!Failure.RawUsageLocs.insert(FixLocation.getRawEncoding()).second)
-    return;
-
-  if (!Failure.ShouldFix())
-    return;
-
-  if (!utils::rangeCanBeFixed(Range, SourceMgr))
-    Failure.FixStatus = IdentifierNamingCheck::ShouldFixStatus::InsideMacro;
-}
-
-/// Convenience method when the usage to be added is a NamedDecl
-static void addUsage(IdentifierNamingCheck::NamingCheckFailureMap &Failures,
-                     const NamedDecl *Decl, SourceRange Range,
-                     SourceManager *SourceMgr = nullptr) {
-  return addUsage(Failures,
-                  IdentifierNamingCheck::NamingCheckId(Decl->getLocation(),
-                                                       Decl->getNameAsString()),
-                  Range, SourceMgr);
-}
-
-void IdentifierNamingCheck::check(const MatchFinder::MatchResult &Result) {
-  if (const auto *Decl =
-          Result.Nodes.getNodeAs<CXXConstructorDecl>("classRef")) {
-
-    addUsage(NamingCheckFailures, Decl->getParent(),
-             Decl->getNameInfo().getSourceRange());
-
-    for (const auto *Init : Decl->inits()) {
-      if (!Init->isWritten() || Init->isInClassMemberInitializer())
-        continue;
-      if (const auto *FD = Init->getAnyMember())
-        addUsage(NamingCheckFailures, FD,
-                 SourceRange(Init->getMemberLocation()));
-      // Note: delegating constructors and base class initializers are handled
-      // via the "typeLoc" matcher.
-    }
-    return;
-  }
-
-  if (const auto *Decl =
-          Result.Nodes.getNodeAs<CXXDestructorDecl>("classRef")) {
-
-    SourceRange Range = Decl->getNameInfo().getSourceRange();
-    if (Range.getBegin().isInvalid())
-      return;
-    // The first token that will be found is the ~ (or the equivalent trigraph),
-    // we want instead to replace the next token, that will be the identifier.
-    Range.setBegin(CharSourceRange::getTokenRange(Range).getEnd());
-
-    addUsage(NamingCheckFailures, Decl->getParent(), Range);
-    return;
-  }
-
-  if (const auto *Loc = Result.Nodes.getNodeAs<TypeLoc>("typeLoc")) {
-    NamedDecl *Decl = nullptr;
-    if (const auto &Ref = Loc->getAs<TagTypeLoc>()) {
-      Decl = Ref.getDecl();
-    } else if (const auto &Ref = Loc->getAs<InjectedClassNameTypeLoc>()) {
-      Decl = Ref.getDecl();
-    } else if (const auto &Ref = Loc->getAs<UnresolvedUsingTypeLoc>()) {
-      Decl = Ref.getDecl();
-    } else if (const auto &Ref = Loc->getAs<TemplateTypeParmTypeLoc>()) {
-      Decl = Ref.getDecl();
-    }
-
-    if (Decl) {
-      addUsage(NamingCheckFailures, Decl, Loc->getSourceRange());
-      return;
-    }
-
-    if (const auto &Ref = Loc->getAs<TemplateSpecializationTypeLoc>()) {
-      const auto *Decl =
-          Ref.getTypePtr()->getTemplateName().getAsTemplateDecl();
-
-      SourceRange Range(Ref.getTemplateNameLoc(), Ref.getTemplateNameLoc());
-      if (const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl)) {
-        if (const auto *TemplDecl = ClassDecl->getTemplatedDecl())
-          addUsage(NamingCheckFailures, TemplDecl, Range);
-        return;
-      }
-    }
-
-    if (const auto &Ref =
-            Loc->getAs<DependentTemplateSpecializationTypeLoc>()) {
-      if (const auto *Decl = Ref.getTypePtr()->getAsTagDecl())
-        addUsage(NamingCheckFailures, Decl, Loc->getSourceRange());
-      return;
-    }
-  }
-
-  if (const auto *Loc =
-          Result.Nodes.getNodeAs<NestedNameSpecifierLoc>("nestedNameLoc")) {
-    if (NestedNameSpecifier *Spec = Loc->getNestedNameSpecifier()) {
-      if (NamespaceDecl *Decl = Spec->getAsNamespace()) {
-        addUsage(NamingCheckFailures, Decl, Loc->getLocalSourceRange());
-        return;
-      }
-    }
-  }
-
-  if (const auto *Decl = Result.Nodes.getNodeAs<UsingDecl>("using")) {
-    for (const auto *Shadow : Decl->shadows()) {
-      addUsage(NamingCheckFailures, Shadow->getTargetDecl(),
-               Decl->getNameInfo().getSourceRange());
-    }
-    return;
-  }
-
-  if (const auto *DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>("declRef")) {
-    SourceRange Range = DeclRef->getNameInfo().getSourceRange();
-    addUsage(NamingCheckFailures, DeclRef->getDecl(), Range,
-             Result.SourceManager);
-    return;
-  }
-
-  if (const auto *MemberRef =
-          Result.Nodes.getNodeAs<MemberExpr>("memberExpr")) {
-    SourceRange Range = MemberRef->getMemberNameInfo().getSourceRange();
-    addUsage(NamingCheckFailures, MemberRef->getMemberDecl(), Range,
-             Result.SourceManager);
-    return;
-  }
+llvm::Optional<RenamerClangTidyCheck::FailureInfo>
+IdentifierNamingCheck::GetDeclFailureInfo(const NamedDecl *Decl,
+                                          const SourceManager &SM) const {
+  StyleKind SK = findStyleKind(Decl, NamingStyles);
+  if (SK == SK_Invalid)
+    return None;
 
-  if (const auto *Decl = Result.Nodes.getNodeAs<NamedDecl>("decl")) {
-    if (!Decl->getIdentifier() || Decl->getName().empty() || Decl->isImplicit())
-      return;
-
-    // Fix type aliases in value declarations
-    if (const auto *Value = Result.Nodes.getNodeAs<ValueDecl>("decl")) {
-      if (const auto *TypePtr = Value->getType().getTypePtrOrNull()) {
-        if (const auto *Typedef = TypePtr->getAs<TypedefType>()) {
-          addUsage(NamingCheckFailures, Typedef->getDecl(),
-                   Value->getSourceRange());
-        }
-      }
-    }
+  if (!NamingStyles[SK])
+    return None;
 
-    // Fix type aliases in function declarations
-    if (const auto *Value = Result.Nodes.getNodeAs<FunctionDecl>("decl")) {
-      if (const auto *Typedef =
-              Value->getReturnType().getTypePtr()->getAs<TypedefType>()) {
-        addUsage(NamingCheckFailures, Typedef->getDecl(),
-                 Value->getSourceRange());
-      }
-      for (unsigned i = 0; i < Value->getNumParams(); ++i) {
-        if (const auto *Typedef = Value->parameters()[i]
-                                      ->getType()
-                                      .getTypePtr()
-                                      ->getAs<TypedefType>()) {
-          addUsage(NamingCheckFailures, Typedef->getDecl(),
-                   Value->getSourceRange());
-        }
-      }
-    }
+  const NamingStyle &Style = *NamingStyles[SK];
+  StringRef Name = Decl->getName();
+  if (matchesStyle(Name, Style))
+    return None;
 
-    // Ignore ClassTemplateSpecializationDecl which are creating duplicate
-    // replacements with CXXRecordDecl
-    if (isa<ClassTemplateSpecializationDecl>(Decl))
-      return;
-
-    StyleKind SK = findStyleKind(Decl, NamingStyles);
-    if (SK == SK_Invalid)
-      return;
-
-    if (!NamingStyles[SK])
-      return;
-
-    const NamingStyle &Style = *NamingStyles[SK];
-    StringRef Name = Decl->getName();
-    if (matchesStyle(Name, Style))
-      return;
-
-    std::string KindName = fixupWithCase(StyleNames[SK], CT_LowerCase);
-    std::replace(KindName.begin(), KindName.end(), '_', ' ');
-
-    std::string Fixup = fixupWithStyle(Name, Style);
-    if (StringRef(Fixup).equals(Name)) {
-      if (!IgnoreFailedSplit) {
-        LLVM_DEBUG(llvm::dbgs()
-                   << Decl->getBeginLoc().printToString(*Result.SourceManager)
-                   << llvm::format(": unable to split words for %s '%s'\n",
-                                   KindName.c_str(), Name.str().c_str()));
-      }
-    } else {
-      NamingCheckFailure &Failure = NamingCheckFailures[NamingCheckId(
-          Decl->getLocation(), Decl->getNameAsString())];
-      SourceRange Range =
-          DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
-              .getSourceRange();
-
-      const IdentifierTable &Idents = Decl->getASTContext().Idents;
-      auto CheckNewIdentifier = Idents.find(Fixup);
-      if (CheckNewIdentifier != Idents.end()) {
-        const IdentifierInfo *Ident = CheckNewIdentifier->second;
-        if (Ident->isKeyword(getLangOpts()))
-          Failure.FixStatus = ShouldFixStatus::ConflictsWithKeyword;
-        else if (Ident->hasMacroDefinition())
-          Failure.FixStatus = ShouldFixStatus::ConflictsWithMacroDefinition;
-      }
+  std::string KindName = fixupWithCase(StyleNames[SK], CT_LowerCase);
+  std::replace(KindName.begin(), KindName.end(), '_', ' ');
 
-      Failure.Fixup = std::move(Fixup);
-      Failure.KindName = std::move(KindName);
-      addUsage(NamingCheckFailures, Decl, Range);
+  std::string Fixup = fixupWithStyle(Name, Style);
+  if (StringRef(Fixup).equals(Name)) {
+    if (!IgnoreFailedSplit) {
+      LLVM_DEBUG(llvm::dbgs()
+                 << Decl->getBeginLoc().printToString(SM)
+                 << llvm::format(": unable to split words for %s '%s'\n",
+                                 KindName.c_str(), Name.str().c_str()));
     }
+    return None;
   }
+  return FailureInfo{std::move(KindName), std::move(Fixup)};
 }
 
-void IdentifierNamingCheck::checkMacro(SourceManager &SourceMgr,
-                                       const Token &MacroNameTok,
-                                       const MacroInfo *MI) {
+llvm::Optional<RenamerClangTidyCheck::FailureInfo>
+IdentifierNamingCheck::GetMacroFailureInfo(const Token &MacroNameTok,
+                                           const SourceManager &SM) const {
   if (!NamingStyles[SK_MacroDefinition])
-    return;
+    return None;
 
   StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
   const NamingStyle &Style = *NamingStyles[SK_MacroDefinition];
   if (matchesStyle(Name, Style))
-    return;
+    return None;
 
   std::string KindName =
       fixupWithCase(StyleNames[SK_MacroDefinition], CT_LowerCase);
@@ -929,74 +662,22 @@ void IdentifierNamingCheck::checkMacro(SourceManager &SourceMgr,
   if (StringRef(Fixup).equals(Name)) {
     if (!IgnoreFailedSplit) {
       LLVM_DEBUG(llvm::dbgs()
-                 << MacroNameTok.getLocation().printToString(SourceMgr)
+                 << MacroNameTok.getLocation().printToString(SM)
                  << llvm::format(": unable to split words for %s '%s'\n",
                                  KindName.c_str(), Name.str().c_str()));
     }
-  } else {
-    NamingCheckId ID(MI->getDefinitionLoc(), Name);
-    NamingCheckFailure &Failure = NamingCheckFailures[ID];
-    SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
-
-    Failure.Fixup = std::move(Fixup);
-    Failure.KindName = std::move(KindName);
-    addUsage(NamingCheckFailures, ID, Range);
+    return None;
   }
+  return FailureInfo{std::move(KindName), std::move(Fixup)};
 }
 
-void IdentifierNamingCheck::expandMacro(const Token &MacroNameTok,
-                                        const MacroInfo *MI) {
-  StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
-  NamingCheckId ID(MI->getDefinitionLoc(), Name);
-
-  auto Failure = NamingCheckFailures.find(ID);
-  if (Failure == NamingCheckFailures.end())
-    return;
-
-  SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
-  addUsage(NamingCheckFailures, ID, Range);
-}
-
-void IdentifierNamingCheck::onEndOfTranslationUnit() {
-  for (const auto &Pair : NamingCheckFailures) {
-    const NamingCheckId &Decl = Pair.first;
-    const NamingCheckFailure &Failure = Pair.second;
-
-    if (Failure.KindName.empty())
-      continue;
-
-    if (Failure.ShouldNotify()) {
-      auto Diag =
-          diag(Decl.first,
-               "invalid case style for %0 '%1'%select{|" // Case 0 is empty on
-                                                         // purpose, because we
-                                                         // intent to provide a
-                                                         // fix
-               "; cannot be fixed because '%3' would conflict with a keyword|"
-               "; cannot be fixed because '%3' would conflict with a macro "
-               "definition}2")
-          << Failure.KindName << Decl.second
-          << static_cast<int>(Failure.FixStatus) << Failure.Fixup;
-
-      if (Failure.ShouldFix()) {
-        for (const auto &Loc : Failure.RawUsageLocs) {
-          // We assume that the identifier name is made of one token only. This
-          // is always the case as we ignore usages in macros that could build
-          // identifier names by combining multiple tokens.
-          //
-          // For destructors, we already take care of it by remembering the
-          // location of the start of the identifier and not the start of the
-          // tilde.
-          //
-          // Other multi-token identifiers, such as operators are not checked at
-          // all.
-          Diag << FixItHint::CreateReplacement(
-              SourceRange(SourceLocation::getFromRawEncoding(Loc)),
-              Failure.Fixup);
-        }
-      }
-    }
-  }
+RenamerClangTidyCheck::DiagInfo
+IdentifierNamingCheck::GetDiagInfo(const NamingCheckId &ID,
+                                   const NamingCheckFailure &Failure) const {
+  return DiagInfo{"invalid case style for %0 '%1'",
+                  [&](DiagnosticBuilder &diag) {
+                    diag << Failure.Info.KindName << ID.second;
+                  }};
 }
 
 } // namespace readability

diff  --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
index f4130972a6ea..86cd52f5e751 100644
--- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
@@ -9,8 +9,7 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H
 
-#include "../ClangTidyCheck.h"
-
+#include "../utils/RenamerClangTidyCheck.h"
 namespace clang {
 
 class MacroInfo;
@@ -31,17 +30,12 @@ namespace readability {
 /// 
diff erent rules for 
diff erent kind of identifier. In general, the
 /// rules are falling back to a more generic rule if the specific case is not
 /// configured.
-class IdentifierNamingCheck : public ClangTidyCheck {
+class IdentifierNamingCheck final : public RenamerClangTidyCheck {
 public:
   IdentifierNamingCheck(StringRef Name, ClangTidyContext *Context);
   ~IdentifierNamingCheck();
 
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
-  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
-  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
-  void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
-                           Preprocessor *ModuleExpanderPP) override;
-  void onEndOfTranslationUnit() override;
 
   enum CaseType {
     CT_AnyCase = 0,
@@ -65,66 +59,18 @@ class IdentifierNamingCheck : public ClangTidyCheck {
     std::string Suffix;
   };
 
-  /// This enum will be used in %select of the diagnostic message.
-  /// Each value below IgnoreFailureThreshold should have an error message.
-  enum class ShouldFixStatus {
-    ShouldFix,
-    ConflictsWithKeyword, /// The fixup will conflict with a language keyword,
-                          /// so we can't fix it automatically.
-    ConflictsWithMacroDefinition, /// The fixup will conflict with a macro
-                                  /// definition, so we can't fix it
-                                  /// automatically.
-
-    /// Values pass this threshold will be ignored completely
-    /// i.e no message, no fixup.
-    IgnoreFailureThreshold,
-
-    InsideMacro, /// If the identifier was used or declared within a macro we
-                 /// won't offer a fixup for safety reasons.
-  };
-
-  /// Holds an identifier name check failure, tracking the kind of the
-  /// identifier, its possible fixup and the starting locations of all the
-  /// identifier usages.
-  struct NamingCheckFailure {
-    std::string KindName;
-    std::string Fixup;
-
-    /// Whether the failure should be fixed or not.
-    ///
-    /// ie: if the identifier was used or declared within a macro we won't offer
-    /// a fixup for safety reasons.
-    bool ShouldFix() const { return FixStatus == ShouldFixStatus::ShouldFix; }
-
-    bool ShouldNotify() const {
-      return FixStatus < ShouldFixStatus::IgnoreFailureThreshold;
-    }
-
-    ShouldFixStatus FixStatus = ShouldFixStatus::ShouldFix;
-
-    /// A set of all the identifier usages starting SourceLocation, in
-    /// their encoded form.
-    llvm::DenseSet<unsigned> RawUsageLocs;
-
-    NamingCheckFailure() = default;
-  };
-
-  typedef std::pair<SourceLocation, std::string> NamingCheckId;
-
-  typedef llvm::DenseMap<NamingCheckId, NamingCheckFailure>
-      NamingCheckFailureMap;
-
-  /// Check Macros for style violations.
-  void checkMacro(SourceManager &sourceMgr, const Token &MacroNameTok,
-                  const MacroInfo *MI);
-
-  /// Add a usage of a macro if it already has a violation.
-  void expandMacro(const Token &MacroNameTok, const MacroInfo *MI);
-
 private:
+  llvm::Optional<FailureInfo>
+  GetDeclFailureInfo(const NamedDecl *Decl,
+                     const SourceManager &SM) const override;
+  llvm::Optional<FailureInfo>
+  GetMacroFailureInfo(const Token &MacroNameTok,
+                      const SourceManager &SM) const override;
+  DiagInfo GetDiagInfo(const NamingCheckId &ID,
+                       const NamingCheckFailure &Failure) const override;
+
   std::vector<llvm::Optional<NamingStyle>> NamingStyles;
   bool IgnoreFailedSplit;
-  NamingCheckFailureMap NamingCheckFailures;
 };
 
 } // namespace readability

diff  --git a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt
index fc383a318b9c..885c83798a04 100644
--- a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt
@@ -13,6 +13,7 @@ add_clang_library(clangTidyUtils
   LexerUtils.cpp
   NamespaceAliaser.cpp
   OptionsUtils.cpp
+  RenamerClangTidyCheck.cpp
   TransformerClangTidyCheck.cpp
   TypeTraits.cpp
   UsingInserter.cpp

diff  --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
new file mode 100644
index 000000000000..dfcd0818ea95
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
@@ -0,0 +1,422 @@
+//===--- RenamerClangTidyCheck.cpp - clang-tidy ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RenamerClangTidyCheck.h"
+#include "ASTUtils.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
+
+#define DEBUG_TYPE "clang-tidy"
+
+using namespace clang::ast_matchers;
+
+namespace llvm {
+
+/// Specialisation of DenseMapInfo to allow NamingCheckId objects in DenseMaps
+template <>
+struct DenseMapInfo<clang::tidy::RenamerClangTidyCheck::NamingCheckId> {
+  using NamingCheckId = clang::tidy::RenamerClangTidyCheck::NamingCheckId;
+
+  static inline NamingCheckId getEmptyKey() {
+    return NamingCheckId(
+        clang::SourceLocation::getFromRawEncoding(static_cast<unsigned>(-1)),
+        "EMPTY");
+  }
+
+  static inline NamingCheckId getTombstoneKey() {
+    return NamingCheckId(
+        clang::SourceLocation::getFromRawEncoding(static_cast<unsigned>(-2)),
+        "TOMBSTONE");
+  }
+
+  static unsigned getHashValue(NamingCheckId Val) {
+    assert(Val != getEmptyKey() && "Cannot hash the empty key!");
+    assert(Val != getTombstoneKey() && "Cannot hash the tombstone key!");
+
+    std::hash<NamingCheckId::second_type> SecondHash;
+    return Val.first.getRawEncoding() + SecondHash(Val.second);
+  }
+
+  static bool isEqual(const NamingCheckId &LHS, const NamingCheckId &RHS) {
+    if (RHS == getEmptyKey())
+      return LHS == getEmptyKey();
+    if (RHS == getTombstoneKey())
+      return LHS == getTombstoneKey();
+    return LHS == RHS;
+  }
+};
+
+} // namespace llvm
+
+namespace clang {
+namespace tidy {
+
+namespace {
+
+/// Callback supplies macros to RenamerClangTidyCheck::checkMacro
+class RenamerClangTidyCheckPPCallbacks : public PPCallbacks {
+public:
+  RenamerClangTidyCheckPPCallbacks(Preprocessor *PP,
+                                   RenamerClangTidyCheck *Check)
+      : PP(PP), Check(Check) {}
+
+  /// MacroDefined calls checkMacro for macros in the main file
+  void MacroDefined(const Token &MacroNameTok,
+                    const MacroDirective *MD) override {
+    Check->checkMacro(PP->getSourceManager(), MacroNameTok, MD->getMacroInfo());
+  }
+
+  /// MacroExpands calls expandMacro for macros in the main file
+  void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
+                    SourceRange /*Range*/,
+                    const MacroArgs * /*Args*/) override {
+    Check->expandMacro(MacroNameTok, MD.getMacroInfo());
+  }
+
+private:
+  Preprocessor *PP;
+  RenamerClangTidyCheck *Check;
+};
+
+} // namespace
+
+RenamerClangTidyCheck::RenamerClangTidyCheck(StringRef CheckName,
+                                             ClangTidyContext *Context)
+    : ClangTidyCheck(CheckName, Context) {}
+RenamerClangTidyCheck::~RenamerClangTidyCheck() = default;
+
+void RenamerClangTidyCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(namedDecl().bind("decl"), this);
+  Finder->addMatcher(usingDecl().bind("using"), this);
+  Finder->addMatcher(declRefExpr().bind("declRef"), this);
+  Finder->addMatcher(cxxConstructorDecl(unless(isImplicit())).bind("classRef"),
+                     this);
+  Finder->addMatcher(cxxDestructorDecl(unless(isImplicit())).bind("classRef"),
+                     this);
+  Finder->addMatcher(typeLoc().bind("typeLoc"), this);
+  Finder->addMatcher(nestedNameSpecifierLoc().bind("nestedNameLoc"), this);
+  Finder->addMatcher(
+      functionDecl(unless(cxxMethodDecl(isImplicit())),
+                   hasBody(forEachDescendant(memberExpr().bind("memberExpr")))),
+      this);
+  Finder->addMatcher(
+      cxxConstructorDecl(
+          unless(isImplicit()),
+          forEachConstructorInitializer(
+              allOf(isWritten(), withInitializer(forEachDescendant(
+                                     memberExpr().bind("memberExpr")))))),
+      this);
+  Finder->addMatcher(fieldDecl(hasInClassInitializer(
+                         forEachDescendant(memberExpr().bind("memberExpr")))),
+                     this);
+}
+
+void RenamerClangTidyCheck::registerPPCallbacks(
+    const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
+  ModuleExpanderPP->addPPCallbacks(
+      std::make_unique<RenamerClangTidyCheckPPCallbacks>(ModuleExpanderPP,
+                                                         this));
+}
+
+static void addUsage(RenamerClangTidyCheck::NamingCheckFailureMap &Failures,
+                     const RenamerClangTidyCheck::NamingCheckId &Decl,
+                     SourceRange Range, SourceManager *SourceMgr = nullptr) {
+  // Do nothing if the provided range is invalid.
+  if (Range.getBegin().isInvalid() || Range.getEnd().isInvalid())
+    return;
+
+  // If we have a source manager, use it to convert to the spelling location for
+  // performing the fix. This is necessary because macros can map the same
+  // spelling location to 
diff erent source locations, and we only want to fix
+  // the token once, before it is expanded by the macro.
+  SourceLocation FixLocation = Range.getBegin();
+  if (SourceMgr)
+    FixLocation = SourceMgr->getSpellingLoc(FixLocation);
+  if (FixLocation.isInvalid())
+    return;
+
+  // Try to insert the identifier location in the Usages map, and bail out if it
+  // is already in there
+  RenamerClangTidyCheck::NamingCheckFailure &Failure = Failures[Decl];
+  if (!Failure.RawUsageLocs.insert(FixLocation.getRawEncoding()).second)
+    return;
+
+  if (!Failure.ShouldFix())
+    return;
+
+  if (!utils::rangeCanBeFixed(Range, SourceMgr))
+    Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro;
+}
+
+/// Convenience method when the usage to be added is a NamedDecl
+static void addUsage(RenamerClangTidyCheck::NamingCheckFailureMap &Failures,
+                     const NamedDecl *Decl, SourceRange Range,
+                     SourceManager *SourceMgr = nullptr) {
+  return addUsage(Failures,
+                  RenamerClangTidyCheck::NamingCheckId(Decl->getLocation(),
+                                                       Decl->getNameAsString()),
+                  Range, SourceMgr);
+}
+
+void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) {
+  if (const auto *Decl =
+          Result.Nodes.getNodeAs<CXXConstructorDecl>("classRef")) {
+
+    addUsage(NamingCheckFailures, Decl->getParent(),
+             Decl->getNameInfo().getSourceRange());
+
+    for (const auto *Init : Decl->inits()) {
+      if (!Init->isWritten() || Init->isInClassMemberInitializer())
+        continue;
+      if (const FieldDecl *FD = Init->getAnyMember())
+        addUsage(NamingCheckFailures, FD,
+                 SourceRange(Init->getMemberLocation()));
+      // Note: delegating constructors and base class initializers are handled
+      // via the "typeLoc" matcher.
+    }
+    return;
+  }
+
+  if (const auto *Decl =
+          Result.Nodes.getNodeAs<CXXDestructorDecl>("classRef")) {
+
+    SourceRange Range = Decl->getNameInfo().getSourceRange();
+    if (Range.getBegin().isInvalid())
+      return;
+    // The first token that will be found is the ~ (or the equivalent trigraph),
+    // we want instead to replace the next token, that will be the identifier.
+    Range.setBegin(CharSourceRange::getTokenRange(Range).getEnd());
+
+    addUsage(NamingCheckFailures, Decl->getParent(), Range);
+    return;
+  }
+
+  if (const auto *Loc = Result.Nodes.getNodeAs<TypeLoc>("typeLoc")) {
+    NamedDecl *Decl = nullptr;
+    if (const auto &Ref = Loc->getAs<TagTypeLoc>())
+      Decl = Ref.getDecl();
+    else if (const auto &Ref = Loc->getAs<InjectedClassNameTypeLoc>())
+      Decl = Ref.getDecl();
+    else if (const auto &Ref = Loc->getAs<UnresolvedUsingTypeLoc>())
+      Decl = Ref.getDecl();
+    else if (const auto &Ref = Loc->getAs<TemplateTypeParmTypeLoc>())
+      Decl = Ref.getDecl();
+    // further TypeLocs handled below
+
+    if (Decl) {
+      addUsage(NamingCheckFailures, Decl, Loc->getSourceRange());
+      return;
+    }
+
+    if (const auto &Ref = Loc->getAs<TemplateSpecializationTypeLoc>()) {
+      const TemplateDecl *Decl =
+          Ref.getTypePtr()->getTemplateName().getAsTemplateDecl();
+
+      SourceRange Range(Ref.getTemplateNameLoc(), Ref.getTemplateNameLoc());
+      if (const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl)) {
+        if (const NamedDecl *TemplDecl = ClassDecl->getTemplatedDecl())
+          addUsage(NamingCheckFailures, TemplDecl, Range);
+        return;
+      }
+    }
+
+    if (const auto &Ref =
+            Loc->getAs<DependentTemplateSpecializationTypeLoc>()) {
+      if (const TagDecl *Decl = Ref.getTypePtr()->getAsTagDecl())
+        addUsage(NamingCheckFailures, Decl, Loc->getSourceRange());
+      return;
+    }
+  }
+
+  if (const auto *Loc =
+          Result.Nodes.getNodeAs<NestedNameSpecifierLoc>("nestedNameLoc")) {
+    if (const NestedNameSpecifier *Spec = Loc->getNestedNameSpecifier()) {
+      if (const NamespaceDecl *Decl = Spec->getAsNamespace()) {
+        addUsage(NamingCheckFailures, Decl, Loc->getLocalSourceRange());
+        return;
+      }
+    }
+  }
+
+  if (const auto *Decl = Result.Nodes.getNodeAs<UsingDecl>("using")) {
+    for (const auto *Shadow : Decl->shadows())
+      addUsage(NamingCheckFailures, Shadow->getTargetDecl(),
+               Decl->getNameInfo().getSourceRange());
+    return;
+  }
+
+  if (const auto *DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>("declRef")) {
+    SourceRange Range = DeclRef->getNameInfo().getSourceRange();
+    addUsage(NamingCheckFailures, DeclRef->getDecl(), Range,
+             Result.SourceManager);
+    return;
+  }
+
+  if (const auto *MemberRef =
+          Result.Nodes.getNodeAs<MemberExpr>("memberExpr")) {
+    SourceRange Range = MemberRef->getMemberNameInfo().getSourceRange();
+    addUsage(NamingCheckFailures, MemberRef->getMemberDecl(), Range,
+             Result.SourceManager);
+    return;
+  }
+
+  if (const auto *Decl = Result.Nodes.getNodeAs<NamedDecl>("decl")) {
+    if (!Decl->getIdentifier() || Decl->getName().empty() || Decl->isImplicit())
+      return;
+
+    // Fix type aliases in value declarations.
+    if (const auto *Value = Result.Nodes.getNodeAs<ValueDecl>("decl")) {
+      if (const Type *TypePtr = Value->getType().getTypePtrOrNull()) {
+        if (const auto *Typedef = TypePtr->getAs<TypedefType>())
+          addUsage(NamingCheckFailures, Typedef->getDecl(),
+                   Value->getSourceRange());
+      }
+    }
+
+    // Fix type aliases in function declarations.
+    if (const auto *Value = Result.Nodes.getNodeAs<FunctionDecl>("decl")) {
+      if (const auto *Typedef =
+              Value->getReturnType().getTypePtr()->getAs<TypedefType>())
+        addUsage(NamingCheckFailures, Typedef->getDecl(),
+                 Value->getSourceRange());
+      for (unsigned i = 0; i < Value->getNumParams(); ++i) {
+        if (const TypedefType *Typedef = Value->parameters()[i]
+                                             ->getType()
+                                             .getTypePtr()
+                                             ->getAs<TypedefType>())
+          addUsage(NamingCheckFailures, Typedef->getDecl(),
+                   Value->getSourceRange());
+      }
+    }
+
+    // Ignore ClassTemplateSpecializationDecl which are creating duplicate
+    // replacements with CXXRecordDecl.
+    if (isa<ClassTemplateSpecializationDecl>(Decl))
+      return;
+
+    Optional<FailureInfo> MaybeFailure =
+        GetDeclFailureInfo(Decl, *Result.SourceManager);
+    if (!MaybeFailure)
+      return;
+    FailureInfo &Info = *MaybeFailure;
+    NamingCheckFailure &Failure = NamingCheckFailures[NamingCheckId(
+        Decl->getLocation(), Decl->getNameAsString())];
+    SourceRange Range =
+        DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
+            .getSourceRange();
+
+    const IdentifierTable &Idents = Decl->getASTContext().Idents;
+    auto CheckNewIdentifier = Idents.find(Info.Fixup);
+    if (CheckNewIdentifier != Idents.end()) {
+      const IdentifierInfo *Ident = CheckNewIdentifier->second;
+      if (Ident->isKeyword(getLangOpts()))
+        Failure.FixStatus = ShouldFixStatus::ConflictsWithKeyword;
+      else if (Ident->hasMacroDefinition())
+        Failure.FixStatus = ShouldFixStatus::ConflictsWithMacroDefinition;
+    }
+
+    Failure.Info = std::move(Info);
+    addUsage(NamingCheckFailures, Decl, Range);
+  }
+}
+
+void RenamerClangTidyCheck::checkMacro(SourceManager &SourceMgr,
+                                       const Token &MacroNameTok,
+                                       const MacroInfo *MI) {
+  Optional<FailureInfo> MaybeFailure =
+      GetMacroFailureInfo(MacroNameTok, SourceMgr);
+  if (!MaybeFailure)
+    return;
+  FailureInfo &Info = *MaybeFailure;
+  StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
+  NamingCheckId ID(MI->getDefinitionLoc(), Name);
+  NamingCheckFailure &Failure = NamingCheckFailures[ID];
+  SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
+
+  Failure.Info = std::move(Info);
+  addUsage(NamingCheckFailures, ID, Range);
+}
+
+void RenamerClangTidyCheck::expandMacro(const Token &MacroNameTok,
+                                        const MacroInfo *MI) {
+  StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
+  NamingCheckId ID(MI->getDefinitionLoc(), Name);
+
+  auto Failure = NamingCheckFailures.find(ID);
+  if (Failure == NamingCheckFailures.end())
+    return;
+
+  SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
+  addUsage(NamingCheckFailures, ID, Range);
+}
+
+static std::string
+getDiagnosticSuffix(const RenamerClangTidyCheck::ShouldFixStatus FixStatus,
+                    const std::string &Fixup) {
+  if (Fixup.empty())
+    return "; cannot be fixed automatically";
+  if (FixStatus == RenamerClangTidyCheck::ShouldFixStatus::ShouldFix)
+    return {};
+  if (FixStatus >=
+      RenamerClangTidyCheck::ShouldFixStatus::IgnoreFailureThreshold)
+    return {};
+  if (FixStatus == RenamerClangTidyCheck::ShouldFixStatus::ConflictsWithKeyword)
+    return "; cannot be fixed because '" + Fixup +
+           "' would conflict with a keyword";
+  if (FixStatus ==
+      RenamerClangTidyCheck::ShouldFixStatus::ConflictsWithMacroDefinition)
+    return "; cannot be fixed because '" + Fixup +
+           "' would conflict with a macro definition";
+
+  llvm_unreachable("invalid ShouldFixStatus");
+}
+
+void RenamerClangTidyCheck::onEndOfTranslationUnit() {
+  for (const auto &Pair : NamingCheckFailures) {
+    const NamingCheckId &Decl = Pair.first;
+    const NamingCheckFailure &Failure = Pair.second;
+
+    if (Failure.Info.KindName.empty())
+      continue;
+
+    if (Failure.ShouldNotify()) {
+      auto DiagInfo = GetDiagInfo(Decl, Failure);
+      auto Diag = diag(Decl.first,
+                       DiagInfo.Text + getDiagnosticSuffix(Failure.FixStatus,
+                                                           Failure.Info.Fixup));
+      DiagInfo.ApplyArgs(Diag);
+
+      if (Failure.ShouldFix()) {
+        for (const auto &Loc : Failure.RawUsageLocs) {
+          // We assume that the identifier name is made of one token only. This
+          // is always the case as we ignore usages in macros that could build
+          // identifier names by combining multiple tokens.
+          //
+          // For destructors, we already take care of it by remembering the
+          // location of the start of the identifier and not the start of the
+          // tilde.
+          //
+          // Other multi-token identifiers, such as operators are not checked at
+          // all.
+          Diag << FixItHint::CreateReplacement(
+              SourceRange(SourceLocation::getFromRawEncoding(Loc)),
+              Failure.Info.Fixup);
+        }
+      }
+    }
+  }
+}
+
+} // namespace tidy
+} // namespace clang

diff  --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h
new file mode 100644
index 000000000000..a9182b11b602
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h
@@ -0,0 +1,150 @@
+//===--- RenamderClangTidyCheck.h - clang-tidy ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_RENAMERCLANGTIDYCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_RENAMERCLANGTIDYCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Optional.h"
+#include <string>
+#include <utility>
+
+namespace clang {
+
+class MacroInfo;
+
+namespace tidy {
+
+/// Base class for clang-tidy checks that want to flag declarations and/or
+/// macros for renaming based on customizable criteria.
+class RenamerClangTidyCheck : public ClangTidyCheck {
+public:
+  RenamerClangTidyCheck(StringRef CheckName, ClangTidyContext *Context);
+  ~RenamerClangTidyCheck();
+
+  /// Derived classes should not implement any matching logic themselves; this
+  /// class will do the matching and call the derived class'
+  /// GetDeclFailureInfo() and GetMacroFailureInfo() for determining whether a
+  /// given identifier passes or fails the check.
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override final;
+  void
+  check(const ast_matchers::MatchFinder::MatchResult &Result) override final;
+  void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+                           Preprocessor *ModuleExpanderPP) override final;
+  void onEndOfTranslationUnit() override final;
+
+  /// This enum will be used in %select of the diagnostic message.
+  /// Each value below IgnoreFailureThreshold should have an error message.
+  enum class ShouldFixStatus {
+    ShouldFix,
+
+    /// The fixup will conflict with a language keyword,
+    /// so we can't fix it automatically.
+    ConflictsWithKeyword,
+
+    /// The fixup will conflict with a macro
+    /// definition, so we can't fix it
+    /// automatically.
+    ConflictsWithMacroDefinition,
+
+    /// Values pass this threshold will be ignored completely
+    /// i.e no message, no fixup.
+    IgnoreFailureThreshold,
+
+    /// If the identifier was used or declared within a macro we
+    /// won't offer a fixup for safety reasons.
+    InsideMacro,
+  };
+
+  /// Information describing a failed check
+  struct FailureInfo {
+    std::string KindName; // Tag or misc info to be used as derived classes need
+    std::string Fixup;    // The name that will be proposed as a fix-it hint
+  };
+
+  /// Holds an identifier name check failure, tracking the kind of the
+  /// identifier, its possible fixup and the starting locations of all the
+  /// identifier usages.
+  struct NamingCheckFailure {
+    FailureInfo Info;
+
+    /// Whether the failure should be fixed or not.
+    ///
+    /// e.g.: if the identifier was used or declared within a macro we won't
+    /// offer a fixup for safety reasons.
+    bool ShouldFix() const {
+      return FixStatus == ShouldFixStatus::ShouldFix && !Info.Fixup.empty();
+    }
+
+    bool ShouldNotify() const {
+      return FixStatus < ShouldFixStatus::IgnoreFailureThreshold;
+    }
+
+    ShouldFixStatus FixStatus = ShouldFixStatus::ShouldFix;
+
+    /// A set of all the identifier usages starting SourceLocation, in
+    /// their encoded form.
+    llvm::DenseSet<unsigned> RawUsageLocs;
+
+    NamingCheckFailure() = default;
+  };
+
+  using NamingCheckId = std::pair<SourceLocation, std::string>;
+
+  using NamingCheckFailureMap =
+      llvm::DenseMap<NamingCheckId, NamingCheckFailure>;
+
+  /// Check Macros for style violations.
+  void checkMacro(SourceManager &sourceMgr, const Token &MacroNameTok,
+                  const MacroInfo *MI);
+
+  /// Add a usage of a macro if it already has a violation.
+  void expandMacro(const Token &MacroNameTok, const MacroInfo *MI);
+
+protected:
+  /// Overridden by derived classes, returns information about if and how a Decl
+  /// failed the check. A 'None' result means the Decl did not fail the check.
+  virtual llvm::Optional<FailureInfo>
+  GetDeclFailureInfo(const NamedDecl *Decl, const SourceManager &SM) const = 0;
+
+  /// Overridden by derived classes, returns information about if and how a
+  /// macro failed the check. A 'None' result means the macro did not fail the
+  /// check.
+  virtual llvm::Optional<FailureInfo>
+  GetMacroFailureInfo(const Token &MacroNameTok,
+                      const SourceManager &SM) const = 0;
+
+  /// Represents customized diagnostic text and how arguments should be applied.
+  /// Example usage:
+  ///
+  /// return DiagInfo{"my %1 very %2 special %3 text",
+  ///                  [=](DiagnosticBuilder &diag) {
+  ///                    diag << arg1 << arg2 << arg3;
+  ///                  }};
+  struct DiagInfo {
+    std::string Text;
+    llvm::unique_function<void(DiagnosticBuilder &)> ApplyArgs;
+  };
+
+  /// Overridden by derived classes, returns a description of the diagnostic
+  /// that should be emitted for the given failure. The base class will then
+  /// further customize the diagnostic by adding info about whether the fix-it
+  /// can be automatically applied or not.
+  virtual DiagInfo GetDiagInfo(const NamingCheckId &ID,
+                               const NamingCheckFailure &Failure) const = 0;
+
+private:
+  NamingCheckFailureMap NamingCheckFailures;
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_RENAMERCLANGTIDYCHECK_H


        


More information about the cfe-commits mailing list