Fix SchemaTreeNamespace population via augment
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / StatementContextBase.java
index 65656d4efa5ba85c3e4541b6cf033756f4170547..2e0a591b8e16746da64eff7029ef3055c0872787 100644 (file)
@@ -96,22 +96,45 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
 
     private static final Logger LOG = LoggerFactory.getLogger(StatementContextBase.class);
 
-    //
-    // {@link CopyHistory} encoded as a single byte. We still have 4 bits unused.
-    //
+    // Bottom 4 bits, encoding a CopyHistory, aight?
+    private static final byte COPY_ORIGINAL              = 0x00;
     private static final byte COPY_LAST_TYPE_MASK        = 0x03;
+    @Deprecated(since = "7.0.9")
     private static final byte COPY_ADDED_BY_USES         = 0x04;
     private static final byte COPY_ADDED_BY_AUGMENTATION = 0x08;
-    private static final byte COPY_ORIGINAL              = 0x00;
 
-    private final byte copyHistory;
+    // Top four bits, of which we define the topmost two to 0. We use the bottom two to encode last CopyType, aight?
+    private static final int COPY_CHILD_TYPE_SHIFT       = 4;
+
+    private static final CopyType @NonNull [] COPY_TYPE_VALUES = CopyType.values();
 
     static {
-        final int copyTypes = CopyType.values().length;
+        final int copyTypes = COPY_TYPE_VALUES.length;
         // This implies CopyType.ordinal() is <= COPY_TYPE_MASK
         verify(copyTypes == COPY_LAST_TYPE_MASK + 1, "Unexpected %s CopyType values", copyTypes);
     }
 
+    /**
+     * 8 bits worth of instance storage. This is treated as a constant bit field with following structure:
+     * <pre>
+     *   <code>
+     * |7|6|5|4|3|2|1|0|
+     * |0 0|cct|a|u|lst|
+     *   </code>
+     * </pre>
+     *
+     * <p>
+     * The four allocated fields are:
+     * <ul>
+     *   <li>{@code lst}, encoding the four states corresponding to {@link CopyHistory#getLastOperation()}</li>
+     *   <li>{@code u}, encoding {@link #isAddedByUses()}</li>
+     *   <li>{@code a}, encoding {@link #isAugmenting()}</li>
+     *   <li>{@code cct} encoding {@link #childCopyType()}</li>
+     * </ul>
+     * We still have two unused bits.
+     */
+    private final byte bitsAight;
+
     // Note: this field can strictly be derived in InferredStatementContext, but it forms the basis of many of our
     //       operations, hence we want to keep it close by.
     private final @NonNull StatementDefinitionContext<A, D, E> definition;
@@ -130,24 +153,26 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     // Copy constructor used by subclasses to implement reparent()
     StatementContextBase(final StatementContextBase<A, D, E> original) {
         super(original);
-        this.copyHistory = original.copyHistory;
+        this.bitsAight = original.bitsAight;
         this.definition = original.definition;
         this.executionOrder = original.executionOrder;
     }
 
     StatementContextBase(final StatementDefinitionContext<A, D, E> def) {
         this.definition = requireNonNull(def);
-        this.copyHistory = COPY_ORIGINAL;
+        this.bitsAight = COPY_ORIGINAL;
     }
 
     StatementContextBase(final StatementDefinitionContext<A, D, E> def, final CopyType copyType) {
         this.definition = requireNonNull(def);
-        this.copyHistory = (byte) copyFlags(copyType);
+        this.bitsAight = (byte) copyFlags(copyType);
     }
 
-    StatementContextBase(final StatementContextBase<A, D, E> prototype, final CopyType copyType) {
+    StatementContextBase(final StatementContextBase<A, D, E> prototype, final CopyType copyType,
+            final CopyType childCopyType) {
         this.definition = prototype.definition;
-        this.copyHistory = (byte) (copyFlags(copyType) | prototype.copyHistory & ~COPY_LAST_TYPE_MASK);
+        this.bitsAight = (byte) (copyFlags(copyType)
+            | prototype.bitsAight & ~COPY_LAST_TYPE_MASK | childCopyType.ordinal() << COPY_CHILD_TYPE_SHIFT);
     }
 
     private static int copyFlags(final CopyType copyType) {
@@ -196,18 +221,24 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     }
 
     @Override
+    @Deprecated(since = "7.0.9")
     public final boolean isAddedByUses() {
-        return (copyHistory & COPY_ADDED_BY_USES) != 0;
+        return (bitsAight & COPY_ADDED_BY_USES) != 0;
     }
 
     @Override
     public final boolean isAugmenting() {
-        return (copyHistory & COPY_ADDED_BY_AUGMENTATION) != 0;
+        return (bitsAight & COPY_ADDED_BY_AUGMENTATION) != 0;
     }
 
     @Override
     public final CopyType getLastOperation() {
-        return CopyType.values()[copyHistory & COPY_LAST_TYPE_MASK];
+        return COPY_TYPE_VALUES[bitsAight & COPY_LAST_TYPE_MASK];
+    }
+
+    // This method exists only for space optimization of InferredStatementContext
+    final CopyType childCopyType() {
+        return COPY_TYPE_VALUES[bitsAight >> COPY_CHILD_TYPE_SHIFT & COPY_LAST_TYPE_MASK];
     }
 
     //
@@ -446,7 +477,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
 
     @Override
     final boolean doTryToCompletePhase(final byte targetOrder) {
-        final boolean finished = phaseMutation.isEmpty() ? true : runMutations(targetOrder);
+        final boolean finished = phaseMutation.isEmpty() || runMutations(targetOrder);
         if (completeChildren(targetOrder) && finished) {
             onPhaseCompleted(targetOrder);
             return true;
@@ -468,7 +499,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     private boolean runMutations(final byte targetOrder) {
         final ModelProcessingPhase phase = verifyNotNull(ModelProcessingPhase.ofExecutionOrder(targetOrder));
         final Collection<ContextMutation> openMutations = phaseMutation.get(phase);
-        return openMutations.isEmpty() ? true : runMutations(phase, openMutations);
+        return openMutations.isEmpty() || runMutations(phase, openMutations);
     }
 
     private boolean runMutations(final ModelProcessingPhase phase, final Collection<ContextMutation> openMutations) {
@@ -779,8 +810,13 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     public final Mutable<?, ?, ?> childCopyOf(final StmtContext<?, ?, ?> stmt, final CopyType type,
             final QNameModule targetModule) {
         checkEffectiveModelCompleted(stmt);
-        checkArgument(stmt instanceof StatementContextBase, "Unsupported statement %s", stmt);
-        return childCopyOf((StatementContextBase<?, ?, ?>) stmt, type, targetModule);
+        if (stmt instanceof StatementContextBase) {
+            return childCopyOf((StatementContextBase<?, ?, ?>) stmt, type, targetModule);
+        } else if (stmt instanceof ReplicaStatementContext) {
+            return ((ReplicaStatementContext<?, ?, ?>) stmt).replicaAsChildOf(this);
+        } else {
+            throw new IllegalArgumentException("Unsupported statement " + stmt);
+        }
     }
 
     private <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>> Mutable<X, Y, Z> childCopyOf(
@@ -812,6 +848,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
 
             copy = new InferredStatementContext<>(result, original, childCopyType, type, targetModule);
             result.addEffectiveSubstatement(copy);
+            result.definition.onStatementAdded(result);
         } else {
             result = copy = new InferredStatementContext<>(this, original, type, type, targetModule);
         }