Index: clang-tools-extra/clang-tidy/ClangTidy.cpp =================================================================== --- clang-tools-extra/clang-tidy/ClangTidy.cpp +++ clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -41,6 +41,7 @@ #include "clang/Tooling/Tooling.h" #include "llvm/Support/Process.h" #include +#include #include #if CLANG_TIDY_ENABLE_STATIC_ANALYZER @@ -408,6 +409,53 @@ return !Check->isLanguageVersionSupported(Context.getLangOpts()); }); + ClangTidyOptions::OptionMap AllCheckOptions = getCheckOptions(); + + llvm::erase_if(Checks, [&](std::unique_ptr &Check) { + // Do not delete primary checks + if (!Check->isAlias(&Context)) { + return false; + } + + // Get name of primary check + StringRef CheckName = Check->getID(); + StringRef CheckType = Context.MapCheckToCheckType[CheckName]; + StringRef PrimaryCheckName = + Context.MapCheckTypeToChecks[CheckType].front(); + + // If the check is an alias, delete it only if it's a *perfect* alias, + // i.e. it has the same options as the primary check + for (auto const &Option : AllCheckOptions) { + StringRef Key = Option.getKey(); + StringRef Value = Option.getValue().Value; + + if (Key.startswith(CheckName)) { + StringRef OptionName = Key.substr(CheckName.size() + 1); + + std::string PrimaryCheckOptionName = + PrimaryCheckName.str() + "." + OptionName.str(); + StringRef PrimaryCheckValue = + AllCheckOptions[StringRef(PrimaryCheckOptionName)].Value; + + // Found one option that is different from primary check -> keep + if (PrimaryCheckValue != Value) { + std::cout << "Alias check \"" << CheckName.str() << "\" of \"" + << PrimaryCheckName.str() << "\"" + << " has a different option: " << Key.str() << "=" + << Value.str() << " vs " << PrimaryCheckOptionName << "=" + << PrimaryCheckValue.str() + << ". Keeping alias check as it's not a perfect alias" + << std::endl; + return false; + } + } + } + + // We have a perfect alias -> remove + std::cout << "Removing perfect alias " << Check->getID().str() << std::endl; + return true; + }); + ast_matchers::MatchFinder::MatchFinderOptions FinderOptions; std::unique_ptr Profiling; Index: clang-tools-extra/clang-tidy/ClangTidyCheck.h =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyCheck.h +++ clang-tools-extra/clang-tidy/ClangTidyCheck.h @@ -125,6 +125,13 @@ configurationDiag(StringRef Description, DiagnosticIDs::Level Level = DiagnosticIDs::Warning) const; + bool isAlias(ClangTidyContext *Context) { + StringRef CheckType = Context->MapCheckToCheckType[getID()]; + return std::find(Context->MapCheckTypeToChecks[CheckType].begin(), + Context->MapCheckTypeToChecks[CheckType].end(), getID()) != + Context->MapCheckTypeToChecks[CheckType].begin(); + } + /// Should store all options supported by this check with their /// current values or default values for options that haven't been overridden. /// @@ -132,6 +139,8 @@ /// whether it has the default value or it has been overridden. virtual void storeOptions(ClangTidyOptions::OptionMap &Options) {} + StringRef getID() const override { return CheckName; } + /// Provides access to the ``ClangTidyCheck`` options via check-local /// names. /// @@ -408,7 +417,6 @@ private: void run(const ast_matchers::MatchFinder::MatchResult &Result) override; - StringRef getID() const override { return CheckName; } std::string CheckName; ClangTidyContext *Context; Index: clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -182,6 +182,13 @@ DiagEngine->getDiagnosticIDs()->getDescription(DiagnosticID))); } + // { "cppcoreguidelines-avoid-c-arrays": "AvoidCArraysCheck" } + std::map MapCheckToCheckType; + + // { "AvoidCArraysCheck": ["modernize-avoid-c-arrays", + // "cppcoreguidelines-avoid-c-arrays"]} + std::map> MapCheckTypeToChecks; + private: // Writes to Stats. friend class ClangTidyDiagnosticConsumer; Index: clang-tools-extra/clang-tidy/ClangTidyModule.h =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyModule.h +++ clang-tools-extra/clang-tidy/ClangTidyModule.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYMODULE_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYMODULE_H +#include "ClangTidyDiagnosticConsumer.h" #include "ClangTidyOptions.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -21,6 +22,9 @@ class ClangTidyCheck; class ClangTidyContext; +#define CLANG_TIDY_REGISTER_CHECK(Factory, CheckType, CheckName) \ + Factory.registerCheck(CheckName, #CheckType) + /// A collection of \c ClangTidyCheckFactory instances. /// /// All clang-tidy modules register their check factories with an instance of @@ -35,6 +39,9 @@ /// For all checks that have default constructors, use \c registerCheck. void registerCheckFactory(llvm::StringRef Name, CheckFactory Factory); + void registerCheckFactory(llvm::StringRef Name, llvm::StringRef Type, + CheckFactory Factory); + /// Registers the \c CheckType with the name \p Name. /// /// This method should be used for all \c ClangTidyChecks that don't require @@ -63,6 +70,38 @@ }); } + template + void registerCheck(llvm::StringRef CheckName, llvm::StringRef CheckTypeStr) { + registerCheckFactory( + CheckName, [CheckName, CheckTypeStr](llvm::StringRef Name, + ClangTidyContext *Context) { + StringRef CheckTypeStrUnqualified = CheckTypeStr; + bool isAliasCheck = false; + if (CheckTypeStr.contains("::")) { + isAliasCheck = true; + CheckTypeStrUnqualified = + CheckTypeStr.substr(CheckTypeStr.rfind("::") + 2); + } + + Context->MapCheckToCheckType[CheckName] = CheckTypeStrUnqualified; + + // If the check is an alias, we push it to the end of the list of + // checks associated with the check name + if (isAliasCheck) { + Context->MapCheckTypeToChecks[CheckTypeStrUnqualified].push_back( + CheckName); + } + // Otherwise, if we found a primary check, put it first in the list + else { + Context->MapCheckTypeToChecks[CheckTypeStrUnqualified].insert( + Context->MapCheckTypeToChecks[CheckTypeStrUnqualified].begin(), + CheckName); + } + + return std::make_unique(Name, Context); + }); + } + /// Create instances of checks that are enabled. std::vector> createChecks(ClangTidyContext *Context); Index: clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp +++ clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp @@ -45,8 +45,8 @@ class CppCoreGuidelinesModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { - CheckFactories.registerCheck( - "cppcoreguidelines-avoid-c-arrays"); + CLANG_TIDY_REGISTER_CHECK(CheckFactories, modernize::AvoidCArraysCheck, + "cppcoreguidelines-avoid-c-arrays"); CheckFactories.registerCheck( "cppcoreguidelines-avoid-goto"); CheckFactories.registerCheck( @@ -64,7 +64,8 @@ CheckFactories.registerCheck( "cppcoreguidelines-narrowing-conversions"); CheckFactories.registerCheck("cppcoreguidelines-no-malloc"); - CheckFactories.registerCheck( + CLANG_TIDY_REGISTER_CHECK( + CheckFactories, misc::NonPrivateMemberVariablesInClassesCheck, "cppcoreguidelines-non-private-member-variables-in-classes"); CheckFactories.registerCheck( "cppcoreguidelines-owning-memory"); Index: clang-tools-extra/clang-tidy/hicpp/HICPPTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/hicpp/HICPPTidyModule.cpp +++ clang-tools-extra/clang-tidy/hicpp/HICPPTidyModule.cpp @@ -48,8 +48,8 @@ class HICPPModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { - CheckFactories.registerCheck( - "hicpp-avoid-c-arrays"); + CLANG_TIDY_REGISTER_CHECK(CheckFactories, modernize::AvoidCArraysCheck, + "hicpp-avoid-c-arrays"); CheckFactories.registerCheck( "hicpp-avoid-goto"); CheckFactories.registerCheck( Index: clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -42,8 +42,9 @@ CheckFactories.registerCheck("misc-no-recursion"); CheckFactories.registerCheck( "misc-non-copyable-objects"); - CheckFactories.registerCheck( - "misc-non-private-member-variables-in-classes"); + CLANG_TIDY_REGISTER_CHECK(CheckFactories, + NonPrivateMemberVariablesInClassesCheck, + "misc-non-private-member-variables-in-classes"); CheckFactories.registerCheck( "misc-redundant-expression"); CheckFactories.registerCheck("misc-static-assert"); Index: clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -51,7 +51,8 @@ public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck("modernize-avoid-bind"); - CheckFactories.registerCheck("modernize-avoid-c-arrays"); + CLANG_TIDY_REGISTER_CHECK(CheckFactories, AvoidCArraysCheck, + "modernize-avoid-c-arrays"); CheckFactories.registerCheck( "modernize-concat-nested-namespaces"); CheckFactories.registerCheck(