schema tree CHANGE better checking of name collisions
diff --git a/src/common.h b/src/common.h
index c075979..c60f93e 100644
--- a/src/common.h
+++ b/src/common.h
@@ -135,6 +135,7 @@
#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_DUPSTMT LYVE_SYNTAX_YANG, "Duplicate keyword \"%s\"."
+#define LY_VCODE_DUPIDENT LYVE_SYNTAX_YANG, "Duplicate identifier \"%s\" of %s statement."
#define LY_VCODE_INVAL LYVE_SYNTAX_YANG, "Invalid value \"%.*s\" of \"%s\"."
#define LY_VCODE_MISSTMT LYVE_SYNTAX_YANG, "Missing mandatory keyword \"%s\" as a child of \"%s\"."
#define LY_VCODE_INORD LYVE_SYNTAX_YANG, "Invalid keyword \"%s\", it cannot appear after \"%s\"."
@@ -165,7 +166,7 @@
* some of the currently present schemas.
*
* @param[in] ctx Context where to search
- * @param[in] module Name of the module where the submodule is supposed to belongs-to.
+ * @param[in] module Name of the module where the submodule is supposed to belongs-to. If NULL, the module name is not checked.
* @param[in] submodule Name of the submodule to find.
* @param[in] revision Optional revision of the submodule to find. If not specified, the latest revision is returned.
* @return Pointer to the specified submodule if it is present in the context.
diff --git a/src/context.c b/src/context.c
index 2394faf..c0eca67 100644
--- a/src/context.c
+++ b/src/context.c
@@ -441,12 +441,18 @@
{
const struct lys_module *mod;
struct lysp_include *inc;
- unsigned int index = 0, u;
+ unsigned int v, u;
- while ((mod = ly_ctx_get_module_by_iter(ctx, module, offsetof(struct lysp_module, name), &index))) {
+ assert(submodule);
+
+ for (v = 0; v < ctx->list.count; ++v) {
+ mod = ctx->list.objs[v];
if (!mod->parsed) {
continue;
}
+ if (module && strcmp(module, mod->parsed->name)) {
+ continue;
+ }
LY_ARRAY_FOR(mod->parsed->includes, u) {
if (mod->parsed->includes[u].submodule && !strcmp(submodule, mod->parsed->includes[u].submodule->name)) {
diff --git a/src/parser_yang.c b/src/parser_yang.c
index 5435eab..ab6f7ac 100644
--- a/src/parser_yang.c
+++ b/src/parser_yang.c
@@ -46,6 +46,16 @@
#define is_yangidentchar(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || \
c == '_' || c == '-' || c == '.')
+#define CHECK_UNIQUENESS(CTX, ARRAY, MEMBER, STMT, IDENT) \
+ if (ARRAY) { \
+ for (unsigned int u = 0; u < LY_ARRAY_SIZE(ARRAY) - 1; ++u) { \
+ if (!strcmp((ARRAY)[u].MEMBER, IDENT)) { \
+ LOGVAL_YANG(CTX, LY_VCODE_DUPIDENT, IDENT, STMT); \
+ return LY_EVALID; \
+ } \
+ } \
+ }
+
#define INSERT_WORD(CTX, BUF, TARGET, WORD, LEN) \
if (BUF) {(TARGET) = lydict_insert_zc((CTX)->ctx, WORD);}\
else {(TARGET) = lydict_insert((CTX)->ctx, WORD, LEN);}
@@ -1305,6 +1315,13 @@
INSERT_WORD(ctx, buf, inc->name, word, word_len);
+ /* 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(ctx->mod->name, inc->name) || ly_ctx_get_module_latest(ctx->ctx, inc->name)) {
+ LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Name collision between module and submodule of name \"%s\".", inc->name);
+ return LY_EVALID;
+ }
+
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
switch (kw) {
case YANG_DESCRIPTION:
@@ -4304,8 +4321,10 @@
/* get value */
ret = get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
LY_CHECK_RET(ret);
-
INSERT_WORD(ctx, buf, feat->name, word, word_len);
+
+ CHECK_UNIQUENESS(ctx, *features, name, "feature", feat->name);
+
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
LY_CHECK_RET(ret);
@@ -4359,8 +4378,10 @@
/* get value */
ret = get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
LY_CHECK_RET(ret);
-
INSERT_WORD(ctx, buf, ident->name, word, word_len);
+
+ CHECK_UNIQUENESS(ctx, *identities, name, "identity", ident->name);
+
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
LY_CHECK_RET(ret);
@@ -4414,8 +4435,16 @@
/* (sub)module name */
ret = get_argument(ctx, data, Y_IDENTIF_ARG, &word, &buf, &word_len);
LY_CHECK_RET(ret);
-
INSERT_WORD(ctx, buf, mod->name, word, word_len);
+
+ /* submodules share the namespace with the module names, so there must not be
+ * a submodule of the same name in the context, no need for revision matching */
+ if (ly_ctx_get_submodule(ctx->ctx, NULL, mod->name, NULL)) {
+ LOGVAL_YANG(ctx, LYVE_SYNTAX_YANG, "Name collision between %s of name \"%s\".",
+ mod->submodule ? "submodules" : "module and submodule", mod->name);
+ return LY_EVALID;
+ }
+
YANG_READ_SUBSTMT_FOR(ctx, data, kw, word, word_len, ret) {
LY_CHECK_RET(ret);
@@ -4641,6 +4670,7 @@
mod->submodule = 1;
}
mod->ctx = ctx;
+ context.mod = mod;
/* substatements */
ret = parse_sub_module(&context, &data, mod);
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 874ca01..fe38709 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -1281,7 +1281,7 @@
LOGERR(ctx, LY_EINVAL, "Invalid schema input format.");
break;
}
- LY_CHECK_RET(ret, NULL);
+ LY_CHECK_ERR_RET(ret, free(mod), NULL);
/* make sure that the newest revision is at position 0 */
lysp_sort_revisions(mod->parsed->revs);
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 8971864..4e07c7d 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -871,8 +871,10 @@
struct lysc_ext_instance *exts; /**< list of the extension instances ([sized array](@ref sizedarrays)) */
uint8_t implemented:1; /**< flag if the module is implemented, not just imported */
- uint8_t latest_revision:1; /**< flag if the module was loaded without specific revision and is
- the latest revision found */
+ uint8_t latest_revision:2; /**< flag to mark the latest available revision:
+ 1 - the latest revision in searchdirs was not searched yet and this is the
+ latest revision in the current context
+ 2 - searchdirs were searched and this is the latest available revision */
uint8_t version; /**< yang-version (LYS_VERSION values) */
};
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 0c5c3ac..0bc2443 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -43,6 +43,7 @@
*/
struct ly_parser_ctx {
struct ly_ctx *ctx;
+ struct lysp_module *mod;
uint64_t line; /* line number */
uint64_t indent; /* current position on the line for YANG indentation */
};