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 |