YANG parser BUGFIX updating pointers to objects stored in sized arrays

When creating parsed schema tree, various sized arrays are resized
(reallocated) as necessary so the location of the objects stored in them
may change. Therefore it is necessary to update all such pointers
(typically parent pointer) when the parsing is finished.
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 9cc2bac..1015593 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -126,6 +126,9 @@
 LY_ERR parse_list(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_node **siblings);
 LY_ERR parse_grouping(struct lys_parser_ctx *ctx, const char **data, struct lysp_node *parent, struct lysp_grp **groupings);
 
+static LY_ERR parse_finalize_reallocated(struct lys_parser_ctx *ctx, struct lysp_grp *groupings, struct lysp_augment *augments,
+                                         struct lysp_action *actions, struct lysp_notif *notifs);
+
 /**
  * @brief Add another character to dynamic buffer, a low-level function.
  *
@@ -2861,7 +2864,7 @@
     }
 
     /* store data for collision check */
-    if (parent) {
+    if (parent && !(parent->nodetype & (LYS_GROUPING | LYS_ACTION | LYS_INOUT | LYS_NOTIF))) {
         ly_set_add(&ctx->tpdfs_nodes, parent, 0);
     }
 
@@ -2885,8 +2888,6 @@
     char *word;
     size_t word_len;
     enum yang_keyword kw;
-    unsigned int u;
-    struct lysp_node *child;
 
     if (inout_p->nodetype) {
         LOGVAL_YANG(ctx, LY_VCODE_DUPSTMT, ly_stmt2str(inout_kw));
@@ -2898,7 +2899,7 @@
     inout_p->parent = parent;
 
     /* parse substatements */
-    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
+    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
         switch (kw) {
         case YANG_ANYDATA:
             YANG_CHECK_STMTVER2_RET(ctx, "anydata", ly_stmt2str(inout_kw));
@@ -2942,12 +2943,11 @@
             return LY_EVALID;
         }
     }
+    LY_CHECK_RET(ret);
+checks:
     /* finalize parent pointers to the reallocated items */
-    LY_ARRAY_FOR(inout_p->groupings, u) {
-        LY_LIST_FOR(inout_p->groupings[u].data, child) {
-            child->parent = (struct lysp_node*)&inout_p->groupings[u];
-        }
-    }
+    LY_CHECK_RET(parse_finalize_reallocated(ctx, inout_p->groupings, NULL, NULL, NULL));
+
     return ret;
 }
 
@@ -2968,8 +2968,6 @@
     size_t word_len;
     enum yang_keyword kw;
     struct lysp_action *act;
-    struct lysp_node *child;
-    unsigned int u;
 
     LY_ARRAY_NEW_RET(ctx->ctx, *actions, act, LY_EMEM);
 
@@ -2979,7 +2977,7 @@
     act->nodetype = LYS_ACTION;
     act->parent = parent;
 
-    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
+    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
         switch (kw) {
         case YANG_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &act->dsc, Y_STR_ARG, &act->exts));
@@ -3015,12 +3013,11 @@
             return LY_EVALID;
         }
     }
+    LY_CHECK_RET(ret);
+checks:
     /* finalize parent pointers to the reallocated items */
-    LY_ARRAY_FOR(act->groupings, u) {
-        LY_LIST_FOR(act->groupings[u].data, child) {
-            child->parent = (struct lysp_node*)&act->groupings[u];
-        }
-    }
+    LY_CHECK_RET(parse_finalize_reallocated(ctx, act->groupings, NULL, NULL, NULL));
+
     return ret;
 }
 
@@ -3041,8 +3038,6 @@
     size_t word_len;
     enum yang_keyword kw;
     struct lysp_notif *notif;
-    struct lysp_node *child;
-    unsigned int u;
 
     LY_ARRAY_NEW_RET(ctx->ctx, *notifs, notif, LY_EMEM);
 
@@ -3052,7 +3047,7 @@
     notif->nodetype = LYS_NOTIF;
     notif->parent = parent;
 
-    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
+    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
         switch (kw) {
         case YANG_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &notif->dsc, Y_STR_ARG, &notif->exts));
@@ -3110,12 +3105,11 @@
             return LY_EVALID;
         }
     }
+    LY_CHECK_RET(ret);
+checks:
     /* finalize parent pointers to the reallocated items */
-    LY_ARRAY_FOR(notif->groupings, u) {
-        LY_LIST_FOR(notif->groupings[u].data, child) {
-            child->parent = (struct lysp_node*)&notif->groupings[u];
-        }
-    }
+    LY_CHECK_RET(parse_finalize_reallocated(ctx, notif->groupings, NULL, NULL, NULL));
+
     return ret;
 }
 
@@ -3136,8 +3130,6 @@
     size_t word_len;
     enum yang_keyword kw;
     struct lysp_grp *grp;
-    struct lysp_node *child;
-    unsigned int u;
 
     LY_ARRAY_NEW_RET(ctx->ctx, *groupings, grp, LY_EMEM);
 
@@ -3147,7 +3139,7 @@
     grp->nodetype = LYS_GROUPING;
     grp->parent = parent;
 
-    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
+    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
         switch (kw) {
         case YANG_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &grp->dsc, Y_STR_ARG, &grp->exts));
@@ -3206,12 +3198,11 @@
             return LY_EVALID;
         }
     }
+    LY_CHECK_RET(ret);
+checks:
     /* finalize parent pointers to the reallocated items */
-    LY_ARRAY_FOR(grp->groupings, u) {
-        LY_LIST_FOR(grp->groupings[u].data, child) {
-            child->parent = (struct lysp_node*)&grp->groupings[u];
-        }
-    }
+    LY_CHECK_RET(parse_finalize_reallocated(ctx, grp->groupings, NULL, grp->actions, grp->notifs));
+
     return ret;
 }
 
@@ -3241,7 +3232,7 @@
     aug->nodetype = LYS_AUGMENT;
     aug->parent = parent;
 
-    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
+    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
         switch (kw) {
         case YANG_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &aug->dsc, Y_STR_ARG, &aug->exts));
@@ -3303,10 +3294,115 @@
             return LY_EVALID;
         }
     }
+    LY_CHECK_RET(ret);
+checks:
+    /* finalize parent pointers to the reallocated items */
+    LY_CHECK_RET(parse_finalize_reallocated(ctx, NULL, NULL, aug->actions, aug->notifs));
+
     return ret;
 }
 
 /**
+ * @brief Finalize some of the structures in case they are stored in sized array,
+ * which can be possibly reallocated and some other data may point to them.
+ *
+ * Update parent pointers in the nodes inside grouping/augment/RPC/Notification, which could be reallocated.
+ *
+ * @param[in] mod Parsed module to be updated.
+ * @return LY_ERR value (currently only LY_SUCCESS, but it can change in future).
+ */
+static LY_ERR
+parse_finalize_reallocated(struct lys_parser_ctx *ctx, struct lysp_grp *groupings, struct lysp_augment *augments,
+                           struct lysp_action *actions, struct lysp_notif *notifs)
+{
+    unsigned int u, v;
+    struct lysp_node *child;
+
+    /* finalize parent pointers to the reallocated items */
+
+    /* gropings */
+    LY_ARRAY_FOR(groupings, u) {
+        LY_LIST_FOR(groupings[u].data, child) {
+            child->parent = (struct lysp_node*)&groupings[u];
+        }
+        LY_ARRAY_FOR(groupings[u].actions, v) {
+            groupings[u].actions[v].parent = (struct lysp_node*)&groupings[u];
+        }
+        LY_ARRAY_FOR(groupings[u].notifs, v) {
+            groupings[u].notifs[v].parent = (struct lysp_node*)&groupings[u];
+        }
+        LY_ARRAY_FOR(groupings[u].groupings, v) {
+            groupings[u].groupings[v].parent = (struct lysp_node*)&groupings[u];
+        }
+        if (groupings[u].typedefs) {
+            ly_set_add(&ctx->tpdfs_nodes, &groupings[u], 0);
+        }
+    }
+
+    /* augments */
+    LY_ARRAY_FOR(augments, u) {
+        LY_LIST_FOR(augments[u].child, child) {
+            child->parent = (struct lysp_node*)&augments[u];
+        }
+        LY_ARRAY_FOR(augments[u].actions, v) {
+            augments[u].actions[v].parent = (struct lysp_node*)&augments[u];
+        }
+        LY_ARRAY_FOR(augments[u].notifs, v) {
+            augments[u].notifs[v].parent = (struct lysp_node*)&augments[u];
+        }
+    }
+
+    /* actions */
+    LY_ARRAY_FOR(actions, u) {
+        if (actions[u].input.parent) {
+            actions[u].input.parent = (struct lysp_node*)&actions[u];
+            LY_LIST_FOR(actions[u].input.data, child) {
+                child->parent = (struct lysp_node*)&actions[u].input;
+            }
+            LY_ARRAY_FOR(actions[u].input.groupings, v) {
+                actions[u].input.groupings[v].parent = (struct lysp_node*)&actions[u].input;
+            }
+            if (actions[u].input.typedefs) {
+                ly_set_add(&ctx->tpdfs_nodes, &actions[u].input, 0);
+            }
+        }
+        if (actions[u].output.parent) {
+            actions[u].output.parent = (struct lysp_node*)&actions[u];
+            LY_LIST_FOR(actions[u].output.data, child) {
+                child->parent = (struct lysp_node*)&actions[u].output;
+            }
+            LY_ARRAY_FOR(actions[u].output.groupings, v) {
+                actions[u].output.groupings[v].parent = (struct lysp_node*)&actions[u].output;
+            }
+            if (actions[u].output.typedefs) {
+                ly_set_add(&ctx->tpdfs_nodes, &actions[u].output, 0);
+            }
+        }
+        LY_ARRAY_FOR(actions[u].groupings, v) {
+            actions[u].groupings[v].parent = (struct lysp_node*)&actions[u];
+        }
+        if (actions[u].typedefs) {
+            ly_set_add(&ctx->tpdfs_nodes, &actions[u], 0);
+        }
+    }
+
+    /* notifications */
+    LY_ARRAY_FOR(notifs, u) {
+        LY_LIST_FOR(notifs[u].data, child) {
+            child->parent = (struct lysp_node*)&notifs[u];
+        }
+        LY_ARRAY_FOR(notifs[u].groupings, v) {
+            notifs[u].groupings[v].parent = (struct lysp_node*)&notifs[u];
+        }
+        if (notifs[u].typedefs) {
+            ly_set_add(&ctx->tpdfs_nodes, &notifs[u], 0);
+        }
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
  * @brief Parse the uses statement.
  *
  * @param[in] ctx yang parser context for logging.
@@ -3344,7 +3440,7 @@
     INSERT_WORD(ctx, buf, uses->name, word, word_len);
 
     /* parse substatements */
-    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
+    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
         switch (kw) {
         case YANG_DESCRIPTION:
             LY_CHECK_RET(parse_text_field(ctx, data, LYEXT_SUBSTMT_DESCRIPTION, 0, &uses->dsc, Y_STR_ARG, &uses->exts));
@@ -3376,6 +3472,10 @@
             return LY_EVALID;
         }
     }
+checks:
+    /* finalize parent pointers to the reallocated items */
+    LY_CHECK_RET(parse_finalize_reallocated(ctx, NULL, uses->augments, NULL, NULL));
+
     return ret;
 }
 
@@ -3595,7 +3695,6 @@
     enum yang_keyword kw;
     struct lysp_node *iter;
     struct lysp_node_container *cont;
-    unsigned int u;
 
     /* create structure */
     cont = calloc(1, sizeof *cont);
@@ -3616,7 +3715,7 @@
     INSERT_WORD(ctx, buf, cont->name, word, word_len);
 
     /* parse substatements */
-    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret,) {
+    YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret, goto checks) {
         switch (kw) {
         case YANG_CONFIG:
             LY_CHECK_RET(parse_config(ctx, data, &cont->flags, &cont->exts));
@@ -3690,12 +3789,9 @@
             return LY_EVALID;
         }
     }
+checks:
     /* finalize parent pointers to the reallocated items */
-    LY_ARRAY_FOR(cont->groupings, u) {
-        LY_LIST_FOR(cont->groupings[u].data, iter) {
-            iter->parent = (struct lysp_node*)&cont->groupings[u];
-        }
-    }
+    LY_CHECK_RET(parse_finalize_reallocated(ctx, cont->groupings, NULL, cont->actions, cont->notifs));
     return ret;
 }
 
@@ -3717,7 +3813,6 @@
     enum yang_keyword kw;
     struct lysp_node *iter;
     struct lysp_node_list *list;
-    unsigned int u;
 
     /* create structure */
     list = calloc(1, sizeof *list);
@@ -3825,13 +3920,10 @@
         }
     }
     LY_CHECK_RET(ret);
-    /* finalize parent pointers to the reallocated items */
-    LY_ARRAY_FOR(list->groupings, u) {
-        LY_LIST_FOR(list->groupings[u].data, iter) {
-            iter->parent = (struct lysp_node*)&list->groupings[u];
-        }
-    }
 checks:
+    /* finalize parent pointers to the reallocated items */
+    LY_CHECK_RET(parse_finalize_reallocated(ctx, list->groupings, NULL, list->actions, list->notifs));
+
     if (list->max && list->min > list->max) {
         LOGVAL_YANG(ctx, LYVE_SEMANTICS,
                     "Invalid combination of min-elements and max-elements: min value %u is bigger than the max value %u.",
@@ -4360,32 +4452,6 @@
 }
 
 /**
- * @brief Finalize some of the (sub)module structure after parsing.
- *
- * Update parent pointers in the nodes inside grouping/RPC/Notification, which could be reallocated.
- *
- * @param[in] mod Parsed module to be updated.
- * @return LY_ERR value (currently only LY_SUCCESS, but it can change in future).
- */
-static LY_ERR
-parse_sub_module_finalize(struct lysp_module *mod)
-{
-    unsigned int u;
-    struct lysp_node *child;
-
-    /* finalize parent pointers to the reallocated items */
-    LY_ARRAY_FOR(mod->groupings, u) {
-        LY_LIST_FOR(mod->groupings[u].data, child) {
-            child->parent = (struct lysp_node*)&mod->groupings[u];
-        }
-    }
-
-    /* TODO the same finalization for rpcs and notifications, do also in the relevant nodes */
-
-    return LY_SUCCESS;
-}
-
-/**
  * @brief Parse module substatements.
  *
  * @param[in] ctx yang parser context for logging.
@@ -4573,7 +4639,7 @@
 
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(parse_sub_module_finalize(mod));
+    LY_CHECK_RET(parse_finalize_reallocated(ctx, mod->groupings, mod->augments, mod->rpcs, mod->notifs));
 
     /* mandatory substatements */
     if (!mod->mod->ns) {
@@ -4779,7 +4845,7 @@
 
 checks:
     /* finalize parent pointers to the reallocated items */
-    LY_CHECK_RET(parse_sub_module_finalize((struct lysp_module*)submod));
+    LY_CHECK_RET(parse_finalize_reallocated(ctx, submod->groupings, submod->augments, submod->rpcs, submod->notifs));
 
     /* mandatory substatements */
     if (!submod->belongsto) {