Rework AugmentRuntimeType and Choice/Case linkage
[mdsal.git] / binding / mdsal-binding-generator / src / main / java / org / opendaylight / mdsal / binding / generator / impl / reactor / AbstractTypeObjectGenerator.java
index 9090f2453db546354a7ae778125f72ecb4588821..845fb0dcba8b4f785f946ff92d50966b9c676581 100644 (file)
@@ -42,6 +42,7 @@ import org.opendaylight.mdsal.binding.model.ri.TypeConstants;
 import org.opendaylight.mdsal.binding.model.ri.Types;
 import org.opendaylight.mdsal.binding.model.ri.generated.type.builder.AbstractEnumerationBuilder;
 import org.opendaylight.mdsal.binding.model.ri.generated.type.builder.GeneratedPropertyBuilderImpl;
+import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.binding.RegexPatterns;
@@ -222,7 +223,8 @@ import org.slf4j.LoggerFactory;
  * type indirection in YANG constructs is therefore explicitly excluded from the generated Java code, but the Binding
  * Specification still takes them into account when determining types as outlined above.
  */
-abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> extends AbstractDependentGenerator<T> {
+abstract class AbstractTypeObjectGenerator<S extends EffectiveStatement<?, ?>, R extends RuntimeType>
+        extends AbstractDependentGenerator<S, R> {
     private static final class UnionDependencies implements Immutable {
         private final Map<EffectiveStatement<?, ?>, TypeReference> identityTypes = new HashMap<>();
         private final Map<EffectiveStatement<?, ?>, TypeReference> leafTypes = new HashMap<>();
@@ -281,6 +283,11 @@ abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> e
 
     private final TypeEffectiveStatement<?> type;
 
+    // FIXME: these fields should be better-controlled with explicit sequencing guards. It it currently stands, we are
+    //        expending two (or more) additional fields to express downstream linking. If we had the concept of
+    //        resolution step (an enum), we could just get by with a simple queue of Step/Callback pairs, which would
+    //        trigger as needed. See how we manage baseGen/inferred fields.
+
     /**
      * The generator corresponding to our YANG base type. It produces the superclass of our encapsulated type. If it is
      * {@code null}, this generator is the root of the hierarchy.
@@ -289,9 +296,15 @@ abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> e
     private TypeReference refType;
     private List<GeneratedType> auxiliaryGeneratedTypes = List.of();
     private UnionDependencies unionDependencies;
-    private List<AbstractTypeObjectGenerator<?>> inferred = List.of();
+    private List<AbstractTypeObjectGenerator<?, ?>> inferred = List.of();
+
+    /**
+     * The type of single-element return type of the getter method associated with this generator. This is retained for
+     * run-time type purposes. It may be uninitialized, in which case this object must have a generated type.
+     */
+    private Type methodReturnTypeElement;
 
-    AbstractTypeObjectGenerator(final T statement, final AbstractCompositeGenerator<?> parent) {
+    AbstractTypeObjectGenerator(final S statement, final AbstractCompositeGenerator<?, ?> parent) {
         super(statement, parent);
         type = statement().findFirstEffectiveSubstatement(TypeEffectiveStatement.class).orElseThrow();
     }
@@ -312,16 +325,16 @@ abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> e
             return;
         }
 
-        final AbstractExplicitGenerator<?> prev = previous();
+        final AbstractExplicitGenerator<S, R> prev = previous();
         if (prev != null) {
             verify(prev instanceof AbstractTypeObjectGenerator, "Unexpected previous %s", prev);
-            ((AbstractTypeObjectGenerator<?>) prev).linkInferred(this);
+            ((AbstractTypeObjectGenerator<S, R>) prev).linkInferred(this);
         } else {
             linkBaseGen(context.resolveTypedef(typeName));
         }
     }
 
-    private void linkInferred(final AbstractTypeObjectGenerator<?> downstream) {
+    private void linkInferred(final AbstractTypeObjectGenerator<?, ?> downstream) {
         if (inferred == null) {
             downstream.linkBaseGen(verifyNotNull(baseGen, "Mismatch on linking between %s and %s", this, downstream));
             return;
@@ -335,13 +348,13 @@ abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> e
 
     private void linkBaseGen(final TypedefGenerator upstreamBaseGen) {
         verify(baseGen == null, "Attempted to replace base %s with %s in %s", baseGen, upstreamBaseGen, this);
-        final List<AbstractTypeObjectGenerator<?>> downstreams = verifyNotNull(inferred,
+        final List<AbstractTypeObjectGenerator<?, ?>> downstreams = verifyNotNull(inferred,
             "Duplicated linking of %s", this);
         baseGen = verifyNotNull(upstreamBaseGen);
         baseGen.addDerivedGenerator(this);
         inferred = null;
 
-        for (AbstractTypeObjectGenerator<?> downstream : downstreams) {
+        for (AbstractTypeObjectGenerator<?, ?> downstream : downstreams) {
             downstream.linkBaseGen(upstreamBaseGen);
         }
     }
@@ -359,7 +372,7 @@ abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> e
                 .map(context::resolveIdentity)
                 .collect(Collectors.toUnmodifiableList()));
         } else if (TypeDefinitions.LEAFREF.equals(arg)) {
-            final AbstractTypeObjectGenerator<?> targetGenerator = context.resolveLeafref(
+            final AbstractTypeObjectGenerator<?, ?> targetGenerator = context.resolveLeafref(
                 type.findFirstEffectiveSubstatementArgument(PathEffectiveStatement.class).orElseThrow());
             checkArgument(targetGenerator != this, "Effective model contains self-referencing leaf %s",
                 statement().argument());
@@ -443,7 +456,28 @@ abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> e
         return methodReturnElementType(builderFactory);
     }
 
+    @Override
+    final Type runtimeJavaType() {
+        if (methodReturnTypeElement != null) {
+            return methodReturnTypeElement;
+        }
+        final var genType = generatedType();
+        if (genType.isPresent()) {
+            return genType.orElseThrow();
+        }
+        final var prev = verifyNotNull(previous(), "No previous generator for %s", this);
+        return prev.runtimeJavaType();
+    }
+
     final @NonNull Type methodReturnElementType(final @NonNull TypeBuilderFactory builderFactory) {
+        var local = methodReturnTypeElement;
+        if (local == null) {
+            methodReturnTypeElement = local = createMethodReturnElementType(builderFactory);
+        }
+        return local;
+    }
+
+    private @NonNull Type createMethodReturnElementType(final @NonNull TypeBuilderFactory builderFactory) {
         final GeneratedType generatedType = tryGeneratedType(builderFactory);
         if (generatedType != null) {
             // We have generated a type here, so return it. This covers 'bits', 'enumeration' and 'union'.
@@ -455,7 +489,7 @@ abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> e
             return refType.methodReturnType(builderFactory);
         }
 
-        final AbstractExplicitGenerator<?> prev = previous();
+        final AbstractExplicitGenerator<?, ?> prev = previous();
         if (prev != null) {
             // We have been added through augment/uses, defer to the original definition
             return prev.methodReturnType(builderFactory);
@@ -513,8 +547,8 @@ abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> e
             return;
         }
 
-        final AbstractTypeObjectGenerator<?> prev =
-            (AbstractTypeObjectGenerator<?>) verifyNotNull(previous(), "Missing previous link in %s", this);
+        final AbstractTypeObjectGenerator<?, ?> prev =
+            (AbstractTypeObjectGenerator<?, ?>) verifyNotNull(previous(), "Missing previous link in %s", this);
         if (prev.refType instanceof ResolvedLeafref) {
             // We should be already inheriting the correct type
             return;
@@ -593,7 +627,7 @@ abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> e
 
         // builder.setSchemaPath(typedef.getPath());
         builder.setModuleName(module.statement().argument().getLocalName());
-        addCodegenInformation(typedef, builder);
+        builderFactory.addCodegenInformation(typedef, builder);
         annotateDeprecatedIfNecessary(typedef, builder);
         makeSerializable(builder);
         return builder.build();
@@ -631,7 +665,7 @@ abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> e
 
 //        builder.setSchemaPath(typedef.getPath());
         builder.setModuleName(moduleName);
-        addCodegenInformation(typedef, builder);
+        builderFactory.addCodegenInformation(typedef, builder);
 
         annotateDeprecatedIfNecessary(typedef, builder);
 
@@ -656,7 +690,7 @@ abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> e
 
 //        builder.setSchemaPath(typedef.getPath());
         builder.setModuleName(module.statement().argument().getLocalName());
-        addCodegenInformation(definingStatement, builder);
+        builderFactory.addCodegenInformation(definingStatement, builder);
 
         annotateDeprecatedIfNecessary(definingStatement, builder);
 
@@ -710,7 +744,7 @@ abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> e
                     Type baseType = SIMPLE_TYPES.get(subName);
                     if (baseType == null) {
                         // This has to be a reference to a typedef, let's lookup it up and pick up its type
-                        final AbstractTypeObjectGenerator<?> baseGen = verifyNotNull(
+                        final AbstractTypeObjectGenerator<?, ?> baseGen = verifyNotNull(
                             dependencies.baseTypes.get(subName), "Cannot resolve base type %s in %s", subName,
                             definingStatement);
                         baseType = baseGen.methodReturnType(builderFactory);
@@ -807,7 +841,7 @@ abstract class AbstractTypeObjectGenerator<T extends EffectiveStatement<?, ?>> e
         for (String part : unionName.localNameComponents()) {
             sb.append(part);
         }
-        return JavaTypeName.create(unionName.packageName(), sb.append("Builder").toString());
+        return JavaTypeName.create(unionName.packageName(), sb.append(BindingMapping.BUILDER_SUFFIX).toString());
     }
 
     // FIXME: we should not rely on TypeDefinition