Index: clang-tools-extra/clang-tidy/ClangTidy.cpp =================================================================== --- clang-tools-extra/clang-tidy/ClangTidy.cpp +++ clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -445,6 +445,17 @@ if (Context.isCheckEnabled(CheckFactory.first)) CheckNames.push_back(CheckFactory.first); } + for (const auto &AliasCheckFactory : CheckFactories->aliases()) { + if (Context.isCheckEnabled(AliasCheckFactory.first)) + CheckNames.push_back(AliasCheckFactory.first); + for (auto StringRefPair = + StringRef(AliasCheckFactory.second.first).split(';'); + !StringRefPair.first.empty(); + StringRefPair = StringRefPair.second.split(';')) { + if (Context.isCheckEnabled(StringRefPair.first)) + CheckNames.push_back(StringRefPair.first); + } + } #if CLANG_ENABLE_STATIC_ANALYZER for (const auto &AnalyzerCheck : getAnalyzerCheckersAndPackages( Index: clang-tools-extra/clang-tidy/ClangTidyCheck.h =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyCheck.h +++ clang-tools-extra/clang-tidy/ClangTidyCheck.h @@ -170,7 +170,7 @@ int64_t Value) const; private: - std::string NamePrefix; + SmallVector NamePrefixes; const ClangTidyOptions::OptionMap &CheckOptions; }; Index: clang-tools-extra/clang-tidy/ClangTidyCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyCheck.cpp +++ clang-tools-extra/clang-tidy/ClangTidyCheck.cpp @@ -7,12 +7,13 @@ //===----------------------------------------------------------------------===// #include "ClangTidyCheck.h" +#include "llvm/ADT/SmallVector.h" namespace clang { namespace tidy { ClangTidyCheck::ClangTidyCheck(StringRef CheckName, ClangTidyContext *Context) - : CheckName(CheckName), Context(Context), + : CheckName(CheckName.split(';').first), Context(Context), Options(CheckName, Context->getOptions().CheckOptions) { assert(Context != nullptr); assert(!CheckName.empty()); @@ -30,35 +31,46 @@ check(Result); } -ClangTidyCheck::OptionsView::OptionsView(StringRef CheckName, - const ClangTidyOptions::OptionMap &CheckOptions) - : NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions) {} +ClangTidyCheck::OptionsView::OptionsView( + StringRef CheckName, const ClangTidyOptions::OptionMap &CheckOptions) + : CheckOptions(CheckOptions) { + llvm::SmallVector CheckNames; + CheckName.split(CheckNames, ';', -1, false); + for (const auto &Name : CheckNames) { + NamePrefixes.emplace_back((Name + ".").str()); + } + assert(!NamePrefixes.empty()); +} std::string ClangTidyCheck::OptionsView::get(StringRef LocalName, StringRef Default) const { - const auto &Iter = CheckOptions.find(NamePrefix + LocalName.str()); - if (Iter != CheckOptions.end()) - return Iter->second; + for (const auto &NamePrefix : NamePrefixes) { + const auto &Iter = CheckOptions.find(NamePrefix + LocalName.str()); + if (Iter != CheckOptions.end()) + return Iter->second; + } return Default; } std::string ClangTidyCheck::OptionsView::getLocalOrGlobal(StringRef LocalName, StringRef Default) const { - auto Iter = CheckOptions.find(NamePrefix + LocalName.str()); - if (Iter != CheckOptions.end()) - return Iter->second; - // Fallback to global setting, if present. - Iter = CheckOptions.find(LocalName.str()); - if (Iter != CheckOptions.end()) - return Iter->second; + for (const auto &NamePrefix : NamePrefixes) { + auto Iter = CheckOptions.find(NamePrefix + LocalName.str()); + if (Iter != CheckOptions.end()) + return Iter->second; + // Fallback to global setting, if present. + Iter = CheckOptions.find(LocalName.str()); + if (Iter != CheckOptions.end()) + return Iter->second; + } return Default; } void ClangTidyCheck::OptionsView::store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const { - Options[NamePrefix + LocalName.str()] = Value; + Options[NamePrefixes.front() + LocalName.str()] = Value; } void ClangTidyCheck::OptionsView::store(ClangTidyOptions::OptionMap &Options, Index: clang-tools-extra/clang-tidy/ClangTidyModule.h =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyModule.h +++ clang-tools-extra/clang-tidy/ClangTidyModule.h @@ -11,6 +11,7 @@ #include "ClangTidy.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" #include #include #include @@ -34,6 +35,13 @@ /// For all checks that have default constructors, use \c registerCheck. void registerCheckFactory(StringRef Name, CheckFactory Factory); + /// Registers check \p Factory with name \p Name that is an alias to + /// another check called \p AliasToName. + /// + /// For all checks that have default constructors, use \c registerCheck. + void registerCheckFactory(StringRef Name, StringRef AliasToName, + CheckFactory Factory); + /// Registers the \c CheckType with the name \p Name. /// /// This method should be used for all \c ClangTidyChecks that don't require @@ -62,6 +70,16 @@ }); } + /// Registers the \c CheckType with the name \p Name that is an alias to + /// another check called \p AliasToName. + template + void registerCheck(StringRef CheckName, StringRef AliasToName) { + registerCheckFactory(CheckName, AliasToName, + [](StringRef Name, ClangTidyContext *Context) { + return std::make_unique(Name, Context); + }); + } + /// Create instances of checks that are enabled. std::vector> createChecks(ClangTidyContext *Context); @@ -69,10 +87,22 @@ typedef std::map FactoryMap; FactoryMap::const_iterator begin() const { return Factories.begin(); } FactoryMap::const_iterator end() const { return Factories.end(); } - bool empty() const { return Factories.empty(); } + typedef std::map> + AliasFactoryMap; + AliasFactoryMap::const_iterator alias_begin() const { + return AliasFactories.begin(); + } + AliasFactoryMap::const_iterator alias_end() const { + return AliasFactories.end(); + } + llvm::iterator_range aliases() const { + return {alias_begin(), alias_end()}; + } + bool empty() const { return Factories.empty() && AliasFactories.empty(); } private: FactoryMap Factories; + AliasFactoryMap AliasFactories; }; /// A clang-tidy module groups a number of \c ClangTidyChecks and gives Index: clang-tools-extra/clang-tidy/ClangTidyModule.cpp =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyModule.cpp +++ clang-tools-extra/clang-tidy/ClangTidyModule.cpp @@ -11,15 +11,31 @@ //===----------------------------------------------------------------------===// #include "ClangTidyModule.h" +#include "llvm/Support/raw_ostream.h" +#include namespace clang { namespace tidy { void ClangTidyCheckFactories::registerCheckFactory(StringRef Name, CheckFactory Factory) { + if (AliasFactories.count(Name)) + return; // Check already registered as alias Factories[Name] = std::move(Factory); } +void ClangTidyCheckFactories::registerCheckFactory(StringRef Name, + StringRef AliasToName, + CheckFactory Factory) { + Factories.erase(AliasToName); + auto &Current = AliasFactories[AliasToName]; + if (Current.second) // Check if already declared + Current.first.append((";" + Name).str()); + else + Current = std::make_pair(Name, std::move(Factory)); + assert(AliasFactories.count(AliasToName) != 0); +} + std::vector> ClangTidyCheckFactories::createChecks(ClangTidyContext *Context) { std::vector> Checks; @@ -27,6 +43,23 @@ if (Context->isCheckEnabled(Factory.first)) Checks.emplace_back(Factory.second(Factory.first, Context)); } + for (const auto &AliasFactory : AliasFactories) { + SmallString<256> Buffer; + llvm::raw_svector_ostream Builder(Buffer); + if (Context->isCheckEnabled(AliasFactory.first)) + Builder << AliasFactory.first << ';'; + SmallVector Split; + StringRef AliasNames = AliasFactory.second.first; + AliasNames.split(Split, ';', -1, false); + for (StringRef Aliases : Split) { + if (Context->isCheckEnabled(Aliases)) + Builder << Aliases << ';'; + } + if (!Buffer.empty()) { + Buffer.pop_back(); // Remove the last ';' + Checks.emplace_back(AliasFactory.second.second(Buffer, Context)); + } + } return Checks; } Index: clang-tools-extra/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/docs/ReleaseNotes.rst +++ clang-tools-extra/docs/ReleaseNotes.rst @@ -67,6 +67,9 @@ Improvements to clang-tidy -------------------------- +- Clang tidy is now aware of alias checks and will only run one instance of + an alias check that's enabled by different names. + New checks ^^^^^^^^^^