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 20 namespace clang { 21 namespace tooling { 22 namespace internal { 23 24 inline llvm::Error findError() { return llvm::Error::success(); } 25 26 inline void ignoreError() {} 27 28 template <typename FirstT, typename... RestT> 29 void 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. 37 template <typename FirstT, typename... RestT> 38 llvm::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 46 template <typename RuleType, typename... RequirementTypes, size_t... Is> 47 void 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 66 inline 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. 70 template <typename FirstT, typename... RestT> 71 void 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 86 template <typename... RequirementTypes, size_t... Is> 87 void 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. 96 template <typename Base, typename First, typename... Rest> 97 struct HasBaseOf : std::conditional<HasBaseOf<Base, First>::value || 98 HasBaseOf<Base, Rest...>::value, 99 std::true_type, std::false_type>::type {}; 100 101 template <typename Base, typename T> 102 struct 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. 106 template <typename Base, typename First, typename... Rest> 107 struct AreBaseOf : std::conditional<AreBaseOf<Base, First>::value && 108 AreBaseOf<Base, Rest...>::value, 109 std::true_type, std::false_type>::type {}; 110 111 template <typename Base, typename T> 112 struct AreBaseOf<Base, T> : std::is_base_of<Base, T> {}; 113 114 } // end namespace internal 115 116 template <typename RuleType, typename... RequirementTypes> 117 std::unique_ptr<RefactoringActionRule> 118 createRefactoringActionRule(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