Add SchemaInferenceStack.enterTypedef() 67/95967/4
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 30 Apr 2021 17:42:22 +0000 (19:42 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Fri, 30 Apr 2021 17:48:40 +0000 (19:48 +0200)
This method got left out, unfortunately, leading to an inability to
resolve leafrefs inside typedefs where a default namespace is needed.

JIRA: YANGTOOLS-1282
Change-Id: Ia89fce3f7edffa6e68b268d08a0ca5e3c3800d17
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
model/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStack.java
model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT1233Test.java
model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT1282Test.java [new file with mode: 0644]
model/yang-model-util/src/test/resources/yt1282.yang [new file with mode: 0644]

index 86e026ecffa4c9a7026617d2d9e7cf29779da961..75a8f50d675c67e92362066117e3ecd31d7a62ec 100644 (file)
@@ -55,6 +55,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.opendaylight.yangtools.yang.model.spi.AbstractEffectiveStatementInference;
@@ -305,13 +306,24 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
     }
 
     /**
-     * Check if the stack is in instantiated context. This indicates the stack is non-empty and there is no grouping
-     * (or similar construct) present in the stack.
+     * Check if the stack is in instantiated context. This indicates the stack is non-empty and there are only screma
+     * tree statements in the stack.
      *
-     * @return False if the stack is empty or contains a grouping, true otherwise.
+     * @return False if the stack is empty or contains a statement which is not a {@link SchemaTreeEffectiveStatement},
+     *         true otherwise.
      */
     public boolean inInstantiatedContext() {
-        return groupingDepth == 0 && !deque.isEmpty();
+        return groupingDepth == 0 && !deque.isEmpty()
+            && deque.stream().allMatch(SchemaTreeEffectiveStatement.class::isInstance);
+    }
+
+    /**
+     * Check if the stack is in a {@code grouping} context.
+     *
+     * @return False if the stack contains a grouping.
+     */
+    public boolean inGrouping() {
+        return groupingDepth != 0;
     }
 
     /**
@@ -329,7 +341,7 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
      * {@link #enterSchemaTree(QName)}, except it handles the use case where traversal ignores actual {@code case}
      * intermediate schema tree children.
      *
-     * @param nodeIdentifier Node identifier of the grouping to enter
+     * @param nodeIdentifier Node identifier of the choice to enter
      * @return Resolved choice
      * @throws NullPointerException if {@code nodeIdentifier} is null
      * @throws IllegalArgumentException if the corresponding choice cannot be found
@@ -427,6 +439,18 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
         return pushData(requireNonNull(nodeIdentifier));
     }
 
+    /**
+     * Lookup a {@code typedef} by its node identifier and push it to the stack.
+     *
+     * @param nodeIdentifier Node identifier of the typedef to enter
+     * @return Resolved choice
+     * @throws NullPointerException if {@code nodeIdentifier} is null
+     * @throws IllegalArgumentException if the corresponding typedef cannot be found
+     */
+    public @NonNull TypedefEffectiveStatement enterTypedef(final QName nodeIdentifier) {
+        return pushTypedef(requireNonNull(nodeIdentifier));
+    }
+
     /**
      * Pop the current statement from the stack.
      *
@@ -718,6 +742,29 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
         return ret;
     }
 
+    private @NonNull TypedefEffectiveStatement pushTypedef(final @NonNull QName nodeIdentifier) {
+        final EffectiveStatement<?, ?> parent = deque.peekFirst();
+        return parent != null ? pushTypedef(parent, nodeIdentifier) : pushFirstTypedef(nodeIdentifier);
+    }
+
+    private @NonNull TypedefEffectiveStatement pushTypedef(final @NonNull EffectiveStatement<?, ?> parent,
+            final @NonNull QName nodeIdentifier) {
+        // TODO: 8.0.0: revisit this once we have TypedefNamespace working
+        final TypedefEffectiveStatement ret = parent.streamEffectiveSubstatements(TypedefEffectiveStatement.class)
+            .filter(stmt -> nodeIdentifier.equals(stmt.argument()))
+            .findFirst()
+            .orElseThrow(() -> new IllegalArgumentException("Grouping " + nodeIdentifier + " not present"));
+        deque.push(ret);
+        return ret;
+    }
+
+    private @NonNull TypedefEffectiveStatement pushFirstTypedef(final @NonNull QName nodeIdentifier) {
+        final ModuleEffectiveStatement module = getModule(nodeIdentifier);
+        final TypedefEffectiveStatement ret = pushTypedef(module, nodeIdentifier);
+        currentModule = module;
+        return ret;
+    }
+
     private @NonNull ModuleEffectiveStatement getModule(final @NonNull QName nodeIdentifier) {
         final ModuleEffectiveStatement module = effectiveModel.getModuleStatements().get(nodeIdentifier.getModule());
         checkArgument(module != null, "Module for %s not found", nodeIdentifier);
@@ -756,6 +803,8 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
                 tmp.enterSchemaTree(((SchemaTreeEffectiveStatement<?> )stmt).argument());
             } else if (stmt instanceof GroupingEffectiveStatement) {
                 tmp.enterGrouping(((GroupingEffectiveStatement) stmt).argument());
+            } else if (stmt instanceof TypedefEffectiveStatement) {
+                tmp.enterTypedef(((TypedefEffectiveStatement) stmt).argument());
             } else {
                 throw new VerifyException("Unexpected statement " + stmt);
             }
index fb7823ac8a20c6748d48f56e30752521910e4bbf..080886789ba9ad8179ff625c59926be376bac1c4 100644 (file)
@@ -43,6 +43,7 @@ public class YT1233Test {
     @Test
     public void testExitToGrouping() {
         final GroupingEffectiveStatement baz = stack.enterGrouping(QName.create("foo", "baz"));
+        assertTrue(stack.inGrouping());
         final DataTreeEffectiveStatement<?> xyzzy = stack.enterDataTree(QName.create("foo", "xyzzy"));
         assertSame(xyzzy, stack.exitToDataTree());
         assertSame(baz, stack.currentStatement());
diff --git a/model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT1282Test.java b/model/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT1282Test.java
new file mode 100644 (file)
index 0000000..edffa68
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2021 PANTHEON.tech, 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.util;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LeafEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.PathEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class YT1282Test {
+    private static EffectiveModelContext context;
+
+    private final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
+
+    @BeforeClass
+    public static void beforeClass() {
+        context = YangParserTestUtils.parseYangResource("/yt1282.yang");
+    }
+
+    @Test
+    public void testResolveTypedef() {
+        final TypeEffectiveStatement<?> type = stack.enterTypedef(QName.create("foo", "foo"))
+            .findFirstEffectiveSubstatement(TypeEffectiveStatement.class).orElseThrow();
+        assertFalse(stack.inInstantiatedContext());
+        assertFalse(stack.inGrouping());
+
+        final EffectiveStatement<?, ?> bar = stack.resolvePathExpression(
+            type.findFirstEffectiveSubstatementArgument(PathEffectiveStatement.class).orElseThrow());
+        assertThat(bar, instanceOf(LeafEffectiveStatement.class));
+        assertEquals(QName.create("foo", "bar"), bar.argument());
+    }
+}
diff --git a/model/yang-model-util/src/test/resources/yt1282.yang b/model/yang-model-util/src/test/resources/yt1282.yang
new file mode 100644 (file)
index 0000000..06f9c8a
--- /dev/null
@@ -0,0 +1,14 @@
+module foo {
+  prefix foo;
+  namespace foo;
+
+  typedef foo {
+    type leafref {
+      path /bar;
+    }
+  }
+
+  leaf bar {
+    type int64;
+  }
+}