Fix isSupportedToBuildEffective() propagation 18/103318/2
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 22 Nov 2022 17:47:49 +0000 (18:47 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 22 Nov 2022 19:42:52 +0000 (20:42 +0100)
InferredStatementContext has bad interaction with ImplictStmtCtx -- the
latter fizzles when it is not supported by features. This leads to a
failure to build effective context, as the prototype cannot be built and
therefore an attempt to reuse it fails.

Adjust InferredStatementContext to check if its prototype can be built
and carry over that fact when it is not.

JIRA: YANGTOOLS-1465
Change-Id: Iad05b0c6a06b6d9f837b70ced0da8cdc8ed3ed97
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
parser/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/InferredStatementContext.java
parser/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ReactorStmtCtx.java
parser/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/YT1465Test.java [new file with mode: 0644]
parser/yang-parser-rfc7950/src/test/resources/bugs/YT1465/foo.yang [new file with mode: 0644]

index 9271aa669c4efc525186efb6a9fc41535eb2a899..9bd41212df7efd409b09c04f9520a41ae08328ee 100644 (file)
@@ -709,6 +709,19 @@ final class InferredStatementContext<A, D extends DeclaredStatement<A>, E extend
         return isIgnoringConfig(parent);
     }
 
+    @Override
+    public boolean isSupportedToBuildEffective() {
+        // Our prototype may have fizzled, for example due to it being a implicit statement guarded by if-feature which
+        // evaluates to false. If that happens, this statement also needs to report unsupported -- and we want to cache
+        // that information for future reuse.
+        boolean ret = super.isSupportedToBuildEffective();
+        if (ret && !prototype.isSupportedToBuildEffective()) {
+            setUnsupported();
+            ret = false;
+        }
+        return ret;
+    }
+
     @Override
     protected boolean isParentSupportedByFeatures() {
         return parent.isSupportedByFeatures();
index 4544771beaeb1ea506a86d934fc5354b8f5c05f1..2f27f2480f83f64a2c19e61bf039de775e0f7f5b 100644 (file)
@@ -458,7 +458,7 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
     //
     //
 
-    // Non-final form ImplicitStmtCtx
+    // Non-final for ImplicitStmtCtx/InferredStatementContext
     @Override
     public boolean isSupportedToBuildEffective() {
         return isSupportedToBuildEffective;
diff --git a/parser/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/YT1465Test.java b/parser/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/YT1465Test.java
new file mode 100644 (file)
index 0000000..0593db3
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2022 PANTHEON.tech s.r.o. 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.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Set;
+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.stmt.CaseEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ContainerEffectiveStatement;
+
+public class YT1465Test extends AbstractYangTest {
+    @Test
+    public void supportedLeafInChoiceAugment() throws Exception {
+        final var baz = assertBaz(StmtTestUtils.parseYangSource("/bugs/YT1465/foo.yang", null));
+        final var schemas = baz.schemaTreeNodes();
+        assertEquals(2, schemas.size());
+        final var it = schemas.iterator();
+
+        final var first = it.next();
+        assertThat(first, instanceOf(CaseEffectiveStatement.class));
+        assertEquals(QName.create("foo", "one"), first.argument());
+
+        final var second = it.next();
+        assertThat(second, instanceOf(CaseEffectiveStatement.class));
+        assertEquals(QName.create("foo", "two"), second.argument());
+    }
+
+    @Test
+    public void unsupportedLeafInChoiceAugment() throws Exception {
+        final var baz = assertBaz(StmtTestUtils.parseYangSource("/bugs/YT1465/foo.yang", Set.of()));
+        final var schemas = baz.schemaTreeNodes();
+        assertEquals(1, schemas.size());
+        final var first = schemas.iterator().next();
+        assertThat(first, instanceOf(CaseEffectiveStatement.class));
+        assertEquals(QName.create("foo", "one"), first.argument());
+    }
+
+    private static ChoiceEffectiveStatement assertBaz(final EffectiveModelContext ctx) {
+        final var foo = ctx.findModuleStatements("foo").iterator().next()
+            .findFirstEffectiveSubstatement(ContainerEffectiveStatement.class).orElseThrow();
+        assertEquals(QName.create("foo", "foo"), foo.argument());
+
+        final var bar = foo.findFirstEffectiveSubstatement(ContainerEffectiveStatement.class).orElseThrow();
+        assertEquals(QName.create("foo", "bar"), bar.argument());
+
+        final var baz = bar.findFirstEffectiveSubstatement(ChoiceEffectiveStatement.class).orElseThrow();
+        assertEquals(QName.create("foo", "baz"), baz.argument());
+        return baz;
+    }
+}
diff --git a/parser/yang-parser-rfc7950/src/test/resources/bugs/YT1465/foo.yang b/parser/yang-parser-rfc7950/src/test/resources/bugs/YT1465/foo.yang
new file mode 100644 (file)
index 0000000..03c5f46
--- /dev/null
@@ -0,0 +1,25 @@
+module foo {
+  namespace foo;
+  prefix foo;
+
+  feature foo;
+
+  container foo;
+
+  augment /foo {
+    container bar {
+      choice baz {
+        mandatory true;
+
+        leaf one {
+          type string;
+        }
+
+        leaf two {
+          if-feature foo;
+          type string;
+        }
+      }
+    }
+  }
+}