RefactoringActionRulesInternal.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===--- RefactoringActionRulesInternal.h - Clang refactoring library -----===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #ifndef LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGACTIONRULESINTERNAL_H
  14. #define LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGACTIONRULESINTERNAL_H
  15. #include "clang/Basic/LLVM.h"
  16. #include "clang/Tooling/Refactoring/RefactoringActionRule.h"
  17. #include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h"
  18. #include "clang/Tooling/Refactoring/RefactoringResultConsumer.h"
  19. #include "clang/Tooling/Refactoring/RefactoringRuleContext.h"
  20. #include "llvm/Support/Error.h"
  21. #include <type_traits>
  22. namespace clang {
  23. namespace tooling {
  24. namespace internal {
  25. inline llvm::Error findError() { return llvm::Error::success(); }
  26. inline void ignoreError() {}
  27. template <typename FirstT, typename... RestT>
  28. void ignoreError(Expected<FirstT> &First, Expected<RestT> &... Rest) {
  29. if (!First)
  30. llvm::consumeError(First.takeError());
  31. ignoreError(Rest...);
  32. }
  33. /// Scans the tuple and returns a valid \c Error if any of the values are
  34. /// invalid.
  35. template <typename FirstT, typename... RestT>
  36. llvm::Error findError(Expected<FirstT> &First, Expected<RestT> &... Rest) {
  37. if (!First) {
  38. ignoreError(Rest...);
  39. return First.takeError();
  40. }
  41. return findError(Rest...);
  42. }
  43. template <typename RuleType, typename... RequirementTypes, size_t... Is>
  44. void invokeRuleAfterValidatingRequirements(
  45. RefactoringResultConsumer &Consumer, RefactoringRuleContext &Context,
  46. const std::tuple<RequirementTypes...> &Requirements,
  47. std::index_sequence<Is...>) {
  48. // Check if the requirements we're interested in can be evaluated.
  49. auto Values =
  50. std::make_tuple(std::get<Is>(Requirements).evaluate(Context)...);
  51. auto Err = findError(std::get<Is>(Values)...);
  52. if (Err)
  53. return Consumer.handleError(std::move(Err));
  54. // Construct the target action rule by extracting the evaluated
  55. // requirements from Expected<> wrappers and then run it.
  56. auto Rule =
  57. RuleType::initiate(Context, std::move((*std::get<Is>(Values)))...);
  58. if (!Rule)
  59. return Consumer.handleError(Rule.takeError());
  60. Rule->invoke(Consumer, Context);
  61. }
  62. inline void visitRefactoringOptionsImpl(RefactoringOptionVisitor &) {}
  63. /// Scans the list of requirements in a rule and visits all the refactoring
  64. /// options that are used by all the requirements.
  65. template <typename FirstT, typename... RestT>
  66. void visitRefactoringOptionsImpl(RefactoringOptionVisitor &Visitor,
  67. const FirstT &First, const RestT &... Rest) {
  68. struct OptionGatherer {
  69. RefactoringOptionVisitor &Visitor;
  70. void operator()(const RefactoringOptionsRequirement &Requirement) {
  71. for (const auto &Option : Requirement.getRefactoringOptions())
  72. Option->passToVisitor(Visitor);
  73. }
  74. void operator()(const RefactoringActionRuleRequirement &) {}
  75. };
  76. (OptionGatherer{Visitor})(First);
  77. return visitRefactoringOptionsImpl(Visitor, Rest...);
  78. }
  79. template <typename... RequirementTypes, size_t... Is>
  80. void visitRefactoringOptions(
  81. RefactoringOptionVisitor &Visitor,
  82. const std::tuple<RequirementTypes...> &Requirements,
  83. std::index_sequence<Is...>) {
  84. visitRefactoringOptionsImpl(Visitor, std::get<Is>(Requirements)...);
  85. }
  86. /// A type trait that returns true when the given type list has at least one
  87. /// type whose base is the given base type.
  88. template <typename Base, typename First, typename... Rest>
  89. struct HasBaseOf : std::conditional_t<HasBaseOf<Base, First>::value ||
  90. HasBaseOf<Base, Rest...>::value,
  91. std::true_type, std::false_type> {};
  92. template <typename Base, typename T>
  93. struct HasBaseOf<Base, T> : std::is_base_of<Base, T> {};
  94. /// A type trait that returns true when the given type list contains types that
  95. /// derive from Base.
  96. template <typename Base, typename First, typename... Rest>
  97. struct AreBaseOf : std::conditional_t<AreBaseOf<Base, First>::value &&
  98. AreBaseOf<Base, Rest...>::value,
  99. std::true_type, std::false_type> {};
  100. template <typename Base, typename T>
  101. struct AreBaseOf<Base, T> : std::is_base_of<Base, T> {};
  102. } // end namespace internal
  103. template <typename RuleType, typename... RequirementTypes>
  104. std::unique_ptr<RefactoringActionRule>
  105. createRefactoringActionRule(const RequirementTypes &... Requirements) {
  106. static_assert(std::is_base_of<RefactoringActionRuleBase, RuleType>::value,
  107. "Expected a refactoring action rule type");
  108. static_assert(internal::AreBaseOf<RefactoringActionRuleRequirement,
  109. RequirementTypes...>::value,
  110. "Expected a list of refactoring action rules");
  111. class Rule final : public RefactoringActionRule {
  112. public:
  113. Rule(std::tuple<RequirementTypes...> Requirements)
  114. : Requirements(Requirements) {}
  115. void invoke(RefactoringResultConsumer &Consumer,
  116. RefactoringRuleContext &Context) override {
  117. internal::invokeRuleAfterValidatingRequirements<RuleType>(
  118. Consumer, Context, Requirements,
  119. std::index_sequence_for<RequirementTypes...>());
  120. }
  121. bool hasSelectionRequirement() override {
  122. return internal::HasBaseOf<SourceSelectionRequirement,
  123. RequirementTypes...>::value;
  124. }
  125. void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) override {
  126. internal::visitRefactoringOptions(
  127. Visitor, Requirements,
  128. std::index_sequence_for<RequirementTypes...>());
  129. }
  130. private:
  131. std::tuple<RequirementTypes...> Requirements;
  132. };
  133. return std::make_unique<Rule>(std::make_tuple(Requirements...));
  134. }
  135. } // end namespace tooling
  136. } // end namespace clang
  137. #endif // LLVM_CLANG_TOOLING_REFACTORING_REFACTORINGACTIONRULESINTERNAL_H
  138. #ifdef __GNUC__
  139. #pragma GCC diagnostic pop
  140. #endif