Rework EffectiveStatementBase statement order restoration 88/85988/2
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 26 Nov 2019 10:03:27 +0000 (11:03 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 26 Nov 2019 17:44:48 +0000 (18:44 +0100)
Rather than relying on mutation of effective substatements when we
are building an effective statements (and thus requiring StmtContext
to be StatementContextBase), use simple filtering to implement
statement ordering.

This limits the scope of mutable state, explains what is going
on and allows use of different StmtContext implementations.

JIRA: YANGTOOLS-1042
Change-Id: I84a2517ef0ce666fbc2f2c6faa3b0d0a43eef6eb
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
(cherry picked from commit 75276bc6d944ff002de8149108d60603349d49c6)

yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/EffectiveStatementBase.java

index 2ed6bcdbdd741e34c12e880814e53080c704b0df..08ab75f794bf91d83fdf7482f6b173ff4e5cc375 100644 (file)
@@ -321,6 +321,15 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         return Collections.unmodifiableCollection(effective);
     }
 
+    /**
+     * Remove a set of statements from effective statements.
+     *
+     * @param statements statements to be removed
+     * @deprecated This method was used by EffectiveStatementBase to restore proper order of effects of uses statements.
+     *             It is no longer used in that capacity and slated for removal.
+     */
+    // FIXME: 5.0.0: remove this method
+    @Deprecated
     public void removeStatementsFromEffectiveSubstatements(
             final Collection<? extends StmtContext<?, ?, ?>> statements) {
         if (!effective.isEmpty()) {
index 8542bbc550a9f6afab5376920cb3b1a470c91321..e078fa2fcb8f8282feff20a45f914e72d420add3 100644 (file)
@@ -14,18 +14,18 @@ import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
 import java.util.function.Predicate;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-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.meta.IdentifierNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
-import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
 
 public abstract class EffectiveStatementBase<A, D extends DeclaredStatement<A>> implements EffectiveStatement<A, D> {
     private final @NonNull ImmutableList<? extends EffectiveStatement<?, ?>> substatements;
@@ -36,21 +36,60 @@ public abstract class EffectiveStatementBase<A, D extends DeclaredStatement<A>>
      * @param ctx context of statement.
      */
     protected EffectiveStatementBase(final StmtContext<A, D, ?> ctx) {
-        final Collection<? extends StmtContext<?, ?, ?>> effectiveSubstatements = ctx.effectiveSubstatements();
         final Collection<StmtContext<?, ?, ?>> substatementsInit = new ArrayList<>();
 
+        /*
+         * This dance is required to ensure that effects of 'uses' nodes are applied in the same order as
+         * the statements were defined -- i.e. if we have something like this:
+         *
+         * container foo {
+         *   uses bar;
+         *   uses baz;
+         * }
+         *
+         * grouping baz {
+         *   leaf baz {
+         *     type string;
+         *   }
+         * }
+         *
+         * grouping bar {
+         *   leaf bar {
+         *     type string;
+         *   }
+         * }
+         *
+         * The reactor would first inline 'uses baz' as that definition is the first one completely resolved and then
+         * inline 'uses bar'. Here we are iterating in declaration order re-inline the statements.
+         *
+         * TODO: this really should be handled by UsesStatementSupport such that 'uses baz' would have a prerequisite
+         *       of a resolved 'uses bar'.
+         */
+        Set<StmtContext<?, ?, ?>> filteredStatements = null;
         for (final StmtContext<?, ?, ?> declaredSubstatement : ctx.declaredSubstatements()) {
             if (declaredSubstatement.isSupportedByFeatures()) {
                 substatementsInit.add(declaredSubstatement);
-                if (YangStmtMapping.USES == declaredSubstatement.getPublicDefinition()) {
-                    final Collection<? extends StmtContext<?, ?, ?>> effect =
-                            declaredSubstatement.getEffectOfStatement();
+
+                final Collection<? extends StmtContext<?, ?, ?>> effect = declaredSubstatement.getEffectOfStatement();
+                if (!effect.isEmpty()) {
+                    if (filteredStatements == null) {
+                        filteredStatements = new HashSet<>();
+                    }
+                    filteredStatements.addAll(effect);
                     substatementsInit.addAll(effect);
-                    ((StatementContextBase<?, ?, ?>) ctx).removeStatementsFromEffectiveSubstatements(effect);
                 }
             }
         }
-        substatementsInit.addAll(effectiveSubstatements);
+
+        if (filteredStatements != null) {
+            for (StmtContext<?, ?, ?> stmt : ctx.effectiveSubstatements()) {
+                if (!filteredStatements.contains(stmt)) {
+                    substatementsInit.add(stmt);
+                }
+            }
+        } else {
+            substatementsInit.addAll(ctx.effectiveSubstatements());
+        }
 
         this.substatements = ImmutableList.copyOf(initSubstatements(ctx, substatementsInit));
     }