private final @NonNull StatementDefinitionContext<A, D, E> definition;
private final @NonNull StatementSourceReference statementDeclSource;
private final StmtContext<?, ?, ?> originalCtx;
+ private final StmtContext<?, ?, ?> prevCopyCtx;
private final CopyHistory copyHistory;
private final String rawArgument;
this.rawArgument = def.internArgument(rawArgument);
this.copyHistory = CopyHistory.original();
this.originalCtx = null;
+ this.prevCopyCtx = null;
}
StatementContextBase(final StatementDefinitionContext<A, D, E> def, final StatementSourceReference ref,
this.rawArgument = rawArgument;
this.copyHistory = CopyHistory.of(copyType, CopyHistory.original());
this.originalCtx = null;
+ this.prevCopyCtx = null;
}
StatementContextBase(final StatementContextBase<A, D, E> original, final CopyType copyType) {
this.rawArgument = original.rawArgument;
this.copyHistory = CopyHistory.of(copyType, original.getCopyHistory());
this.originalCtx = original.getOriginalCtx().orElse(original);
+ this.prevCopyCtx = original;
}
StatementContextBase(final StatementContextBase<A, D, E> original) {
this.rawArgument = original.rawArgument;
this.copyHistory = original.getCopyHistory();
this.originalCtx = original.getOriginalCtx().orElse(original);
+ this.prevCopyCtx = original;
this.substatements = original.substatements;
this.effective = original.effective;
}
return Optional.ofNullable(originalCtx);
}
+ @Override
+ public Optional<? extends StmtContext<?, ?, ?>> getPreviousCopyCtx() {
+ return Optional.ofNullable(prevCopyCtx);
+ }
+
@Override
public ModelProcessingPhase getCompletedPhase() {
return completedPhase;
* statement, otherwise false
*/
private static boolean isConditionalAugmentStmt(final StmtContext<?, ?, ?> ctx) {
- return ctx.getPublicDefinition() == YangStmtMapping.AUGMENT
- && StmtContextUtils.findFirstSubstatement(ctx, WhenStatement.class) != null;
+ return ctx.getPublicDefinition() == YangStmtMapping.AUGMENT && hasWhenSubstatement(ctx);
+ }
+
+ private static boolean hasWhenSubstatement(final StmtContext<?, ?, ?> ctx) {
+ return StmtContextUtils.findFirstSubstatement(ctx, WhenStatement.class) != null;
}
private static void copyStatement(final Mutable<?, ?, ?> original, final StatementContextBase<?, ?, ?> target,
}
if (!skipCheckOfMandatoryNodes && typeOfCopy == CopyType.ADDED_BY_AUGMENTATION
- && reguiredCheckOfMandatoryNodes(sourceCtx, targetCtx)) {
+ && requireCheckOfMandatoryNodes(sourceCtx, targetCtx)) {
checkForMandatoryNodes(sourceCtx);
}
sourceCtx.rawStatementArgument());
}
- private static boolean reguiredCheckOfMandatoryNodes(final StmtContext<?, ?, ?> sourceCtx,
+ private static boolean requireCheckOfMandatoryNodes(final StmtContext<?, ?, ?> sourceCtx,
Mutable<?, ?, ?> targetCtx) {
/*
* If the statement argument is not QName, it cannot be mandatory
* statement, therefore return false and skip mandatory nodes validation
*/
- if (!(sourceCtx.getStatementArgument() instanceof QName)) {
+ final Object arg = sourceCtx.getStatementArgument();
+ if (!(arg instanceof QName)) {
return false;
}
- final QName sourceStmtQName = (QName) sourceCtx.getStatementArgument();
+ final QName sourceStmtQName = (QName) arg;
// RootStatementContext, for example
final Mutable<?, ?, ?> root = targetCtx.getRoot();
do {
- Verify.verify(targetCtx.getStatementArgument() instanceof QName,
- "Argument of augment target statement must be QName.");
- final QName targetStmtQName = (QName) targetCtx.getStatementArgument();
+ final Object targetArg = targetCtx.getStatementArgument();
+ Verify.verify(targetArg instanceof QName, "Argument of augment target statement must be QName, not %s",
+ targetArg);
+ final QName targetStmtQName = (QName) targetArg;
/*
* If target is from another module, return true and perform mandatory nodes validation
*/
|| StmtContextUtils.isNotMandatoryNodeOfType(targetCtx, YangStmtMapping.LIST)) {
return false;
}
+
+ // This could be an augmentation stacked on top of a previous augmentation from the same module, which is
+ // conditional -- in which case we do not run further checks
+ if (targetCtx.getCopyHistory().getLastOperation() == CopyType.ADDED_BY_AUGMENTATION) {
+ final Optional<? extends StmtContext<?, ?, ?>> optPrevCopy = targetCtx.getPreviousCopyCtx();
+ if (optPrevCopy.isPresent()) {
+ final StmtContext<?, ?, ?> original = optPrevCopy.get();
+ final Object origArg = original.coerceStatementArgument();
+ Verify.verify(origArg instanceof QName, "Unexpected statement argument %s", origArg);
+
+ if (sourceStmtQName.getModule().equals(((QName) origArg).getModule())
+ && hasWhenSubstatement(getParentAugmentation(original))) {
+ return false;
+ }
+ }
+ }
} while ((targetCtx = targetCtx.getParentContext()) != root);
/*
return false;
}
+ private static StmtContext<?, ?, ?> getParentAugmentation(final StmtContext<?, ?, ?> child) {
+ StmtContext<?, ?, ?> parent = Verify.verifyNotNull(child.getParentContext(), "Child %s has not parent", child);
+ while (parent.getPublicDefinition() != YangStmtMapping.AUGMENT) {
+ parent = Verify.verifyNotNull(parent.getParentContext(), "Failed to find augmentation parent of %s", child);
+ }
+ return parent;
+ }
+
private static final ImmutableSet<YangStmtMapping> NOCOPY_DEF_SET = ImmutableSet.of(YangStmtMapping.USES,
YangStmtMapping.WHEN, YangStmtMapping.DESCRIPTION, YangStmtMapping.REFERENCE, YangStmtMapping.STATUS);
--- /dev/null
+/*
+ * 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.hamcrest.Matchers.isA;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+public class YT956Test {
+ private static final QName ANOTHER_CONTAINER = QName.create("http://www.example.com/anothermodule",
+ "another-container");
+ private static final QName FIRST_AUGMENT = QName.create("http://www.example.com/mainmodule", "first-augment");
+
+ @Test
+ public void testAugmentationConditional() throws Exception {
+ final DataSchemaNode another = StmtTestUtils.parseYangSources("/bugs/YT956/")
+ .findDataChildByName(ANOTHER_CONTAINER).get();
+ assertThat(another, isA(ContainerSchemaNode.class));
+ final ContainerSchemaNode anotherContainer = (ContainerSchemaNode) another;
+
+ final DataSchemaNode first = anotherContainer.findDataChildByName(FIRST_AUGMENT).get();
+ assertThat(first, isA(ContainerSchemaNode.class));
+ final ContainerSchemaNode firstAugment = (ContainerSchemaNode) first;
+
+ // Augmentation needs to be added
+ assertEquals(3, firstAugment.getChildNodes().size());
+ }
+}
--- /dev/null
+module another-module {
+ yang-version 1.1;
+ namespace "http://www.example.com/anothermodule";
+ prefix am;
+
+ container another-container {
+ leaf type {
+ type string;
+ mandatory true;
+ }
+ }
+}
--- /dev/null
+module mainmodule {
+ yang-version 1.1;
+ namespace "http://www.example.com/mainmodule";
+ prefix mm;
+
+ include sub-module-1;
+ include sub-module-2;
+}
--- /dev/null
+submodule sub-module-1 {
+ yang-version 1.1;
+
+ belongs-to mainmodule {
+ prefix mm;
+ }
+
+ import another-module {
+ prefix am;
+ }
+
+ augment '/am:another-container' {
+ when "am:type = 'test'";
+ container first-augment {
+
+ }
+ }
+}
--- /dev/null
+submodule sub-module-2 {
+ yang-version 1.1;
+
+ belongs-to mainmodule {
+ prefix mm;
+ }
+
+ import another-module {
+ prefix am;
+ }
+
+ include sub-module-1;
+
+ grouping dummygrouping {
+ leaf dummyleaf {
+ type string;
+ mandatory true;
+ }
+ }
+
+ grouping first {
+ leaf first-leaf {
+ type string;
+ mandatory true;
+ }
+ }
+
+ grouping second {
+ uses first;
+ leaf second-leaf {
+ type string;
+ mandatory true;
+ }
+ }
+
+ augment '/am:another-container/mm:first-augment' {
+ uses dummygrouping;
+ }
+
+ augment '/am:another-container/mm:first-augment' {
+ uses second;
+ }
+}
boolean isSupportedToBuildEffective();
+ boolean isSupportedByFeatures();
+
Collection<? extends StmtContext<?, ?, ?>> getEffectOfStatement();
+ /**
+ * Return the executive summary of the copy process that has produced this context.
+ *
+ * @return A simplified summary of the copy process.
+ */
CopyHistory getCopyHistory();
- boolean isSupportedByFeatures();
-
+ /**
+ * Return the statement context of the original definition, if this statement is an instantiated copy.
+ *
+ * @return Original definition, if this statement was copied.
+ */
Optional<StmtContext<?, ?, ?>> getOriginalCtx();
+ /**
+ * Return the context of the previous copy of this statement -- effectively walking towards the source origin
+ * of this statement.
+ *
+ * @return Context of the previous copy of this statement, if this statement has been copied.
+ */
+ Optional<? extends StmtContext<?, ?, ?>> getPreviousCopyCtx();
+
ModelProcessingPhase getCompletedPhase();
/**