final var implicitParent = definition().getImplicitParentFor(this, support.getPublicView());
if (implicitParent.isPresent()) {
final var parent = createUndeclared(offset, implicitParent.orElseThrow(), ref, argument);
- ret = new UndeclaredStmtCtx<>(parent, support, argument);
+ ret = new ImplicitStmtCtx<>(parent, support, argument);
parent.addEffectiveSubstatement(ret);
} else {
- ret = new UndeclaredStmtCtx<>(this, support, argument);
+ ret = new ImplicitStmtCtx<>(this, support, argument);
substatements = substatements.put(offset, ret);
}
support.onStatementAdded(ret);
--- /dev/null
+/*
+ * Copyright (c) 2022 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.parser.stmt.reactor;
+
+import static com.google.common.base.Verify.verify;
+
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
+
+/**
+ * A statement which has not been declared, but exists in the statement hierarchy through being an implicit intermediate
+ * statement -- like a {@code case} created by a {@code leaf} inside a {@code choice}.
+ *
+ * <p>
+ * That the contract of this class requires the caller to add child effective statement, if that does not happen, you
+ * get to keep the pieces.
+ *
+ * @param <A> Argument type
+ * @param <D> Declared Statement representation
+ * @param <E> Effective Statement representation
+ */
+final class ImplicitStmtCtx<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
+ extends UndeclaredStmtCtx<A, D, E> {
+ private boolean checkedSubstatement;
+
+ // Exposed for AbstractResumedStatement.createUndeclared()
+ ImplicitStmtCtx(final StatementContextBase<?, ?, ?> parent, final StatementSupport<A, D, E> support,
+ final String rawArgument) {
+ super(parent, support, rawArgument);
+ }
+
+ @Override
+ public boolean isSupportedToBuildEffective() {
+ // The availability of this statement depends on its first substatement, added by the sole user of this class.
+ // We do not really have a reasonable lifecycle hook (yet?), so here we deactivate just before the state could
+ // be leaked.
+ if (!checkedSubstatement) {
+ final var substatements = effectiveSubstatements();
+ verify(!substatements.isEmpty(), "Unexpected empty substatements in %s", this);
+ final var substatement = substatements.iterator().next();
+ // Note: isSupportedByFeatures() is implemented as a walk towards root and we are walking in the opposite
+ // direction. This check therefore must never be checked as part of isSupportedByFeatures() -- for
+ // that reason we first in our direction (which may involve recursive calls to this method in a
+ // substatement)
+ if (!substatement.isSupportedToBuildEffective() || !substatement.isSupportedByFeatures()) {
+ setUnsupported();
+ }
+ checkedSubstatement = true;
+ }
+ return super.isSupportedToBuildEffective();
+ }
+}
//
//
+ // Non-final form ImplicitStmtCtx
@Override
- public final boolean isSupportedToBuildEffective() {
+ public boolean isSupportedToBuildEffective() {
return isSupportedToBuildEffective;
}
import org.opendaylight.yangtools.yang.parser.spi.source.ImplicitSubstatement;
/**
-/**
- * Core reactor statement implementation of {@link Mutable}.
+ * A statement which has not been declared, but exists in the statement hierarchy through some inference.
*
* @param <A> Argument type
* @param <D> Declared Statement representation
* @param <E> Effective Statement representation
*/
-final class UndeclaredStmtCtx<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
+class UndeclaredStmtCtx<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
extends OriginalStmtCtx<A, D, E> implements UndeclaredCurrent<A, D> {
private final StatementContextBase<?, ?, ?> parent;
private final A argument;
this.argument = castArgument(original);
}
- // Exposed for AbstractResumedStatement
+ // Exposed for ImplicitStmtCtx
UndeclaredStmtCtx(final StatementContextBase<?, ?, ?> parent, final StatementSupport<A, D, E> support,
final String rawArgument) {
super(new StatementDefinitionContext<>(support), ImplicitSubstatement.of(parent.sourceReference()));
--- /dev/null
+/*
+ * Copyright (c) 2022 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.stmt;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+import java.util.Set;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ContainerEffectiveStatement;
+
+public class YT1431Test {
+ @Test
+ public void testUnsupportedChoiceLeaf() throws Exception {
+ final var module = StmtTestUtils.parseYangSource("/bugs/YT1431/foo.yang", Set.of())
+ .findModuleStatement(QName.create("foo", "foo"))
+ .orElseThrow();
+ final var choice = module.findFirstEffectiveSubstatement(ChoiceEffectiveStatement.class).orElseThrow();
+ assertEquals(List.of(), choice.effectiveSubstatements());
+ }
+
+ @Test
+ public void testUnsupportedChoiceLeafAugment() throws Exception {
+ final var module = StmtTestUtils.parseYangSource("/bugs/YT1431/bar.yang", Set.of())
+ .findModuleStatement(QName.create("bar", "bar"))
+ .orElseThrow();
+ final var choice = module.findFirstEffectiveSubstatement(ContainerEffectiveStatement.class).orElseThrow()
+ .findFirstEffectiveSubstatement(ChoiceEffectiveStatement.class)
+ .orElseThrow();
+ assertEquals(List.of(), choice.effectiveSubstatements());
+ }
+}
--- /dev/null
+module bar {
+ namespace bar;
+ prefix bar;
+
+ feature bar;
+
+ container foo;
+
+ augment /foo {
+ choice bar {
+ leaf baz {
+ if-feature bar;
+ type string;
+ }
+ }
+ }
+}
--- /dev/null
+module foo {
+ namespace foo;
+ prefix foo;
+
+ feature foo;
+
+ choice foo {
+ leaf bar {
+ if-feature foo;
+ type string;
+ }
+ }
+}