diff --git a/clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.h b/clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.h --- a/clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.h +++ b/clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.h @@ -31,19 +31,32 @@ // }; class TransformerClangTidyCheck : public ClangTidyCheck { public: - // All cases in \p R must have a non-null \c Explanation, even though \c - // Explanation is optional for RewriteRule in general. Because the primary - // purpose of clang-tidy checks is to provide users with diagnostics, we - // assume that a missing explanation is a bug. If no explanation is desired, - // indicate that explicitly (for example, by passing `text("no explanation")` - // to `makeRule` as the `Explanation` argument). + // \p MakeRule generates the rewrite rule to be used by the check, based on + // the given language and clang-tidy options. It can return \c None to handle + // cases where the options disable the check. + // + // All cases in the rule generated by \p MakeRule must have a non-null \c + // Explanation, even though \c Explanation is optional for RewriteRule in + // general. Because the primary purpose of clang-tidy checks is to provide + // users with diagnostics, we assume that a missing explanation is a bug. If + // no explanation is desired, indicate that explicitly (for example, by + // passing `text("no explanation")` to `makeRule` as the `Explanation` + // argument). + TransformerClangTidyCheck(std::function( + const LangOptions &, const OptionsView &)> + MakeRule, + StringRef Name, ClangTidyContext *Context); + + // Convenience overload of the constructor when the rule doesn't depend on any + // of the language or clang-tidy options. TransformerClangTidyCheck(tooling::RewriteRule R, StringRef Name, ClangTidyContext *Context); + void registerMatchers(ast_matchers::MatchFinder *Finder) final; void check(const ast_matchers::MatchFinder::MatchResult &Result) final; private: - tooling::RewriteRule Rule; + Optional Rule; }; } // namespace utils diff --git a/clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.cpp --- a/clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/utils/TransformerClangTidyCheck.cpp @@ -25,9 +25,23 @@ " explicitly provide an empty explanation if none is desired"); } +TransformerClangTidyCheck::TransformerClangTidyCheck( + std::function(const LangOptions &, + const OptionsView &)> + MakeRule, + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), Rule(MakeRule(getLangOpts(), Options)) { + assert(llvm::all_of(Rule.Cases, [](const RewriteRule::Case &C) { + return C.Explanation != nullptr; + }) && + "clang-tidy checks must have an explanation by default;" + " explicitly provide an empty explanation if none is desired"); +} + void TransformerClangTidyCheck::registerMatchers( ast_matchers::MatchFinder *Finder) { - Finder->addDynamicMatcher(tooling::detail::buildMatcher(Rule), this); + if (Rule) + Finder->addDynamicMatcher(tooling::detail::buildMatcher(*Rule), this); } void TransformerClangTidyCheck::check( @@ -43,7 +57,8 @@ Root->second.getSourceRange().getBegin()); assert(RootLoc.isValid() && "Invalid location for Root node of match."); - RewriteRule::Case Case = tooling::detail::findSelectedCase(Result, Rule); + assert(Rule && "check() should not fire if Rule is None"); + RewriteRule::Case Case = tooling::detail::findSelectedCase(Result, *Rule); Expected> Transformations = tooling::detail::translateEdits(Result, Case.Edits); if (!Transformations) {