1 //===--- RefactoringActionRuleRequirements.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_RULE_REQUIREMENTS_H
10 #define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_REQUIREMENTS_H
11 
12 #include "clang/Basic/LLVM.h"
13 #include "clang/Tooling/Refactoring/ASTSelection.h"
14 #include "clang/Tooling/Refactoring/RefactoringDiagnostic.h"
15 #include "clang/Tooling/Refactoring/RefactoringOption.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 
23 /// A refactoring action rule requirement determines when a refactoring action
24 /// rule can be invoked. The rule can be invoked only when all of the
25 /// requirements are satisfied.
26 ///
27 /// Subclasses must implement the
28 /// 'Expected<T> evaluate(RefactoringRuleContext &) const' member function.
29 /// \c T is used to determine the return type that is passed to the
30 /// refactoring rule's constructor.
31 /// For example, the \c SourceRangeSelectionRequirement subclass defines
32 /// 'Expected<SourceRange> evaluate(RefactoringRuleContext &Context) const'
33 /// function. When this function returns a non-error value, the resulting
34 /// source range is passed to the specific refactoring action rule
35 /// constructor (provided all other requirements are satisfied).
36 class RefactoringActionRuleRequirement {
37   // Expected<T> evaluate(RefactoringRuleContext &Context) const;
38 };
39 
40 /// A base class for any requirement that expects some part of the source to be
41 /// selected in an editor (or the refactoring tool with the -selection option).
42 class SourceSelectionRequirement : public RefactoringActionRuleRequirement {};
43 
44 /// A selection requirement that is satisfied when any portion of the source
45 /// text is selected.
46 class SourceRangeSelectionRequirement : public SourceSelectionRequirement {
47 public:
48   Expected<SourceRange> evaluate(RefactoringRuleContext &Context) const {
49     if (Context.getSelectionRange().isValid())
50       return Context.getSelectionRange();
51     return Context.createDiagnosticError(diag::err_refactor_no_selection);
52   }
53 };
54 
55 /// An AST selection requirement is satisfied when any portion of the AST
56 /// overlaps with the selection range.
57 ///
58 /// The requirement will be evaluated only once during the initiation and
59 /// search of matching refactoring action rules.
60 class ASTSelectionRequirement : public SourceRangeSelectionRequirement {
61 public:
62   Expected<SelectedASTNode> evaluate(RefactoringRuleContext &Context) const;
63 };
64 
65 /// A selection requirement that is satisfied when the selection range overlaps
66 /// with a number of neighbouring statements in the AST. The statemenst must be
67 /// contained in declaration like a function. The selection range must be a
68 /// non-empty source selection (i.e. cursors won't be accepted).
69 ///
70 /// The requirement will be evaluated only once during the initiation and search
71 /// of matching refactoring action rules.
72 ///
73 /// \see CodeRangeASTSelection
74 class CodeRangeASTSelectionRequirement : public ASTSelectionRequirement {
75 public:
76   Expected<CodeRangeASTSelection>
77   evaluate(RefactoringRuleContext &Context) const;
78 };
79 
80 /// A base class for any requirement that requires some refactoring options.
81 class RefactoringOptionsRequirement : public RefactoringActionRuleRequirement {
82 public:
83   virtual ~RefactoringOptionsRequirement() {}
84 
85   /// Returns the set of refactoring options that are used when evaluating this
86   /// requirement.
87   virtual ArrayRef<std::shared_ptr<RefactoringOption>>
88   getRefactoringOptions() const = 0;
89 };
90 
91 /// A requirement that evaluates to the value of the given \c OptionType when
92 /// the \c OptionType is a required option. When the \c OptionType is an
93 /// optional option, the requirement will evaluate to \c None if the option is
94 /// not specified or to an appropriate value otherwise.
95 template <typename OptionType>
96 class OptionRequirement : public RefactoringOptionsRequirement {
97 public:
98   OptionRequirement() : Opt(createRefactoringOption<OptionType>()) {}
99 
100   ArrayRef<std::shared_ptr<RefactoringOption>>
101   getRefactoringOptions() const final override {
102     return Opt;
103   }
104 
105   Expected<typename OptionType::ValueType>
106   evaluate(RefactoringRuleContext &) const {
107     return static_cast<OptionType *>(Opt.get())->getValue();
108   }
109 
110 private:
111   /// The partially-owned option.
112   ///
113   /// The ownership of the option is shared among the different requirements
114   /// because the same option can be used by multiple rules in one refactoring
115   /// action.
116   std::shared_ptr<RefactoringOption> Opt;
117 };
118 
119 } // end namespace tooling
120 } // end namespace clang
121 
122 #endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_REQUIREMENTS_H
123