@@ -155,22 +155,15 @@ class ClassFileToSourceStubConverter(
155
155
val isNested = (descriptor as ? ClassDescriptor )?.isNested ? : false
156
156
val isInner = isNested && (descriptor as ? ClassDescriptor )?.isInner ? : false
157
157
158
- val flags = when {
159
- (descriptor.containingDeclaration as ? ClassDescriptor )?.kind == ClassKind .INTERFACE -> {
160
- // Classes inside interfaces should always be public and static.
161
- // See com.sun.tools.javac.comp.Enter.visitClassDef for more information.
162
- (clazz.access or Opcodes .ACC_PUBLIC or Opcodes .ACC_STATIC ) and
163
- Opcodes .ACC_PRIVATE .inv () and Opcodes .ACC_PROTECTED .inv () // Remove private and protected modifiers
164
- }
165
- ! isInner && isNested -> clazz.access or Opcodes .ACC_STATIC
166
- else -> clazz.access
167
- }
168
-
169
- val modifiers = convertModifiers(flags, ElementKind .CLASS , packageFqName, clazz.visibleAnnotations, clazz.invisibleAnnotations)
158
+ val flags = getClassAccessFlags(clazz, descriptor, isInner, isNested)
170
159
171
160
val isEnum = clazz.isEnum()
172
161
val isAnnotation = clazz.isAnnotation()
173
162
163
+ val modifiers = convertModifiers(flags,
164
+ if (isEnum) ElementKind .ENUM else ElementKind .CLASS ,
165
+ packageFqName, clazz.visibleAnnotations, clazz.invisibleAnnotations)
166
+
174
167
val isDefaultImpls = clazz.name.endsWith(" ${descriptor.name.asString()} /DefaultImpls" )
175
168
&& isPublic(clazz.access) && isFinal(clazz.access)
176
169
&& descriptor is ClassDescriptor
@@ -181,14 +174,7 @@ class ClassFileToSourceStubConverter(
181
174
return null
182
175
}
183
176
184
- val simpleName = when (descriptor) {
185
- is PackageFragmentDescriptor -> {
186
- val className = if (packageFqName.isEmpty()) clazz.name else clazz.name.drop(packageFqName.length + 1 )
187
- if (className.isEmpty()) throw IllegalStateException (" Invalid package facade class name: ${clazz.name} " )
188
- className
189
- }
190
- else -> if (isDefaultImpls) " DefaultImpls" else descriptor.name.asString()
191
- }
177
+ val simpleName = getClassName(clazz, descriptor, isDefaultImpls, packageFqName)
192
178
193
179
val interfaces = mapJList(clazz.interfaces) {
194
180
if (isAnnotation && it == " java/lang/annotation/Annotation" ) return @mapJList null
@@ -200,7 +186,49 @@ class ClassFileToSourceStubConverter(
200
186
val hasSuperClass = clazz.superName != " java/lang/Object" && ! isEnum
201
187
val genericType = signatureParser.parseClassSignature(clazz.signature, superClass, interfaces)
202
188
203
- val fields = mapJList<FieldNode , JCTree >(clazz.fields) { convertField(it, packageFqName) }
189
+ class EnumValueData (val field : FieldNode , val innerClass : InnerClassNode ? , val correspondingClass : ClassNode ? )
190
+
191
+ val enumValuesData = clazz.fields.filter { it.isEnumValue() }.map { field ->
192
+ var foundInnerClass: InnerClassNode ? = null
193
+ var correspondingClass: ClassNode ? = null
194
+
195
+ for (innerClass in clazz.innerClasses) {
196
+ // Class should have the same name as enum value
197
+ if (innerClass.innerName != field.name) continue
198
+ val classNode = kaptContext.compiledClasses.firstOrNull { it.name == innerClass.name } ? : continue
199
+
200
+ // Super class name of the class should be our enum class
201
+ if (classNode.superName != clazz.name) continue
202
+
203
+ correspondingClass = classNode
204
+ foundInnerClass = innerClass
205
+ break
206
+ }
207
+
208
+ EnumValueData (field, foundInnerClass, correspondingClass)
209
+ }
210
+
211
+ val enumValues: JavacList <JCTree > = mapJList(enumValuesData) { data ->
212
+ val constructorArguments = Type .getArgumentTypes(clazz.methods.firstOrNull {
213
+ it.name == " <init>" && Type .getArgumentsAndReturnSizes(it.desc).shr(2 ) >= 2
214
+ }?.desc ? : " ()Z" )
215
+
216
+ val args = mapJList(constructorArguments.drop(2 )) { convertLiteralExpression(getDefaultValue(it)) }
217
+
218
+ val def = data.correspondingClass?.let { convertClass(it, packageFqName, false ) }
219
+
220
+ convertField(data.field, packageFqName, treeMaker.NewClass (
221
+ /* enclosing = */ null ,
222
+ /* typeArgs = */ JavacList .nil(),
223
+ /* clazz = */ treeMaker.Ident (treeMaker.name(data.field.name)),
224
+ /* args = */ args,
225
+ /* def = */ def))
226
+ }
227
+
228
+ val fields = mapJList<FieldNode , JCTree >(clazz.fields) {
229
+ if (it.isEnumValue()) null else convertField(it, packageFqName)
230
+ }
231
+
204
232
val methods = mapJList<MethodNode , JCTree >(clazz.methods) {
205
233
if (isEnum) {
206
234
if (it.name == " values" && it.desc == " ()[L${clazz.name} ;" ) return @mapJList null
@@ -209,7 +237,9 @@ class ClassFileToSourceStubConverter(
209
237
210
238
convertMethod(it, clazz, packageFqName)
211
239
}
240
+
212
241
val nestedClasses = mapJList<InnerClassNode , JCTree >(clazz.innerClasses) { innerClass ->
242
+ if (enumValuesData.any { it.innerClass == innerClass }) return @mapJList null
213
243
if (innerClass.outerName != clazz.name) return @mapJList null
214
244
val innerClassNode = kaptContext.compiledClasses.firstOrNull { it.name == innerClass.name } ? : return @mapJList null
215
245
convertClass(innerClassNode, packageFqName, false )
@@ -221,10 +251,32 @@ class ClassFileToSourceStubConverter(
221
251
genericType.typeParameters,
222
252
if (hasSuperClass) genericType.superClass else null ,
223
253
genericType.interfaces,
224
- fields + methods + nestedClasses)
254
+ enumValues + fields + methods + nestedClasses)
255
+ }
256
+
257
+ private fun getClassAccessFlags (clazz : ClassNode , descriptor : DeclarationDescriptor , isInner : Boolean , isNested : Boolean ) = when {
258
+ (descriptor.containingDeclaration as ? ClassDescriptor )?.kind == ClassKind .INTERFACE -> {
259
+ // Classes inside interfaces should always be public and static.
260
+ // See com.sun.tools.javac.comp.Enter.visitClassDef for more information.
261
+ (clazz.access or Opcodes .ACC_PUBLIC or Opcodes .ACC_STATIC ) and
262
+ Opcodes .ACC_PRIVATE .inv () and Opcodes .ACC_PROTECTED .inv () // Remove private and protected modifiers
263
+ }
264
+ ! isInner && isNested -> clazz.access or Opcodes .ACC_STATIC
265
+ else -> clazz.access
266
+ }
267
+
268
+ private fun getClassName (clazz : ClassNode , descriptor : DeclarationDescriptor , isDefaultImpls : Boolean , packageFqName : String ): String {
269
+ return when (descriptor) {
270
+ is PackageFragmentDescriptor -> {
271
+ val className = if (packageFqName.isEmpty()) clazz.name else clazz.name.drop(packageFqName.length + 1 )
272
+ if (className.isEmpty()) throw IllegalStateException (" Invalid package facade class name: ${clazz.name} " )
273
+ className
274
+ }
275
+ else -> if (isDefaultImpls) " DefaultImpls" else descriptor.name.asString()
276
+ }
225
277
}
226
278
227
- private fun convertField (field : FieldNode , packageFqName : String ): JCVariableDecl ? {
279
+ private fun convertField (field : FieldNode , packageFqName : String , explicitInitializer : JCExpression ? = null ): JCVariableDecl ? {
228
280
if (isSynthetic(field.access)) return null
229
281
val descriptor = kaptContext.origins[field]?.descriptor
230
282
@@ -244,7 +296,8 @@ class ClassFileToSourceStubConverter(
244
296
245
297
val value = field.value
246
298
247
- val initializer = convertValueOfPrimitiveTypeOrString(value)
299
+ val initializer = explicitInitializer
300
+ ? : convertValueOfPrimitiveTypeOrString(value)
248
301
? : if (isFinal(field.access)) convertLiteralExpression(getDefaultValue(type)) else null
249
302
250
303
return treeMaker.VarDef (modifiers, name, typeExpression, initializer)
@@ -460,6 +513,7 @@ class ClassFileToSourceStubConverter(
460
513
} ? : annotations
461
514
462
515
val flags = when (kind) {
516
+ ElementKind .ENUM -> access and CLASS_MODIFIERS and Opcodes .ACC_ABSTRACT .inv ().toLong()
463
517
ElementKind .CLASS -> access and CLASS_MODIFIERS
464
518
ElementKind .METHOD -> access and METHOD_MODIFIERS
465
519
ElementKind .FIELD -> access and FIELD_MODIFIERS
0 commit comments