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()) {