1 //===--- RefactoringActionRulesInternal.h - Clang refactoring library -----===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H
11 #define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H
13 #include "clang/Basic/LLVM.h"
14 #include "clang/Tooling/Refactoring/RefactoringActionRule.h"
15 #include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h"
16 #include "clang/Tooling/Refactoring/RefactoringResultConsumer.h"
17 #include "clang/Tooling/Refactoring/RefactoringRuleContext.h"
18 #include "llvm/Support/Error.h"
19 #include <type_traits>
25 inline llvm::Error findError() { return llvm::Error::success(); }
27 inline void ignoreError() {}
29 template <typename FirstT, typename... RestT>
30 void ignoreError(Expected<FirstT> &First, Expected<RestT> &... Rest) {
32 llvm::consumeError(First.takeError());
36 /// Scans the tuple and returns a valid \c Error if any of the values are
38 template <typename FirstT, typename... RestT>
39 llvm::Error findError(Expected<FirstT> &First, Expected<RestT> &... Rest) {
42 return First.takeError();
44 return findError(Rest...);
47 template <typename RuleType, typename... RequirementTypes, size_t... Is>
48 void invokeRuleAfterValidatingRequirements(
49 RefactoringResultConsumer &Consumer, RefactoringRuleContext &Context,
50 const std::tuple<RequirementTypes...> &Requirements,
51 llvm::index_sequence<Is...>) {
52 // Check if the requirements we're interested in can be evaluated.
54 std::make_tuple(std::get<Is>(Requirements).evaluate(Context)...);
55 auto Err = findError(std::get<Is>(Values)...);
57 return Consumer.handleError(std::move(Err));
58 // Construct the target action rule by extracting the evaluated
59 // requirements from Expected<> wrappers and then run it.
61 RuleType::initiate(Context, std::move((*std::get<Is>(Values)))...);
63 return Consumer.handleError(Rule.takeError());
64 Rule->invoke(Consumer, Context);
67 inline void visitRefactoringOptionsImpl(RefactoringOptionVisitor &) {}
69 /// Scans the list of requirements in a rule and visits all the refactoring
70 /// options that are used by all the requirements.
71 template <typename FirstT, typename... RestT>
72 void visitRefactoringOptionsImpl(RefactoringOptionVisitor &Visitor,
73 const FirstT &First, const RestT &... Rest) {
74 struct OptionGatherer {
75 RefactoringOptionVisitor &Visitor;
77 void operator()(const RefactoringOptionsRequirement &Requirement) {
78 for (const auto &Option : Requirement.getRefactoringOptions())
79 Option->passToVisitor(Visitor);
81 void operator()(const RefactoringActionRuleRequirement &) {}
83 (OptionGatherer{Visitor})(First);
84 return visitRefactoringOptionsImpl(Visitor, Rest...);
87 template <typename... RequirementTypes, size_t... Is>
88 void visitRefactoringOptions(
89 RefactoringOptionVisitor &Visitor,
90 const std::tuple<RequirementTypes...> &Requirements,
91 llvm::index_sequence<Is...>) {
92 visitRefactoringOptionsImpl(Visitor, std::get<Is>(Requirements)...);
95 /// A type trait that returns true when the given type list has at least one
96 /// type whose base is the given base type.
97 template <typename Base, typename First, typename... Rest>
98 struct HasBaseOf : std::conditional<HasBaseOf<Base, First>::value ||
99 HasBaseOf<Base, Rest...>::value,
100 std::true_type, std::false_type>::type {};
102 template <typename Base, typename T>
103 struct HasBaseOf<Base, T> : std::is_base_of<Base, T> {};
105 /// A type trait that returns true when the given type list contains types that
106 /// derive from Base.
107 template <typename Base, typename First, typename... Rest>
108 struct AreBaseOf : std::conditional<AreBaseOf<Base, First>::value &&
109 AreBaseOf<Base, Rest...>::value,
110 std::true_type, std::false_type>::type {};
112 template <typename Base, typename T>
113 struct AreBaseOf<Base, T> : std::is_base_of<Base, T> {};
115 } // end namespace internal
117 template <typename RuleType, typename... RequirementTypes>
118 std::unique_ptr<RefactoringActionRule>
119 createRefactoringActionRule(const RequirementTypes &... Requirements) {
120 static_assert(std::is_base_of<RefactoringActionRuleBase, RuleType>::value,
121 "Expected a refactoring action rule type");
122 static_assert(internal::AreBaseOf<RefactoringActionRuleRequirement,
123 RequirementTypes...>::value,
124 "Expected a list of refactoring action rules");
126 class Rule final : public RefactoringActionRule {
128 Rule(std::tuple<RequirementTypes...> Requirements)
129 : Requirements(Requirements) {}
131 void invoke(RefactoringResultConsumer &Consumer,
132 RefactoringRuleContext &Context) override {
133 internal::invokeRuleAfterValidatingRequirements<RuleType>(
134 Consumer, Context, Requirements,
135 llvm::index_sequence_for<RequirementTypes...>());
138 bool hasSelectionRequirement() override {
139 return internal::HasBaseOf<SourceSelectionRequirement,
140 RequirementTypes...>::value;
143 void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) override {
144 internal::visitRefactoringOptions(
145 Visitor, Requirements,
146 llvm::index_sequence_for<RequirementTypes...>());
149 std::tuple<RequirementTypes...> Requirements;
152 return llvm::make_unique<Rule>(std::make_tuple(Requirements...));
155 } // end namespace tooling
156 } // end namespace clang
158 #endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_INTERNAL_H