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