Fix identityref bug when it's a typedef
When identityref was a typedef, YangSchema::validIdentities was not
working at all.
Change-Id: Ib94db4ac0d61a0eb716ae0c1e022fade3e52ef86
diff --git a/src/yang_schema.cpp b/src/yang_schema.cpp
index 0ace2f7..6507f08 100644
--- a/src/yang_schema.cpp
+++ b/src/yang_schema.cpp
@@ -144,20 +144,61 @@
}
namespace {
-std::set<enum_> enumValues(const libyang::S_Type& typeArg)
+enum class ResolveMode {
+ Enum,
+ Identity
+};
+/** @brief Resolves a typedef to a type which defines values.
+ * When we need allowed values of a type and that type is a typedef, we need to recurse into the typedef until we find a
+ * type which defines values. These values are the allowed values.
+ * Example:
+ *
+ * typedef MyOtherEnum {
+ * type enumeration {
+ * enum "A";
+ * enum "B";
+ * }
+ * }
+ *
+ * typedef MyEnum {
+ * type MyOtherEnum;
+ * }
+ *
+ * If `toResolve` points to MyEnum, then just doing ->enums()->enm() returns nothing and that means that this particular
+ * typedef (MyEnum) did not say which values are allowed. So, we need to dive into the parent enum (MyOtherEnum) with
+ * ->der()->type(). This typedef (MyOtherEnum) DID specify allowed values and enums()->enm() WILL contain them. These
+ * values are the only relevant values and we don't care about other parent typedefs. We return these values to the
+ * caller.
+ *
+ * For enums, this function simply returns all allowed enums.
+ * For identities, this function returns which bases `toResolve` has.
+ */
+template <ResolveMode TYPE>
+auto resolveTypedef(const libyang::S_Type& toResolve)
{
- auto type = typeArg;
- auto enm = type->info()->enums()->enm();
- // The enum can be a derived type and enm() only returns values,
- // if that specific typedef changed the possible values. So we go
- // up the hierarchy until we find a typedef that defined these values.
- while (enm.empty()) {
+ auto type = toResolve;
+ auto getValuesFromType = [] (const libyang::S_Type& type) {
+ if constexpr (TYPE == ResolveMode::Identity) {
+ return type->info()->ident()->ref();
+ } else {
+ return type->info()->enums()->enm();
+ }
+ };
+ auto values = getValuesFromType(type);
+ while (values.empty()) {
type = type->der()->type();
- enm = type->info()->enums()->enm();
+ values = getValuesFromType(type);
}
+ return values;
+}
+
+std::set<enum_> enumValues(const libyang::S_Type& type)
+{
+ auto values = resolveTypedef<ResolveMode::Enum>(type);
+
std::vector<libyang::S_Type_Enum> enabled;
- std::copy_if(enm.begin(), enm.end(), std::back_inserter(enabled), [](const libyang::S_Type_Enum& it) {
+ std::copy_if(values.begin(), values.end(), std::back_inserter(enabled), [](const libyang::S_Type_Enum& it) {
auto iffeatures = it->iffeature();
return std::all_of(iffeatures.begin(), iffeatures.end(), [](auto it) { return it->value(); });
});
@@ -171,10 +212,7 @@
{
std::set<identityRef_> identSet;
- // auto topLevelModule = leaf->module();
-
- auto info = type->info();
- for (auto base : info->ident()->ref()) { // Iterate over all bases
+ for (auto base : resolveTypedef<ResolveMode::Identity>(type)) { // Iterate over all bases
identSet.emplace(base->module()->name(), base->name());
// Iterate over derived identities (this is recursive!)
for (auto derived : base->der()->schema()) {
diff --git a/tests/yang.cpp b/tests/yang.cpp
index 1720d79..37b473d 100644
--- a/tests/yang.cpp
+++ b/tests/yang.cpp
@@ -81,6 +81,16 @@
base "pizza";
}
+ typedef foodTypedef {
+ type identityref {
+ base food;
+ }
+ }
+
+ leaf leafFoodTypedef {
+ type foodTypedef;
+ }
+
container a {
container a2 {
container a3 {
@@ -754,6 +764,19 @@
type = yang::Bits{{"carry", "sign", "overflow"}};
}
+ SECTION("foodTypedef")
+ {
+ node.first = "example-schema";
+ node.second = "leafFoodTypedef";
+ type = yang::IdentityRef{{
+ {"example-schema", "food"},
+ {"example-schema", "fruit"},
+ {"example-schema", "hawaii"},
+ {"example-schema", "pizza"},
+ {"second-schema", "pineapple"},
+ }};
+ }
+
REQUIRE(ys.leafType(path, node) == yang::TypeInfo(type, std::nullopt, expectedDescription));
}
@@ -801,7 +824,8 @@
{"example-schema"s, "dummyLeaf"},
{"example-schema"s, "addresses"},
{"example-schema"s, "subLeaf"},
- {"example-schema"s, "flagBits"}};
+ {"example-schema"s, "flagBits"},
+ {"example-schema"s, "leafFoodTypedef"}};
}
SECTION("example-schema:a")
@@ -864,6 +888,7 @@
{"example-schema"s, "leafEnumTypedef"},
{"example-schema"s, "leafEnumTypedefRestricted"},
{"example-schema"s, "leafEnumTypedefRestricted2"},
+ {"example-schema"s, "leafFoodTypedef"},
{"example-schema"s, "leafInt16"},
{"example-schema"s, "leafInt32"},
{"example-schema"s, "leafInt64"},
@@ -930,6 +955,7 @@
{boost::none, "/example-schema:leafEnumTypedef"},
{boost::none, "/example-schema:leafEnumTypedefRestricted"},
{boost::none, "/example-schema:leafEnumTypedefRestricted2"},
+ {boost::none, "/example-schema:leafFoodTypedef"},
{boost::none, "/example-schema:leafInt16"},
{boost::none, "/example-schema:leafInt32"},
{boost::none, "/example-schema:leafInt64"},