[NFC][RISCV] Remove CFIIndex argument from allocateStack (#117871)
[llvm-project.git] / clang / unittests / Tooling / RefactoringActionRulesTest.cpp
blobcdd1faf0e38d461e8a8f0f392d23f157a0b4e0ff
1 //===- unittest/Tooling/RefactoringTestActionRulesTest.cpp ----------------===//
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 //===----------------------------------------------------------------------===//
9 #include "ReplacementTest.h"
10 #include "RewriterTestContext.h"
11 #include "clang/Tooling/Refactoring.h"
12 #include "clang/Tooling/Refactoring/Extract/Extract.h"
13 #include "clang/Tooling/Refactoring/RefactoringAction.h"
14 #include "clang/Tooling/Refactoring/RefactoringDiagnostic.h"
15 #include "clang/Tooling/Refactoring/Rename/SymbolName.h"
16 #include "clang/Tooling/Tooling.h"
17 #include "llvm/Support/Errc.h"
18 #include "gtest/gtest.h"
19 #include <optional>
21 using namespace clang;
22 using namespace tooling;
24 namespace {
26 class RefactoringActionRulesTest : public ::testing::Test {
27 protected:
28 void SetUp() override {
29 Context.Sources.setMainFileID(
30 Context.createInMemoryFile("input.cpp", DefaultCode));
33 RewriterTestContext Context;
34 std::string DefaultCode = std::string(100, 'a');
37 Expected<AtomicChanges>
38 createReplacements(const std::unique_ptr<RefactoringActionRule> &Rule,
39 RefactoringRuleContext &Context) {
40 class Consumer final : public RefactoringResultConsumer {
41 void handleError(llvm::Error Err) override { Result = std::move(Err); }
43 void handle(AtomicChanges SourceReplacements) override {
44 Result = std::move(SourceReplacements);
46 void handle(SymbolOccurrences Occurrences) override {
47 RefactoringResultConsumer::handle(std::move(Occurrences));
50 public:
51 std::optional<Expected<AtomicChanges>> Result;
54 Consumer C;
55 Rule->invoke(C, Context);
56 return std::move(*C.Result);
59 TEST_F(RefactoringActionRulesTest, MyFirstRefactoringRule) {
60 class ReplaceAWithB : public SourceChangeRefactoringRule {
61 std::pair<SourceRange, int> Selection;
63 public:
64 ReplaceAWithB(std::pair<SourceRange, int> Selection)
65 : Selection(Selection) {}
67 static Expected<ReplaceAWithB>
68 initiate(RefactoringRuleContext &Cotnext,
69 std::pair<SourceRange, int> Selection) {
70 return ReplaceAWithB(Selection);
73 Expected<AtomicChanges>
74 createSourceReplacements(RefactoringRuleContext &Context) {
75 const SourceManager &SM = Context.getSources();
76 SourceLocation Loc =
77 Selection.first.getBegin().getLocWithOffset(Selection.second);
78 AtomicChange Change(SM, Loc);
79 llvm::Error E = Change.replace(SM, Loc, 1, "b");
80 if (E)
81 return std::move(E);
82 return AtomicChanges{Change};
86 class SelectionRequirement : public SourceRangeSelectionRequirement {
87 public:
88 Expected<std::pair<SourceRange, int>>
89 evaluate(RefactoringRuleContext &Context) const {
90 Expected<SourceRange> R =
91 SourceRangeSelectionRequirement::evaluate(Context);
92 if (!R)
93 return R.takeError();
94 return std::make_pair(*R, 20);
97 auto Rule =
98 createRefactoringActionRule<ReplaceAWithB>(SelectionRequirement());
100 // When the requirements are satisfied, the rule's function must be invoked.
102 RefactoringRuleContext RefContext(Context.Sources);
103 SourceLocation Cursor =
104 Context.Sources.getLocForStartOfFile(Context.Sources.getMainFileID())
105 .getLocWithOffset(10);
106 RefContext.setSelectionRange({Cursor, Cursor});
108 Expected<AtomicChanges> ErrorOrResult =
109 createReplacements(Rule, RefContext);
110 ASSERT_FALSE(!ErrorOrResult);
111 AtomicChanges Result = std::move(*ErrorOrResult);
112 ASSERT_EQ(Result.size(), 1u);
113 std::string YAMLString =
114 const_cast<AtomicChange &>(Result[0]).toYAMLString();
116 ASSERT_STREQ("---\n"
117 "Key: 'input.cpp:30'\n"
118 "FilePath: input.cpp\n"
119 "Error: ''\n"
120 "InsertedHeaders: []\n"
121 "RemovedHeaders: []\n"
122 "Replacements:\n"
123 " - FilePath: input.cpp\n"
124 " Offset: 30\n"
125 " Length: 1\n"
126 " ReplacementText: b\n"
127 "...\n",
128 YAMLString.c_str());
131 // When one of the requirements is not satisfied, invoke should return a
132 // valid error.
134 RefactoringRuleContext RefContext(Context.Sources);
135 Expected<AtomicChanges> ErrorOrResult =
136 createReplacements(Rule, RefContext);
138 ASSERT_TRUE(!ErrorOrResult);
139 unsigned DiagID;
140 llvm::handleAllErrors(ErrorOrResult.takeError(),
141 [&](DiagnosticError &Error) {
142 DiagID = Error.getDiagnostic().second.getDiagID();
144 EXPECT_EQ(DiagID, diag::err_refactor_no_selection);
148 TEST_F(RefactoringActionRulesTest, ReturnError) {
149 class ErrorRule : public SourceChangeRefactoringRule {
150 public:
151 static Expected<ErrorRule> initiate(RefactoringRuleContext &,
152 SourceRange R) {
153 return ErrorRule(R);
156 ErrorRule(SourceRange R) {}
157 Expected<AtomicChanges> createSourceReplacements(RefactoringRuleContext &) {
158 return llvm::make_error<llvm::StringError>(
159 "Error", llvm::make_error_code(llvm::errc::invalid_argument));
163 auto Rule =
164 createRefactoringActionRule<ErrorRule>(SourceRangeSelectionRequirement());
165 RefactoringRuleContext RefContext(Context.Sources);
166 SourceLocation Cursor =
167 Context.Sources.getLocForStartOfFile(Context.Sources.getMainFileID());
168 RefContext.setSelectionRange({Cursor, Cursor});
169 Expected<AtomicChanges> Result = createReplacements(Rule, RefContext);
171 ASSERT_TRUE(!Result);
172 std::string Message;
173 llvm::handleAllErrors(Result.takeError(), [&](llvm::StringError &Error) {
174 Message = Error.getMessage();
176 EXPECT_EQ(Message, "Error");
179 std::optional<SymbolOccurrences>
180 findOccurrences(RefactoringActionRule &Rule, RefactoringRuleContext &Context) {
181 class Consumer final : public RefactoringResultConsumer {
182 void handleError(llvm::Error) override {}
183 void handle(SymbolOccurrences Occurrences) override {
184 Result = std::move(Occurrences);
186 void handle(AtomicChanges Changes) override {
187 RefactoringResultConsumer::handle(std::move(Changes));
190 public:
191 std::optional<SymbolOccurrences> Result;
194 Consumer C;
195 Rule.invoke(C, Context);
196 return std::move(C.Result);
199 TEST_F(RefactoringActionRulesTest, ReturnSymbolOccurrences) {
200 class FindOccurrences : public FindSymbolOccurrencesRefactoringRule {
201 SourceRange Selection;
203 public:
204 FindOccurrences(SourceRange Selection) : Selection(Selection) {}
206 static Expected<FindOccurrences> initiate(RefactoringRuleContext &,
207 SourceRange Selection) {
208 return FindOccurrences(Selection);
211 Expected<SymbolOccurrences>
212 findSymbolOccurrences(RefactoringRuleContext &) override {
213 SymbolOccurrences Occurrences;
214 Occurrences.push_back(SymbolOccurrence(SymbolName("test"),
215 SymbolOccurrence::MatchingSymbol,
216 Selection.getBegin()));
217 return std::move(Occurrences);
221 auto Rule = createRefactoringActionRule<FindOccurrences>(
222 SourceRangeSelectionRequirement());
224 RefactoringRuleContext RefContext(Context.Sources);
225 SourceLocation Cursor =
226 Context.Sources.getLocForStartOfFile(Context.Sources.getMainFileID());
227 RefContext.setSelectionRange({Cursor, Cursor});
228 std::optional<SymbolOccurrences> Result = findOccurrences(*Rule, RefContext);
230 ASSERT_FALSE(!Result);
231 SymbolOccurrences Occurrences = std::move(*Result);
232 EXPECT_EQ(Occurrences.size(), 1u);
233 EXPECT_EQ(Occurrences[0].getKind(), SymbolOccurrence::MatchingSymbol);
234 EXPECT_EQ(Occurrences[0].getNameRanges().size(), 1u);
235 EXPECT_EQ(Occurrences[0].getNameRanges()[0],
236 SourceRange(Cursor, Cursor.getLocWithOffset(strlen("test"))));
239 TEST_F(RefactoringActionRulesTest, EditorCommandBinding) {
240 const RefactoringDescriptor &Descriptor = ExtractFunction::describe();
241 EXPECT_EQ(Descriptor.Name, "extract-function");
242 EXPECT_EQ(
243 Descriptor.Description,
244 "(WIP action; use with caution!) Extracts code into a new function");
245 EXPECT_EQ(Descriptor.Title, "Extract Function");
248 } // end anonymous namespace