mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
[CommandLine] Add callbacks to Options
Summary: Add a new cl::callback attribute to Option. This attribute specifies a callback function that is called when an option is seen, and can be used to set other options, as in option A implies option B. If the option is a `cl::list`, and `cl::CommaSeparated` is also specified, the callback will fire once for each value. This could be used to validate combinations or selectively set other options. Reviewers: beanz, thomasfinch, MaskRay, thopre, serge-sans-paille Reviewed By: beanz Subscribers: llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D70620
This commit is contained in:
parent
7d2c6fd3c7
commit
4da312a2f1
@ -996,6 +996,31 @@ This section describes the basic attributes that you can specify on options.
|
||||
* The **cl::cat** attribute specifies the option category that the option
|
||||
belongs to. The category should be a `cl::OptionCategory`_ object.
|
||||
|
||||
.. _cl::callback:
|
||||
|
||||
* The **cl::callback** attribute specifies a callback function that is
|
||||
called when an option is seen, and can be used to set other options,
|
||||
as in option B implies option A. If the option is a `cl::list`_,
|
||||
and `cl::CommaSeparated`_ is also specified, the callback will fire
|
||||
once for each value. This could be used to validate combinations or
|
||||
selectively set other options.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
cl::opt<bool> OptA("a", cl::desc("option a"));
|
||||
cl::opt<bool> OptB(
|
||||
"b", cl::desc("option b -- This option turns on option a"),
|
||||
cl::callback([&](const bool &) { OptA = true; }));
|
||||
cl::list<std::string, cl::list<std::string>> List(
|
||||
"list",
|
||||
cl::desc("option list -- This option turns on options a when "
|
||||
"'foo' is included in list"),
|
||||
cl::CommaSeparated,
|
||||
cl::callback([&](const std::string &Str) {
|
||||
if (Str == "foo")
|
||||
OptA = true;
|
||||
}));
|
||||
|
||||
Option Modifiers
|
||||
----------------
|
||||
|
||||
|
@ -90,6 +90,9 @@ Non-comprehensive list of changes in this release
|
||||
``-cfguard-nochecks`` option. Note that this feature should always be used
|
||||
with optimizations enabled.
|
||||
|
||||
* ``Callbacks`` have been added to ``CommandLine Options``. These can
|
||||
be used to validate of selectively enable other options.
|
||||
|
||||
Changes to the LLVM IR
|
||||
----------------------
|
||||
|
||||
|
@ -471,6 +471,43 @@ struct sub {
|
||||
template <class Opt> void apply(Opt &O) const { O.addSubCommand(Sub); }
|
||||
};
|
||||
|
||||
// Specify a callback function to be called when an option is seen.
|
||||
// Can be used to set other options automatically.
|
||||
template <typename R, typename Ty> struct cb {
|
||||
std::function<R(Ty)> CB;
|
||||
|
||||
cb(std::function<R(Ty)> CB) : CB(CB) {}
|
||||
|
||||
template <typename Opt> void apply(Opt &O) const { O.setCallback(CB); }
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename F>
|
||||
struct callback_traits : public callback_traits<decltype(&F::operator())> {};
|
||||
|
||||
template <typename R, typename C, typename... Args>
|
||||
struct callback_traits<R (C::*)(Args...) const> {
|
||||
using result_type = R;
|
||||
using arg_type = typename std::tuple_element<0, std::tuple<Args...>>::type;
|
||||
static_assert(sizeof...(Args) == 1, "callback function must have one and only one parameter");
|
||||
static_assert(std::is_same<result_type, void>::value,
|
||||
"callback return type must be void");
|
||||
static_assert(
|
||||
std::is_lvalue_reference<arg_type>::value &&
|
||||
std::is_const<typename std::remove_reference<arg_type>::type>::value,
|
||||
"callback arg_type must be a const lvalue reference");
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename F>
|
||||
cb<typename detail::callback_traits<F>::result_type,
|
||||
typename detail::callback_traits<F>::arg_type>
|
||||
callback(F CB) {
|
||||
using result_type = typename detail::callback_traits<F>::result_type;
|
||||
using arg_type = typename detail::callback_traits<F>::arg_type;
|
||||
return cb<result_type, arg_type>(CB);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// OptionValue class
|
||||
|
||||
@ -1344,6 +1381,7 @@ class opt : public Option,
|
||||
return true; // Parse error!
|
||||
this->setValue(Val);
|
||||
this->setPosition(pos);
|
||||
Callback(Val);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1402,6 +1440,7 @@ public:
|
||||
|
||||
template <class T> DataType &operator=(const T &Val) {
|
||||
this->setValue(Val);
|
||||
Callback(Val);
|
||||
return this->getValue();
|
||||
}
|
||||
|
||||
@ -1411,6 +1450,14 @@ public:
|
||||
apply(this, Ms...);
|
||||
done();
|
||||
}
|
||||
|
||||
void setCallback(
|
||||
std::function<void(const typename ParserClass::parser_data_type &)> CB) {
|
||||
Callback = CB;
|
||||
}
|
||||
|
||||
std::function<void(const typename ParserClass::parser_data_type &)> Callback =
|
||||
[](const typename ParserClass::parser_data_type &) {};
|
||||
};
|
||||
|
||||
extern template class opt<unsigned>;
|
||||
@ -1550,6 +1597,7 @@ class list : public Option, public list_storage<DataType, StorageClass> {
|
||||
list_storage<DataType, StorageClass>::addValue(Val);
|
||||
setPosition(pos);
|
||||
Positions.push_back(pos);
|
||||
Callback(Val);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1596,6 +1644,14 @@ public:
|
||||
apply(this, Ms...);
|
||||
done();
|
||||
}
|
||||
|
||||
void setCallback(
|
||||
std::function<void(const typename ParserClass::parser_data_type &)> CB) {
|
||||
Callback = CB;
|
||||
}
|
||||
|
||||
std::function<void(const typename ParserClass::parser_data_type &)> Callback =
|
||||
[](const typename ParserClass::parser_data_type &) {};
|
||||
};
|
||||
|
||||
// multi_val - Modifier to set the number of additional values.
|
||||
@ -1696,6 +1752,7 @@ class bits : public Option, public bits_storage<DataType, Storage> {
|
||||
this->addValue(Val);
|
||||
setPosition(pos);
|
||||
Positions.push_back(pos);
|
||||
Callback(Val);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ public:
|
||||
~StackOption() override { this->removeArgument(); }
|
||||
|
||||
template <class DT> StackOption<T> &operator=(const DT &V) {
|
||||
this->setValue(V);
|
||||
Base::operator=(V);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
@ -1722,4 +1722,66 @@ TEST(CommandLineTest, OptionErrorMessageSuggest) {
|
||||
|
||||
cl::ResetAllOptionOccurrences();
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST(CommandLineTest, Callback) {
|
||||
cl::ResetCommandLineParser();
|
||||
|
||||
StackOption<bool> OptA("a", cl::desc("option a"));
|
||||
StackOption<bool> OptB(
|
||||
"b", cl::desc("option b -- This option turns on option a"),
|
||||
cl::callback([&](const bool &) { OptA = true; }));
|
||||
StackOption<bool> OptC(
|
||||
"c", cl::desc("option c -- This option turns on options a and b"),
|
||||
cl::callback([&](const bool &) { OptB = true; }));
|
||||
StackOption<std::string, cl::list<std::string>> List(
|
||||
"list",
|
||||
cl::desc("option list -- This option turns on options a, b, and c when "
|
||||
"'foo' is included in list"),
|
||||
cl::CommaSeparated,
|
||||
cl::callback([&](const std::string &Str) {
|
||||
if (Str == "foo")
|
||||
OptC = true;
|
||||
}));
|
||||
|
||||
const char *args1[] = {"prog", "-a"};
|
||||
EXPECT_TRUE(cl::ParseCommandLineOptions(2, args1));
|
||||
EXPECT_TRUE(OptA);
|
||||
EXPECT_FALSE(OptB);
|
||||
EXPECT_FALSE(OptC);
|
||||
EXPECT_TRUE(List.size() == 0);
|
||||
cl::ResetAllOptionOccurrences();
|
||||
|
||||
const char *args2[] = {"prog", "-b"};
|
||||
EXPECT_TRUE(cl::ParseCommandLineOptions(2, args2));
|
||||
EXPECT_TRUE(OptA);
|
||||
EXPECT_TRUE(OptB);
|
||||
EXPECT_FALSE(OptC);
|
||||
EXPECT_TRUE(List.size() == 0);
|
||||
cl::ResetAllOptionOccurrences();
|
||||
|
||||
const char *args3[] = {"prog", "-c"};
|
||||
EXPECT_TRUE(cl::ParseCommandLineOptions(2, args3));
|
||||
EXPECT_TRUE(OptA);
|
||||
EXPECT_TRUE(OptB);
|
||||
EXPECT_TRUE(OptC);
|
||||
EXPECT_TRUE(List.size() == 0);
|
||||
cl::ResetAllOptionOccurrences();
|
||||
|
||||
const char *args4[] = {"prog", "--list=foo,bar"};
|
||||
EXPECT_TRUE(cl::ParseCommandLineOptions(2, args4));
|
||||
EXPECT_TRUE(OptA);
|
||||
EXPECT_TRUE(OptB);
|
||||
EXPECT_TRUE(OptC);
|
||||
EXPECT_TRUE(List.size() == 2);
|
||||
cl::ResetAllOptionOccurrences();
|
||||
|
||||
const char *args5[] = {"prog", "--list=bar"};
|
||||
EXPECT_TRUE(cl::ParseCommandLineOptions(2, args5));
|
||||
EXPECT_FALSE(OptA);
|
||||
EXPECT_FALSE(OptB);
|
||||
EXPECT_FALSE(OptC);
|
||||
EXPECT_TRUE(List.size() == 1);
|
||||
|
||||
cl::ResetAllOptionOccurrences();
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
Loading…
x
Reference in New Issue
Block a user