@@ -23,8 +23,9 @@ import com.squareup.kotlinpoet.ParameterSpec
23
23
import com.squareup.kotlinpoet.ParameterizedTypeName
24
24
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
25
25
import com.squareup.kotlinpoet.PropertySpec
26
+ import com.squareup.kotlinpoet.TypeVariableName
26
27
import com.squareup.kotlinpoet.asTypeName
27
- import org.modelix.metamodel.ITypedConcept
28
+ import org.modelix.metamodel.IConceptOfTypedNode
28
29
import org.modelix.metamodel.generator.MetaModelGenerator
29
30
import org.modelix.metamodel.generator.NameConfig
30
31
import org.modelix.metamodel.generator.ProcessedChildLink
@@ -66,6 +67,9 @@ internal class ModelQLExtensionsGenerator(
66
67
is ProcessedChildLink -> {
67
68
addChildGetter(feature)
68
69
addChildSetter(feature)
70
+ if (! feature.type.resolved.abstract) {
71
+ addDefaultChildSetter(feature)
72
+ }
69
73
}
70
74
71
75
is ProcessedReferenceLink -> {
@@ -80,7 +84,7 @@ internal class ModelQLExtensionsGenerator(
80
84
81
85
private fun FileSpec.Builder.addReferenceSetter (referenceLink : ProcessedReferenceLink ) {
82
86
val targetType = referenceLink.type.resolved.nodeWrapperInterfaceType().copy(nullable = referenceLink.optional)
83
- val inputStepType = IMonoStep :: class .asTypeName().parameterizedBy(concept.nodeWrapperInterfaceType() )
87
+ val inputStepType = getSetterReceiverType( )
84
88
85
89
val parameterType = IMonoStep ::class .asTypeName().parameterizedBy(targetType)
86
90
.let { if (referenceLink.optional) it.copy(nullable = true ) else it }
@@ -159,26 +163,23 @@ internal class ModelQLExtensionsGenerator(
159
163
160
164
private fun FileSpec.Builder.addChildSetter (childLink : ProcessedChildLink ) {
161
165
val targetType = childLink.type.resolved.nodeWrapperInterfaceType()
162
- val returnType = IMonoStep :: class .asTypeName().parameterizedBy( targetType)
163
- val receiverType = IMonoStep ::class .asTypeName().parameterizedBy(concept.nodeWrapperInterfaceType() )
164
- val conceptParameter = ParameterSpec .builder( " concept " , ITypedConcept :: class .asTypeName()). apply {
165
- if ( ! childLink.type.resolved.abstract) {
166
- defaultValue( " %T " , childLink.type.resolved.conceptWrapperInterfaceClass())
167
- }
168
- } .build()
166
+ val outType = TypeVariableName ( " Out " , targetType)
167
+ val returnType = IMonoStep ::class .asTypeName().parameterizedBy(outType )
168
+ val receiverType = getSetterReceiverType()
169
+ val conceptParameter = ParameterSpec .builder(
170
+ name = " concept " ,
171
+ type = IConceptOfTypedNode :: class .asTypeName().parameterizedBy(outType),
172
+ ) .build()
169
173
170
- val funName = if (childLink.multiple) childLink.adderMethodName() else childLink.setterName( )
174
+ val funName = getSetterName (childLink)
171
175
172
176
val funSpec = FunSpec .builder(funName).runBuild {
177
+ addTypeVariable(outType)
173
178
returns(returnType)
174
179
receiver(receiverType)
175
180
addParameter(conceptParameter)
176
181
if (childLink.multiple) {
177
- val indexParameter = ParameterSpec .builder(" index" , Int ::class .asTypeName())
178
- .defaultValue(" -1" )
179
- .build()
180
-
181
- addParameter(indexParameter)
182
+ addIndexParameter()
182
183
addStatement(
183
184
" return %T.addNewChild(this, %T.%N, index, concept)" ,
184
185
TypedModelQL ::class .asTypeName(),
@@ -198,6 +199,55 @@ internal class ModelQLExtensionsGenerator(
198
199
addFunction(funSpec)
199
200
}
200
201
202
+ /*
203
+ If we use the concept companion object as a default value for the concept parameter,
204
+ the kotlin compiler reports a type mismatch since it cannot properly infer the type variable.
205
+ That's why we need a separate default setter.
206
+ */
207
+ private fun FileSpec.Builder.addDefaultChildSetter (childLink : ProcessedChildLink ) {
208
+ val targetType = childLink.type.resolved.conceptWrapperInterfaceClass()
209
+ val returnType = IMonoStep ::class .asTypeName().parameterizedBy(childLink.type.resolved.nodeWrapperInterfaceType())
210
+ val receiverType = getSetterReceiverType()
211
+
212
+ val funName = getSetterName(childLink)
213
+
214
+ val funSpec = FunSpec .builder(funName).runBuild {
215
+ returns(returnType)
216
+ receiver(receiverType)
217
+ if (childLink.multiple) {
218
+ addIndexParameter()
219
+ addStatement(
220
+ " return %T.addNewChild(this, %T.%N, index, %T)" ,
221
+ TypedModelQL ::class .asTypeName(),
222
+ concept.conceptObjectType(),
223
+ childLink.generatedName,
224
+ targetType,
225
+ )
226
+ } else {
227
+ addStatement(
228
+ " return %T.setChild(this, %T.%N, %T)" ,
229
+ TypedModelQL ::class .asTypeName(),
230
+ concept.conceptObjectType(),
231
+ childLink.generatedName,
232
+ targetType,
233
+ )
234
+ }
235
+ }
236
+
237
+ addFunction(funSpec)
238
+ }
239
+
240
+ private fun FunSpec.Builder.addIndexParameter () {
241
+ val indexParameter = ParameterSpec .builder(" index" , Int ::class .asTypeName())
242
+ .defaultValue(" -1" )
243
+ .build()
244
+
245
+ addParameter(indexParameter)
246
+ }
247
+
248
+ private fun getSetterName (childLink : ProcessedChildLink ) =
249
+ if (childLink.multiple) childLink.adderMethodName() else childLink.setterName()
250
+
201
251
private fun FileSpec.Builder.addChildGetter (childLink : ProcessedChildLink ) {
202
252
val inputStepType = (if (childLink.multiple) IProducingStep ::class else IMonoStep ::class).asTypeName()
203
253
val outputStepType = (if (childLink.multiple) IFluxStep ::class else IMonoStep ::class).asTypeName()
@@ -225,8 +275,7 @@ internal class ModelQLExtensionsGenerator(
225
275
}
226
276
227
277
private fun FileSpec.Builder.addPropertySetter (property : ProcessedProperty ) {
228
- val inputStepType = IMonoStep ::class .asTypeName()
229
- .parameterizedBy(concept.nodeWrapperInterfaceType())
278
+ val inputStepType = getSetterReceiverType()
230
279
231
280
val parameterType = IMonoStep ::class .asTypeName()
232
281
.parameterizedBy(property.asKotlinType(alwaysUseNonNullableProperties))
@@ -246,6 +295,9 @@ internal class ModelQLExtensionsGenerator(
246
295
addFunction(setterSpec)
247
296
}
248
297
298
+ private fun getSetterReceiverType () =
299
+ IMonoStep ::class .asTypeName().parameterizedBy(concept.nodeWrapperInterfaceType())
300
+
249
301
private fun FileSpec.Builder.addPropertyGetterForStepType (
250
302
property : ProcessedProperty ,
251
303
stepType : ClassName ,
0 commit comments