arphaman created this revision.
Herald added a subscriber: mgorny.
This patch implements a couple of functions that were described in my RFC from
last week that’s available at
http://lists.llvm.org/pipermail/cfe-dev/2017-July/054831.html. This patch adds
the following pieces: `apply` function, `selectionRequirement` function, and
the `selection::SourceSelectionRange` constraint.
This code will be used as a base to start moving the functionality and tests
for clang-rename over to clang-refactor.
Unfortunately I had to use slightly different code for MSVC in the
`selectionRequirement` overloads that take a lambda as MSVC fails to deduce the
return type because of how it handles templates. I came up with a solution that
seems to work with MSVC 2015 (the min version supported by LLVM), and I’ve
tested the lambda overload code with cl 19.00.23506.
Repository:
rL LLVM
https://reviews.llvm.org/D36075
Files:
include/clang/Basic/LLVM.h
include/clang/Tooling/Refactoring/AtomicChange.h
include/clang/Tooling/Refactoring/DiagOr.h
include/clang/Tooling/Refactoring/RefactoringActionRules.h
include/clang/Tooling/Refactoring/RefactoringOperationController.h
include/clang/Tooling/Refactoring/RefactoringResult.h
include/clang/Tooling/Refactoring/SourceSelectionConstraints.h
unittests/Tooling/CMakeLists.txt
unittests/Tooling/RefactoringActionRulesTest.cpp
Index: unittests/Tooling/RefactoringActionRulesTest.cpp
===================================================================
--- /dev/null
+++ unittests/Tooling/RefactoringActionRulesTest.cpp
@@ -0,0 +1,148 @@
+//===- unittest/Tooling/RefactoringTestActionRulesTest.cpp ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ReplacementTest.h"
+#include "RewriterTestContext.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace tooling;
+using namespace refactoring_action_rules;
+
+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');
+};
+
+TEST_F(RefactoringActionRulesTest, MyFirstRefactoringRule) {
+ auto ReplaceAWithB =
+ [](std::pair<selection::SourceSelectionRange, int> Selection)
+ -> Expected<RefactoringResult> {
+ const SourceManager &SM = Selection.first.getSources();
+ SourceLocation Loc = Selection.first.getRange().getBegin().getLocWithOffset(
+ Selection.second);
+ AtomicChange Change(SM, Loc);
+ llvm::Error E = Change.replace(SM, Loc, 1, "b");
+ if (E)
+ return std::move(E);
+ return Change;
+ };
+ auto Rule =
+ apply(ReplaceAWithB,
+ selectionRequirement([](selection::SourceSelectionRange Selection) {
+ return std::make_pair(Selection, 20);
+ }));
+
+ // When the requirements are satisifed, the rule's function must be invoked.
+ {
+ RefactoringOperationController Operation(Context.Sources);
+ SourceLocation Cursor =
+ Context.Sources.getLocForStartOfFile(Context.Sources.getMainFileID())
+ .getLocWithOffset(10);
+ Operation.setSelectionRange({Cursor, Cursor});
+
+ DiagOr<Expected<RefactoringResult>> DiagOrResult = Rule->perform(Operation);
+ ASSERT_FALSE(!DiagOrResult);
+ Expected<RefactoringResult> Result = std::move(*DiagOrResult);
+ ASSERT_FALSE(!Result);
+ ASSERT_EQ(Result->getKind(), RefactoringResult::AtomicChanges);
+ ASSERT_EQ(Result->getChanges().size(), 1u);
+ std::string YAMLString = Result->getChanges()[0].toYAMLString();
+
+ ASSERT_STREQ("---\n"
+ "Key: 'input.cpp:30'\n"
+ "FilePath: input.cpp\n"
+ "Error: ''\n"
+ "InsertedHeaders: \n"
+ "RemovedHeaders: \n"
+ "Replacements: \n" // Extra whitespace here!
+ " - 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, perform should return either
+ // None or a valid diagnostic.
+ {
+ RefactoringOperationController Operation(Context.Sources);
+ DiagOr<Expected<RefactoringResult>> DiagOrResult = Rule->perform(Operation);
+
+ ASSERT_TRUE(!DiagOrResult);
+ auto DiagOrNone = DiagOrResult.getDiag();
+ ASSERT_TRUE(!DiagOrNone);
+ }
+}
+
+TEST_F(RefactoringActionRulesTest, ReturnError) {
+ Expected<RefactoringResult> (*Func)(selection::SourceSelectionRange) =
+ [](selection::SourceSelectionRange) -> Expected<RefactoringResult> {
+ return llvm::make_error<llvm::StringError>(
+ "Error", std::make_error_code(std::errc::bad_message));
+ };
+ auto Rule =
+ apply(Func, selectionRequirement(
+ selection::identity<selection::SourceSelectionRange>()));
+
+ RefactoringOperationController Operation(Context.Sources);
+ SourceLocation Cursor =
+ Context.Sources.getLocForStartOfFile(Context.Sources.getMainFileID());
+ Operation.setSelectionRange({Cursor, Cursor});
+ DiagOr<Expected<RefactoringResult>> Result = Rule->perform(Operation);
+
+ ASSERT_FALSE(!Result);
+ ASSERT_TRUE(!*Result);
+ std::string Value;
+ llvm::handleAllErrors(
+ (*Result).takeError(),
+ [&](const llvm::StringError &Error) { Value = Error.getMessage(); });
+ EXPECT_EQ(Value, "Error");
+}
+
+TEST_F(RefactoringActionRulesTest, ReturnInitiationDiagnostic) {
+ DiagOr<int> (*SelectionConstraint)(selection::SourceSelectionRange) =
+ [](selection::SourceSelectionRange) -> DiagOr<int> {
+ return DiagOr<int>(
+ StoredDiagnostic(DiagnosticsEngine::Error, 0, "Diagnostic"));
+ };
+ auto Rule = apply(
+ [](int) -> Expected<RefactoringResult> {
+ llvm::report_fatal_error("Should not run!");
+ },
+ selectionRequirement(SelectionConstraint));
+
+ RefactoringOperationController Operation(Context.Sources);
+ SourceLocation Cursor =
+ Context.Sources.getLocForStartOfFile(Context.Sources.getMainFileID());
+ Operation.setSelectionRange({Cursor, Cursor});
+ DiagOr<Expected<RefactoringResult>> Result = Rule->perform(Operation);
+
+ ASSERT_TRUE(!Result);
+ auto DiagOrNone = Result.getDiag();
+ ASSERT_FALSE(!DiagOrNone);
+ StoredDiagnostic Diag = *DiagOrNone;
+ EXPECT_EQ(Diag.getLevel(), DiagnosticsEngine::Error);
+ EXPECT_EQ(Diag.getID(), 0u);
+ EXPECT_EQ(Diag.getMessage(), "Diagnostic");
+}
+
+} // end anonymous namespace
Index: unittests/Tooling/CMakeLists.txt
===================================================================
--- unittests/Tooling/CMakeLists.txt
+++ unittests/Tooling/CMakeLists.txt
@@ -23,6 +23,7 @@
RecursiveASTVisitorTestDeclVisitor.cpp
RecursiveASTVisitorTestExprVisitor.cpp
RecursiveASTVisitorTestTypeLocVisitor.cpp
+ RefactoringActionRulesTest.cpp
RefactoringCallbacksTest.cpp
RefactoringTest.cpp
ReplacementsYamlTest.cpp
Index: include/clang/Tooling/Refactoring/SourceSelectionConstraints.h
===================================================================
--- /dev/null
+++ include/clang/Tooling/Refactoring/SourceSelectionConstraints.h
@@ -0,0 +1,61 @@
+//===--- SourceSelectionConstraints.h - Clang refactoring library ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_SOURCE_SELECTION_CONSTRAINTS_H
+#define LLVM_CLANG_TOOLING_REFACTOR_SOURCE_SELECTION_CONSTRAINTS_H
+
+#include "clang/Basic/SourceLocation.h"
+#include <type_traits>
+
+namespace clang {
+namespace tooling {
+namespace selection {
+
+/// This constraint is satisfied when any portion of the source text is
+/// selected. It can be used be used to obtain the raw source selection range.
+struct SourceSelectionRange {
+ SourceSelectionRange(const SourceManager &SM, SourceRange Range)
+ : SM(SM), Range(Range) {}
+
+ const SourceManager &getSources() const { return SM; }
+ SourceRange getRange() const { return Range; }
+
+private:
+ const SourceManager &SM;
+ SourceRange Range;
+};
+
+namespace traits {
+
+/// A type trait that returns true iff the given type is a valid selection
+/// constraint.
+template <typename T> struct IsConstraint : public std::false_type {};
+
+} // end namespace traits
+
+/// A identity function that returns the given selection constraint is provided
+/// for convenience, as it can be passed to \c requiredSelection directly.
+template <typename T> T (*identity())(T) {
+ static_assert(
+ traits::IsConstraint<T>::value,
+ "selection::identity can be used with selection constraints only");
+ return [](T Value) { return std::move(Value); };
+}
+
+namespace traits {
+
+template <>
+struct IsConstraint<SourceSelectionRange> : public std::true_type {};
+
+} // end namespace traits
+} // end namespace selection
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_SOURCE_SELECTION_CONSTRAINTS_H
Index: include/clang/Tooling/Refactoring/RefactoringResult.h
===================================================================
--- /dev/null
+++ include/clang/Tooling/Refactoring/RefactoringResult.h
@@ -0,0 +1,49 @@
+//===--- RefactoringResult.h - Clang refactoring library ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RESULT_H
+#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RESULT_H
+
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+
+namespace clang {
+namespace tooling {
+
+/// Refactoring result is a variant that stores a set of source changes or
+/// a set of found symbol occurrences.
+struct RefactoringResult {
+ enum ResultKind {
+ /// A set of source replacements represented using a vector of
+ /// \c AtomicChanges.
+ AtomicChanges
+ };
+
+ RefactoringResult(AtomicChange Change) : Kind(AtomicChanges) {
+ Changes.push_back(std::move(Change));
+ }
+ RefactoringResult(RefactoringResult &&Other) = default;
+ RefactoringResult &operator=(RefactoringResult &&Other) = default;
+
+ ResultKind getKind() const { return Kind; }
+
+ llvm::MutableArrayRef<AtomicChange> getChanges() {
+ assert(getKind() == AtomicChanges &&
+ "Refactoring didn't produce atomic changes");
+ return Changes;
+ }
+
+private:
+ ResultKind Kind;
+ std::vector<AtomicChange> Changes;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_RESULT_H
Index: include/clang/Tooling/Refactoring/RefactoringOperationController.h
===================================================================
--- /dev/null
+++ include/clang/Tooling/Refactoring/RefactoringOperationController.h
@@ -0,0 +1,42 @@
+//===--- RefactoringOperationController.h - Clang refactoring library -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPERATION_CONTROLLER_H
+#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPERATION_CONTROLLER_H
+
+#include "clang/Basic/SourceManager.h"
+
+namespace clang {
+namespace tooling {
+
+/// Encapsulates all of the possible state that an individual refactoring
+/// operation might have. Controls the process of initiation of refactoring
+/// operations, by feeding the right information to the functions that
+/// evaluate the refactoring action rule requirements.
+class RefactoringOperationController {
+public:
+ RefactoringOperationController(const SourceManager &SM) : SM(SM) {}
+
+ const SourceManager &getSources() const { return SM; }
+
+ /// Returns the current source selection range as set by the
+ /// refactoring engine. Can be invalid.
+ SourceRange getSelectionRange() const { return SelectionRange; }
+
+ void setSelectionRange(SourceRange R) { SelectionRange = R; }
+
+private:
+ const SourceManager &SM;
+ SourceRange SelectionRange;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPERATION_CONTROLLER_H
Index: include/clang/Tooling/Refactoring/RefactoringActionRules.h
===================================================================
--- /dev/null
+++ include/clang/Tooling/Refactoring/RefactoringActionRules.h
@@ -0,0 +1,306 @@
+//===--- RefactoringActionRules.h - Clang refactoring library -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_H
+#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Tooling/Refactoring/DiagOr.h"
+#include "clang/Tooling/Refactoring/RefactoringOperationController.h"
+#include "clang/Tooling/Refactoring/RefactoringResult.h"
+#include "clang/Tooling/Refactoring/SourceSelectionConstraints.h"
+#include "llvm/Support/Error.h"
+#include <type_traits>
+
+namespace clang {
+namespace tooling {
+
+/// A common refactoring action rule interface.
+class RefactoringActionRule {
+public:
+ virtual ~RefactoringActionRule() {}
+
+ /// The refactoring engine calls this method when trying to perform a
+ /// refactoring operation. The specific rule must return a valid diagnostic
+ /// or \c None when the refactoring action couldn't be initiated, an error
+ /// when the rule fails after initiation, or a valid refactoring result when
+ /// the action runs successfully.
+ virtual DiagOr<Expected<RefactoringResult>>
+ perform(RefactoringOperationController &Controller) = 0;
+};
+
+/// A set of refactoring action rules that should have unique initiation
+/// requirements.
+using RefactoringActionRules =
+ std::vector<std::unique_ptr<RefactoringActionRule>>;
+
+namespace refactoring_action_rules {
+
+namespace detail {
+
+struct RequirementBase {};
+
+} // end namespace detail
+
+namespace traits {
+
+/// A type trait that returns true iff the given type is a valid rule
+/// requirement.
+template <typename First, typename... Rest>
+struct IsRequirement : std::conditional<IsRequirement<First>::value &&
+ IsRequirement<Rest...>::value,
+ std::true_type, std::false_type>::type {
+};
+
+template <typename T>
+struct IsRequirement<T>
+ : std::conditional<std::is_base_of<detail::RequirementBase, T>::value,
+ std::true_type, std::false_type>::type {};
+
+} // end namespace traits
+
+namespace detail {
+
+/// Defines a type alias of type \T when given \c DiagOr<T>, or \c T otherwise.
+template <typename T> struct DropDiagOr { using Type = T; };
+
+template <typename T> struct DropDiagOr<DiagOr<T>> { using Type = T; };
+
+/// The \c requiredSelection refactoring action requirement is represented
+/// using this type.
+template <typename InputT, typename OutputT>
+struct SourceSelectionRequirement
+ : std::enable_if<selection::traits::IsConstraint<InputT>::value,
+ RequirementBase>::type {
+ using OutputType = typename DropDiagOr<OutputT>::Type;
+ using FunctionType = OutputT (*)(InputT);
+
+ SourceSelectionRequirement(FunctionType Function) : Function(Function) {}
+
+private:
+ OutputT (*Function)(InputT);
+ friend class BaseSpecializedRule;
+};
+
+/// A wrapper class around \c RefactoringActionRule that defines some helper
+/// methods that are used by the subclasses.
+class BaseSpecializedRule : public RefactoringActionRule {
+protected:
+ /// Evaluates a source selection action rule requirement.
+ template <typename InputT, typename OutputT>
+ static DiagOr<typename DropDiagOr<OutputT>::Type> evaluate(
+ RefactoringOperationController &Controller,
+ const SourceSelectionRequirement<InputT, OutputT> &SelectionRequirement) {
+ Optional<InputT> Value = evalSelection<InputT>(Controller);
+ if (!Value)
+ return None;
+ return SelectionRequirement.Function(*Value);
+ }
+
+ /// Returns \c T when given \c DiagOr<T>, or \c T otherwise.
+ template <typename T> static T &&removeDiagOr(DiagOr<T> &&X) {
+ assert(X && "unexpected diagnostic!");
+ return std::move(*X);
+ }
+ template <typename T> static T &&removeDiagOr(T &&X) { return std::move(X); }
+
+ using OptionalDiagOrNone = Optional<Optional<StoredDiagnostic>>;
+
+ /// Scans the tuple and returns a \c StoredDiagnostic or an \c Optional<None>
+ /// from the first invalid \c DiagOr value. Returns \c None if all values
+ /// are valid.
+ template <typename FirstT, typename... RestT>
+ static OptionalDiagOrNone findDiagOrNone(FirstT &First, RestT &... Rest) {
+ OptionalDiagOrNone Result = takeDiagOrNone(First);
+ if (Result.hasValue())
+ return Result;
+ return findDiagOrNone(Rest...);
+ }
+
+private:
+ /// Evaluates a selection constraint.
+ template <typename T>
+ static typename std::enable_if<selection::traits::IsConstraint<T>::value,
+ llvm::Optional<T>>::type
+ evalSelection(RefactoringOperationController &Controller);
+
+ static OptionalDiagOrNone findDiagOrNone() { return OptionalDiagOrNone(); }
+ template <typename T> static OptionalDiagOrNone takeDiagOrNone(T &) {
+ return OptionalDiagOrNone();
+ }
+ template <typename T>
+ static OptionalDiagOrNone takeDiagOrNone(DiagOr<T> &Diag) {
+ return Diag.hasValue() ? OptionalDiagOrNone() : std::move(Diag.getDiag());
+ }
+};
+
+/// Evaluates the \c selection::SourceSelectionRange constraint.
+template <>
+llvm::Optional<selection::SourceSelectionRange>
+BaseSpecializedRule::evalSelection<selection::SourceSelectionRange>(
+ RefactoringOperationController &Controller) {
+ SourceRange R = Controller.getSelectionRange();
+ if (R.isInvalid())
+ return None;
+ return selection::SourceSelectionRange(Controller.getSources(), R);
+}
+
+/// A specialized refactoring action rule that calls the stored function once
+/// all the of the requirements are fullfilled. The values produced during the
+/// evaluation of requirements are passed to the stored function.
+template <typename FunctionType, typename... RequirementTypes>
+class PlainFunctionRule final : public BaseSpecializedRule {
+public:
+ PlainFunctionRule(FunctionType Function,
+ std::tuple<RequirementTypes...> &&Requirements)
+ : Function(Function), Requirements(std::move(Requirements)) {}
+
+ DiagOr<Expected<RefactoringResult>>
+ perform(RefactoringOperationController &Controller) override {
+ return performImpl(Controller,
+ llvm::index_sequence_for<RequirementTypes...>());
+ }
+
+private:
+ template <size_t... Is>
+ DiagOr<Expected<RefactoringResult>>
+ performImpl(RefactoringOperationController &Controller,
+ llvm::index_sequence<Is...>) {
+ // Initiate the operation.
+ auto Values =
+ std::make_tuple(evaluate(Controller, std::get<Is>(Requirements))...);
+ OptionalDiagOrNone InitiationFailure =
+ findDiagOrNone(std::get<Is>(Values)...);
+ if (InitiationFailure)
+ return std::move(*InitiationFailure);
+ // Perform the operation.
+ return Function(removeDiagOr(std::move(std::get<Is>(Values)))...);
+ }
+
+ FunctionType Function;
+ std::tuple<RequirementTypes...> Requirements;
+};
+
+} // end namespace detail
+
+/// Creates a new refactoring action rule that invokes the given function once
+/// all of the requirements are satisfied. The values produced during the
+/// evaluation of requirements are passed to the given function (in the order of
+/// requirements).
+///
+/// \param RefactoringFunction the function that will perform the refactoring
+/// once the requirements are satisfied.
+///
+/// \param Requirements a set of rule requirements that have to be satisfied.
+/// Each requirement must be a valid requirement, i.e. the value of
+/// \c traits::IsRequirement<T> must be true.
+template <typename... RequirementTypes>
+std::unique_ptr<RefactoringActionRule>
+apply(Expected<RefactoringResult> (*RefactoringFunction)(
+ typename RequirementTypes::OutputType...),
+ const RequirementTypes &... Requirements) {
+ static_assert(traits::IsRequirement<RequirementTypes...>::value,
+ "invalid refactoring action rule requirement");
+ return llvm::make_unique<detail::PlainFunctionRule<
+ decltype(RefactoringFunction), RequirementTypes...>>(
+ RefactoringFunction, std::make_tuple(Requirements...));
+}
+
+namespace detail {
+
+template <typename T> struct lambdaDeducer;
+
+template <typename T, typename R, typename A>
+struct lambdaDeducer<R (T::*)(A) const> {
+ using ReturnType = R;
+ using ArgType = A;
+};
+
+} // end namespace detail
+
+#define DEDUCE_LAMBDA_ARG(Callable) \
+ typename detail::lambdaDeducer<decltype(&Callable::operator())>::ArgType
+#define DEDUCE_LAMBDA_RET(Callable) \
+ typename detail::lambdaDeducer<decltype(&Callable::operator())>::ReturnType
+
+#ifdef _MSC_VER
+// MSVC is unable to deduce to the return type that depends on lambda's argument
+// and return types. Fallback to using a C++14's decltype(auto). Luckily
+// it's supported by the minimum version of MSVC compiler that's allowed
+// by LLVM.
+#define DEDUCE_LAMBDA_TYPE(T, Callable) decltype(auto)
+#define DEDUCE_LAMBDA_TYPE_WITH_ARGTYPE(T, Callable, Arg) decltype(auto)
+#else
+// C++11 compliant type deduction that works with other compilers.
+#define DEDUCE_LAMBDA_TYPE(T, Callable) \
+ T<DEDUCE_LAMBDA_ARG(Callable), DEDUCE_LAMBDA_RET(Callable)>
+#define DEDUCE_LAMBDA_TYPE_WITH_ARGTYPE(T, Callable, Arg) \
+ T<Arg, DEDUCE_LAMBDA_RET(Callable)>
+#endif
+
+/// Creates a selection requirement from a function pointer.
+template <typename InputT, typename OutputT>
+detail::SourceSelectionRequirement<InputT, OutputT> selectionRequirement(
+ OutputT (*Constraint)(InputT),
+ typename std::enable_if<
+ selection::traits::IsConstraint<InputT>::value>::type * = nullptr) {
+ return detail::SourceSelectionRequirement<InputT, OutputT>(Constraint);
+}
+
+/// Create a selection requirement from a non-capturing lambda.
+template <typename Callable>
+auto selectionRequirement(
+ Callable Constraint,
+ typename std::enable_if<selection::traits::IsConstraint<
+ DEDUCE_LAMBDA_ARG(Callable)>::value>::type * = nullptr)
+ -> DEDUCE_LAMBDA_TYPE(detail::SourceSelectionRequirement, Callable) {
+ return detail::SourceSelectionRequirement<DEDUCE_LAMBDA_ARG(Callable),
+ DEDUCE_LAMBDA_RET(Callable)>(
+ Constraint);
+}
+
+// These overloads provide a helpful diagnostic when a lambda or a function that
+// takes an invalid selection constraint is given to selectionRequirement.
+template <typename Callable>
+auto selectionRequirement(
+ Callable C, typename std::enable_if<!selection::traits::IsConstraint<
+ DEDUCE_LAMBDA_ARG(Callable)>::value>::type * = nullptr)
+ -> DEDUCE_LAMBDA_TYPE_WITH_ARGTYPE(detail::SourceSelectionRequirement,
+ Callable,
+ selection::SourceSelectionRange) {
+ using OutputT = DEDUCE_LAMBDA_RET(Callable);
+ static_assert(sizeof(OutputT) && false,
+ "The argument type of the function passed into "
+ "'selectionRequirement' must be a valid selection constraint");
+ return detail::SourceSelectionRequirement<selection::SourceSelectionRange,
+ OutputT>(nullptr);
+}
+template <typename InputT, typename OutputT>
+detail::SourceSelectionRequirement<selection::SourceSelectionRange, OutputT>
+selectionRequirement(
+ OutputT (*C)(InputT),
+ typename std::enable_if<
+ !selection::traits::IsConstraint<InputT>::value>::type * = nullptr) {
+ static_assert(sizeof(OutputT) && false,
+ "The argument type of the function passed into "
+ "'selectionRequirement' must be a valid selection constraint");
+ return detail::SourceSelectionRequirement<selection::SourceSelectionRange,
+ OutputT>(nullptr);
+}
+
+#undef DEDUCE_LAMBDA_ARG
+#undef DEDUCE_LAMBDA_RET
+#undef DEDUCE_LAMBDA_TYPE
+#undef DEDUCE_LAMBDA_TYPE_WITH_ARGTYPE
+
+} // end namespace refactoring_action_rules
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULES_H
Index: include/clang/Tooling/Refactoring/DiagOr.h
===================================================================
--- /dev/null
+++ include/clang/Tooling/Refactoring/DiagOr.h
@@ -0,0 +1,52 @@
+//===--- DiagOr.h - Clang refactoring library -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_DIAG_OR_H
+#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_DIAG_OR_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LLVM.h"
+
+namespace clang {
+namespace tooling {
+
+/// A variant that stores a value of given type or an optional diagnostic.
+template <typename T> struct DiagOr {
+ DiagOr(T &&Value) : Value(std::move(Value)) {}
+ DiagOr(llvm::NoneType) {}
+ DiagOr(Optional<StoredDiagnostic> &&Diag) : Diag(std::move(Diag)) {}
+
+ DiagOr(DiagOr<T> &&) = default;
+ DiagOr &operator=(DiagOr<T> &&) = default;
+
+ Optional<StoredDiagnostic> &getDiag() {
+ assert(!Value.hasValue() && "Diagnostic with a value");
+ return Diag;
+ }
+
+ explicit operator bool() const { return hasValue(); }
+ bool hasValue() const { return Value.hasValue(); }
+ const T &operator*() const {
+ assert(Value.hasValue() && "Dereference without a value");
+ return *Value;
+ }
+ T &operator*() {
+ assert(Value.hasValue() && "Dereference without a value");
+ return *Value;
+ }
+
+private:
+ Optional<StoredDiagnostic> Diag;
+ Optional<T> Value;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_DIAG_OR_H
Index: include/clang/Tooling/Refactoring/AtomicChange.h
===================================================================
--- include/clang/Tooling/Refactoring/AtomicChange.h
+++ include/clang/Tooling/Refactoring/AtomicChange.h
@@ -45,6 +45,12 @@
AtomicChange(llvm::StringRef FilePath, llvm::StringRef Key)
: Key(Key), FilePath(FilePath) {}
+ AtomicChange(AtomicChange &&) = default;
+ AtomicChange(const AtomicChange &) = default;
+
+ AtomicChange &operator=(AtomicChange &&) = default;
+ AtomicChange &operator=(const AtomicChange &) = default;
+
/// \brief Returns the atomic change as a YAML string.
std::string toYAMLString();
Index: include/clang/Basic/LLVM.h
===================================================================
--- include/clang/Basic/LLVM.h
+++ include/clang/Basic/LLVM.h
@@ -35,6 +35,7 @@
template<typename T, unsigned N> class SmallVector;
template<typename T> class SmallVectorImpl;
template<typename T> class Optional;
+ template <class T> class Expected;
template<typename T>
struct SaveAndRestore;
@@ -71,6 +72,9 @@
using llvm::SmallVectorImpl;
using llvm::SaveAndRestore;
+ // Error handling.
+ using llvm::Expected;
+
// Reference counting.
using llvm::IntrusiveRefCntPtr;
using llvm::IntrusiveRefCntPtrInfo;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits