utils: Fix bad conversion for enumerations
When an interface contains both a string and an enumeration (or multiple
of each), the variant visitor matches the wrong make specialization.
This is because a string is convertible to variant<string, enum, ...>.
Fix this by moving out all conversions from a string to the template
specialization that first checks if the string can be converted to
an enumeration.
This still leaves a hole where trying to set a fully-qualified
enumeration name to a string property will fail, but I am not sure what
to do about that within the current PIM framework.
Tested: Tested Notify with enumerations on interfaces that contain both
a string and an enumeration.
Signed-off-by: Santosh Puranik <santosh.puranik@in.ibm.com>
Change-Id: I58b93a225ccf0b6b70317b2a2050a4dfa2b1b6f7
diff --git a/utils.hpp b/utils.hpp
index 9f82b47..fbe1d6a 100644
--- a/utils.hpp
+++ b/utils.hpp
@@ -44,11 +44,17 @@
/** @struct Make
* @brief Return variant visitor.
*
- * struct Make specialization if Arg is in T (int -> variant<int, char>).
+ * struct Make specialization if Arg is in T (int -> variant<int, char>),
+ * but not a string. Strings are used to represent enumerations by
+ * sdbusplus, so they are attempted in the following specialization.
*/
template <typename T, typename Arg>
- struct Make<T, Arg,
- typename std::enable_if_t<std::is_convertible_v<Arg, T>>>
+ struct Make<
+ T, Arg,
+ typename std::enable_if_t<
+ !std::is_same_v<std::string,
+ std::remove_cv_t<std::remove_reference_t<Arg>>> &&
+ std::is_convertible_v<Arg, T>>>
{
static auto make(Arg&& arg)
{
@@ -59,16 +65,16 @@
/** @struct Make
* @brief Return variant visitor.
*
- * struct Make specialization if Arg is a string, but not otherwise
- * directly convertable by C++ conversion constructors. Strings might
- * be convertable using underlying sdbusplus routines, so give them an
- * attempt.
+ * struct Make specialization if Arg is a string.Strings might
+ * be convertable (for ex. to enumerations) using underlying sdbusplus
+ * routines, so give them an attempt. In case the string is not convertible
+ * to an enumeration, sdbusplus::message::convert_from_string will return a
+ * string back anyway.
*/
template <typename T, typename Arg>
struct Make<
T, Arg,
typename std::enable_if_t<
- !std::is_convertible_v<Arg, T> &&
std::is_same_v<std::string,
std::remove_cv_t<std::remove_reference_t<Arg>>> &&
sdbusplus::message::has_convert_from_string_v<T>>>