schema parsers CHANGE detect typedef collisions between main module and submodules
diff --git a/src/tree_schema.c b/src/tree_schema.c
index e82ff02..7301326 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -1506,7 +1506,7 @@
 }
 
 struct lys_module *
-lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement,
+lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
                LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
 {
     struct lys_module *mod = NULL, *latest, *mod_dup;
@@ -1522,6 +1522,12 @@
     context.ctx = ctx;
     context.line = 1;
 
+    if (main_ctx) {
+        /* map the typedefs and groupings list from main context to the submodule's context */
+        memcpy(&context.tpdfs_nodes, &main_ctx->tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
+        memcpy(&context.grps_nodes, &main_ctx->grps_nodes, sizeof main_ctx->grps_nodes);
+    }
+
     mod = calloc(1, sizeof *mod);
     LY_CHECK_ERR_RET(!mod, LOGMEM(ctx), NULL);
 
@@ -1557,6 +1563,11 @@
     }
 
     if (mod->parsed->submodule) { /* submodule */
+        if (!main_ctx) {
+            LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
+                   mod->parsed->name);
+            goto error;
+        }
         /* decide the latest revision */
         latest_p = ly_ctx_get_submodule(ctx, mod->parsed->belongsto, mod->parsed->name, NULL);
         if (latest_p) {
@@ -1575,6 +1586,9 @@
         } else {
             mod->parsed->latest_revision = 1;
         }
+        /* remap possibly changed and reallocated typedefs and groupings list back to the main context */
+        memcpy(&main_ctx->tpdfs_nodes, &context.tpdfs_nodes, sizeof main_ctx->tpdfs_nodes);
+        memcpy(&main_ctx->grps_nodes, &context.grps_nodes, sizeof main_ctx->grps_nodes);
     } else { /* module */
         /* check for duplicity in the context */
         mod_dup = (struct lys_module*)ly_ctx_get_module(ctx, mod->parsed->name, mod->parsed->revs ? mod->parsed->revs[0].date : NULL);
@@ -1650,7 +1664,7 @@
         }
         LY_ARRAY_FOR(mod->parsed->includes, u) {
             inc = &mod->parsed->includes[u];
-            if (!inc->submodule && lysp_load_submodule(ctx, mod->parsed, inc)) {
+            if (!inc->submodule && lysp_load_submodule(&context, mod->parsed, inc)) {
                 goto error_ctx;
             }
         }
@@ -1673,16 +1687,7 @@
 API struct lys_module *
 lys_parse_mem(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format)
 {
-    struct lys_module *result;
-
-    result = lys_parse_mem_(ctx, data, format, 1, NULL, NULL);
-    if (result && result->parsed->submodule) {
-        LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
-               result->parsed->name);
-        lys_module_free(result, NULL);
-        return NULL;
-    }
-    return result;
+    return lys_parse_mem_(ctx, data, format, 1, NULL, NULL, NULL);
 }
 
 static void
@@ -1709,7 +1714,7 @@
 }
 
 struct lys_module *
-lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement,
+lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
               LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
 {
     struct lys_module *mod;
@@ -1728,7 +1733,7 @@
         return NULL;
     }
 
-    mod = lys_parse_mem_(ctx, addr, format, implement, custom_check, check_data);
+    mod = lys_parse_mem_(ctx, addr, format, implement, main_ctx, custom_check, check_data);
     ly_munmap(addr, length);
 
     if (mod && !mod->parsed->filepath) {
@@ -1741,20 +1746,11 @@
 API struct lys_module *
 lys_parse_fd(struct ly_ctx *ctx, int fd, LYS_INFORMAT format)
 {
-    struct lys_module *result;
-
-    result = lys_parse_fd_(ctx, fd, format, 1, NULL, NULL);
-    if (result && result->parsed->submodule) {
-        LOGERR(ctx, LY_EDENIED, "Input data contains submodule \"%s\" which cannot be parsed directly without its main module.",
-               result->parsed->name);
-        lys_module_free(result, NULL);
-        return NULL;
-    }
-    return result;
+    return lys_parse_fd_(ctx, fd, format, 1, NULL, NULL, NULL);
 }
 
 struct lys_module *
-lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement,
+lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
                 LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data)
 {
     int fd;
@@ -1767,7 +1763,7 @@
     fd = open(path, O_RDONLY);
     LY_CHECK_ERR_RET(fd == -1, LOGERR(ctx, LY_ESYS, "Opening file \"%s\" failed (%s).", path, strerror(errno)), NULL);
 
-    mod = lys_parse_fd_(ctx, fd, format, implement, custom_check, check_data);
+    mod = lys_parse_fd_(ctx, fd, format, implement, main_ctx, custom_check, check_data);
     close(fd);
     LY_CHECK_RET(!mod, NULL);
 
@@ -1811,16 +1807,7 @@
 API struct lys_module *
 lys_parse_path(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format)
 {
-    struct lys_module *result;
-
-    result = lys_parse_path_(ctx, path, format, 1, NULL, NULL);
-    if (result && result->parsed->submodule) {
-        LOGERR(ctx, LY_EDENIED, "Input file \"%s\" contains submodule \"%s\" which cannot be parsed directly without its main module.",
-               path, result->parsed->name);
-        lys_module_free(result, NULL);
-        return NULL;
-    }
-    return result;
+    return lys_parse_path_(ctx, path, format, 1, NULL, NULL, NULL);
 }
 
 API LY_ERR
diff --git a/src/tree_schema_helpers.c b/src/tree_schema_helpers.c
index f7904d3..df72591 100644
--- a/src/tree_schema_helpers.c
+++ b/src/tree_schema_helpers.c
@@ -323,11 +323,9 @@
                    "Invalid name \"%s\" of typedef - name collision with another top-level type.", name);
             return LY_EEXIST;
         }
-        if (!lyht_find(tpdfs_scoped, &name, hash, NULL)) {
-            LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_SYNTAX_YANG,
-                   "Invalid name \"%s\" of typedef - top-level type collide with a scoped type.", name);
-            return LY_EEXIST;
-        }
+        /* it is not necessary to test collision with the scoped types - in lysp_check_typedefs, all the
+         * top-level typedefs are inserted into the tables before the scoped typedefs, so the collision
+         * is detected in the first branch few lines above */
     }
 
     return LY_SUCCESS;
@@ -356,6 +354,13 @@
             goto cleanup;
         }
     }
+    LY_ARRAY_FOR(ctx->mod->includes, i) {
+        LY_ARRAY_FOR(ctx->mod->includes[i].submodule->typedefs, u) {
+            if (lysp_check_typedef(ctx, NULL, &ctx->mod->includes[i].submodule->typedefs[u], ids_global, ids_scoped)) {
+                goto cleanup;
+            }
+        }
+    }
     for (u = 0; u < ctx->tpdfs_nodes.count; ++u) {
         typedefs = lysp_node_typedefs((struct lysp_node *)ctx->tpdfs_nodes.objs[u]);
         LY_ARRAY_FOR(*typedefs, i) {
@@ -463,7 +468,7 @@
 }
 
 LY_ERR
-lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement,
+lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct ly_parser_ctx *main_ctx,
                      struct lys_module **result)
 {
     int fd;
@@ -489,7 +494,7 @@
     check_data.name = name;
     check_data.revision = revision;
     check_data.path = filepath;
-    mod = lys_parse_fd_(ctx, fd, format, implement,
+    mod = lys_parse_fd_(ctx, fd, format, implement, main_ctx,
                         lysp_load_module_check, &check_data);
     close(fd);
     LY_CHECK_ERR_GOTO(!mod, ly_errcode(ctx), cleanup);
@@ -544,7 +549,7 @@
                                       &format, &module_data, &module_data_free) == LY_SUCCESS) {
                     check_data.name = name;
                     check_data.revision = revision;
-                    *mod = lys_parse_mem_(ctx, module_data, format, implement,
+                    *mod = lys_parse_mem_(ctx, module_data, format, implement, NULL,
                                           lysp_load_module_check, &check_data);
                     if (module_data_free) {
                         module_data_free((void*)module_data, ctx->imp_clb_data);
@@ -558,7 +563,7 @@
 search_file:
             if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
                 /* module was not received from the callback or there is no callback set */
-                lys_module_localfile(ctx, name, revision, implement, mod);
+                lys_module_localfile(ctx, name, revision, implement, NULL, mod);
             }
             if (!(*mod) && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
                 goto search_clb;
@@ -601,7 +606,7 @@
 }
 
 LY_ERR
-lysp_load_submodule(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
+lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc)
 {
     struct lys_module *submod;
     const char *submodule_data = NULL;
@@ -610,31 +615,31 @@
     struct lysp_load_module_check_data check_data = {0};
 
     /* submodule not present in the context, get the input data and parse it */
-    if (!(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+    if (!(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
 search_clb:
-        if (ctx->imp_clb) {
-            if (ctx->imp_clb(mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL, ctx->imp_clb_data,
+        if (ctx->ctx->imp_clb) {
+            if (ctx->ctx->imp_clb(mod->name, NULL, inc->name, inc->rev[0] ? inc->rev : NULL, ctx->ctx->imp_clb_data,
                                   &format, &submodule_data, &submodule_data_free) == LY_SUCCESS) {
                 check_data.name = inc->name;
                 check_data.revision = inc->rev[0] ? inc->rev : NULL;
                 check_data.submoduleof = mod->name;
-                submod = lys_parse_mem_(ctx, submodule_data, format, mod->implemented,
+                submod = lys_parse_mem_(ctx->ctx, submodule_data, format, mod->implemented, ctx,
                                         lysp_load_module_check, &check_data);
                 if (submodule_data_free) {
-                    submodule_data_free((void*)submodule_data, ctx->imp_clb_data);
+                    submodule_data_free((void*)submodule_data, ctx->ctx->imp_clb_data);
                 }
             }
         }
-        if (!submod && !(ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+        if (!submod && !(ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
             goto search_file;
         }
     } else {
 search_file:
-        if (!(ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
+        if (!(ctx->ctx->flags & LY_CTX_DISABLE_SEARCHDIRS)) {
             /* module was not received from the callback or there is no callback set */
-            lys_module_localfile(ctx, inc->name, inc->rev[0] ? inc->rev : NULL, mod->implemented, &submod);
+            lys_module_localfile(ctx->ctx, inc->name, inc->rev[0] ? inc->rev : NULL, mod->implemented, ctx, &submod);
         }
-        if (!submod && (ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
+        if (!submod && (ctx->ctx->flags & LY_CTX_PREFER_SEARCHDIRS)) {
             goto search_clb;
         }
     }
@@ -649,7 +654,7 @@
         free(submod);
     }
     if (!inc->submodule) {
-        LOGVAL(ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.", inc->name, mod->name);
+        LOGVAL(ctx->ctx, LY_VLOG_NONE, NULL, LYVE_REFERENCE, "Including \"%s\" submodule into \"%s\" failed.", inc->name, mod->name);
         return LY_EVALID;
     }
 
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 73a77b3..a73fb0a 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -115,13 +115,13 @@
 /**
  * @brief Parse included submodule into the simply parsed YANG module.
  *
- * @param[in] ctx libyang context
+ * @param[in] ctx parser context
  * @param[in] mod Module including a submodule.
  * @param[in,out] inc Include structure holding all available information about the include statement, the parsed
  * submodule is stored into this structure.
  * @return LY_ERR value.
  */
-LY_ERR lysp_load_submodule(struct ly_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc);
+LY_ERR lysp_load_submodule(struct ly_parser_ctx *ctx, struct lysp_module *mod, struct lysp_include *inc);
 
 /**
  * @brief Get address of a node's typedefs list if any.
@@ -210,11 +210,12 @@
  * format.
  * @param[in] format Format of the input data (YANG or YIN).
  * @param[in] implement Flag if the schema is supposed to be marked as implemented.
+ * @param[in] main_ctx Parser context of the main module in case of parsing submodule.
  * @param[in] custom_check Callback to check the parsed schema before it is accepted.
  * @param[in] check_data Caller's data to pass to the custom_check callback.
  * @return Pointer to the data model structure or NULL on error.
  */
-struct lys_module *lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement,
+struct lys_module *lys_parse_mem_(struct ly_ctx *ctx, const char *data, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
                                   LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data);
 
 /**
@@ -231,11 +232,12 @@
  *            in the specified format.
  * @param[in] format Format of the input data (YANG or YIN).
  * @param[in] implement Flag if the schema is supposed to be marked as implemented.
+ * @param[in] main_ctx Parser context of the main module in case of parsing submodule.
  * @param[in] custom_check Callback to check the parsed schema before it is accepted.
  * @param[in] check_data Caller's data to pass to the custom_check callback.
  * @return Pointer to the data model structure or NULL on error.
  */
-struct lys_module *lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement,
+struct lys_module *lys_parse_fd_(struct ly_ctx *ctx, int fd, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
                                  LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data);
 
 /**
@@ -253,11 +255,12 @@
  * @param[in] path Path to the file with the model in the specified format.
  * @param[in] format Format of the input data (YANG or YIN).
  * @param[in] implement Flag if the schema is supposed to be marked as implemented.
+ * @param[in] main_ctx Parser context of the main module in case of parsing submodule.
  * @param[in] custom_check Callback to check the parsed schema before it is accepted.
  * @param[in] check_data Caller's data to pass to the custom_check callback.
  * @return Pointer to the data model structure or NULL on error.
  */
-struct lys_module *lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement,
+struct lys_module *lys_parse_path_(struct ly_ctx *ctx, const char *path, LYS_INFORMAT format, int implement, struct ly_parser_ctx *main_ctx,
                                    LY_ERR (*custom_check)(struct ly_ctx *ctx, struct lysp_module *mod, void *data), void *check_data);
 
 /**
@@ -271,10 +274,12 @@
  * @param[in] name Name of the (sub)module to load.
  * @param[in] revision Optional revision of the (sub)module to load, if NULL the newest revision is being loaded.
  * @param[in] implement Flag if the (sub)module is supposed to be marked as implemented.
+ * @param[in] main_ctx Parser context of the main module in case of loading submodule.
  * @param[out] result Parsed YANG schema tree of the requested module. If it is a module, it is already in the context!
  * @return LY_ERR value, in case of LY_SUCCESS, the \arg result is always provided.
  */
-LY_ERR lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct lys_module **result);
+LY_ERR lys_module_localfile(struct ly_ctx *ctx, const char *name, const char *revision, int implement, struct ly_parser_ctx *main_ctx,
+                            struct lys_module **result);
 
 /**
  * @brief Make the module implemented.
diff --git a/tests/src/test_context.c b/tests/src/test_context.c
index c880d46..641a9e7 100644
--- a/tests/src/test_context.c
+++ b/tests/src/test_context.c
@@ -324,7 +324,7 @@
     /* selecting correct revision of the submodules */
     ly_ctx_reset_latests(ctx);
     ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule y {belongs-to a {prefix a;} revision 2018-10-31;}");
-    mod2 = lys_parse_mem_(ctx, "module a {namespace urn:a;prefix a;include y; revision 2018-10-31;}", LYS_IN_YANG, 0, NULL, NULL);
+    mod2 = lys_parse_mem_(ctx, "module a {namespace urn:a;prefix a;include y; revision 2018-10-31;}", LYS_IN_YANG, 0, NULL, NULL, NULL);
     assert_non_null(mod2);
     assert_string_equal("2018-10-31", mod2->parsed->includes[0].submodule->revs[0].date);
 
@@ -392,10 +392,10 @@
     /* invalid attempts - implementing module of the same name and inserting the same module */
     assert_null(lys_parse_mem(ctx, str2, LYS_IN_YANG));
     logbuf_assert("Module \"a\" is already implemented in the context.");
-    assert_null(lys_parse_mem_(ctx, str1, LYS_IN_YANG, 0, NULL, NULL));
+    assert_null(lys_parse_mem_(ctx, str1, LYS_IN_YANG, 0, NULL, NULL, NULL));
     logbuf_assert("Module \"a\" of revision \"2018-10-23\" is already present in the context.");
     /* insert the second module only as imported, not implemented */
-    mod2 = lys_parse_mem_(ctx, str2, LYS_IN_YANG, 0, NULL, NULL);
+    mod2 = lys_parse_mem_(ctx, str2, LYS_IN_YANG, 0, NULL, NULL, NULL);
     assert_non_null(mod);
     assert_non_null(mod2);
     assert_ptr_not_equal(mod, mod2);
@@ -404,7 +404,7 @@
     mod2 = ly_ctx_get_module_latest_ns(ctx, mod->parsed->ns);
     assert_ptr_equal(mod, mod2);
     /* work with module with no revision */
-    mod = lys_parse_mem_(ctx, str0, LYS_IN_YANG, 0, NULL, NULL);
+    mod = lys_parse_mem_(ctx, str0, LYS_IN_YANG, 0, NULL, NULL, NULL);
     assert_non_null(mod);
     assert_ptr_equal(mod, ly_ctx_get_module(ctx, "a", NULL));
     assert_ptr_not_equal(mod, ly_ctx_get_module_latest(ctx, "a"));
diff --git a/tests/src/test_tree_schema_helpers.c b/tests/src/test_tree_schema_helpers.c
index 8a298b6..7521a60 100644
--- a/tests/src/test_tree_schema_helpers.c
+++ b/tests/src/test_tree_schema_helpers.c
@@ -16,6 +16,7 @@
 
 #include <stdarg.h>
 #include <stddef.h>
+#include <stdio.h>
 #include <setjmp.h>
 #include <cmocka.h>
 
@@ -23,18 +24,28 @@
 
 #define BUFSIZE 1024
 char logbuf[BUFSIZE] = {0};
+int store = -1; /* negative for infinite logging, positive for limited logging */
 
 /* set to 0 to printing error messages to stderr instead of checking them in code */
 #define ENABLE_LOGGER_CHECKING 1
 
+#if ENABLE_LOGGER_CHECKING
 static void
 logger(LY_LOG_LEVEL level, const char *msg, const char *path)
 {
     (void) level; /* unused */
-    (void) path; /* unused */
-
-    strncpy(logbuf, msg, BUFSIZE - 1);
+    if (store) {
+        if (path && path[0]) {
+            snprintf(logbuf, BUFSIZE - 1, "%s %s", msg, path);
+        } else {
+            strncpy(logbuf, msg, BUFSIZE - 1);
+        }
+        if (store > 0) {
+            --store;
+        }
+    }
 }
+#endif
 
 static int
 logger_setup(void **state)
@@ -116,6 +127,16 @@
     LY_ARRAY_FREE(revs);
 }
 
+static LY_ERR test_imp_clb(const char *UNUSED(mod_name), const char *UNUSED(mod_rev), const char *UNUSED(submod_name),
+                           const char *UNUSED(sub_rev), void *user_data, LYS_INFORMAT *format,
+                           const char **module_data, void (**free_module_data)(void *model_data, void *user_data))
+{
+    *module_data = user_data;
+    *format = LYS_IN_YANG;
+    *free_module_data = NULL;
+    return LY_SUCCESS;
+}
+
 static void
 test_typedef(void **state)
 {
@@ -126,6 +147,71 @@
 
     assert_int_equal(LY_SUCCESS, ly_ctx_new(NULL, LY_CTX_DISABLE_SEARCHDIRS, &ctx));
 
+    str = "module a {namespace urn:a; prefix a; typedef binary {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"binary\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef bits {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"bits\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef boolean {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"boolean\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef decimal64 {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"decimal64\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef empty {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"empty\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef enumeration {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"enumeration\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef int8 {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"int8\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef int16 {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"int16\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef int32 {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"int32\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef int64 {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"int64\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef instance-identifier {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"instance-identifier\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef identityref {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"identityref\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef leafref {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"leafref\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef string {type int8;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"string\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef union {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"union\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef uint8 {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"uint8\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef uint16 {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"uint16\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef uint32 {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"uint32\" of typedef - name collision with a built-in type.");
+    str = "module a {namespace urn:a; prefix a; typedef uint64 {type string;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"uint64\" of typedef - name collision with a built-in type.");
+
+    str = "module mytypes {namespace urn:types; prefix t; typedef binary_ {type string;} typedef bits_ {type string;} typedef boolean_ {type string;} "
+          "typedef decimal64_ {type string;} typedef empty_ {type string;} typedef enumeration_ {type string;} typedef int8_ {type string;} typedef int16_ {type string;}"
+          "typedef int32_ {type string;} typedef int64_ {type string;} typedef instance-identifier_ {type string;} typedef identityref_ {type string;}"
+          "typedef leafref_ {type string;} typedef string_ {type int8;} typedef union_ {type string;} typedef uint8_ {type string;} typedef uint16_ {type string;}"
+          "typedef uint32_ {type string;} typedef uint64_ {type string;}}";
+    assert_non_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+
     str = "module a {namespace urn:a; prefix a; typedef test {type string;} typedef test {type int8;}}";
     assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
     logbuf_assert("Invalid name \"test\" of typedef - name collision with another top-level type.");
@@ -138,6 +224,25 @@
     assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
     logbuf_assert("Invalid name \"y\" of typedef - name collision with another scoped type.");
 
+    str = "module a {namespace urn:a; prefix a; container c {typedef y {type int8;} typedef y {type string;}}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"y\" of typedef - name collision with sibling type.");
+
+    ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule b {belongs-to a {prefix a;} typedef x {type string;}}");
+    str = "module a {namespace urn:a; prefix a; include b; typedef x {type int8;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"x\" of typedef - name collision with another top-level type.");
+
+    ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule b {belongs-to a {prefix a;} container c {typedef x {type string;}}}");
+    str = "module a {namespace urn:a; prefix a; include b; typedef x {type int8;}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"x\" of typedef - scoped type collide with a top-level type.");
+
+    ly_ctx_set_module_imp_clb(ctx, test_imp_clb, "submodule b {belongs-to a {prefix a;} typedef x {type int8;}}");
+    str = "module a {namespace urn:a; prefix a; include b; container c {typedef x {type string;}}}";
+    assert_null(lys_parse_mem(ctx, str, LYS_IN_YANG));
+    logbuf_assert("Invalid name \"x\" of typedef - scoped type collide with a top-level type.");
+
     ly_ctx_destroy(ctx, NULL);
 }