//===--- RefactoringActionRulesInternal.h - Clang refactoring library -----===// // // 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_TOOLING_REFACTORING_REFACTORINGACTIONRULESINTERNAL_H #define LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGACTIONRULESINTERNAL_H #include "clang/Basic/LLVM.h" #include "clang/Tooling/Refactoring/RefactoringActionRule.h" #include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h" #include "clang/Tooling/Refactoring/RefactoringResultConsumer.h" #include "clang/Tooling/Refactoring/RefactoringRuleContext.h" #include "llvm/Support/Error.h" #include namespace clang { namespace tooling { namespace internal { inline llvm::Error findError() { return llvm::Error::success(); } inline void ignoreError() {} template void ignoreError(Expected &First, Expected &... Rest) { if (!First) llvm::consumeError(First.takeError()); ignoreError(Rest...); } /// Scans the tuple and returns a valid \c Error if any of the values are /// invalid. template llvm::Error findError(Expected &First, Expected &... Rest) { if (!First) { ignoreError(Rest...); return First.takeError(); } return findError(Rest...); } template void invokeRuleAfterValidatingRequirements( RefactoringResultConsumer &Consumer, RefactoringRuleContext &Context, const std::tuple &Requirements, std::index_sequence) { // Check if the requirements we're interested in can be evaluated. auto Values = std::make_tuple(std::get(Requirements).evaluate(Context)...); auto Err = findError(std::get(Values)...); if (Err) return Consumer.handleError(std::move(Err)); // Construct the target action rule by extracting the evaluated // requirements from Expected<> wrappers and then run it. auto Rule = RuleType::initiate(Context, std::move((*std::get(Values)))...); if (!Rule) return Consumer.handleError(Rule.takeError()); Rule->invoke(Consumer, Context); } inline void visitRefactoringOptionsImpl(RefactoringOptionVisitor &) {} /// Scans the list of requirements in a rule and visits all the refactoring /// options that are used by all the requirements. template void visitRefactoringOptionsImpl(RefactoringOptionVisitor &Visitor, const FirstT &First, const RestT &... Rest) { struct OptionGatherer { RefactoringOptionVisitor &Visitor; void operator()(const RefactoringOptionsRequirement &Requirement) { for (const auto &Option : Requirement.getRefactoringOptions()) Option->passToVisitor(Visitor); } void operator()(const RefactoringActionRuleRequirement &) {} }; (OptionGatherer{Visitor})(First); return visitRefactoringOptionsImpl(Visitor, Rest...); } template void visitRefactoringOptions( RefactoringOptionVisitor &Visitor, const std::tuple &Requirements, std::index_sequence) { visitRefactoringOptionsImpl(Visitor, std::get(Requirements)...); } /// A type trait that returns true when the given type list has at least one /// type whose base is the given base type. template struct HasBaseOf : std::conditional_t::value || HasBaseOf::value, std::true_type, std::false_type> {}; template struct HasBaseOf : std::is_base_of {}; /// A type trait that returns true when the given type list contains types that /// derive from Base. template struct AreBaseOf : std::conditional_t::value && AreBaseOf::value, std::true_type, std::false_type> {}; template struct AreBaseOf : std::is_base_of {}; } // end namespace internal template std::unique_ptr createRefactoringActionRule(const RequirementTypes &... Requirements) { static_assert(std::is_base_of::value, "Expected a refactoring action rule type"); static_assert(internal::AreBaseOf::value, "Expected a list of refactoring action rules"); class Rule final : public RefactoringActionRule { public: Rule(std::tuple Requirements) : Requirements(Requirements) {} void invoke(RefactoringResultConsumer &Consumer, RefactoringRuleContext &Context) override { internal::invokeRuleAfterValidatingRequirements( Consumer, Context, Requirements, std::index_sequence_for()); } bool hasSelectionRequirement() override { return internal::HasBaseOf::value; } void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) override { internal::visitRefactoringOptions( Visitor, Requirements, std::index_sequence_for()); } private: std::tuple Requirements; }; return std::make_unique(std::make_tuple(Requirements...)); } } // end namespace tooling } // end namespace clang #endif // LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGACTIONRULESINTERNAL_H