schema compile CHANGE support for deviation of mandatory property
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 1c23753..376bab4 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -567,6 +567,7 @@
  *       6 LYS_MAND_TRUE    |x|x|x|x|x|x| | | | | | | | |
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *       7 LYS_ORDBY_USER   | | | |x|x| | | | | | | | | |
+ *         LYS_MAND_FALSE   | |x|x| | |x| | | | | | | | |
  *                          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *       8 LYS_ORDBY_SYSTEM | | | |x|x| | | | | | | | | |
  *         LYS_PRESENCE     |x| | | | | | | | | | | | | |
@@ -601,7 +602,9 @@
                                           The ::lysc_node_leaflist and ::lysc_node_leaflist have this flag in case that min-elements > 0.
                                           The ::lysc_node_container has this flag if it is not a presence container and it has at least one
                                           child with LYS_MAND_TRUE. */
-#define LYS_MAND_FALSE   0x40        /**< mandatory false; applicable only to ::lysp_node_choice, ::lysp_node_leaf and ::lysp_node_anydata */
+#define LYS_MAND_FALSE   0x40        /**< mandatory false; applicable only to ::lysp_node_choice/::lysc_node_choice,
+                                          ::lysp_node_leaf/::lysc_node_leaf and ::lysp_node_anydata/::lysc_node_anydata.
+                                          This flag is present only in case the mandatory false statement was explicitly specified. */
 #define LYS_MAND_MASK    0x60        /**< mask for mandatory values */
 #define LYS_PRESENCE     0x80        /**< flag for presence property of a container, applicable only to ::lysc_node_container */
 #define LYS_UNIQUE       0x80        /**< flag for leafs being part of a unique set, applicable only to ::lysc_node_leaf */
@@ -635,7 +638,7 @@
                                           away when it is refined to be mandatory node. Similarly it is used for deviations to distinguish
                                           between own default or the default values taken from the type. */
 #define LYS_SET_UNITS    0x0400      /**< flag to know if the leaf's/leaflist's units are their own (flag set) or it is taken from the type. */
-#define LYS_SET_CONFIG   0x0800      /**< flag to know if the config property set explicitely (flag set) or it is inherited. */
+#define LYS_SET_CONFIG   0x0800      /**< flag to know if the config property was set explicitly (flag set) or it is inherited. */
 
 #define LYS_FLAGS_COMPILED_MASK 0xff /**< mask for flags that maps to the compiled structures */
 /** @} */
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index e04e409..06054a6 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -3864,7 +3864,7 @@
     } else { /* unset flag */
         for (; parent && parent->nodetype == LYS_CONTAINER && (parent->flags & LYS_MAND_TRUE); parent = parent->parent) {
             for (iter = (struct lysc_node*)lysc_node_children(parent); iter; iter = iter->next) {
-                if (iter->flags && LYS_MAND_TRUE) {
+                if (iter->flags & LYS_MAND_TRUE) {
                     /* there is another mandatory node */
                     return;
                 }
@@ -4065,6 +4065,68 @@
 }
 
 /**
+ * @brief Apply refined or deviated mandatory flag to the target node.
+ *
+ * @param[in] ctx Compile context.
+ * @param[in] node Target node where the mandatory property is supposed to be changed.
+ * @param[in] mandatory_flag Node's mandatory flag to be applied to the @p node.
+ * @param[in] nodeid Schema nodeid used to identify target of refine/deviation (for logging).
+ * @param[in] refine_flag Flag to distinguish if the change is caused by refine (flag set) or deviation (for logging).
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lys_compile_change_mandatory(struct lysc_ctx *ctx, struct lysc_node *node, uint16_t mandatory_flag, const char *nodeid, int refine_flag)
+{
+    if (!(node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_ANYXML | LYS_CHOICE))) {
+        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+               "Invalid %s of mandatory in \"%s\" - %s cannot hold mandatory statement.",
+               refine_flag ? "refine" : "deviation", nodeid, lys_nodetype2str(node->nodetype));
+        return LY_EVALID;
+    }
+
+    if (mandatory_flag & LYS_MAND_TRUE) {
+        /* check if node has default value */
+        if (node->nodetype & LYS_LEAF) {
+            if (node->flags & LYS_SET_DFLT) {
+                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                       "Invalid %s of mandatory in \"%s\" - leaf already has \"default\" statement.",
+                       refine_flag ? "refine" : "deviation", nodeid);
+                return LY_EVALID;
+            } else {
+                /* remove the default value taken from the leaf's type */
+                FREE_STRING(ctx->ctx, ((struct lysc_node_leaf*)node)->dflt);
+                ((struct lysc_node_leaf*)node)->dflt = NULL;
+            }
+        } else if ((node->nodetype & LYS_CHOICE) && ((struct lysc_node_choice*)node)->dflt) {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                   "Invalid %s of mandatory in \"%s\" - choice already has \"default\" statement.",
+                   refine_flag ? "refine" : "deviation", nodeid);
+            return LY_EVALID;
+        }
+        if (node->parent && (node->parent->flags & LYS_SET_DFLT)) {
+            LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
+                   "Invalid %s of mandatory in \"%s\" under the default case.",
+                   refine_flag ? "refine" : "deviation", nodeid);
+            return LY_EVALID;
+        }
+
+        node->flags &= ~LYS_MAND_FALSE;
+        node->flags |= LYS_MAND_TRUE;
+        lys_compile_mandatory_parents(node->parent, 1);
+    } else {
+        /* make mandatory false */
+        node->flags &= ~LYS_MAND_TRUE;
+        node->flags |= LYS_MAND_FALSE;
+        lys_compile_mandatory_parents(node->parent, 0);
+        if ((node->nodetype & LYS_LEAF) && !((struct lysc_node_leaf*)node)->dflt) {
+            /* get the type's default value if any */
+            DUP_STRING(ctx->ctx, ((struct lysc_node_leaf*)node)->type->dflt, ((struct lysc_node_leaf*)node)->dflt);
+        }
+    }
+    return LY_SUCCESS;
+}
+
+/**
  * @brief Compile parsed uses statement - resolve target grouping and connect its content into parent.
  * If present, also apply uses's modificators.
  *
@@ -4289,48 +4351,7 @@
 
         /* mandatory */
         if (rfn->flags & LYS_MAND_MASK) {
-            if (!(node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_ANYXML | LYS_CHOICE))) {
-                LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                       "Invalid refine of mandatory in \"%s\" - %s cannot hold mandatory statement.",
-                       rfn->nodeid, lys_nodetype2str(node->nodetype));
-                goto error;
-            }
-            /* in compiled flags, only the LYS_MAND_TRUE is present */
-            if (rfn->flags & LYS_MAND_TRUE) {
-                /* check if node has default value */
-                if (node->nodetype & LYS_LEAF) {
-                    if (node->flags & LYS_SET_DFLT) {
-                        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                               "Invalid refine of mandatory in \"%s\" - leaf already has \"default\" statement.", rfn->nodeid);
-                        goto error;
-                    } else {
-                        /* remove the default value taken from the leaf's type */
-                        FREE_STRING(ctx->ctx, ((struct lysc_node_leaf*)node)->dflt);
-                        ((struct lysc_node_leaf*)node)->dflt = NULL;
-                    }
-                } else if ((node->nodetype & LYS_CHOICE) && ((struct lysc_node_choice*)node)->dflt) {
-                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                           "Invalid refine of mandatory in \"%s\" - choice already has \"default\" statement.", rfn->nodeid);
-                    goto error;
-                }
-                if (node->parent && (node->parent->flags & LYS_SET_DFLT)) {
-                    LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_SEMANTICS,
-                           "Invalid refine of mandatory in \"%s\" - %s under the default case.",
-                           rfn->nodeid, lys_nodetype2str(node->nodetype));
-                    goto error;
-                }
-
-                node->flags |= LYS_MAND_TRUE;
-                lys_compile_mandatory_parents(node->parent, 1);
-            } else {
-                /* make mandatory false */
-                node->flags &= ~LYS_MAND_TRUE;
-                lys_compile_mandatory_parents(node->parent, 0);
-                if ((node->nodetype & LYS_LEAF) && !((struct lysc_node_leaf*)node)->dflt) {
-                    /* get the type's default value if any */
-                    DUP_STRING(ctx->ctx, ((struct lysc_node_leaf*)node)->type->dflt, ((struct lysc_node_leaf*)node)->dflt);
-                }
-            }
+            LY_CHECK_GOTO(lys_compile_change_mandatory(ctx, node, rfn->flags, rfn->nodeid, 1), error);
         }
 
         /* presence */
@@ -4990,6 +5011,15 @@
                 }
 
                 /* [mandatory-stmt] */
+                if (d_add->flags & LYS_MAND_MASK) {
+                    if (devs[u]->target->flags & LYS_MAND_MASK) {
+                        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LYVE_REFERENCE,
+                               "Invalid deviation (%s) adding \"mandatory\" property which already exists (with value \"mandatory %s\").",
+                               devs[u]->nodeid, devs[u]->target->flags & LYS_MAND_TRUE ? "true" : "false");
+                        goto cleanup;
+                    }
+                    LY_CHECK_GOTO(lys_compile_change_mandatory(ctx, devs[u]->target, d_add->flags, devs[u]->nodeid, 0), cleanup);
+                }
 
                 /* [min-elements-stmt] */
 
@@ -5182,6 +5212,14 @@
                 }
 
                 /* [mandatory-stmt] */
+                if (d_rpl->flags & LYS_MAND_MASK) {
+                    if (!(devs[u]->target->flags & LYS_MAND_MASK)) {
+                        LOGVAL(ctx->ctx, LY_VLOG_STR, ctx->path, LY_VCODE_DEV_NOT_PRESENT, devs[u]->nodeid,
+                               "replacing", "mandatory", d_rpl->flags & LYS_MAND_TRUE ? "mandatory true" : "mandatory false");
+                        goto cleanup;
+                    }
+                    LY_CHECK_GOTO(lys_compile_change_mandatory(ctx, devs[u]->target, d_rpl->flags, devs[u]->nodeid, 0), cleanup);
+                }
 
                 /* [min-elements-stmt] */