summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/clang/unittests/Tooling/RefactoringActionRulesTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/llvm/clang/unittests/Tooling/RefactoringActionRulesTest.cpp')
-rw-r--r--gnu/llvm/clang/unittests/Tooling/RefactoringActionRulesTest.cpp247
1 files changed, 247 insertions, 0 deletions
diff --git a/gnu/llvm/clang/unittests/Tooling/RefactoringActionRulesTest.cpp b/gnu/llvm/clang/unittests/Tooling/RefactoringActionRulesTest.cpp
new file mode 100644
index 00000000000..b471cf207cf
--- /dev/null
+++ b/gnu/llvm/clang/unittests/Tooling/RefactoringActionRulesTest.cpp
@@ -0,0 +1,247 @@
+//===- unittest/Tooling/RefactoringTestActionRulesTest.cpp ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReplacementTest.h"
+#include "RewriterTestContext.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/Extract/Extract.h"
+#include "clang/Tooling/Refactoring/RefactoringAction.h"
+#include "clang/Tooling/Refactoring/RefactoringDiagnostic.h"
+#include "clang/Tooling/Refactoring/Rename/SymbolName.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/Errc.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace tooling;
+
+namespace {
+
+class RefactoringActionRulesTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ Context.Sources.setMainFileID(
+ Context.createInMemoryFile("input.cpp", DefaultCode));
+ }
+
+ RewriterTestContext Context;
+ std::string DefaultCode = std::string(100, 'a');
+};
+
+Expected<AtomicChanges>
+createReplacements(const std::unique_ptr<RefactoringActionRule> &Rule,
+ RefactoringRuleContext &Context) {
+ class Consumer final : public RefactoringResultConsumer {
+ void handleError(llvm::Error Err) override { Result = std::move(Err); }
+
+ void handle(AtomicChanges SourceReplacements) override {
+ Result = std::move(SourceReplacements);
+ }
+ void handle(SymbolOccurrences Occurrences) override {
+ RefactoringResultConsumer::handle(std::move(Occurrences));
+ }
+
+ public:
+ Optional<Expected<AtomicChanges>> Result;
+ };
+
+ Consumer C;
+ Rule->invoke(C, Context);
+ return std::move(*C.Result);
+}
+
+TEST_F(RefactoringActionRulesTest, MyFirstRefactoringRule) {
+ class ReplaceAWithB : public SourceChangeRefactoringRule {
+ std::pair<SourceRange, int> Selection;
+
+ public:
+ ReplaceAWithB(std::pair<SourceRange, int> Selection)
+ : Selection(Selection) {}
+
+ static Expected<ReplaceAWithB>
+ initiate(RefactoringRuleContext &Cotnext,
+ std::pair<SourceRange, int> Selection) {
+ return ReplaceAWithB(Selection);
+ }
+
+ Expected<AtomicChanges>
+ createSourceReplacements(RefactoringRuleContext &Context) {
+ const SourceManager &SM = Context.getSources();
+ SourceLocation Loc =
+ Selection.first.getBegin().getLocWithOffset(Selection.second);
+ AtomicChange Change(SM, Loc);
+ llvm::Error E = Change.replace(SM, Loc, 1, "b");
+ if (E)
+ return std::move(E);
+ return AtomicChanges{Change};
+ }
+ };
+
+ class SelectionRequirement : public SourceRangeSelectionRequirement {
+ public:
+ Expected<std::pair<SourceRange, int>>
+ evaluate(RefactoringRuleContext &Context) const {
+ Expected<SourceRange> R =
+ SourceRangeSelectionRequirement::evaluate(Context);
+ if (!R)
+ return R.takeError();
+ return std::make_pair(*R, 20);
+ }
+ };
+ auto Rule =
+ createRefactoringActionRule<ReplaceAWithB>(SelectionRequirement());
+
+ // When the requirements are satisfied, the rule's function must be invoked.
+ {
+ RefactoringRuleContext RefContext(Context.Sources);
+ SourceLocation Cursor =
+ Context.Sources.getLocForStartOfFile(Context.Sources.getMainFileID())
+ .getLocWithOffset(10);
+ RefContext.setSelectionRange({Cursor, Cursor});
+
+ Expected<AtomicChanges> ErrorOrResult =
+ createReplacements(Rule, RefContext);
+ ASSERT_FALSE(!ErrorOrResult);
+ AtomicChanges Result = std::move(*ErrorOrResult);
+ ASSERT_EQ(Result.size(), 1u);
+ std::string YAMLString =
+ const_cast<AtomicChange &>(Result[0]).toYAMLString();
+
+ ASSERT_STREQ("---\n"
+ "Key: 'input.cpp:30'\n"
+ "FilePath: input.cpp\n"
+ "Error: ''\n"
+ "InsertedHeaders: []\n"
+ "RemovedHeaders: []\n"
+ "Replacements:\n"
+ " - FilePath: input.cpp\n"
+ " Offset: 30\n"
+ " Length: 1\n"
+ " ReplacementText: b\n"
+ "...\n",
+ YAMLString.c_str());
+ }
+
+ // When one of the requirements is not satisfied, invoke should return a
+ // valid error.
+ {
+ RefactoringRuleContext RefContext(Context.Sources);
+ Expected<AtomicChanges> ErrorOrResult =
+ createReplacements(Rule, RefContext);
+
+ ASSERT_TRUE(!ErrorOrResult);
+ unsigned DiagID;
+ llvm::handleAllErrors(ErrorOrResult.takeError(),
+ [&](DiagnosticError &Error) {
+ DiagID = Error.getDiagnostic().second.getDiagID();
+ });
+ EXPECT_EQ(DiagID, diag::err_refactor_no_selection);
+ }
+}
+
+TEST_F(RefactoringActionRulesTest, ReturnError) {
+ class ErrorRule : public SourceChangeRefactoringRule {
+ public:
+ static Expected<ErrorRule> initiate(RefactoringRuleContext &,
+ SourceRange R) {
+ return ErrorRule(R);
+ }
+
+ ErrorRule(SourceRange R) {}
+ Expected<AtomicChanges> createSourceReplacements(RefactoringRuleContext &) {
+ return llvm::make_error<llvm::StringError>(
+ "Error", llvm::make_error_code(llvm::errc::invalid_argument));
+ }
+ };
+
+ auto Rule =
+ createRefactoringActionRule<ErrorRule>(SourceRangeSelectionRequirement());
+ RefactoringRuleContext RefContext(Context.Sources);
+ SourceLocation Cursor =
+ Context.Sources.getLocForStartOfFile(Context.Sources.getMainFileID());
+ RefContext.setSelectionRange({Cursor, Cursor});
+ Expected<AtomicChanges> Result = createReplacements(Rule, RefContext);
+
+ ASSERT_TRUE(!Result);
+ std::string Message;
+ llvm::handleAllErrors(Result.takeError(), [&](llvm::StringError &Error) {
+ Message = Error.getMessage();
+ });
+ EXPECT_EQ(Message, "Error");
+}
+
+Optional<SymbolOccurrences> findOccurrences(RefactoringActionRule &Rule,
+ RefactoringRuleContext &Context) {
+ class Consumer final : public RefactoringResultConsumer {
+ void handleError(llvm::Error) override {}
+ void handle(SymbolOccurrences Occurrences) override {
+ Result = std::move(Occurrences);
+ }
+ void handle(AtomicChanges Changes) override {
+ RefactoringResultConsumer::handle(std::move(Changes));
+ }
+
+ public:
+ Optional<SymbolOccurrences> Result;
+ };
+
+ Consumer C;
+ Rule.invoke(C, Context);
+ return std::move(C.Result);
+}
+
+TEST_F(RefactoringActionRulesTest, ReturnSymbolOccurrences) {
+ class FindOccurrences : public FindSymbolOccurrencesRefactoringRule {
+ SourceRange Selection;
+
+ public:
+ FindOccurrences(SourceRange Selection) : Selection(Selection) {}
+
+ static Expected<FindOccurrences> initiate(RefactoringRuleContext &,
+ SourceRange Selection) {
+ return FindOccurrences(Selection);
+ }
+
+ Expected<SymbolOccurrences>
+ findSymbolOccurrences(RefactoringRuleContext &) override {
+ SymbolOccurrences Occurrences;
+ Occurrences.push_back(SymbolOccurrence(SymbolName("test"),
+ SymbolOccurrence::MatchingSymbol,
+ Selection.getBegin()));
+ return std::move(Occurrences);
+ }
+ };
+
+ auto Rule = createRefactoringActionRule<FindOccurrences>(
+ SourceRangeSelectionRequirement());
+
+ RefactoringRuleContext RefContext(Context.Sources);
+ SourceLocation Cursor =
+ Context.Sources.getLocForStartOfFile(Context.Sources.getMainFileID());
+ RefContext.setSelectionRange({Cursor, Cursor});
+ Optional<SymbolOccurrences> Result = findOccurrences(*Rule, RefContext);
+
+ ASSERT_FALSE(!Result);
+ SymbolOccurrences Occurrences = std::move(*Result);
+ EXPECT_EQ(Occurrences.size(), 1u);
+ EXPECT_EQ(Occurrences[0].getKind(), SymbolOccurrence::MatchingSymbol);
+ EXPECT_EQ(Occurrences[0].getNameRanges().size(), 1u);
+ EXPECT_EQ(Occurrences[0].getNameRanges()[0],
+ SourceRange(Cursor, Cursor.getLocWithOffset(strlen("test"))));
+}
+
+TEST_F(RefactoringActionRulesTest, EditorCommandBinding) {
+ const RefactoringDescriptor &Descriptor = ExtractFunction::describe();
+ EXPECT_EQ(Descriptor.Name, "extract-function");
+ EXPECT_EQ(
+ Descriptor.Description,
+ "(WIP action; use with caution!) Extracts code into a new function");
+ EXPECT_EQ(Descriptor.Title, "Extract Function");
+}
+
+} // end anonymous namespace