@@ -7,17 +7,35 @@ import com.squareup.kotlinpoet.KModifier
7
7
import com.squareup.kotlinpoet.LambdaTypeName
8
8
import com.squareup.kotlinpoet.ParameterSpec
9
9
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
10
+ import com.squareup.kotlinpoet.TypeName
10
11
import com.squareup.kotlinpoet.TypeSpec
11
12
import com.squareup.kotlinpoet.TypeVariableName
12
13
13
- // Helper that provide utilities to handle generic classes.
14
+ /* *
15
+ * Provides utilities to handle generic classes and generate KotlinPoet builders for them.
16
+ *
17
+ * @property className The base [ClassName] representing the class.
18
+ * @param numberOfGenericParameters The number of generic type parameters for the class.
19
+ */
14
20
class GenericClassNameInfo (
15
21
val className : ClassName ,
16
22
numberOfGenericParameters : Int
17
23
) {
24
+ /* *
25
+ * Return list of generic argument type names.
26
+ *
27
+ * Example: genericTypes = [P0, P1]
28
+ */
18
29
val genericTypes = Array (numberOfGenericParameters) {
19
30
TypeVariableName (" P$it " )
20
31
}.toList()
32
+
33
+
34
+ /* *
35
+ * Parameterized [ClassName] with generic type variables.
36
+ *
37
+ * Example: MyClass<P0, P1>
38
+ */
21
39
val genericClassName = className.run {
22
40
if (genericTypes.isNotEmpty()) {
23
41
parameterizedBy(genericTypes)
@@ -26,7 +44,18 @@ class GenericClassNameInfo(
26
44
}
27
45
}
28
46
47
+ /* *
48
+ * List of reified type variables for inline functions.
49
+ *
50
+ * Example: [reified P0, reified P1]
51
+ */
29
52
val reifiedTypes = genericTypes.map { it.copy(reified = true ) }
53
+
54
+ /* *
55
+ * Parameterized [ClassName] with reified generic type variables.
56
+ *
57
+ * Example: MyClass<reified P0, reified P1>
58
+ */
30
59
val reifiedClassName = className.run {
31
60
if (reifiedTypes.isNotEmpty()) {
32
61
parameterizedBy(reifiedTypes)
@@ -35,6 +64,11 @@ class GenericClassNameInfo(
35
64
}
36
65
}
37
66
67
+ /* *
68
+ * Parameterized [ClassName] with generic parameters erased to [ANY].
69
+ *
70
+ * Example: MyClass<Any, Any>
71
+ */
38
72
val erasedGenericClassName = className.run {
39
73
if (genericTypes.isNotEmpty()) {
40
74
parameterizedBy(genericTypes.map { ANY })
@@ -43,28 +77,97 @@ class GenericClassNameInfo(
43
77
}
44
78
}
45
79
46
- fun toTypeSpecBuilder () = TypeSpec
47
- .classBuilder(className)
48
- .addTypeVariables(genericTypes)
80
+ /* *
81
+ * Combine optional [prefix], core [genericTypes], and optional [suffix] into one list.
82
+ */
83
+ private fun allTypeVariables (
84
+ prefix : List <TypeVariableName > = emptyList(),
85
+ suffix : List <TypeVariableName > = emptyList()
86
+ ) = prefix + genericTypes + suffix
87
+
88
+ /* *
89
+ * Builds a [TypeSpec.Builder] for the class with type variables.
90
+ *
91
+ * Example: toTypeSpecBuilder(prefix, suffix) -> TypeSpec.classBuilder("MyClass").addTypeVariables(prefix + [P0,P1] + suffix)
92
+ */
93
+ fun toTypeSpecBuilder (
94
+ prefix : List <TypeVariableName > = emptyList(),
95
+ suffix : List <TypeVariableName > = emptyList()
96
+ ) = TypeSpec .classBuilder(className.simpleName)
97
+ .addTypeVariables(allTypeVariables(prefix, suffix))
98
+
99
+ /* *
100
+ * Builds a [FunSpec.Builder] with generic type variables.
101
+ *
102
+ * Example: builder("foo", prefix, suffix) -> builder("foo").addTypeVariables(prefix + [P0,P1] + suffix)
103
+ */
104
+ fun toFunSpecBuilder (
105
+ name : String ,
106
+ prefix : List <TypeVariableName > = emptyList(),
107
+ suffix : List <TypeVariableName > = emptyList()
108
+ ) = FunSpec .builder(name)
109
+ .addTypeVariables(allTypeVariables(prefix, suffix))
49
110
50
- fun toFunSpecBuilder (name : String ) = FunSpec
51
- .builder(name)
52
- .addTypeVariables(genericTypes)
53
111
54
- fun toExtensionFunSpecBuilder (name : String ) = toFunSpecBuilder(name).receiver(genericClassName)
55
112
56
- fun toReifiedFunSpecBuilder (name : String ) = FunSpec
57
- .builder(name)
58
- .addTypeVariables(reifiedTypes)
113
+ /* *
114
+ * Builds an extension [FunSpec.Builder] on [genericClassName].
115
+ *
116
+ * Example: fun <X,P0,P1,Y> MyClass<P0,P1>.foo() {...}
117
+ */
118
+ fun toExtensionFunSpecBuilder (
119
+ name : String ,
120
+ prefix : List <TypeVariableName > = emptyList(),
121
+ suffix : List <TypeVariableName > = emptyList()
122
+ ) = toFunSpecBuilder(name, prefix, suffix)
123
+ .receiver(genericClassName)
124
+
125
+
126
+ /* *
127
+ * Begin building a reified inline FunSpec with reified type parameters.
128
+ *
129
+ * Example: inline fun <X, reified P0, reified P1, Y> foo() {...}
130
+ */
131
+ fun toReifiedFunSpecBuilder (
132
+ name : String ,
133
+ prefix : List <TypeVariableName > = emptyList(),
134
+ suffix : List <TypeVariableName > = emptyList()
135
+ ) = FunSpec .builder(name)
59
136
.addModifiers(KModifier .INLINE )
137
+ .addTypeVariables(prefix + reifiedTypes + suffix)
138
+
139
+
140
+ /* *
141
+ * Begin building a reified inline extension FunSpec on the class.
142
+ *
143
+ * Example: inline fun <reified P0, reified P1> MyClass<P0, P1>.foo() {...}
144
+ */
145
+ fun toReifiedExtensionFunSpecBuilder (
146
+ name : String ,
147
+ prefix : List <TypeVariableName > = emptyList(),
148
+ suffix : List <TypeVariableName > = emptyList()
149
+ ) = toReifiedFunSpecBuilder(name, prefix, suffix)
150
+ .receiver(reifiedClassName)
60
151
61
- fun toReifiedExtensionFunSpecBuilder (name : String ) = toReifiedFunSpecBuilder(name).receiver(reifiedClassName)
62
152
153
+ /* *
154
+ * Generate a list of parameters matching the generic type variables.
155
+ *
156
+ * Example: [ParameterSpec("p0", P0), ParameterSpec("p1", P1)]
157
+ */
63
158
fun toParameterSpecList () = genericTypes
64
159
.mapIndexed { index: Int , typeVariableName: TypeVariableName ->
65
160
ParameterSpec .builder(" p$index " , typeVariableName).build()
66
161
}
67
162
163
+ /* *
164
+ * Build a comma-separated argument string based on a template.
165
+ *
166
+ * @param template String template where occurrences of `{$indexKey}` will be replaced by index
167
+ * @param indexKey placeholder key in template (e.g., "%d")
168
+ *
169
+ * Example: toArgumentsString("p%{i}", "{i}") -> "p0, p1"
170
+ */
68
171
fun toArgumentsString (template : String , indexKey : String ): String {
69
172
return buildString {
70
173
genericTypes.mapIndexed { index: Int , typeVariableName: TypeVariableName ->
@@ -74,8 +177,13 @@ class GenericClassNameInfo(
74
177
}
75
178
}
76
179
77
- fun toLambdaTypeName (returnType : TypeVariableName ) = LambdaTypeName .get(
78
- receiver = null ,
180
+ /* *
181
+ * Create a LambdaTypeName taking generic types as parameters and returning [returnType].
182
+ *
183
+ * Example: toLambdaTypeName(R) -> (p0: P0, p1: P1) -> R
184
+ */
185
+ fun toLambdaTypeName (returnType : TypeName , receiver : TypeName ? = null) = LambdaTypeName .get(
186
+ receiver = receiver,
79
187
parameters = genericTypes
80
188
.mapIndexed { index: Int , typeVariableName: TypeVariableName ->
81
189
ParameterSpec .builder(" p$index " , typeVariableName).build()
0 commit comments