Fix if-feature propagation for implicit case statements
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / AbstractResumedStatement.java
index f5b33582799fafbab1d14b39e795f26ce64e21e1..03d20e81d900b0adcbcb670e5501c6fdd2d061aa 100644 (file)
@@ -10,29 +10,20 @@ package org.opendaylight.yangtools.yang.parser.stmt.reactor;
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.base.Verify.verify;
 import static com.google.common.base.Verify.verifyNotNull;
-import static java.util.Objects.requireNonNull;
 
-import com.google.common.collect.ImmutableList;
 import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
 import java.util.stream.Stream;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 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.model.api.meta.StatementOrigin;
-import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementFactory;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
-import org.opendaylight.yangtools.yang.parser.spi.source.ImplicitSubstatement;
 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
 import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter.ResumedStatement;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Intermediate subclass of StatementContextBase facing the parser stream via implementation of ResumedStatement. This
@@ -43,20 +34,16 @@ import org.slf4j.LoggerFactory;
  * @param <E> Effective Statement representation
  */
 abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
-        extends StatementContextBase<A, D, E> implements ResumedStatement {
-    private static final Logger LOG = LoggerFactory.getLogger(AbstractResumedStatement.class);
-
-    private final @NonNull StatementSourceReference statementDeclSource;
+        extends OriginalStmtCtx<A, D, E> implements ResumedStatement {
     private final String rawArgument;
 
-    private List<ReactorStmtCtx<?, ?, ?>> effective = ImmutableList.of();
     private StatementMap substatements = StatementMap.empty();
     private @Nullable D declaredInstance;
+    private boolean implicitDeclared;
 
     // Copy constructor
     AbstractResumedStatement(final AbstractResumedStatement<A, D, E> original) {
         super(original);
-        this.statementDeclSource = original.statementDeclSource;
         this.rawArgument = original.rawArgument;
         this.substatements = original.substatements;
         this.declaredInstance = original.declaredInstance;
@@ -64,33 +51,10 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
 
     AbstractResumedStatement(final StatementDefinitionContext<A, D, E> def, final StatementSourceReference ref,
             final String rawArgument) {
-        super(def);
-        this.statementDeclSource = requireNonNull(ref);
+        super(def, ref);
         this.rawArgument = def.support().internArgument(rawArgument);
     }
 
-    AbstractResumedStatement(final StatementDefinitionContext<A, D, E> def, final StatementSourceReference ref,
-            final String rawArgument, final CopyType copyType) {
-        super(def, copyType);
-        this.statementDeclSource = requireNonNull(ref);
-        this.rawArgument = rawArgument;
-    }
-
-    @Override
-    public final Optional<StmtContext<A, D, E>> getOriginalCtx() {
-        return Optional.empty();
-    }
-
-    @Override
-    public final Optional<StmtContext<A, D, E>> getPreviousCopyCtx() {
-        return Optional.empty();
-    }
-
-    @Override
-    public final StatementSourceReference sourceReference() {
-        return statementDeclSource;
-    }
-
     @Override
     public final String rawArgument() {
         return rawArgument;
@@ -98,33 +62,7 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
 
     @Override
     public Collection<? extends StatementContextBase<?, ?, ?>> mutableDeclaredSubstatements() {
-        return substatements;
-    }
-
-    @Override
-    public final Collection<? extends Mutable<?, ?, ?>> mutableEffectiveSubstatements() {
-        return mutableEffectiveSubstatements(effective);
-    }
-
-    @Override
-    public final void removeStatementFromEffectiveSubstatements(final StatementDefinition statementDef) {
-        effective = removeStatementFromEffectiveSubstatements(effective, statementDef);
-    }
-
-    @Override
-    public final void removeStatementFromEffectiveSubstatements(final StatementDefinition statementDef,
-            final String statementArg) {
-        effective = removeStatementFromEffectiveSubstatements(effective, statementDef, statementArg);
-    }
-
-    @Override
-    public final void addEffectiveSubstatement(final Mutable<?, ?, ?> substatement) {
-        effective = addEffectiveSubstatement(effective, substatement);
-    }
-
-    @Override
-    final void addEffectiveSubstatementsImpl(final Collection<? extends Mutable<?, ?, ?>> statements) {
-        effective = addEffectiveSubstatementsImpl(effective, statements);
+        return verifyNotNull(substatements);
     }
 
     @Override
@@ -140,9 +78,16 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
         return declaredInstance = definition().getFactory().createDeclared(this, substatementsAsDeclared());
     }
 
+    @SuppressWarnings({ "rawtypes", "unchecked" })
     private @NonNull Stream<DeclaredStatement<?>> substatementsAsDeclared() {
-        // FIXME: YANGTOOLS-1383: this stream includes implicit case statements, but it should not
-        return substatements.stream().map(AbstractResumedStatement::declared);
+        final Stream<AbstractResumedStatement<?, ?, ?>> stream;
+        if (implicitDeclared) {
+            stream = substatements.stream().map(AbstractResumedStatement::unmaskUndeclared);
+        } else {
+            stream = (Stream) substatements.stream();
+        }
+
+        return stream.map(AbstractResumedStatement::declared);
     }
 
     @Override
@@ -152,7 +97,7 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
 
     @Override
     public final StatementSourceReference getSourceReference() {
-        return statementDeclSource;
+        return sourceReference();
     }
 
     @Override
@@ -160,6 +105,33 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
         return fullyDefined();
     }
 
+    @Override
+    final E createEffective(final StatementFactory<A, D, E> factory) {
+        return createEffective(factory, this, streamDeclared(), streamEffective());
+    }
+
+    // Creates EffectiveStatement through full materialization and assumes declared statement presence
+    private @NonNull E createEffective(final StatementFactory<A, D, E> factory,
+            final StatementContextBase<A, D, E> ctx, final Stream<? extends StmtContext<?, ?, ?>> declared,
+            final Stream<? extends StmtContext<?, ?, ?>> effective) {
+        // Statement reference count infrastructure makes an assumption that effective statement is only built after
+        // the declared statement is already done. Statements tracked by this class always have a declared view, and
+        // we need to ensure that is built before we touch effective substatements.
+        //
+        // Once the effective substatement stream has been exhausted, reference counting will triggers a sweep, hence
+        // the substatements may be gone by the time the factory attempts to acquire the declared statement.
+        ctx.declared();
+
+        return factory.createEffective(ctx, declared, effective);
+    }
+
+    @Override
+    final E createInferredEffective(final StatementFactory<A, D, E> factory,
+            final InferredStatementContext<A, D, E> ctx, final Stream<? extends StmtContext<?, ?, ?>> declared,
+            final Stream<? extends StmtContext<?, ?, ?>> effective) {
+        return createEffective(factory, ctx, declared, effective);
+    }
+
     /**
      * Create a new substatement at the specified offset.
      *
@@ -181,71 +153,47 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
         checkState(inProgressPhase != ModelProcessingPhase.EFFECTIVE_MODEL,
                 "Declared statement cannot be added in effective phase at: %s", sourceReference());
 
+        final SubstatementContext<X, Y, Z> ret;
         final var implicitParent = definition().getImplicitParentFor(this, def.getPublicView());
         if (implicitParent.isPresent()) {
-            return createImplicitParent(offset, implicitParent.orElseThrow(), ref, argument)
-                .createSubstatement(0, def, ref, argument);
+            implicitDeclared = true;
+            final var parent = createUndeclared(offset, implicitParent.orElseThrow(), ref, argument);
+            ret = new SubstatementContext<>(parent, def, ref, argument);
+            parent.addEffectiveSubstatement(ret);
+        } else {
+            ret = new SubstatementContext<>(this, def, ref, argument);
+            substatements = substatements.put(offset, ret);
         }
 
-        final AbstractResumedStatement<X, Y, Z> ret = new SubstatementContext<>(this, def, ref, argument);
-        substatements = substatements.put(offset, ret);
         def.onStatementAdded(ret);
         return ret;
     }
 
-    @Override
-    final AbstractResumedStatement<A, D, E> unmodifiedEffectiveSource() {
-        // This statement is comes from the source
-        return this;
-    }
-
-    @Override
-    final boolean hasEmptySubstatements() {
-        return substatements.size() == 0 && effective.isEmpty();
-    }
-
-    @Override
-    final boolean noSensitiveSubstatements() {
-        return hasEmptySubstatements()
-            || noSensitiveSubstatements(substatements) && noSensitiveSubstatements(effective);
-    }
-
-    @Override
-    final Iterator<ReactorStmtCtx<?, ?, ?>> effectiveChildrenToComplete() {
-        return effective.iterator();
+    private <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>>
+            UndeclaredStmtCtx<X, Y, Z> createUndeclared(final int offset, final StatementSupport<X, Y, Z> support,
+                final StatementSourceReference ref, final String argument) {
+        final UndeclaredStmtCtx<X, Y, Z> ret;
+        final var implicitParent = definition().getImplicitParentFor(this, support.getPublicView());
+        if (implicitParent.isPresent()) {
+            final var parent = createUndeclared(offset, implicitParent.orElseThrow(), ref, argument);
+            ret = new ImplicitStmtCtx<>(parent, support, argument);
+            parent.addEffectiveSubstatement(ret);
+        } else {
+            ret = new ImplicitStmtCtx<>(this, support, argument);
+            substatements = substatements.put(offset, ret);
+        }
+        support.onStatementAdded(ret);
+        return ret;
     }
 
     @Override
     final Stream<? extends @NonNull StmtContext<?, ?, ?>> streamDeclared() {
-        return declaredSubstatements().stream().filter(StmtContext::isSupportedToBuildEffective);
-    }
-
-    @Override
-    final Stream<? extends @NonNull StmtContext<?, ?, ?>> streamEffective() {
-        return effective.stream().filter(StmtContext::isSupportedToBuildEffective);
+        return substatements.stream().filter(StmtContext::isSupportedToBuildEffective);
     }
 
     @Override
-    final void markNoParentRef() {
-        markNoParentRef(substatements);
-        markNoParentRef(effective);
-    }
-
-    @Override
-    final int sweepSubstatements() {
-        // First we need to sweep all statements, which may trigger sweeps all across the place, for example:
-        // - 'effective' member sweeping a 'substatements' member
-        // - 'substatements' member sweeping a 'substatements' member which came before it during iteration
-        // We then iterate once again, counting what remains unswept
-        sweep(substatements);
-        sweep(effective);
-        final int count = countUnswept(substatements) + countUnswept(effective);
-        if (count != 0) {
-            LOG.debug("{} children left to sweep from {}", count, this);
-        }
+    final void dropDeclaredSubstatements() {
         substatements = null;
-        effective = null;
-        return count;
     }
 
     /**
@@ -256,13 +204,17 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
      * @return Substatement, or null if substatement does not exist.
      */
     final @Nullable AbstractResumedStatement<?, ?, ?> enterSubstatement(final int offset) {
-        var ret = substatements.get(offset);
-        if (ret != null) {
-            while (ret.origin() == StatementOrigin.CONTEXT) {
-                ret = verifyNotNull(ret.substatements.get(0));
-            }
+        final var stmt = substatements.get(offset);
+        return stmt == null ? null : unmaskUndeclared(stmt);
+    }
+
+    private static @NonNull AbstractResumedStatement<?, ?, ?> unmaskUndeclared(final ReactorStmtCtx<?, ?, ?> stmt) {
+        var ret = stmt;
+        while (!(ret instanceof AbstractResumedStatement)) {
+            verify(ret instanceof UndeclaredStmtCtx, "Unexpectred statement %s", ret);
+            ret = ((UndeclaredStmtCtx<?, ?, ?>) ret).getResumedSubstatement();
         }
-        return ret;
+        return (AbstractResumedStatement<?, ?, ?>) ret;
     }
 
     /**
@@ -280,25 +232,26 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
 
         var ret = verifyParent(parent);
         // Unwind all undeclared statements
-        while (ret.origin() == StatementOrigin.CONTEXT) {
+        while (!(ret instanceof AbstractResumedStatement)) {
             ret.finishDeclaration(phase);
             ret = verifyParent(ret.getParentContext());
         }
-        return ret;
+        return (AbstractResumedStatement<?, ?, ?>) ret;
     }
 
-    // FIXME: AbstractResumedStatement should only ever have AbstractResumedStatement parents, which would remove the
-    //        need for this method. In ordered to do that we need to untangle SubstatementContext's users and do not
-    //        allow it being reparent()ed.
-    private static AbstractResumedStatement<?, ?, ?> verifyParent(final StatementContextBase<?, ?, ?> parent) {
-        verify(parent instanceof AbstractResumedStatement, "Unexpected parent context %s", parent);
-        return (AbstractResumedStatement<?, ?, ?>) parent;
+    // FIXME: AbstractResumedStatement should only ever have OriginalStmtCtx parents, which would remove the need for
+    //        this method. In ordered to do that we need to untangle SubstatementContext's users and do not allow it
+    //        being reparent()ed.
+    private static OriginalStmtCtx<?, ?, ?> verifyParent(final StatementContextBase<?, ?, ?> parent) {
+        verify(parent instanceof OriginalStmtCtx, "Unexpected parent context %s", parent);
+        return (OriginalStmtCtx<?, ?, ?>) parent;
     }
 
     final void resizeSubstatements(final int expectedSize) {
         substatements = substatements.ensureCapacity(expectedSize);
     }
 
+    @Override
     final void declarationFinished(final ModelProcessingPhase phase) {
         finishChildrenDeclaration(phase);
         finishDeclaration(phase);
@@ -308,19 +261,4 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
         checkState(isFullyDefined());
         substatements.forEach(stmt -> stmt.declarationFinished(phase));
     }
-
-    /**
-     * Ends declared section of current node for the specified phase.
-     *
-     * @param phase processing phase that ended
-     */
-    private void finishDeclaration(final ModelProcessingPhase phase) {
-        definition().onDeclarationFinished(this, phase);
-    }
-
-    private AbstractResumedStatement<?, ?, ?> createImplicitParent(final int offset,
-            final StatementSupport<?, ?, ?> implicitParent, final StatementSourceReference ref, final String argument) {
-        return createSubstatement(offset, new StatementDefinitionContext<>(implicitParent),
-            ImplicitSubstatement.of(ref), argument);
-    }
 }