RefactoringActionRulesInternal.h revision 360784
1//===--- RefactoringActionRulesInternal.h - Clang refactoring library -----===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8 9#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H 10#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H 11 12#include "clang/Basic/LLVM.h" 13#include "clang/Tooling/Refactoring/RefactoringActionRule.h" 14#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h" 15#include "clang/Tooling/Refactoring/RefactoringResultConsumer.h" 16#include "clang/Tooling/Refactoring/RefactoringRuleContext.h" 17#include "llvm/Support/Error.h" 18#include <type_traits> 19 20namespace clang { 21namespace tooling { 22namespace internal { 23 24inline llvm::Error findError() { return llvm::Error::success(); } 25 26inline void ignoreError() {} 27 28template <typename FirstT, typename... RestT> 29void ignoreError(Expected<FirstT> &First, Expected<RestT> &... Rest) { 30 if (!First) 31 llvm::consumeError(First.takeError()); 32 ignoreError(Rest...); 33} 34 35/// Scans the tuple and returns a valid \c Error if any of the values are 36/// invalid. 37template <typename FirstT, typename... RestT> 38llvm::Error findError(Expected<FirstT> &First, Expected<RestT> &... Rest) { 39 if (!First) { 40 ignoreError(Rest...); 41 return First.takeError(); 42 } 43 return findError(Rest...); 44} 45 46template <typename RuleType, typename... RequirementTypes, size_t... Is> 47void invokeRuleAfterValidatingRequirements( 48 RefactoringResultConsumer &Consumer, RefactoringRuleContext &Context, 49 const std::tuple<RequirementTypes...> &Requirements, 50 std::index_sequence<Is...>) { 51 // Check if the requirements we're interested in can be evaluated. 52 auto Values = 53 std::make_tuple(std::get<Is>(Requirements).evaluate(Context)...); 54 auto Err = findError(std::get<Is>(Values)...); 55 if (Err) 56 return Consumer.handleError(std::move(Err)); 57 // Construct the target action rule by extracting the evaluated 58 // requirements from Expected<> wrappers and then run it. 59 auto Rule = 60 RuleType::initiate(Context, std::move((*std::get<Is>(Values)))...); 61 if (!Rule) 62 return Consumer.handleError(Rule.takeError()); 63 Rule->invoke(Consumer, Context); 64} 65 66inline void visitRefactoringOptionsImpl(RefactoringOptionVisitor &) {} 67 68/// Scans the list of requirements in a rule and visits all the refactoring 69/// options that are used by all the requirements. 70template <typename FirstT, typename... RestT> 71void visitRefactoringOptionsImpl(RefactoringOptionVisitor &Visitor, 72 const FirstT &First, const RestT &... Rest) { 73 struct OptionGatherer { 74 RefactoringOptionVisitor &Visitor; 75 76 void operator()(const RefactoringOptionsRequirement &Requirement) { 77 for (const auto &Option : Requirement.getRefactoringOptions()) 78 Option->passToVisitor(Visitor); 79 } 80 void operator()(const RefactoringActionRuleRequirement &) {} 81 }; 82 (OptionGatherer{Visitor})(First); 83 return visitRefactoringOptionsImpl(Visitor, Rest...); 84} 85 86template <typename... RequirementTypes, size_t... Is> 87void visitRefactoringOptions( 88 RefactoringOptionVisitor &Visitor, 89 const std::tuple<RequirementTypes...> &Requirements, 90 std::index_sequence<Is...>) { 91 visitRefactoringOptionsImpl(Visitor, std::get<Is>(Requirements)...); 92} 93 94/// A type trait that returns true when the given type list has at least one 95/// type whose base is the given base type. 96template <typename Base, typename First, typename... Rest> 97struct HasBaseOf : std::conditional<HasBaseOf<Base, First>::value || 98 HasBaseOf<Base, Rest...>::value, 99 std::true_type, std::false_type>::type {}; 100 101template <typename Base, typename T> 102struct HasBaseOf<Base, T> : std::is_base_of<Base, T> {}; 103 104/// A type trait that returns true when the given type list contains types that 105/// derive from Base. 106template <typename Base, typename First, typename... Rest> 107struct AreBaseOf : std::conditional<AreBaseOf<Base, First>::value && 108 AreBaseOf<Base, Rest...>::value, 109 std::true_type, std::false_type>::type {}; 110 111template <typename Base, typename T> 112struct AreBaseOf<Base, T> : std::is_base_of<Base, T> {}; 113 114} // end namespace internal 115 116template <typename RuleType, typename... RequirementTypes> 117std::unique_ptr<RefactoringActionRule> 118createRefactoringActionRule(const RequirementTypes &... Requirements) { 119 static_assert(std::is_base_of<RefactoringActionRuleBase, RuleType>::value, 120 "Expected a refactoring action rule type"); 121 static_assert(internal::AreBaseOf<RefactoringActionRuleRequirement, 122 RequirementTypes...>::value, 123 "Expected a list of refactoring action rules"); 124 125 class Rule final : public RefactoringActionRule { 126 public: 127 Rule(std::tuple<RequirementTypes...> Requirements) 128 : Requirements(Requirements) {} 129 130 void invoke(RefactoringResultConsumer &Consumer, 131 RefactoringRuleContext &Context) override { 132 internal::invokeRuleAfterValidatingRequirements<RuleType>( 133 Consumer, Context, Requirements, 134 std::index_sequence_for<RequirementTypes...>()); 135 } 136 137 bool hasSelectionRequirement() override { 138 return internal::HasBaseOf<SourceSelectionRequirement, 139 RequirementTypes...>::value; 140 } 141 142 void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) override { 143 internal::visitRefactoringOptions( 144 Visitor, Requirements, 145 std::index_sequence_for<RequirementTypes...>()); 146 } 147 private: 148 std::tuple<RequirementTypes...> Requirements; 149 }; 150 151 return std::make_unique<Rule>(std::make_tuple(Requirements...)); 152} 153 154} // end namespace tooling 155} // end namespace clang 156 157#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H 158