Add DataTreeAwareEffectiveStatement 07/72907/18
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 27 Feb 2018 08:25:29 +0000 (09:25 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Wed, 13 Jun 2018 13:34:47 +0000 (15:34 +0200)
YANG defines two distinct ways to look at a YANG model:
- schema tree: The definition hierarchy specified within a module.
- data tree: An instantiated tree of any data modeled with YANG,
             e.g., configuration data, state data, combined
             configuration and state data, RPC or action input,
             RPC or action output, or notification.

This means that there really are two notions of 'a child node',
based on schema tree, or based on data tree. The data tree is
a strict subset of schema tree. The layout of the data tree is
such that it does not include RPCs, actions nor notifications --
addressing data tree nodes encapsulated in these requires
first reaching the encapsulation point via schema tree walk.

This patch introduces DataTreeAwareEffectiveStatement
and its companion DataTreeEffectiveStatement, updating extant
statements to support it.

Construction of this namespace has a side-effect of finding
duplicate data nodes within each level of hierarchy, thus fixing
YANGTOOLS-883.

JIRA: YANGTOOLS-853
JIRA: YANGTOOLS-883
Change-Id: Id02bb2557845000fe7fa90d1bf56c8425cce24fb
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
Signed-off-by: Jie Han <han.jie@zte.com.cn>
19 files changed:
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/ActionEffectiveStatement.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/AnydataEffectiveStatement.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/AnyxmlEffectiveStatement.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/ContainerEffectiveStatement.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/DataTreeAwareEffectiveStatement.java [new file with mode: 0644]
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/DataTreeEffectiveStatement.java [new file with mode: 0644]
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/InputEffectiveStatement.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/LeafListEffectiveStatement.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/ListEffectiveStatement.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/ModuleEffectiveStatement.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/NotificationEffectiveStatement.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/OutputEffectiveStatement.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/RpcEffectiveStatement.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/SchemaTreeAwareEffectiveStatement.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/AbstractSchemaEffectiveDocumentedNode.java
yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/NameCollisionWithinCaseTest.java [new file with mode: 0644]
yang/yang-parser-rfc7950/src/test/resources/bugs/name-collision-within-case/bar.yang [new file with mode: 0644]
yang/yang-parser-rfc7950/src/test/resources/bugs/name-collision-within-case/baz.yang [new file with mode: 0644]
yang/yang-parser-rfc7950/src/test/resources/bugs/name-collision-within-case/foo.yang [new file with mode: 0644]

index d3dc0725ab5262b9a24a983688370f9b6f2fb3b0..4dbbbe2edcb35e62b1fe1efaf5b74a1829f24ab0 100644 (file)
@@ -12,6 +12,6 @@ import org.opendaylight.yangtools.yang.common.QName;
 
 @Beta
 public interface ActionEffectiveStatement extends SchemaTreeEffectiveStatement<ActionStatement>,
-    SchemaTreeAwareEffectiveStatement<QName, ActionStatement> {
+    DataTreeAwareEffectiveStatement<QName, ActionStatement> {
 
 }
index 798d2ab18765e66ff700a8220c446997238bcc8f..d88a2c96b4bd418fd3d62ec190dacb26269fc1e4 100644 (file)
@@ -10,6 +10,6 @@ package org.opendaylight.yangtools.yang.model.api.stmt;
 import com.google.common.annotations.Beta;
 
 @Beta
-public interface AnydataEffectiveStatement extends SchemaTreeEffectiveStatement<AnydataStatement> {
+public interface AnydataEffectiveStatement extends DataTreeEffectiveStatement<AnydataStatement> {
 
 }
index 20756ba96f994089c6071088bca5539b4a053f65..9e8fdaa537e248bc0736ef7ccee735189643fa2e 100644 (file)
@@ -10,6 +10,6 @@ package org.opendaylight.yangtools.yang.model.api.stmt;
 import com.google.common.annotations.Beta;
 
 @Beta
-public interface AnyxmlEffectiveStatement extends SchemaTreeEffectiveStatement<AnyxmlStatement> {
+public interface AnyxmlEffectiveStatement extends DataTreeEffectiveStatement<AnyxmlStatement> {
 
 }
index f1b2481f7b1ed1306f0343f5134864c496914162..75800b746a8fb868d1bcbf7879033ab7607a14c1 100644 (file)
@@ -11,7 +11,7 @@ import com.google.common.annotations.Beta;
 import org.opendaylight.yangtools.yang.common.QName;
 
 @Beta
-public interface ContainerEffectiveStatement extends SchemaTreeEffectiveStatement<ContainerStatement>,
-     SchemaTreeAwareEffectiveStatement<QName, ContainerStatement> {
+public interface ContainerEffectiveStatement extends DataTreeEffectiveStatement<ContainerStatement>,
+     DataTreeAwareEffectiveStatement<QName, ContainerStatement> {
 
 }
diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/DataTreeAwareEffectiveStatement.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/DataTreeAwareEffectiveStatement.java
new file mode 100644 (file)
index 0000000..f677ec2
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.api.stmt;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+
+/**
+ * Interface implemented by all {@link SchemaTreeAwareEffectiveStatement}s which can contain a {@code data tree} child.
+ *
+ * @param <A> Argument type
+ * @param <D> Class representing declared version of this statement.
+ * @author Robert Varga
+ */
+@Beta
+public interface DataTreeAwareEffectiveStatement<A, D extends DeclaredStatement<A>>
+        extends SchemaTreeAwareEffectiveStatement<A, D> {
+
+    /**
+     * Namespace of {@code data node}s. This is a subtree of {@link SchemaTreeAwareEffectiveStatement.Namespace} in that
+     * all data nodes are also schema nodes. The structure of the tree is different, though, as {@code choice}
+     * and {@code case} statements are glossed over and they do not contribute to the tree hierarchy -- only their
+     * children do.
+     *
+     * <p>
+     * This corresponds to the {@code data tree} view of a YANG-defined data.
+     *
+     * @param <T> Child statement type
+     */
+    @NonNullByDefault
+    abstract class Namespace<T extends DataTreeEffectiveStatement<?>> extends EffectiveStatementNamespace<T> {
+        private Namespace() {
+            // Should never be instantiated
+        }
+    }
+
+    /**
+     * Find a {@code data tree} child {@link DataTreeEffectiveStatement}, as identified by its QName argument.
+     *
+     * @param qname Child identifier
+     * @return Data tree child, or empty
+     * @throws NullPointerException if {@code qname} is null
+     */
+    default <E extends DataTreeEffectiveStatement<?>> @NonNull Optional<E> findDataTreeNode(
+            final @NonNull QName qname) {
+        return Optional.ofNullable(get(Namespace.class, requireNonNull(qname)));
+    }
+}
diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/DataTreeEffectiveStatement.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/stmt/DataTreeEffectiveStatement.java
new file mode 100644 (file)
index 0000000..a55fa80
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.api.stmt;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+
+/**
+ * Common interface grouping all {@link EffectiveStatement}s which are accessible via
+ * {@link DataTreeAwareEffectiveStatement.Namespace}. This such statement corresponds to a {@code data node}.
+ *
+ * <p>
+ * This interface could be named {@code SchemaNodeEffectiveStatement}, but that could induce a notion that it has
+ * something to do with {@link DataSchemaNode} -- which it has not. DataSchemaNode semantics are wrong in may aspects
+ * and while implementations of this interface may also implement DataSchemaNode, the semantics of this interface should
+ * always be preferred and DataSchemaNode is to be treated as deprecated whenever possible.
+ *
+ * @param <D> Declared statement type
+ * @author Robert Varga
+ */
+@Beta
+public interface DataTreeEffectiveStatement<D extends DeclaredStatement<QName>>
+    extends SchemaTreeEffectiveStatement<D> {
+
+}
index b131e6b6aafa59b21962ae13c9d55a98331d00b6..71f90cd24af77319024db053191a55ced73b7732 100644 (file)
@@ -12,6 +12,6 @@ import org.opendaylight.yangtools.yang.common.QName;
 
 @Beta
 public interface InputEffectiveStatement extends SchemaTreeEffectiveStatement<InputStatement>,
-    SchemaTreeAwareEffectiveStatement<QName, InputStatement> {
+    DataTreeAwareEffectiveStatement<QName, InputStatement> {
 
 }
index f113b28ae5d19c605d3f0a88f03ccecca949f58a..2ad962261bc0e7fea5d6cf06ddbbb774818dcb59 100644 (file)
@@ -10,6 +10,6 @@ package org.opendaylight.yangtools.yang.model.api.stmt;
 import com.google.common.annotations.Beta;
 
 @Beta
-public interface LeafListEffectiveStatement extends SchemaTreeEffectiveStatement<LeafListStatement> {
+public interface LeafListEffectiveStatement extends DataTreeEffectiveStatement<LeafListStatement> {
 
 }
index 0ebad88b5819c3c3972ea7a5a123f3157ac554e8..5dbf4bafaec2d0e6b4c19413d9f71023e69a30ce 100644 (file)
@@ -11,7 +11,7 @@ import com.google.common.annotations.Beta;
 import org.opendaylight.yangtools.yang.common.QName;
 
 @Beta
-public interface ListEffectiveStatement extends SchemaTreeEffectiveStatement<ListStatement>,
-    SchemaTreeAwareEffectiveStatement<QName, ListStatement> {
+public interface ListEffectiveStatement extends DataTreeEffectiveStatement<ListStatement>,
+    DataTreeAwareEffectiveStatement<QName, ListStatement> {
 
 }
index a77960d982352a9e849f2a5dbb791ef2d37bc736..af5f42b30da10a89064832255fc6bdae413badfb 100644 (file)
@@ -20,7 +20,7 @@ import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
 //               an ordinary String. We really want this to be a QName, so that we do not need the localQNameModule
 //               bit, but that may be problematic with ModuleStatement, which is getting created before we even know
 //               the namespace :( A type capture of the string may just be sufficient.
-public interface ModuleEffectiveStatement extends SchemaTreeAwareEffectiveStatement<String, ModuleStatement> {
+public interface ModuleEffectiveStatement extends DataTreeAwareEffectiveStatement<String, ModuleStatement> {
     /**
      * Namespace mapping all known prefixes in a module to their modules. Note this namespace includes the module
      * in which it is instantiated.
index 2479d01ca99ab3245d7970f89c8abbcefd2159fc..0d5add2ecf25d88bf7a07756ba14a42e66f59397 100644 (file)
@@ -12,6 +12,6 @@ import org.opendaylight.yangtools.yang.common.QName;
 
 @Beta
 public interface NotificationEffectiveStatement extends SchemaTreeEffectiveStatement<NotificationStatement>,
-    SchemaTreeAwareEffectiveStatement<QName, NotificationStatement> {
+    DataTreeAwareEffectiveStatement<QName, NotificationStatement> {
 
 }
index c7fe425ced2b64300cb35faca239573484a95210..3172152f09171f5fcede53b4b2ad49020e526754 100644 (file)
@@ -12,6 +12,6 @@ import org.opendaylight.yangtools.yang.common.QName;
 
 @Beta
 public interface OutputEffectiveStatement extends SchemaTreeEffectiveStatement<OutputStatement>,
-    SchemaTreeAwareEffectiveStatement<QName, OutputStatement> {
+    DataTreeAwareEffectiveStatement<QName, OutputStatement> {
 
 }
index 6612cd5bd69fc167990934f3bdf739abfd577e0c..87c4b0e133d12261b713022ba1c5364bf0dc13e3 100644 (file)
@@ -12,6 +12,6 @@ import org.opendaylight.yangtools.yang.common.QName;
 
 @Beta
 public interface RpcEffectiveStatement extends SchemaTreeEffectiveStatement<RpcStatement>,
-    SchemaTreeAwareEffectiveStatement<QName, RpcStatement> {
+    DataTreeAwareEffectiveStatement<QName, RpcStatement> {
 
 }
index 89ba9d80433c46a1d5d4fd62a29e2745bbc4f317..ff9363526bd7e9a262a3439dde7bae041d5f3adb 100644 (file)
@@ -48,7 +48,6 @@ public interface SchemaTreeAwareEffectiveStatement<A, D extends DeclaredStatemen
      * @return Schema tree child, or empty
      * @throws NullPointerException if {@code qname} is null
      */
-    // FIXME: make sure this namespace is populated
     default <E extends SchemaTreeEffectiveStatement<?>> @NonNull Optional<E> findSchemaTreeNode(
             final @NonNull QName qname) {
         return Optional.ofNullable(get(Namespace.class, requireNonNull(qname)));
index a3ccf19a05f79328b77d96c47eeae08cb05d1565..dda4fdc22f059f2b579af22afbd6181b494a3226 100644 (file)
@@ -15,6 +15,10 @@ import java.util.Optional;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.model.api.stmt.CaseEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeAwareEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
@@ -31,7 +35,7 @@ import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReferenc
 @Beta
 public abstract class AbstractSchemaEffectiveDocumentedNode<A, D extends DeclaredStatement<A>>
         extends AbstractEffectiveDocumentedNode<A, D> {
-
+    private final Map<QName, DataTreeEffectiveStatement<?>> dataTreeNamespace;
     private final Map<QName, SchemaTreeEffectiveStatement<?>> schemaTreeNamespace;
 
     protected AbstractSchemaEffectiveDocumentedNode(final StmtContext<A, D, ?> ctx) {
@@ -44,7 +48,28 @@ public abstract class AbstractSchemaEffectiveDocumentedNode<A, D extends Declare
                 putChild(schemaChildren, child, ref, "schema");
             });
             schemaTreeNamespace = ImmutableMap.copyOf(schemaChildren);
+
+            if (this instanceof DataTreeAwareEffectiveStatement && !schemaTreeNamespace.isEmpty()) {
+                final Map<QName, DataTreeEffectiveStatement<?>> dataChildren = new LinkedHashMap<>();
+                boolean sameAsSchema = true;
+
+                for (SchemaTreeEffectiveStatement<?> child : schemaTreeNamespace.values()) {
+                    if (child instanceof DataTreeEffectiveStatement) {
+                        putChild(dataChildren, (DataTreeEffectiveStatement<?>) child, ref, "data");
+                    } else {
+                        sameAsSchema = false;
+                        putChoiceDataChildren(dataChildren, ref, child);
+                    }
+                }
+
+                // This is a mighty hack to lower memory usage: if we consumed all schema tree children as data nodes,
+                // the two maps are equal and hence we can share the instance.
+                dataTreeNamespace = sameAsSchema ? (Map) schemaTreeNamespace : ImmutableMap.copyOf(dataChildren);
+            } else {
+                dataTreeNamespace = ImmutableMap.of();
+            }
         } else {
+            dataTreeNamespace = ImmutableMap.of();
             schemaTreeNamespace = ImmutableMap.of();
         }
     }
@@ -57,6 +82,10 @@ public abstract class AbstractSchemaEffectiveDocumentedNode<A, D extends Declare
                 && SchemaTreeAwareEffectiveStatement.Namespace.class.equals(namespace)) {
             return Optional.of((Map<K, V>) schemaTreeNamespace);
         }
+        if (this instanceof DataTreeAwareEffectiveStatement
+                && DataTreeAwareEffectiveStatement.Namespace.class.equals(namespace)) {
+            return Optional.of((Map<K, V>) dataTreeNamespace);
+        }
         return super.getNamespaceContents(namespace);
     }
 
@@ -67,4 +96,19 @@ public abstract class AbstractSchemaEffectiveDocumentedNode<A, D extends Declare
         SourceException.throwIf(prev != null, ref,
                 "Cannot add %s tree child with name %s, a conflicting child already exists", tree, id);
     }
+
+    private static void putChoiceDataChildren(final Map<QName, DataTreeEffectiveStatement<?>> map,
+            final StatementSourceReference ref, final SchemaTreeEffectiveStatement<?> child) {
+        // For choice statements go through all their cases and fetch their data children
+        if (child instanceof ChoiceEffectiveStatement) {
+            child.streamEffectiveSubstatements(CaseEffectiveStatement.class).forEach(
+                caseStmt -> caseStmt.streamEffectiveSubstatements(SchemaTreeEffectiveStatement.class).forEach(stmt -> {
+                    if (stmt instanceof DataTreeEffectiveStatement) {
+                        putChild(map, (DataTreeEffectiveStatement<?>) stmt, ref, "data");
+                    } else {
+                        putChoiceDataChildren(map, ref, stmt);
+                    }
+                }));
+        }
+    }
 }
diff --git a/yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/NameCollisionWithinCaseTest.java b/yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/NameCollisionWithinCaseTest.java
new file mode 100644 (file)
index 0000000..574654d
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.stmt;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+public class NameCollisionWithinCaseTest {
+    @Test
+    public void testChildNameCollisionOfAugmentCase() throws Exception {
+        try {
+            StmtTestUtils.parseYangSource("/bugs/name-collision-within-case/foo.yang");
+            fail("Expected failure due to node name collision");
+        } catch (ReactorException e) {
+            final Throwable cause = e.getCause();
+            assertTrue(cause instanceof SourceException);
+            assertTrue(cause.getMessage().startsWith(
+                "Cannot add data tree child with name (foo?revision=2018-02-11)bar, a conflicting child already exists "
+                        + "[at "));
+        }
+    }
+
+    @Test
+    public void testChildNameCollisionOfAugmentChoice() throws Exception {
+        try {
+            StmtTestUtils.parseYangSource("/bugs/name-collision-within-case/bar.yang");
+            fail("Expected failure due to node name collision");
+        } catch (ReactorException e) {
+            final Throwable cause = e.getCause();
+            assertTrue(cause instanceof SourceException);
+            assertTrue(cause.getMessage().startsWith(
+                "Cannot add data tree child with name (bar?revision=2018-02-11)bar, a conflicting child already exists "
+                        + "[at "));
+        }
+    }
+
+    @Test
+    public void testChildNameCollisionNormal() throws Exception {
+        try {
+            StmtTestUtils.parseYangSource("/bugs/name-collision-within-case/baz.yang");
+            fail("Expected failure due to node name collision");
+        } catch (ReactorException e) {
+            final Throwable cause = e.getCause();
+            assertTrue(cause instanceof SourceException);
+            assertTrue(cause.getMessage().startsWith(
+                "Error in module 'baz': cannot add '(baz?revision=2018-02-28)bar'. Node name collision: "));
+        }
+    }
+}
diff --git a/yang/yang-parser-rfc7950/src/test/resources/bugs/name-collision-within-case/bar.yang b/yang/yang-parser-rfc7950/src/test/resources/bugs/name-collision-within-case/bar.yang
new file mode 100644 (file)
index 0000000..634e2bb
--- /dev/null
@@ -0,0 +1,29 @@
+module bar {
+    yang-version 1.1;
+    namespace bar;
+    prefix bar;
+
+    revision "2018-02-11";
+
+    grouping foo {
+      container bar {
+
+      }
+    }
+
+    container cont {
+      choice bar {
+        case foo {
+          uses foo;
+        }
+      }
+    }
+
+    augment "/cont" {
+      choice foo {
+        case foo {
+          uses foo;
+        }
+      }
+    }
+}
diff --git a/yang/yang-parser-rfc7950/src/test/resources/bugs/name-collision-within-case/baz.yang b/yang/yang-parser-rfc7950/src/test/resources/bugs/name-collision-within-case/baz.yang
new file mode 100644 (file)
index 0000000..49df16b
--- /dev/null
@@ -0,0 +1,25 @@
+module baz {
+    yang-version 1.1;
+    namespace baz;
+    prefix baz;
+
+    revision "2018-02-28";
+
+    grouping foo {
+      container bar {
+
+      }
+    }
+
+    container cont {
+      choice bar {
+        case foo {
+          uses foo;
+        }
+      }
+
+      container bar {
+
+      }
+    }
+}
diff --git a/yang/yang-parser-rfc7950/src/test/resources/bugs/name-collision-within-case/foo.yang b/yang/yang-parser-rfc7950/src/test/resources/bugs/name-collision-within-case/foo.yang
new file mode 100644 (file)
index 0000000..21f661f
--- /dev/null
@@ -0,0 +1,27 @@
+module foo {
+    yang-version 1.1;
+    namespace foo;
+    prefix foo;
+
+    revision "2018-02-11";
+
+    grouping foo {
+      container bar {
+
+      }
+    }
+
+    container cont {
+      choice bar {
+        case foo {
+          uses foo;
+        }
+      }
+    }
+
+    augment "/cont/bar" {
+      case foo2 {
+        uses foo;
+      }
+    }
+}