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 
findError()24 inline llvm::Error findError() { return llvm::Error::success(); }
25 
ignoreError()26 inline void ignoreError() {}
27 
28 template <typename FirstT, typename... RestT>
ignoreError(Expected<FirstT> & First,Expected<RestT> &...Rest)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>
findError(Expected<FirstT> & First,Expected<RestT> &...Rest)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>
invokeRuleAfterValidatingRequirements(RefactoringResultConsumer & Consumer,RefactoringRuleContext & Context,const std::tuple<RequirementTypes...> & Requirements,std::index_sequence<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 
visitRefactoringOptionsImpl(RefactoringOptionVisitor &)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>
visitRefactoringOptionsImpl(RefactoringOptionVisitor & Visitor,const FirstT & First,const RestT &...Rest)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>
visitRefactoringOptions(RefactoringOptionVisitor & Visitor,const std::tuple<RequirementTypes...> & Requirements,std::index_sequence<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