Rework AugmentRuntimeType and Choice/Case linkage
[mdsal.git] / binding / mdsal-binding-generator / src / main / java / org / opendaylight / mdsal / binding / generator / impl / reactor / ChoiceGenerator.java
index 1a6ac7fe5bc4146853c54ec5b0d8bebdf0e0b55f..1b73a7d4d55be018dd55f98437c46d0770e0a535 100644 (file)
@@ -7,11 +7,11 @@
  */
 package org.opendaylight.mdsal.binding.generator.impl.reactor;
 
-import com.google.common.collect.Iterables;
-import java.util.ArrayList;
+import static com.google.common.base.Verify.verify;
+
+import com.google.common.collect.ImmutableList;
 import java.util.List;
-import org.opendaylight.mdsal.binding.generator.impl.rt.DerivedChoiceRuntimeType;
-import org.opendaylight.mdsal.binding.generator.impl.rt.OriginalChoiceRuntimeType;
+import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultChoiceRuntimeType;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.model.api.Type;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
@@ -20,6 +20,7 @@ import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 
@@ -27,6 +28,48 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
  * Generator corresponding to a {@code choice} statement.
  */
 final class ChoiceGenerator extends CompositeSchemaTreeGenerator<ChoiceEffectiveStatement, ChoiceRuntimeType> {
+    static final class ChoiceBuilder extends CompositeRuntimeTypeBuilder<ChoiceEffectiveStatement, ChoiceRuntimeType> {
+        private ImmutableList<CaseRuntimeType> augmentedCases;
+
+        ChoiceBuilder(final ChoiceEffectiveStatement statement) {
+            super(statement);
+        }
+
+        @Override
+        CompositeRuntimeTypeBuilder<ChoiceEffectiveStatement, ChoiceRuntimeType> fillTypes(
+                final ChildLookup lookup,
+                final AbstractCompositeGenerator<ChoiceEffectiveStatement, ChoiceRuntimeType> generator) {
+            fillAugmentedCases(lookup, generator.augments());
+            return super.fillTypes(lookup, generator);
+        }
+
+        @Override
+        boolean isAugmentedChild(final ChildLookup lookup, final QName qname) {
+            for (var augmented : augmentedCases) {
+                if (qname.equals(augmented.statement().argument())) {
+                    return true;
+                }
+            }
+            return super.isAugmentedChild(lookup, qname);
+        }
+
+        @Override
+        ChoiceRuntimeType build(final GeneratedType type, final ChoiceEffectiveStatement statement,
+                final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
+            verify(augments.isEmpty(), "Unexpected augments %s", augments);
+            children.addAll(augmentedCases);
+            return new DefaultChoiceRuntimeType(type, statement, children);
+        }
+
+        private void fillAugmentedCases(final ChildLookup lookup, final List<AbstractAugmentGenerator> augments) {
+            final var builder = ImmutableList.<CaseRuntimeType>builder();
+            for (var augment : augments) {
+                builder.addAll(augment.augmentedCasesIn(lookup, statement()));
+            }
+            augmentedCases = builder.build();
+        }
+    }
+
     ChoiceGenerator(final ChoiceEffectiveStatement statement, final AbstractCompositeGenerator<?, ?> parent) {
         super(statement, parent);
     }
@@ -53,38 +96,7 @@ final class ChoiceGenerator extends CompositeSchemaTreeGenerator<ChoiceEffective
     }
 
     @Override
-    ChoiceRuntimeType createRuntimeType(final GeneratedType type, final ChoiceEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        final var original = getOriginal();
-        if (!statement.equals(original.statement())) {
-            return new DerivedChoiceRuntimeType(type, statement, children, augments,
-                original.runtimeType().orElseThrow());
-        }
-
-        // Pick up any case statements added by augments which are not reflected in our children. This can happen when
-        // a choice is added via uses into two different places and then augmented. Since groupings are reused, validity
-        // of such use is not guarded by compile-time checks.
-        //
-        // Furthermore such case statements can be freely propagated via copy builders and thus can occur in unexpected
-        // places. If that happens, though, the two case statements can be equivalent, e.g. by having the exact same
-        // shape -- in which case Binding -> DOM translation needs to correct this mishap and play pretend the correct
-        // case was used.
-        final var augmentedCases = new ArrayList<CaseRuntimeType>();
-        for (var augment : original.augments()) {
-            for (var gen : augment) {
-                if (gen instanceof CaseGenerator) {
-                    ((CaseGenerator) gen).runtimeType().ifPresent(augmented -> {
-                        for (var child : Iterables.concat(children, augmentedCases)) {
-                            if (child instanceof CaseRuntimeType && child.javaType().equals(augmented.javaType())) {
-                                return;
-                            }
-                        }
-                        augmentedCases.add(augmented);
-                    });
-                }
-            }
-        }
-
-        return new OriginalChoiceRuntimeType(type, statement, children, augments, augmentedCases);
+    ChoiceBuilder createBuilder(final ChoiceEffectiveStatement statement) {
+        return new ChoiceBuilder(statement);
     }
 }