schema compile CHANGE support for RPC/action in deviations and additional tests
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 7916074..98c27d2 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -2985,7 +2985,7 @@
             LY_CHECK_RET(parse_ext(ctx, data, word, word_len, LYEXT_SUBSTMT_SELF, 0, &act->exts));
             break;
         default:
-            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), "action");
+            LOGVAL_YANG(ctx, LY_VCODE_INCHILDSTMT, ly_stmt2str(kw), parent ? "action" : "rpc");
             return LY_EVALID;
         }
     }
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index bbf0d9b..37439dc 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -4888,6 +4888,7 @@
     struct ly_set targets = {0};
     struct lysc_node *target; /* target target of the deviation */
     struct lysc_node_list *list;
+    struct lysc_action *actions;
     struct lysp_deviation *dev;
     struct lysp_deviate *d, **dp_new;
     struct lysp_deviate_add *d_add;
@@ -4930,7 +4931,19 @@
         /* resolve the target */
         LY_CHECK_GOTO(lys_resolve_schema_nodeid(ctx, dev->nodeid, 0, NULL, ctx->mod, 0, 1,
                                                 (const struct lysc_node**)&target, &flags), cleanup);
-
+        if (target->nodetype == LYS_ACTION) {
+            /* move the target pointer to input/output to make them different from the action and
+             * between them. Before the devs[] item is being processed, the target pointer must be fixed
+             * back to the RPC/action node due to a better compatibility and decision code in this function.
+             * The LYSC_OPT_INTERNAL is used as a flag to this change. */
+            if (flags & LYSC_OPT_RPC_INPUT) {
+                target = (struct lysc_node*)&((struct lysc_action*)target)->input;
+                flags |= LYSC_OPT_INTERNAL;
+            } else if (flags & LYSC_OPT_RPC_OUTPUT) {
+                target = (struct lysc_node*)&((struct lysc_action*)target)->output;
+                flags |= LYSC_OPT_INTERNAL;
+            }
+        }
         /* insert into the set of targets with duplicity detection */
         i = ly_set_add(&targets, target, 0);
         if (!devs[i]) {
@@ -5030,15 +5043,55 @@
 
     /* apply deviations */
     for (u = 0; u < devs_p.count && devs[u]; ++u) {
+        if (devs[u]->flags & LYSC_OPT_INTERNAL) {
+            /* fix the target pointer in case of RPC's/action's input/output */
+            if (devs[u]->flags & LYSC_OPT_RPC_INPUT) {
+                devs[u]->target = (struct lysc_node*)((char*)devs[u]->target - offsetof(struct lysc_action, input));
+            } else if (devs[u]->flags & LYSC_OPT_RPC_OUTPUT) {
+                devs[u]->target = (struct lysc_node*)((char*)devs[u]->target - offsetof(struct lysc_action, output));
+            }
+        }
+
         /* not-supported */
         if (devs[u]->not_supported) {
             if (LY_ARRAY_SIZE(devs[u]->deviates) > 1) {
                 LOGWRN(ctx->ctx, "Useless multiple (%u) deviates on node \"%s\" since the node is not-supported.",
                        LY_ARRAY_SIZE(devs[u]->deviates), devs[u]->nodeid);
             }
-            /* remove the target node */
-            lysc_disconnect(devs[u]->target);
-            lysc_node_free(ctx->ctx, devs[u]->target);
+            if (devs[u]->target->nodetype == LYS_ACTION) {
+                if (devs[u]->flags & LYSC_OPT_RPC_INPUT) {
+                    /* remove RPC's/action's input */
+                    lysc_action_inout_free(ctx->ctx, &((struct lysc_action*)devs[u]->target)->input);
+                    memset(&((struct lysc_action*)devs[u]->target)->input, 0, sizeof ((struct lysc_action*)devs[u]->target)->input);
+                } else if (devs[u]->flags & LYSC_OPT_RPC_OUTPUT) {
+                    /* remove RPC's/action's output */
+                    lysc_action_inout_free(ctx->ctx, &((struct lysc_action*)devs[u]->target)->output);
+                    memset(&((struct lysc_action*)devs[u]->target)->output, 0, sizeof ((struct lysc_action*)devs[u]->target)->output);
+                } else {
+                    /* remove RPC/action */
+                    if (devs[u]->target->parent) {
+                        actions = (struct lysc_action*)lysc_node_actions(devs[u]->target->parent);
+                    } else {
+                        actions = devs[u]->target->module->compiled->rpcs;
+                    }
+                    LY_ARRAY_FOR(actions, x) {
+                        if (&actions[x] == (struct lysc_action*)devs[u]->target) {
+                            break;
+                        }
+                    }
+                    if (x < LY_ARRAY_SIZE(actions)) {
+                        lysc_action_free(ctx->ctx, &actions[x]);
+                        memmove(&actions[x], &actions[x + 1], (LY_ARRAY_SIZE(actions) - (x + 1)) * sizeof *actions);
+                        LY_ARRAY_DECREMENT(actions);
+                    }
+                }
+            } else if (devs[u]->target->nodetype == LYS_NOTIF) {
+                /* TODO Notification */
+            } else {
+                /* remove the target node */
+                lysc_disconnect(devs[u]->target);
+                lysc_node_free(ctx->ctx, devs[u]->target);
+            }
 
             continue;
         }
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index a17694a..062524d 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -170,7 +170,7 @@
 
 }
 
-static void
+void
 lysp_action_inout_free(struct ly_ctx *ctx, struct lysp_action_inout *inout)
 {
     struct lysp_node *node, *next;
@@ -630,29 +630,27 @@
 }
 
 void
-lysc_action_free(struct ly_ctx *ctx, struct lysc_action *action)
+lysc_action_inout_free(struct ly_ctx *ctx, struct lysc_action_inout *inout)
 {
     struct lysc_node *child, *child_next;
 
+    FREE_ARRAY(ctx, inout->exts, lysc_ext_instance_free);
+    FREE_ARRAY(ctx, inout->musts, lysc_must_free);
+    LY_LIST_FOR_SAFE(inout->data, child_next, child) {
+        lysc_node_free(ctx, child);
+    }
+}
+
+void
+lysc_action_free(struct ly_ctx *ctx, struct lysc_action *action)
+{
     FREE_STRING(ctx, action->name);
     FREE_STRING(ctx, action->dsc);
     FREE_STRING(ctx, action->ref);
     FREE_ARRAY(ctx, action->iffeatures, lysc_iffeature_free);
     FREE_ARRAY(ctx, action->exts, lysc_ext_instance_free);
-
-    /* input */
-    FREE_ARRAY(ctx, action->input.exts, lysc_ext_instance_free);
-    FREE_ARRAY(ctx, action->input.musts, lysc_must_free);
-    LY_LIST_FOR_SAFE(action->input.data, child_next, child) {
-        lysc_node_free(ctx, child);
-    }
-
-    /* output */
-    FREE_ARRAY(ctx, action->output.exts, lysc_ext_instance_free);
-    FREE_ARRAY(ctx, action->output.musts, lysc_must_free);
-    LY_LIST_FOR_SAFE(action->output.data, child_next, child) {
-        lysc_node_free(ctx, child);
-    }
+    lysc_action_inout_free(ctx, &action->input);
+    lysc_action_inout_free(ctx, &action->output);
 }
 
 static void
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index f5b9174..57c381b 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -958,6 +958,10 @@
         return "anydata";
     case LYS_CASE:
         return "case";
+    case LYS_ACTION:
+        return "RPC/action";
+    case LYS_NOTIF:
+        return "Notification";
     default:
         return "unknown";
     }
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 792ce51..c20daad 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -500,6 +500,22 @@
 void lysc_must_free(struct ly_ctx *ctx, struct lysc_must *must);
 
 /**
+ * @brief Free the data inside compiled input/output structure.
+ * @param[in] ctx libyang context where the string data resides in a dictionary.
+ * @param[in,out] inout Compiled inout structure to be cleaned.
+ * Since the structure is part of the RPC/action structure, it is not freed itself.
+ */
+void lysc_action_inout_free(struct ly_ctx *ctx, struct lysc_action_inout *inout);
+
+/**
+ * @brief Free the data inside compiled RPC/action structure.
+ * @param[in] ctx libyang context where the string data resides in a dictionary.
+ * @param[in,out] action Compiled action structure to be cleaned.
+ * Since the structure is typically part of the sized array, the structure itself is not freed.
+ */
+void lysc_action_free(struct ly_ctx *ctx, struct lysc_action *action);
+
+/**
  * @brief Free the compiled extension instance structure.
  * @param[in] ctx libyang context where the string data resides in a dictionary.
  * @param[in,out] ext Compiled extension instance structure to be cleaned.