Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 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_REFACTORING_REFACTORINGACTIONRULESINTERNAL_H |
||
| 10 | #define LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGACTIONRULESINTERNAL_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_t<HasBaseOf<Base, First>::value || |
||
| 98 | HasBaseOf<Base, Rest...>::value, |
||
| 99 | std::true_type, std::false_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_t<AreBaseOf<Base, First>::value && |
||
| 108 | AreBaseOf<Base, Rest...>::value, |
||
| 109 | std::true_type, std::false_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_REFACTORING_REFACTORINGACTIONRULESINTERNAL_H |