Unify GeneratedType verification
[mdsal.git] / binding / mdsal-binding-generator / src / main / java / org / opendaylight / mdsal / binding / generator / impl / reactor / TypedefGenerator.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 static com.google.common.base.Verify.verifyNotNull;
11 import static java.util.Objects.requireNonNull;
12
13 import java.util.ArrayList;
14 import java.util.List;
15 import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultTypedefRuntimeType;
16 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
17 import org.opendaylight.mdsal.binding.model.api.Type;
18 import org.opendaylight.mdsal.binding.model.api.YangSourceDefinition;
19 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTOBuilder;
20 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
21 import org.opendaylight.mdsal.binding.model.ri.TypeConstants;
22 import org.opendaylight.mdsal.binding.model.ri.Types;
23 import org.opendaylight.mdsal.binding.runtime.api.TypedefRuntimeType;
24 import org.opendaylight.yangtools.yang.binding.contract.StatementNamespace;
25 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
27 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
28 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
29
30 /**
31  * Generator corresponding to a {@code typedef} statement.
32  */
33 final class TypedefGenerator extends AbstractTypeObjectGenerator<TypedefEffectiveStatement, TypedefRuntimeType> {
34     /**
35      * List of all generators for types directly derived from this typedef. We populate this list during initial type
36      * linking. It allows us to easily cascade inferences made by this typedef down the type derivation tree.
37      */
38     private List<AbstractTypeObjectGenerator<?, ?>> derivedGenerators = null;
39
40     TypedefGenerator(final TypedefEffectiveStatement statement, final AbstractCompositeGenerator<?, ?> parent) {
41         super(statement, parent);
42     }
43
44     @Override
45     StatementNamespace namespace() {
46         return StatementNamespace.TYPEDEF;
47     }
48
49     @Override
50     void pushToInference(final SchemaInferenceStack dataTree) {
51         dataTree.enterTypedef(statement().argument());
52     }
53
54     void addDerivedGenerator(final AbstractTypeObjectGenerator<?, ?> derivedGenerator) {
55         if (derivedGenerators == null) {
56             derivedGenerators = new ArrayList<>(4);
57         }
58         derivedGenerators.add(requireNonNull(derivedGenerator));
59     }
60
61     @Override
62     void bindDerivedGenerators(final TypeReference reference) {
63         // Trigger any derived resolvers ...
64         if (derivedGenerators != null) {
65             for (var derived : derivedGenerators) {
66                 derived.bindTypeDefinition(reference);
67             }
68         }
69         // ... and make sure nobody can come in late
70         derivedGenerators = List.of();
71     }
72
73     @Override
74     ClassPlacement classPlacementImpl() {
75         return ClassPlacement.TOP_LEVEL;
76     }
77
78     @Override
79     TypeDefinition<?> extractTypeDefinition() {
80         return statement().getTypeDefinition();
81     }
82
83     @Override
84     GeneratedTransferObject createDerivedType(final TypeBuilderFactory builderFactory,
85             final GeneratedTransferObject baseType) {
86         final var builder = builderFactory.newGeneratedTOBuilder(typeName());
87         builder.setTypedef(true);
88         builder.setExtendsType(baseType);
89         builder.setIsUnion(baseType.isUnionType());
90         builder.setRestrictions(computeRestrictions());
91         YangSourceDefinition.of(currentModule().statement(), statement()).ifPresent(builder::setYangSourceDefinition);
92
93         final var typedef = statement().getTypeDefinition();
94         annotateDeprecatedIfNecessary(typedef, builder);
95         addStringRegExAsConstant(builder, resolveRegExpressions(typedef));
96         addUnits(builder, typedef);
97
98         if (typedef instanceof BitsTypeDefinition bits) {
99             addValidBits(builder, bits, baseType);
100         }
101
102         makeSerializable(builder);
103         return builder.build();
104     }
105
106     private static void addValidBits(final GeneratedTOBuilder builder, final BitsTypeDefinition typedef,
107             final GeneratedTransferObject baseType) {
108         final var baseDef = verifyNotNull(baseBitsDefinition(baseType), "Could not find definition in %s", baseType);
109         final var myBits = typedef.getBits();
110         if (myBits.size() != baseDef.getBits().size()) {
111             builder.addConstant(Types.immutableSetTypeFor(Types.STRING), TypeConstants.VALID_NAMES_NAME, typedef);
112         }
113     }
114
115     private static BitsTypeDefinition baseBitsDefinition(final GeneratedTransferObject gto) {
116         var wlk = gto;
117         while (wlk != null) {
118             for (var constant : wlk.getConstantDefinitions()) {
119                 if (TypeConstants.VALID_NAMES_NAME.equals(constant.getName())) {
120                     return (BitsTypeDefinition) constant.getValue();
121                 }
122             }
123
124             wlk = wlk.getSuperType();
125         }
126         return null;
127     }
128
129     @Override
130     TypedefRuntimeType createExternalRuntimeType(final Type type) {
131         return new DefaultTypedefRuntimeType(verifyGeneratedType(type), statement());
132     }
133
134     @Override
135     TypedefRuntimeType createInternalRuntimeType(final AugmentResolver resolver,
136             final TypedefEffectiveStatement statement, final Type type) {
137         // 'typedef' statements are not schema tree statements, they should not have internal references
138         throw new UnsupportedOperationException("Should never be called");
139     }
140
141     @Override
142     void addAsGetterMethod(final GeneratedTypeBuilderBase<?> builder, final TypeBuilderFactory builderFactory) {
143         // typedefs are a separate concept
144     }
145 }