yin parser CHANGE add support for include element
diff --git a/src/common.h b/src/common.h
index 0bed0ad..f0f70e4 100644
--- a/src/common.h
+++ b/src/common.h
@@ -178,6 +178,7 @@
 #define LY_VCODE_EOF         LYVE_SYNTAX, "Unexpected end-of-input."
 #define LY_VCODE_NTERM       LYVE_SYNTAX, "%s not terminated."
 #define LY_VCODE_NSUPP       LYVE_SYNTAX, "%s not supported."
+
 #define LY_VCODE_INSTMT      LYVE_SYNTAX_YANG, "Invalid keyword \"%s\"."
 #define LY_VCODE_INCHILDSTMT LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\"."
 #define LY_VCODE_INCHILDSTMT2 LYVE_SYNTAX_YANG, "Invalid keyword \"%s\" as a child of \"%s\" - the statement is allowed only in YANG 1.1 modules."
@@ -191,13 +192,17 @@
 #define LY_VCODE_OOB         LYVE_SYNTAX_YANG, "Value \"%.*s\" is out of \"%s\" bounds."
 #define LY_VCODE_INDEV       LYVE_SYNTAX_YANG, "Deviate \"%s\" does not support keyword \"%s\"."
 #define LY_VCODE_INREGEXP    LYVE_SYNTAX_YANG, "Regular expression \"%s\" is not valid (\"%s\": %s)."
+
+#define LYVCODE_INSUBELEM2   LYVE_SYNTAX_YIN, "Invalid sub-elemnt \"%s\" of \"%s\" element - this sub-element is allowed only in modules with version 1.1 or newer."
 #define LY_VCODE_INVAL_YIN   LYVE_SYNTAX_YIN, "Invalid value \"%s\" of \"%s\"."
 #define LY_VCODE_DUPELEM     LYVE_SYNTAX_YIN, "Duplicate element \"%s\"."
 #define LY_VCODE_INCHILDSTMT_YIN LYVE_SYNTAX_YIN, "Invalid element \"%.*s\" as a child of \"%.*s\"."
 #define LY_VCODE_MISSATTR    LYVE_SYNTAX_YIN, "Missing mandatory child element \"%s\" of %s element ."
 #define LY_VCODE_UNEXP_SUBELEM LYVE_SYNTAX_YIN, "Unexpected child element \"%.*s\" of %s element."
+
 #define LY_VCODE_XP_EOE      LYVE_XPATH, "Unterminated string delimited with %c (%.15s)."
 #define LY_VCODE_XP_INEXPR   LYVE_XPATH, "Invalid character number %u of expression \'%s\'."
+
 #define LY_VCODE_DEV_NODETYPE LYVE_REFERENCE, "Invalid deviation of %s node - it is not possible to %s \"%s\" property."
 #define LY_VCODE_DEV_NOT_PRESENT LYVE_REFERENCE, "Invalid deviation %s \"%s\" property \"%s\" which is not present."
 
diff --git a/src/parser_yin.c b/src/parser_yin.c
index bc2d861..5e4d6a4 100644
--- a/src/parser_yin.c
+++ b/src/parser_yin.c
@@ -1385,6 +1385,36 @@
     return yin_parse_content(ctx, subelems, 3, data, YANG_REVISION, NULL, &rev->exts);
 }
 
+static LY_ERR
+yin_parse_include(struct yin_parser_ctx *ctx, struct yin_arg_record *attrs, const char **data,
+                  struct include_meta *inc_meta)
+{
+    struct lysp_include *inc;
+
+    /* allocate new include */
+    LY_ARRAY_NEW_RET(ctx->xml_ctx.ctx, *inc_meta->includes, inc, LY_EMEM);
+
+    /* parse argument */
+    LY_CHECK_RET(yin_parse_attribute(ctx, attrs, YIN_ARG_MODULE, &inc->name, Y_IDENTIF_ARG, YANG_INCLUDE));
+
+    /* submodules share the namespace with the module names, so there must not be
+     * a module of the same name in the context, no need for revision matching */
+    if (!strcmp(inc_meta->name, inc->name) || ly_ctx_get_module_latest(ctx->xml_ctx.ctx, inc->name)) {
+        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LYVE_SYNTAX_YANG,
+                      "Name collision between module and submodule of name \"%s\".", inc->name);
+        return LY_EVALID;
+    }
+
+    /* parse content */
+    struct yin_subelement subelems[4] = {
+                                            {YANG_DESCRIPTION, &inc->dsc, YIN_SUBELEM_UNIQUE | YIN_SUBELEM_VER2},
+                                            {YANG_REFERENCE, &inc->ref, YIN_SUBELEM_UNIQUE | YIN_SUBELEM_VER2},
+                                            {YANG_REVISION_DATE, &inc->rev, YIN_SUBELEM_UNIQUE},
+                                            {YANG_CUSTOM, NULL, 0},
+                                        };
+    return yin_parse_content(ctx, subelems, 4, data, YANG_INCLUDE, NULL, &inc->exts);
+}
+
 /**
  * @brief Map keyword type to substatement info.
  *
@@ -1530,6 +1560,7 @@
 
                 /* TODO check relative order */
 
+                /* check flags */
                 /* if element is unique and already defined log error */
                 if ((subelem->flags & YIN_SUBELEM_UNIQUE) && (subelem->flags & YIN_SUBELEM_PARSED)) {
                     LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LYVE_SYNTAX_YIN, "Redefinition of %s element in %s element.", ly_stmt2str(kw), ly_stmt2str(current_element));
@@ -1539,6 +1570,12 @@
                     ret = yin_check_subelem_first_constraint(ctx, subelem_info, subelem_info_size, current_element, subelem);
                     LY_CHECK_GOTO(ret, cleanup);
                 }
+                if (subelem->flags & YIN_SUBELEM_VER2) {
+                    if (ctx->mod_version < 2) {
+                        LOGVAL_PARSER((struct lys_parser_ctx *)ctx, LYVCODE_INSUBELEM2, ly_stmt2str(kw), ly_stmt2str(current_element));
+                        return LY_EVALID;
+                    }
+                }
                 subelem->flags |= YIN_SUBELEM_PARSED;
 
                 switch (kw) {
@@ -1635,6 +1672,7 @@
                     ret = yin_parse_import(ctx, attrs, data, (struct lysp_module *)subelem->dest);
                     break;
                 case YANG_INCLUDE:
+                    ret = yin_parse_include(ctx, attrs, data, (struct include_meta *)subelem->dest);
                     break;
                 case YANG_INPUT:
                     break;
diff --git a/src/parser_yin.h b/src/parser_yin.h
index 6f892a5..2fcae20 100644
--- a/src/parser_yin.h
+++ b/src/parser_yin.h
@@ -67,6 +67,7 @@
 #define YIN_SUBELEM_MANDATORY   0x01    /**< is set when subelement is mandatory */
 #define YIN_SUBELEM_UNIQUE      0x02    /**< is set when subelement is unique */
 #define YIN_SUBELEM_FIRST       0x04    /**< is set when subelement is actually yang argument mapped to yin element */
+#define YIN_SUBELEM_VER2        0x08    /**< subelemnt is allowed only in modules with version at least 2 (YANG 1.1) */
 
 #define YIN_SUBELEM_PARSED      0x80    /**< is set during parsing when given subelement is encountered for the first
                                              time to simply check validity of given constraints */
@@ -102,11 +103,18 @@
     struct lysp_tpdf **typedefs;    /**< [Sized array](@ref sizedarrays) of typedefs to add to */
 };
 
+/* Meta information passed to yin_parse_augment function */
 struct augment_meta {
     struct lysp_node *parent;       /**< parent node */
     struct lysp_augment **augments; /**< [Sized array](@ref sizedarrays) of augments to add to */
 };
 
+/* Meta information passed to yin_parse_include function */
+struct include_meta {
+    const char *name;               /**< module/submodule name */
+    struct lysp_include **includes; /**< [Sized array](@ref sizedarrays) of parsed includes to add to */
+};
+
 /**
  * @brief Match argument name.
  *
diff --git a/src/tree_schema_free.c b/src/tree_schema_free.c
index 8ad404f..e3fd817 100644
--- a/src/tree_schema_free.c
+++ b/src/tree_schema_free.c
@@ -64,7 +64,7 @@
     FREE_ARRAY(ctx, import->exts, lysp_ext_instance_free);
 }
 
-static void
+void
 lysp_include_free(struct ly_ctx *ctx, struct lysp_include *include)
 {
     if (include->submodule) {
diff --git a/tests/src/test_parser_yin.c b/tests/src/test_parser_yin.c
index 03d145c..04125c2 100644
--- a/tests/src/test_parser_yin.c
+++ b/tests/src/test_parser_yin.c
@@ -36,6 +36,7 @@
 void lysp_tpdf_free(struct ly_ctx *ctx, struct lysp_tpdf *tpdf);
 void lysp_refine_free(struct ly_ctx *ctx, struct lysp_refine *ref);
 void lysp_revision_free(struct ly_ctx *ctx, struct lysp_revision *rev);
+void lysp_include_free(struct ly_ctx *ctx, struct lysp_include *include);
 
 struct state {
     struct ly_ctx *ctx;
@@ -2371,6 +2372,67 @@
     st->finished_correctly = true;
 }
 
+static void
+test_include_elem(void **state)
+{
+    struct state *st = *state;
+    const char *data;
+    struct lysp_include *includes = NULL;
+    struct include_meta inc_meta = {"module-name", &includes};
+
+    /* max subelems */
+    st->yin_ctx->mod_version = LYS_VERSION_1_1;
+    data = ELEMENT_WRAPPER_START
+                "<include module=\"mod\">"
+                    "<description><text>desc</text></description>"
+                    "<reference><text>ref</text></reference>"
+                    "<revision-date date=\"1999-09-09\"/>"
+                "</include>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &inc_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(includes->name, "mod");
+    assert_string_equal(includes->dsc, "desc");
+    assert_string_equal(includes->ref, "ref");
+    assert_null(includes->exts);
+    assert_string_equal(includes->rev, "1999-09-09");
+    FREE_ARRAY(st->ctx, includes, lysp_include_free);
+    includes = NULL;
+
+    /* min subelems */
+    data = ELEMENT_WRAPPER_START "<include module=\"mod\"/>" ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &inc_meta, NULL, NULL, true), LY_SUCCESS);
+    assert_string_equal(includes->name, "mod");
+    FREE_ARRAY(st->ctx, includes, lysp_include_free);
+    includes = NULL;
+
+    /* invalid combinations */
+    st->yin_ctx->mod_version = LYS_VERSION_1_0;
+    data = ELEMENT_WRAPPER_START
+                "<include module=\"mod\">"
+                    "<description><text>desc</text></description>"
+                    "<revision-date date=\"1999-09-09\"/>"
+                "</include>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &inc_meta, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid sub-elemnt \"description\" of \"include\" element - this sub-element is allowed only in modules with version 1.1 or newer. Line number 1.");
+    FREE_ARRAY(st->ctx, includes, lysp_include_free);
+    includes = NULL;
+
+    st->yin_ctx->mod_version = LYS_VERSION_1_0;
+    data = ELEMENT_WRAPPER_START
+                "<include module=\"mod\">"
+                    "<reference><text>ref</text></reference>"
+                    "<revision-date date=\"1999-09-09\"/>"
+                "</include>"
+           ELEMENT_WRAPPER_END;
+    assert_int_equal(test_element_helper(st, &data, &inc_meta, NULL, NULL, false), LY_EVALID);
+    logbuf_assert("Invalid sub-elemnt \"reference\" of \"include\" element - this sub-element is allowed only in modules with version 1.1 or newer. Line number 1.");
+    FREE_ARRAY(st->ctx, includes, lysp_include_free);
+    includes = NULL;
+
+    st->finished_correctly = true;
+}
+
 int
 main(void)
 {
@@ -2428,6 +2490,8 @@
         cmocka_unit_test_setup_teardown(test_refine_elem, setup_element_test, teardown_element_test),
         cmocka_unit_test_setup_teardown(test_uses_elem, setup_element_test, teardown_element_test),
         cmocka_unit_test_setup_teardown(test_revision_elem, setup_element_test, teardown_element_test),
+        cmocka_unit_test_setup_teardown(test_include_elem, setup_element_test, teardown_element_test),
+
     };
 
     return cmocka_run_group_tests(tests, setup_ly_ctx, destroy_ly_ctx);