[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