Defer copy decisions to StatementSupport 98/87398/1
authorRobert Varga <robert.varga@pantheon.tech>
Sun, 26 Jan 2020 00:22:11 +0000 (01:22 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Mon, 3 Feb 2020 18:52:08 +0000 (19:52 +0100)
Core reactor should have no knowledge of specific statements, but
rather should provide general facilities for statements to decide
what they need to do. A typical example of this are
description/reference/status statements, which are never inlined
from a grouping parent (as they relate to the grouping, not the
copy target).

Add StatementSupport.copyAsChildOf() and implement above case
in terms of the new method.

Furthermore move support code to UsesStatementSupport and make it
use the same mechanics -- eliminating NOCOPY_FROM_GROUPING_SET
in the process of doing so.

JIRA: YANGTOOLS-694
Change-Id: I446266249dfe3f1bcac310bd16aece5185b40fb6
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
14 files changed:
yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/AbstractResumedStatement.java
yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/InferredStatementContext.java
yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java
yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementDefinitionContext.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/description/DescriptionStatementSupport.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/reference/ReferenceStatementSupport.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/status/StatusStatementSupport.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/uses/UsesStatementImpl.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/uses/UsesStatementSupport.java
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractStatementSupport.java
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ForwardingStatementSupport.java
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupport.java
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContext.java
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java

index db3202a522806c1a98f16f6750aaed150a1ed5f9..2123c3578886441ad9439cb0d026d3724a1e9397 100644 (file)
@@ -55,7 +55,7 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
             final String rawArgument) {
         super(def);
         this.statementDeclSource = requireNonNull(ref);
-        this.rawArgument = def.internArgument(rawArgument);
+        this.rawArgument = def.support().internArgument(rawArgument);
     }
 
     AbstractResumedStatement(final StatementDefinitionContext<A, D, E> def, final StatementSourceReference ref,
index 1d7a0578051278bea909131d7afcaf0d31745702..3398f2edd5f72d63c4440fdedbaf2f5b253bdd1b 100644 (file)
@@ -150,15 +150,11 @@ final class InferredStatementContext<A, D extends DeclaredStatement<A>, E extend
     // FIXME: This is messy and is probably wrong in some corner case. Even if it is correct, the way how it is correct
     //        relies on hard-coded maps. At the end of the day, the logic needs to be controlled by statement's
     //        StatementSupport.
-    // FIXME: YANGTOOLS-652: these maps look very much like those in UsesStatementImpl
+    // FIXME: YANGTOOLS-652: this map looks very much like UsesStatementSupport.TOP_REUSED_DEF_SET
     private static final ImmutableSet<YangStmtMapping> REUSED_DEF_SET = ImmutableSet.of(
         YangStmtMapping.TYPE,
         YangStmtMapping.TYPEDEF,
         YangStmtMapping.USES);
-    private static final ImmutableSet<YangStmtMapping> NOCOPY_FROM_GROUPING_SET = ImmutableSet.of(
-        YangStmtMapping.DESCRIPTION,
-        YangStmtMapping.REFERENCE,
-        YangStmtMapping.STATUS);
 
     private void copySubstatement(final Mutable<?, ?, ?> substatement, final Collection<Mutable<?, ?, ?>> buffer) {
         final StatementDefinition def = substatement.getPublicDefinition();
@@ -169,22 +165,8 @@ final class InferredStatementContext<A, D extends DeclaredStatement<A>, E extend
             buffer.add(substatement);
             return;
         }
-        // FIXME: YANGTOOLS-652: formerly known as "needToCopyByUses" (note inverted check, though)
-        if (NOCOPY_FROM_GROUPING_SET.contains(def)) {
-            // This is to say: if parent of source context is a grouping, ignore this statement.
-            if (YangStmtMapping.GROUPING.equals(substatement.coerceParentContext().getPublicDefinition())) {
-                LOG.debug("Skipping grouping statement {}", substatement);
-                return;
-            }
-        }
 
-        // FIXME: YANGTOOLS-694: we are forcing a copy here, hence even statements not affected by parent, copyType
-        //                       or targetModule (and don't forget its substatements!). This really should be a callout
-        //                       to StatementSupport. Note if that callout is allowed to return an Optional, it can
-        //                       take care at least of the 'grouping from uses' case above.
-        final Mutable<?, ?, ?> copy = childCopyOf(substatement, childCopyType, targetModule);
-        LOG.debug("Copying substatement {} for {} as {}", substatement, this, copy);
-        buffer.add(copy);
+        substatement.copyAsChildOf(this, childCopyType, targetModule).ifPresent(buffer::add);
     }
 
     // Statement copy mess ends here
index 6a50e47d4f91992272ee7179125e6cf13fbf3811..32f546d6186c1faf4a381b999f1a80c6c8ba41a0 100644 (file)
@@ -765,12 +765,17 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         addContextToNamespace(namespace, key, stmt);
     }
 
+    @Override
+    public Optional<? extends Mutable<?, ?, ?>> copyAsChildOf(final Mutable<?, ?, ?> parent, final CopyType type,
+            final QNameModule targetModule) {
+        checkEffectiveModelCompleted(this);
+        return definition.support().copyAsChildOf(this, parent, type, targetModule);
+    }
+
     @Override
     public <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>> Mutable<X, Y, Z> childCopyOf(
             final StmtContext<X, Y, Z> stmt, final CopyType type, final QNameModule targetModule) {
-        checkState(stmt.getCompletedPhase() == ModelProcessingPhase.EFFECTIVE_MODEL,
-                "Attempted to copy statement %s which has completed phase %s", stmt, stmt.getCompletedPhase());
-
+        checkEffectiveModelCompleted(stmt);
         checkArgument(stmt instanceof StatementContextBase, "Unsupported statement %s", stmt);
         return childCopyOf((StatementContextBase<X, Y, Z>)stmt, type, targetModule);
     }
@@ -812,6 +817,12 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         return result;
     }
 
+    private static void checkEffectiveModelCompleted(final StmtContext<?, ?, ?> stmt) {
+        final ModelProcessingPhase phase = stmt.getCompletedPhase();
+        checkState(phase == ModelProcessingPhase.EFFECTIVE_MODEL,
+                "Attempted to copy statement %s which has completed phase %s", stmt, phase);
+    }
+
     @Beta
     public final boolean hasImplicitParentSupport() {
         return definition.getFactory() instanceof ImplicitParentAwareStatementSupport;
@@ -897,7 +908,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         if (fl != 0) {
             return fl == SET_IGNORE_CONFIG;
         }
-        if (definition.isIgnoringConfig() || parent.isIgnoringConfig()) {
+        if (definition.support().isIgnoringConfig() || parent.isIgnoringConfig()) {
             flags |= SET_IGNORE_CONFIG;
             return true;
         }
@@ -918,7 +929,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         if (fl != 0) {
             return fl == SET_IGNORE_IF_FEATURE;
         }
-        if (definition.isIgnoringIfFeatures() || parent.isIgnoringIfFeatures()) {
+        if (definition.support().isIgnoringIfFeatures() || parent.isIgnoringIfFeatures()) {
             flags |= SET_IGNORE_IF_FEATURE;
             return true;
         }
index 570da62a649daacf61e22424effe170ee491c4f9..b7df52b3c603f6f7309106795989053005fc65cc 100644 (file)
@@ -109,7 +109,7 @@ public class StatementDefinitionContext<A, D extends DeclaredStatement<A>, E ext
         return toStringHelper.add("statement", getStatementName());
     }
 
-    @NonNull StatementDefinitionContext<?, ?, ?> getSubDefinitionSpecificForArgument(final String argument) {
+    final @NonNull StatementDefinitionContext<?, ?, ?> getSubDefinitionSpecificForArgument(final String argument) {
         if (!hasArgumentSpecificSubDefinitions()) {
             return this;
         }
@@ -125,15 +125,15 @@ public class StatementDefinitionContext<A, D extends DeclaredStatement<A>, E ext
         return potential;
     }
 
-    boolean hasArgumentSpecificSubDefinitions() {
-        return support.hasArgumentSpecificSupports();
+    final StatementSupport<A, D, E> support() {
+        return support;
     }
 
-    String internArgument(final String rawArgument) {
-        return support.internArgument(rawArgument);
+    final boolean hasArgumentSpecificSubDefinitions() {
+        return support.hasArgumentSpecificSupports();
     }
 
-    StatementDefinitionContext<?, ?, ?> getAsUnknownStatementDefinition(
+    final StatementDefinitionContext<?, ?, ?> getAsUnknownStatementDefinition(
             final StatementDefinitionContext<?, ?, ?> yangStmtDef) {
         if (unknownStmtDefsOfYangStmts != null) {
             final StatementDefinitionContext<?, ?, ?> existing = unknownStmtDefsOfYangStmts.get(yangStmtDef);
@@ -152,12 +152,4 @@ public class StatementDefinitionContext<A, D extends DeclaredStatement<A>, E ext
         }
         return ret;
     }
-
-    boolean isIgnoringIfFeatures() {
-        return support.isIgnoringIfFeatures();
-    }
-
-    boolean isIgnoringConfig() {
-        return support.isIgnoringConfig();
-    }
 }
index f83401f7de0acc12de0870c99aacf70e17757228..2fdc3de240241ac92fbc55722ed13ea207c74ea0 100644 (file)
@@ -8,13 +8,18 @@
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.description;
 
 import com.google.common.collect.ImmutableList;
+import java.util.Optional;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement;
 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseStringStatementSupport;
+import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
 
 public final class DescriptionStatementSupport
@@ -36,6 +41,13 @@ public final class DescriptionStatementSupport
         return value;
     }
 
+    @Override
+    public Optional<? extends Mutable<?, ?, ?>> copyAsChildOf(final Mutable<?, ?, ?> stmt,
+            final Mutable<?, ?, ?> parent, final CopyType type, final QNameModule targetModule) {
+        return StmtContextUtils.isChildOfGrouping(stmt) ? Optional.empty()
+                : super.copyAsChildOf(stmt, parent, type, targetModule);
+    }
+
     @Override
     protected SubstatementValidator getSubstatementValidator() {
         return SUBSTATEMENT_VALIDATOR;
@@ -66,4 +78,4 @@ public final class DescriptionStatementSupport
             final DescriptionStatement declared) {
         return new EmptyDescriptionEffectiveStatement(declared);
     }
-}
\ No newline at end of file
+}
index 28ba59ab0f61238195539bfd5554f2b7488b4e26..365e4ce28488e18b1ea799f9a2336b360031d674 100644 (file)
@@ -8,13 +8,18 @@
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.reference;
 
 import com.google.common.collect.ImmutableList;
+import java.util.Optional;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement;
 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseStringStatementSupport;
+import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
 
 public final class ReferenceStatementSupport
@@ -37,6 +42,13 @@ public final class ReferenceStatementSupport
         return value;
     }
 
+    @Override
+    public Optional<? extends Mutable<?, ?, ?>> copyAsChildOf(final Mutable<?, ?, ?> stmt,
+            final Mutable<?, ?, ?> parent, final CopyType type, final QNameModule targetModule) {
+        return StmtContextUtils.isChildOfGrouping(stmt) ? Optional.empty()
+                : super.copyAsChildOf(stmt, parent, type, targetModule);
+    }
+
     @Override
     protected SubstatementValidator getSubstatementValidator() {
         return SUBSTATEMENT_VALIDATOR;
@@ -67,4 +79,4 @@ public final class ReferenceStatementSupport
             final ReferenceStatement declared) {
         return new EmptyReferenceEffectiveStatement(declared);
     }
-}
\ No newline at end of file
+}
index b0e14c755fdf81e19e6e696bb2ad8f57cf719716..d39fd6f0b22b1e3e636fa423740a8612cf41fdea 100644 (file)
@@ -8,7 +8,9 @@
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.status;
 
 import com.google.common.collect.ImmutableList;
+import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
@@ -16,7 +18,10 @@ import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.StatusStatement;
 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseStatementSupport;
+import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 
@@ -80,6 +85,13 @@ public final class StatusStatementSupport
         }
     }
 
+    @Override
+    public Optional<? extends Mutable<?, ?, ?>> copyAsChildOf(final Mutable<?, ?, ?> stmt,
+            final Mutable<?, ?, ?> parent, final CopyType type, final QNameModule targetModule) {
+        return StmtContextUtils.isChildOfGrouping(stmt) ? Optional.empty()
+                : super.copyAsChildOf(stmt, parent, type, targetModule);
+    }
+
     @Override
     protected SubstatementValidator getSubstatementValidator() {
         return SUBSTATEMENT_VALIDATOR;
@@ -131,5 +143,4 @@ public final class StatusStatementSupport
             return new EmptyStatusEffectiveStatement(declared);
         }
     }
-
-}
\ No newline at end of file
+}
index 922e296857f758a2ccd45ecc58203348622fb031..0c302199c71291ee2670d2855140fd5d122052e5 100644 (file)
  */
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.uses;
 
-import com.google.common.base.Verify;
-import com.google.common.collect.ImmutableSet;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Optional;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.common.YangVersion;
-import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
-import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
-import org.opendaylight.yangtools.yang.model.api.stmt.RefineStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
-import org.opendaylight.yangtools.yang.model.api.stmt.UsesEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
-import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ChildSchemaNodeNamespace;
-import org.opendaylight.yangtools.yang.parser.rfc7950.reactor.YangValidationBundles;
 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement;
-import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
-import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
-import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
-import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
-import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
-import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
-import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace;
-import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace.ValidationBundleType;
-import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 final class UsesStatementImpl extends AbstractDeclaredStatement<QName> implements UsesStatement {
-    private static final Logger LOG = LoggerFactory.getLogger(UsesStatementImpl.class);
-
     UsesStatementImpl(final StmtContext<QName, UsesStatement, ?> context) {
         super(context);
     }
-
-    /**
-     * Copy statements from a grouping to a target node.
-     *
-     * @param sourceGrpStmtCtx
-     *            source grouping statement context
-     * @param targetCtx
-     *            target context
-     * @param usesNode
-     *            uses node
-     * @throws SourceException
-     *             instance of SourceException
-     */
-    static void copyFromSourceToTarget(final Mutable<?, ?, ?> sourceGrpStmtCtx,
-            final StatementContextBase<?, ?, ?> targetCtx,
-            final Mutable<QName, UsesStatement, UsesEffectiveStatement> usesNode) {
-        final Collection<? extends Mutable<?, ?, ?>> declared = sourceGrpStmtCtx.mutableDeclaredSubstatements();
-        final Collection<? extends Mutable<?, ?, ?>> effective = sourceGrpStmtCtx.mutableEffectiveSubstatements();
-        final Collection<Mutable<?, ?, ?>> buffer = new ArrayList<>(declared.size() + effective.size());
-        final QNameModule newQNameModule = getNewQNameModule(targetCtx, sourceGrpStmtCtx);
-
-        for (final Mutable<?, ?, ?> original : declared) {
-            if (original.isSupportedByFeatures()) {
-                copyStatement(original, targetCtx, newQNameModule, buffer);
-            }
-        }
-
-        for (final Mutable<?, ?, ?> original : effective) {
-            copyStatement(original, targetCtx, newQNameModule, buffer);
-        }
-
-        targetCtx.addEffectiveSubstatements(buffer);
-        usesNode.addAsEffectOfStatement(buffer);
-    }
-
-    private static void copyStatement(final Mutable<?, ?, ?> original,
-            final StatementContextBase<?, ?, ?> targetCtx, final QNameModule targetModule,
-            final Collection<Mutable<?, ?, ?>> buffer) {
-        if (needToCopyByUses(original)) {
-            final Mutable<?, ?, ?> copy = targetCtx.childCopyOf(original, CopyType.ADDED_BY_USES, targetModule);
-            buffer.add(copy);
-        } else if (isReusedByUsesOnTop(original)) {
-            buffer.add(original);
-        }
-    }
-
-    // FIXME: YANGTOOLS-652: these maps look very much like those in InferredStatementContext
-    private static final ImmutableSet<YangStmtMapping> TOP_REUSED_DEF_SET = ImmutableSet.of(
-        YangStmtMapping.TYPE,
-        YangStmtMapping.TYPEDEF);
-
-    private static boolean isReusedByUsesOnTop(final StmtContext<?, ?, ?> stmtContext) {
-        return TOP_REUSED_DEF_SET.contains(stmtContext.getPublicDefinition());
-    }
-
-    private static final ImmutableSet<YangStmtMapping> NOCOPY_FROM_GROUPING_SET = ImmutableSet.of(
-        YangStmtMapping.DESCRIPTION,
-        YangStmtMapping.REFERENCE,
-        YangStmtMapping.STATUS);
-    private static final ImmutableSet<YangStmtMapping> REUSED_DEF_SET = ImmutableSet.of(
-        YangStmtMapping.TYPE,
-        YangStmtMapping.TYPEDEF,
-        YangStmtMapping.USES);
-
-    public static boolean needToCopyByUses(final StmtContext<?, ?, ?> stmtContext) {
-        final StatementDefinition def = stmtContext.getPublicDefinition();
-        if (REUSED_DEF_SET.contains(def)) {
-            LOG.trace("Will reuse {} statement {}", def, stmtContext);
-            return false;
-        }
-        if (NOCOPY_FROM_GROUPING_SET.contains(def)) {
-            return !YangStmtMapping.GROUPING.equals(stmtContext.coerceParentContext().getPublicDefinition());
-        }
-
-        LOG.trace("Will copy {} statement {}", def, stmtContext);
-        return true;
-    }
-
-    public static void resolveUsesNode(final Mutable<QName, UsesStatement, UsesEffectiveStatement> usesNode,
-            final StmtContext<?, ?, ?> targetNodeStmtCtx) {
-        for (final Mutable<?, ?, ?> subStmtCtx : usesNode.mutableDeclaredSubstatements()) {
-            if (StmtContextUtils.producesDeclared(subStmtCtx, RefineStatement.class)
-                    && areFeaturesSupported(subStmtCtx)) {
-                performRefine(subStmtCtx, targetNodeStmtCtx);
-            }
-        }
-    }
-
-    private static boolean areFeaturesSupported(final StmtContext<?, ?, ?> subStmtCtx) {
-        /*
-         * In case of Yang 1.1, checks whether features are supported.
-         */
-        return !YangVersion.VERSION_1_1.equals(subStmtCtx.getRootVersion()) || subStmtCtx.isSupportedByFeatures();
-    }
-
-    private static void performRefine(final Mutable<?, ?, ?> subStmtCtx, final StmtContext<?, ?, ?> usesParentCtx) {
-        final Object refineArgument = subStmtCtx.getStatementArgument();
-        InferenceException.throwIf(!(refineArgument instanceof SchemaNodeIdentifier),
-            subStmtCtx.getStatementSourceReference(),
-            "Invalid refine argument %s. It must be instance of SchemaNodeIdentifier.", refineArgument);
-
-        final Optional<StmtContext<?, ?, ?>> optRefineTargetCtx = ChildSchemaNodeNamespace.findNode(
-            usesParentCtx, (SchemaNodeIdentifier) refineArgument);
-        InferenceException.throwIf(!optRefineTargetCtx.isPresent(), subStmtCtx.getStatementSourceReference(),
-            "Refine target node %s not found.", refineArgument);
-
-        final StmtContext<?, ?, ?> refineTargetNodeCtx = optRefineTargetCtx.get();
-        if (StmtContextUtils.isUnknownStatement(refineTargetNodeCtx)) {
-            LOG.trace("Refine node '{}' in uses '{}' has target node unknown statement '{}'. "
-                + "Refine has been skipped. At line: {}", subStmtCtx.getStatementArgument(),
-                subStmtCtx.coerceParentContext().getStatementArgument(),
-                refineTargetNodeCtx.getStatementArgument(), subStmtCtx.getStatementSourceReference());
-            subStmtCtx.addAsEffectOfStatement(refineTargetNodeCtx);
-            return;
-        }
-
-        Verify.verify(refineTargetNodeCtx instanceof StatementContextBase);
-        addOrReplaceNodes(subStmtCtx, (StatementContextBase<?, ?, ?>) refineTargetNodeCtx);
-        subStmtCtx.addAsEffectOfStatement(refineTargetNodeCtx);
-    }
-
-    private static void addOrReplaceNodes(final Mutable<?, ?, ?> subStmtCtx,
-            final StatementContextBase<?, ?, ?> refineTargetNodeCtx) {
-        for (final Mutable<?, ?, ?> refineSubstatementCtx : subStmtCtx.mutableDeclaredSubstatements()) {
-            if (isSupportedRefineSubstatement(refineSubstatementCtx)) {
-                addOrReplaceNode(refineSubstatementCtx, refineTargetNodeCtx);
-            }
-        }
-    }
-
-    private static void addOrReplaceNode(final Mutable<?, ?, ?> refineSubstatementCtx,
-            final StatementContextBase<?, ?, ?> refineTargetNodeCtx) {
-
-        final StatementDefinition refineSubstatementDef = refineSubstatementCtx.getPublicDefinition();
-
-        SourceException.throwIf(!isSupportedRefineTarget(refineSubstatementCtx, refineTargetNodeCtx),
-                refineSubstatementCtx.getStatementSourceReference(),
-                "Error in module '%s' in the refine of uses '%s': can not perform refine of '%s' for the target '%s'.",
-                refineSubstatementCtx.getRoot().getStatementArgument(),
-                refineSubstatementCtx.coerceParentContext().getStatementArgument(),
-                refineSubstatementCtx.getPublicDefinition(), refineTargetNodeCtx.getPublicDefinition());
-
-        if (isAllowedToAddByRefine(refineSubstatementDef)) {
-            refineTargetNodeCtx.addEffectiveSubstatement(refineSubstatementCtx);
-        } else {
-            refineTargetNodeCtx.removeStatementFromEffectiveSubstatements(refineSubstatementDef);
-            refineTargetNodeCtx.addEffectiveSubstatement(refineSubstatementCtx);
-        }
-    }
-
-    private static final ImmutableSet<YangStmtMapping> ALLOWED_TO_ADD_BY_REFINE_DEF_SET =
-            ImmutableSet.of(YangStmtMapping.MUST);
-
-    private static boolean isAllowedToAddByRefine(final StatementDefinition publicDefinition) {
-        return ALLOWED_TO_ADD_BY_REFINE_DEF_SET.contains(publicDefinition);
-    }
-
-    private static boolean isSupportedRefineSubstatement(final StmtContext<?, ?, ?> refineSubstatementCtx) {
-        final Collection<?> supportedRefineSubstatements = refineSubstatementCtx.getFromNamespace(
-                ValidationBundlesNamespace.class, ValidationBundleType.SUPPORTED_REFINE_SUBSTATEMENTS);
-
-        return supportedRefineSubstatements == null || supportedRefineSubstatements.isEmpty()
-                || supportedRefineSubstatements.contains(refineSubstatementCtx.getPublicDefinition())
-                || StmtContextUtils.isUnknownStatement(refineSubstatementCtx);
-    }
-
-    private static boolean isSupportedRefineTarget(final StmtContext<?, ?, ?> refineSubstatementCtx,
-            final StmtContext<?, ?, ?> refineTargetNodeCtx) {
-        final Collection<?> supportedRefineTargets = YangValidationBundles.SUPPORTED_REFINE_TARGETS
-                .get(refineSubstatementCtx.getPublicDefinition());
-
-        return supportedRefineTargets == null || supportedRefineTargets.isEmpty()
-                || supportedRefineTargets.contains(refineTargetNodeCtx.getPublicDefinition());
-    }
-
-
-    private static QNameModule getNewQNameModule(final StmtContext<?, ?, ?> targetCtx,
-            final StmtContext<?, ?, ?> stmtContext) {
-        if (targetCtx.getParentContext() == null) {
-            return targetCtx.getFromNamespace(ModuleCtxToModuleQName.class, targetCtx);
-        }
-        if (targetCtx.getPublicDefinition() == YangStmtMapping.AUGMENT) {
-            return StmtContextUtils.getRootModuleQName(targetCtx);
-        }
-
-        final Object targetStmtArgument = targetCtx.getStatementArgument();
-        final Object sourceStmtArgument = stmtContext.getStatementArgument();
-        if (targetStmtArgument instanceof QName && sourceStmtArgument instanceof QName) {
-            return ((QName) targetStmtArgument).getModule();
-        }
-
-        return null;
-    }
 }
index 2c3af93469d367fe3c88334055bf43290004bb90..7a9769310784182fece33c95a215a18ab5990a23 100644 (file)
@@ -7,13 +7,25 @@
  */
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.uses;
 
+import com.google.common.base.Verify;
+import com.google.common.collect.ImmutableSet;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Optional;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.YangVersion;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.model.api.stmt.RefineStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.stmt.UsesEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
+import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ChildSchemaNodeNamespace;
+import org.opendaylight.yangtools.yang.parser.rfc7950.reactor.YangValidationBundles;
 import org.opendaylight.yangtools.yang.parser.spi.GroupingNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractQNameStatementSupport;
+import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceAction;
@@ -24,10 +36,17 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
+import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace.ValidationBundleType;
 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public final class UsesStatementSupport
         extends AbstractQNameStatementSupport<UsesStatement, UsesEffectiveStatement> {
+    private static final Logger LOG = LoggerFactory.getLogger(UsesStatementSupport.class);
     private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(YangStmtMapping
         .USES)
         .addAny(YangStmtMapping.AUGMENT)
@@ -77,8 +96,8 @@ public final class UsesStatementSupport
                 final StatementContextBase<?, ?, ?> sourceGrpStmtCtx =
                         (StatementContextBase<?, ?, ?>) sourceGroupingPre.resolve(ctx);
 
-                UsesStatementImpl.copyFromSourceToTarget(sourceGrpStmtCtx, targetNodeStmtCtx, usesNode);
-                UsesStatementImpl.resolveUsesNode(usesNode, targetNodeStmtCtx);
+                copyFromSourceToTarget(sourceGrpStmtCtx, targetNodeStmtCtx, usesNode);
+                resolveUsesNode(usesNode, targetNodeStmtCtx);
                 StmtContextUtils.validateIfFeatureAndWhenOnListKeys(usesNode);
             }
 
@@ -105,4 +124,171 @@ public final class UsesStatementSupport
     protected SubstatementValidator getSubstatementValidator() {
         return SUBSTATEMENT_VALIDATOR;
     }
-}
\ No newline at end of file
+
+    /**
+     * Copy statements from a grouping to a target node.
+     *
+     * @param sourceGrpStmtCtx
+     *            source grouping statement context
+     * @param targetCtx
+     *            target context
+     * @param usesNode
+     *            uses node
+     * @throws SourceException
+     *             instance of SourceException
+     */
+    private static void copyFromSourceToTarget(final Mutable<?, ?, ?> sourceGrpStmtCtx,
+            final StatementContextBase<?, ?, ?> targetCtx,
+            final Mutable<QName, UsesStatement, UsesEffectiveStatement> usesNode) {
+        final Collection<? extends Mutable<?, ?, ?>> declared = sourceGrpStmtCtx.mutableDeclaredSubstatements();
+        final Collection<? extends Mutable<?, ?, ?>> effective = sourceGrpStmtCtx.mutableEffectiveSubstatements();
+        final Collection<Mutable<?, ?, ?>> buffer = new ArrayList<>(declared.size() + effective.size());
+        final QNameModule newQNameModule = getNewQNameModule(targetCtx, sourceGrpStmtCtx);
+
+        for (final Mutable<?, ?, ?> original : declared) {
+            if (original.isSupportedByFeatures()) {
+                copyStatement(original, targetCtx, newQNameModule, buffer);
+            }
+        }
+
+        for (final Mutable<?, ?, ?> original : effective) {
+            copyStatement(original, targetCtx, newQNameModule, buffer);
+        }
+
+        targetCtx.addEffectiveSubstatements(buffer);
+        usesNode.addAsEffectOfStatement(buffer);
+    }
+
+    // FIXME: YANGTOOLS-652: this map looks very much like InferredStatementContext.REUSED_DEF_SET
+    private static final ImmutableSet<YangStmtMapping> TOP_REUSED_DEF_SET = ImmutableSet.of(
+        YangStmtMapping.TYPE,
+        YangStmtMapping.TYPEDEF);
+
+    private static void copyStatement(final Mutable<?, ?, ?> original,
+            final StatementContextBase<?, ?, ?> targetCtx, final QNameModule targetModule,
+            final Collection<Mutable<?, ?, ?>> buffer) {
+        final StatementDefinition def = original.getPublicDefinition();
+        if (TOP_REUSED_DEF_SET.contains(def)) {
+            buffer.add(original);
+            return;
+        }
+        // Do not propagate uses, as their effects have been accounted for in effective statements
+        // FIXME: YANGTOOLS-652: this check is different from InferredStatementContext. Why is that? We should express
+        //                       a common condition in our own implementation of copyAsChildOf()
+        if (!YangStmtMapping.USES.equals(def)) {
+            original.copyAsChildOf(targetCtx, CopyType.ADDED_BY_USES, targetModule).ifPresent(buffer::add);
+        }
+    }
+
+    private static QNameModule getNewQNameModule(final StmtContext<?, ?, ?> targetCtx,
+            final StmtContext<?, ?, ?> stmtContext) {
+        if (targetCtx.getParentContext() == null) {
+            return targetCtx.getFromNamespace(ModuleCtxToModuleQName.class, targetCtx);
+        }
+        if (targetCtx.getPublicDefinition() == YangStmtMapping.AUGMENT) {
+            return StmtContextUtils.getRootModuleQName(targetCtx);
+        }
+
+        final Object targetStmtArgument = targetCtx.getStatementArgument();
+        final Object sourceStmtArgument = stmtContext.getStatementArgument();
+        if (targetStmtArgument instanceof QName && sourceStmtArgument instanceof QName) {
+            return ((QName) targetStmtArgument).getModule();
+        }
+
+        return null;
+    }
+
+    private static void resolveUsesNode(final Mutable<QName, UsesStatement, UsesEffectiveStatement> usesNode,
+            final StmtContext<?, ?, ?> targetNodeStmtCtx) {
+        for (final Mutable<?, ?, ?> subStmtCtx : usesNode.mutableDeclaredSubstatements()) {
+            if (StmtContextUtils.producesDeclared(subStmtCtx, RefineStatement.class)
+                    && areFeaturesSupported(subStmtCtx)) {
+                performRefine(subStmtCtx, targetNodeStmtCtx);
+            }
+        }
+    }
+
+    private static boolean areFeaturesSupported(final StmtContext<?, ?, ?> subStmtCtx) {
+        /*
+         * In case of Yang 1.1, checks whether features are supported.
+         */
+        return !YangVersion.VERSION_1_1.equals(subStmtCtx.getRootVersion()) || subStmtCtx.isSupportedByFeatures();
+    }
+
+    private static void performRefine(final Mutable<?, ?, ?> subStmtCtx, final StmtContext<?, ?, ?> usesParentCtx) {
+        final Object refineArgument = subStmtCtx.getStatementArgument();
+        InferenceException.throwIf(!(refineArgument instanceof SchemaNodeIdentifier),
+            subStmtCtx.getStatementSourceReference(),
+            "Invalid refine argument %s. It must be instance of SchemaNodeIdentifier.", refineArgument);
+
+        final Optional<StmtContext<?, ?, ?>> optRefineTargetCtx = ChildSchemaNodeNamespace.findNode(
+            usesParentCtx, (SchemaNodeIdentifier) refineArgument);
+        InferenceException.throwIf(!optRefineTargetCtx.isPresent(), subStmtCtx.getStatementSourceReference(),
+            "Refine target node %s not found.", refineArgument);
+
+        final StmtContext<?, ?, ?> refineTargetNodeCtx = optRefineTargetCtx.get();
+        if (StmtContextUtils.isUnknownStatement(refineTargetNodeCtx)) {
+            LOG.trace("Refine node '{}' in uses '{}' has target node unknown statement '{}'. "
+                + "Refine has been skipped. At line: {}", subStmtCtx.getStatementArgument(),
+                subStmtCtx.coerceParentContext().getStatementArgument(),
+                refineTargetNodeCtx.getStatementArgument(), subStmtCtx.getStatementSourceReference());
+            subStmtCtx.addAsEffectOfStatement(refineTargetNodeCtx);
+            return;
+        }
+
+        Verify.verify(refineTargetNodeCtx instanceof StatementContextBase);
+        addOrReplaceNodes(subStmtCtx, (StatementContextBase<?, ?, ?>) refineTargetNodeCtx);
+        subStmtCtx.addAsEffectOfStatement(refineTargetNodeCtx);
+    }
+
+    private static void addOrReplaceNodes(final Mutable<?, ?, ?> subStmtCtx,
+            final StatementContextBase<?, ?, ?> refineTargetNodeCtx) {
+        for (final Mutable<?, ?, ?> refineSubstatementCtx : subStmtCtx.mutableDeclaredSubstatements()) {
+            if (isSupportedRefineSubstatement(refineSubstatementCtx)) {
+                addOrReplaceNode(refineSubstatementCtx, refineTargetNodeCtx);
+            }
+        }
+    }
+
+    private static void addOrReplaceNode(final Mutable<?, ?, ?> refineSubstatementCtx,
+            final StatementContextBase<?, ?, ?> refineTargetNodeCtx) {
+
+        final StatementDefinition refineSubstatementDef = refineSubstatementCtx.getPublicDefinition();
+
+        SourceException.throwIf(!isSupportedRefineTarget(refineSubstatementCtx, refineTargetNodeCtx),
+                refineSubstatementCtx.getStatementSourceReference(),
+                "Error in module '%s' in the refine of uses '%s': can not perform refine of '%s' for the target '%s'.",
+                refineSubstatementCtx.getRoot().getStatementArgument(),
+                refineSubstatementCtx.coerceParentContext().getStatementArgument(),
+                refineSubstatementCtx.getPublicDefinition(), refineTargetNodeCtx.getPublicDefinition());
+
+        if (isAllowedToAddByRefine(refineSubstatementDef)) {
+            refineTargetNodeCtx.addEffectiveSubstatement(refineSubstatementCtx);
+        } else {
+            refineTargetNodeCtx.removeStatementFromEffectiveSubstatements(refineSubstatementDef);
+            refineTargetNodeCtx.addEffectiveSubstatement(refineSubstatementCtx);
+        }
+    }
+
+    private static boolean isAllowedToAddByRefine(final StatementDefinition publicDefinition) {
+        return YangStmtMapping.MUST.equals(publicDefinition);
+    }
+
+    private static boolean isSupportedRefineSubstatement(final StmtContext<?, ?, ?> refineSubstatementCtx) {
+        final Collection<?> supportedRefineSubstatements = refineSubstatementCtx.getFromNamespace(
+                ValidationBundlesNamespace.class, ValidationBundleType.SUPPORTED_REFINE_SUBSTATEMENTS);
+
+        return supportedRefineSubstatements == null || supportedRefineSubstatements.isEmpty()
+                || supportedRefineSubstatements.contains(refineSubstatementCtx.getPublicDefinition())
+                || StmtContextUtils.isUnknownStatement(refineSubstatementCtx);
+    }
+
+    private static boolean isSupportedRefineTarget(final StmtContext<?, ?, ?> refineSubstatementCtx,
+            final StmtContext<?, ?, ?> refineTargetNodeCtx) {
+        final Collection<?> supportedRefineTargets = YangValidationBundles.SUPPORTED_REFINE_TARGETS.get(
+            refineSubstatementCtx.getPublicDefinition());
+
+        return supportedRefineTargets == null || supportedRefineTargets.isEmpty()
+                || supportedRefineTargets.contains(refineTargetNodeCtx.getPublicDefinition());
+    }
+}
index a12cd19660ed4fec5139d2c2b8bc4b15433beb30..1318af957b73707f28d1abd7c6290fbad74d89c4 100644 (file)
@@ -10,11 +10,14 @@ package org.opendaylight.yangtools.yang.parser.spi.meta;
 import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Objects.requireNonNull;
 
+import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
 
 /**
  * Class providing necessary support for processing a YANG statement. This class is intended to be subclassed
@@ -97,18 +100,31 @@ public abstract class AbstractStatementSupport<A, D extends DeclaredStatement<A>
 
     @Override
     public boolean hasArgumentSpecificSupports() {
-        // Most of statement supports don't have any argument specific
-        // supports, so return 'false'.
+        // Most of statement supports don't have any argument specific supports, so return 'false'.
         return false;
     }
 
     @Override
     public StatementSupport<?, ?, ?> getSupportSpecificForArgument(final String argument) {
-        // Most of statement supports don't have any argument specific
-        // supports, so return null.
+        // Most of statement supports don't have any argument specific supports, so return null.
         return null;
     }
 
+    @Override
+    public Optional<? extends Mutable<?, ?, ?>> copyAsChildOf(final Mutable<?, ?, ?> stmt,
+            final Mutable<?, ?, ?> parent, final CopyType copyType, final QNameModule targetModule) {
+        // Most of statement supports will just want to copy the statement
+        // FIXME: YANGTOOLS-694: that is not strictly true. Subclasses of this should indicate if they are themselves
+        //                       copy-sensitive:
+        //                       1) if they are not and cannot be targeted by inference, and all their current
+        //                          substatements are also non-sensitive, we want to return the same context.
+        //                       2) if they are not and their current substatements are sensitive, we want to copy
+        //                          as a lazily-instantiated interceptor to let it deal with substatements when needed
+        //                          (YANGTOOLS-1067 prerequisite)
+        //                       3) otherwise perform this eager copy
+        return Optional.of(parent.childCopyOf(stmt, copyType, targetModule));
+    }
+
     /**
      * Returns corresponding substatement validator of a statement support.
      *
index 56545ccacf668bca3b0f405e9949f4617ff37b90..45ab5b20d6e12b73a5497ba2ea2a86ffc89ba5df 100644 (file)
@@ -9,6 +9,8 @@ package org.opendaylight.yangtools.yang.parser.spi.meta;
 
 import com.google.common.annotations.Beta;
 import com.google.common.collect.ForwardingObject;
+import java.util.Optional;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
@@ -85,4 +87,10 @@ public abstract class ForwardingStatementSupport<A, D extends DeclaredStatement<
     public StatementSupport<?, ?, ?> getSupportSpecificForArgument(final String argument) {
         return delegate().getSupportSpecificForArgument(argument);
     }
+
+    @Override
+    public Optional<? extends Mutable<?, ?, ?>> copyAsChildOf(final Mutable<?, ?, ?> stmt,
+            final Mutable<?, ?, ?> parent, final CopyType type, final QNameModule targetModule) {
+        return delegate().copyAsChildOf(stmt, parent, type, targetModule);
+    }
 }
index f9463a0f2fe4f9ef9149b42590516cbb24b9786c..fb30a4a61204ddd455109565531a639e968b327b 100644 (file)
@@ -17,6 +17,7 @@ import org.opendaylight.yangtools.yang.model.api.meta.ArgumentDefinition;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 
 /**
@@ -32,7 +33,6 @@ import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
  */
 public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
         extends StatementDefinition, StatementFactory<A, D, E> {
-
     /**
      * Returns public statement definition, which will be present in built statements.
      *
@@ -57,11 +57,8 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
     /**
      * Adapts the argument value to match a new module.
      *
-     * @param ctx
-     *            Context, which may be used to access source-specific
-     *            namespaces required for parsing.
-     * @param targetModule
-     *            Target module, may not be null.
+     * @param ctx Context, which may be used to access source-specific namespaces required for parsing.
+     * @param targetModule Target module, may not be null.
      * @return Adapted argument value. The default implementation returns original value stored in context.
      */
     default A adaptArgumentValue(final StmtContext<A, D, E> ctx, final QNameModule targetModule) {
@@ -74,8 +71,7 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      * accessible via {@link StmtContext#getParentContext()}. One such use is populating the parent's namespaces to
      * allow it to locate this child statement.
      *
-     * @param stmt
-     *            Context of added statement. No substatements are available.
+     * @param stmt Context of added statement. No substatements are available.
      */
     void onStatementAdded(StmtContext.Mutable<A, D, E> stmt);
 
@@ -87,8 +83,7 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      * Implementation may use method to perform actions on this event or register modification action using
      * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
      *
-     * @param stmt
-     *            Context of added statement.
+     * @param stmt Context of added statement.
      */
     void onPreLinkageDeclared(StmtContext.Mutable<A, D, E> stmt);
 
@@ -100,10 +95,8 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      * Implementation may use method to perform actions on this event or register modification action using
      * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
      *
-     * @param stmt
-     *            Context of added statement.
-     * @throws SourceException
-     *             when an inconsistency is detected.
+     * @param stmt Context of added statement.
+     * @throws SourceException when an inconsistency is detected.
      */
     void onLinkageDeclared(StmtContext.Mutable<A, D, E> stmt);
 
@@ -115,11 +108,8 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      * Implementation may use method to perform actions on this event or register modification action using
      * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
      *
-     * @param stmt
-     *            Context of added statement. Argument and statement parent is
-     *            accessible.
-     * @throws SourceException
-     *             when an inconsistency is detected.
+     * @param stmt Context of added statement. Argument and statement parent is accessible.
+     * @throws SourceException when an inconsistency is detected.
      */
     void onStatementDefinitionDeclared(StmtContext.Mutable<A, D, E> stmt);
 
@@ -131,11 +121,8 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      * Implementation may use method to perform actions on this event or register modification action using
      * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
      *
-     * @param stmt
-     *            Context of added statement. Argument and statement parent is
-     *            accessible.
-     * @throws SourceException
-     *             when an inconsistency is detected.
+     * @param stmt Context of added statement. Argument and statement parent is accessible.
+     * @throws SourceException when an inconsistency is detected.
      */
     void onFullDefinitionDeclared(StmtContext.Mutable<A, D, E> stmt);
 
@@ -148,17 +135,34 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      * If this support has argument specific supports, the method returns support specific for given argument
      * (e.g. type statement support need to be specialized based on its argument), otherwise returns null.
      *
-     * @param argument
-     *            argument of statement
+     * @param argument argument of statement
      * @return statement support specific for supplied argument or null
      */
     @Nullable StatementSupport<?, ?, ?> getSupportSpecificForArgument(String argument);
 
+    /**
+     * Create an optional copy of specified statement as a substatement of parent.
+     *
+     * <p>
+     * Note that while it may be tempting to return the same context, this is not safe in general case. It is only safe
+     * if the entire subtree is unaffected by changes to parent/namespace/history. This includes the semantics of this
+     * statement (it cannot be a target of any inference effects) as well as any substatements -- an extension statement
+     * is allowed pretty much anywhere and if its semantics are context-dependent, a simple instance reuse will not
+     * work.
+     *
+     * @param stmt Context of statement to be copied statement.
+     * @param parent Parent statement context
+     * @param type Type of copy being performed
+     * @param targetModule Target module, if present
+     * @return Empty if the statement should be ignored, or present with an instance that should be copied into parent.
+     */
+    @NonNull Optional<? extends Mutable<?, ?, ?>> copyAsChildOf(Mutable<?, ?, ?> stmt, Mutable<?, ?, ?> parent,
+            CopyType type, @Nullable QNameModule targetModule);
+
     /**
      * Given a raw string representation of an argument, try to use a shared representation.
      *
-     * @param rawArgument
-     *            Argument string
+     * @param rawArgument Argument string
      * @return A potentially-shard instance
      */
     default String internArgument(final String rawArgument) {
@@ -168,10 +172,9 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
     /**
      * Returns unknown statement form of a regular YANG statement supplied as a parameter to the method.
      *
-     * @param yangStmtDef
-     *            statement definition of a regular yang statement
-     * @return Optional of unknown statement form of a regular yang statement or
-     *         Optional.empty() if it is not supported by this statement support
+     * @param yangStmtDef statement definition of a regular YANG statement
+     * @return Optional of unknown statement form of a regular YANG statement or empty() if it is not supported by this
+     *         statement support
      */
     default Optional<StatementSupport<?, ?, ?>> getUnknownStatementDefinitionOf(final StatementDefinition yangStmtDef) {
         return Optional.empty();
index fac8a7daec54fe41daafb7c560ddbf2bed332a0f..91eb89a005770f9493c7029a3fa7b1e6be4fb2b2 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.yangtools.yang.parser.spi.meta;
 
 import static com.google.common.base.Verify.verifyNotNull;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.VerifyException;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Streams;
@@ -296,6 +297,10 @@ public interface StmtContext<A, D extends DeclaredStatement<A>, E extends Effect
             return childCopyOf(stmt, type, null);
         }
 
+        @Beta
+        @NonNull Optional<? extends Mutable<?, ?, ?>> copyAsChildOf(Mutable<?, ?, ?> parent, CopyType type,
+                @Nullable QNameModule targetModule);
+
         @Override
         default Collection<? extends StmtContext<?, ?, ?>> declaredSubstatements() {
             return mutableDeclaredSubstatements();
index 7d4ffbfe0f78e86be2a100b93bfe830c70799635..1a0f9462b99c9a0b442f6e520877746da81969bd 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.yangtools.yang.parser.spi.meta;
 import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import java.util.Collection;
@@ -645,4 +646,16 @@ public final class StmtContextUtils {
         }
         return Optional.ofNullable(revision);
     }
+
+    /**
+     * Determine if a specific statetement context is a child of a statement context which produces a grouping.
+     *
+     * @param stmt Statement to examine
+     * @return True if parent context is that of a grouping.
+     */
+    @Beta
+    public static boolean isChildOfGrouping(final StmtContext<?, ?, ?> stmt) {
+        final StmtContext<?, ?, ?> parent = stmt.getParentContext();
+        return parent != null && parent.getPublicDefinition() == YangStmtMapping.GROUPING;
+    }
 }