* 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
----------------
``-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
----------------------
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
return true; // Parse error!
this->setValue(Val);
this->setPosition(pos);
+ Callback(Val);
return false;
}
template <class T> DataType &operator=(const T &Val) {
this->setValue(Val);
+ Callback(Val);
return this->getValue();
}
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>;
list_storage<DataType, StorageClass>::addValue(Val);
setPosition(pos);
Positions.push_back(pos);
+ Callback(Val);
return false;
}
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.
this->addValue(Val);
setPosition(pos);
Positions.push_back(pos);
+ Callback(Val);
return false;
}
~StackOption() override { this->removeArgument(); }
template <class DT> StackOption<T> &operator=(const DT &V) {
- this->setValue(V);
+ Base::operator=(V);
return *this;
}
};
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