1a6ac7fe5bc4146853c54ec5b0d8bebdf0e0b55f
[mdsal.git] / binding / mdsal-binding-generator / src / main / java / org / opendaylight / mdsal / binding / generator / impl / reactor / ChoiceGenerator.java
1 /*
2  * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.mdsal.binding.generator.impl.reactor;
9
10 import com.google.common.collect.Iterables;
11 import java.util.ArrayList;
12 import java.util.List;
13 import org.opendaylight.mdsal.binding.generator.impl.rt.DerivedChoiceRuntimeType;
14 import org.opendaylight.mdsal.binding.generator.impl.rt.OriginalChoiceRuntimeType;
15 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
16 import org.opendaylight.mdsal.binding.model.api.Type;
17 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
18 import org.opendaylight.mdsal.binding.model.ri.BindingTypes;
19 import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
20 import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
21 import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
22 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
23 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
24 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
25
26 /**
27  * Generator corresponding to a {@code choice} statement.
28  */
29 final class ChoiceGenerator extends CompositeSchemaTreeGenerator<ChoiceEffectiveStatement, ChoiceRuntimeType> {
30     ChoiceGenerator(final ChoiceEffectiveStatement statement, final AbstractCompositeGenerator<?, ?> parent) {
31         super(statement, parent);
32     }
33
34     @Override
35     void pushToInference(final SchemaInferenceStack dataTree) {
36         // No-op
37     }
38
39     @Override
40     GeneratedType createTypeImpl(final TypeBuilderFactory builderFactory) {
41         final GeneratedTypeBuilder builder = builderFactory.newGeneratedTypeBuilder(typeName());
42         builder.addImplementsType(BindingTypes.choiceIn(Type.of(getParent().typeName())));
43
44         final ModuleGenerator module = currentModule();
45         module.addQNameConstant(builder, localName());
46
47         annotateDeprecatedIfNecessary(builder);
48         builderFactory.addCodegenInformation(module, statement(), builder);
49 //      newType.setSchemaPath(schemaNode.getPath());
50         builder.setModuleName(module.statement().argument().getLocalName());
51
52         return builder.build();
53     }
54
55     @Override
56     ChoiceRuntimeType createRuntimeType(final GeneratedType type, final ChoiceEffectiveStatement statement,
57             final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
58         final var original = getOriginal();
59         if (!statement.equals(original.statement())) {
60             return new DerivedChoiceRuntimeType(type, statement, children, augments,
61                 original.runtimeType().orElseThrow());
62         }
63
64         // Pick up any case statements added by augments which are not reflected in our children. This can happen when
65         // a choice is added via uses into two different places and then augmented. Since groupings are reused, validity
66         // of such use is not guarded by compile-time checks.
67         //
68         // Furthermore such case statements can be freely propagated via copy builders and thus can occur in unexpected
69         // places. If that happens, though, the two case statements can be equivalent, e.g. by having the exact same
70         // shape -- in which case Binding -> DOM translation needs to correct this mishap and play pretend the correct
71         // case was used.
72         final var augmentedCases = new ArrayList<CaseRuntimeType>();
73         for (var augment : original.augments()) {
74             for (var gen : augment) {
75                 if (gen instanceof CaseGenerator) {
76                     ((CaseGenerator) gen).runtimeType().ifPresent(augmented -> {
77                         for (var child : Iterables.concat(children, augmentedCases)) {
78                             if (child instanceof CaseRuntimeType && child.javaType().equals(augmented.javaType())) {
79                                 return;
80                             }
81                         }
82                         augmentedCases.add(augmented);
83                     });
84                 }
85             }
86         }
87
88         return new OriginalChoiceRuntimeType(type, statement, children, augments, augmentedCases);
89     }
90 }