@@ -6,54 +6,80 @@ import kategory.common.utils.knownError
6
6
import me.eugeniomarletti.kotlin.metadata.KotlinClassMetadata
7
7
import me.eugeniomarletti.kotlin.metadata.isDataClass
8
8
import me.eugeniomarletti.kotlin.metadata.kotlinMetadata
9
+ import me.eugeniomarletti.kotlin.metadata.modality
10
+ import org.jetbrains.kotlin.serialization.ProtoBuf
9
11
import java.io.File
10
12
import javax.annotation.processing.Processor
11
13
import javax.annotation.processing.RoundEnvironment
12
14
import javax.lang.model.SourceVersion
13
15
import javax.lang.model.element.Element
16
+ import javax.lang.model.element.ElementKind
17
+ import javax.lang.model.element.ExecutableElement
14
18
import javax.lang.model.element.TypeElement
15
- import javax.lang.model.element.VariableElement
16
- import javax.lang.model.type.TypeKind
17
19
18
20
@AutoService(Processor ::class )
19
21
class OptikalProcessor : AbstractProcessor () {
20
22
21
23
private val annotatedLenses = mutableListOf<AnnotatedLens .Element >()
22
24
25
+ private val annotatedPrisms = mutableListOf<AnnotatedPrism .Element >()
26
+
23
27
override fun getSupportedSourceVersion (): SourceVersion = SourceVersion .latestSupported()
24
28
25
- override fun getSupportedAnnotationTypes () = setOf (lensesAnnotationClass.canonicalName)
29
+ override fun getSupportedAnnotationTypes () = setOf (
30
+ lensesAnnotationClass.canonicalName,
31
+ prismsAnnotationClass.canonicalName
32
+ )
26
33
27
34
override fun onProcess (annotations : Set <TypeElement >, roundEnv : RoundEnvironment ) {
28
35
annotatedLenses + = roundEnv
29
36
.getElementsAnnotatedWith(lensesAnnotationClass)
30
37
.map(this ::evalAnnotatedElement)
31
- .map { annotatedLens ->
32
- when (annotatedLens) {
33
- is AnnotatedLens .InvalidElement -> knownError(annotatedLens.reason)
34
- is AnnotatedLens .Element -> annotatedLens
35
- }
36
- }
38
+
39
+ annotatedPrisms + = roundEnv
40
+ .getElementsAnnotatedWith(prismsAnnotationClass)
41
+ .map(this ::evalAnnotatedPrismElement)
37
42
38
43
if (roundEnv.processingOver()) {
39
44
val generatedDir = File (this .generatedDir!! , " " ).also { it.mkdirs() }
40
45
LensesFileGenerator (annotatedLenses, generatedDir).generate()
46
+ PrismsFileGenerator (annotatedPrisms, generatedDir).generate()
41
47
}
42
48
}
43
49
44
- fun evalAnnotatedElement (element : Element ): AnnotatedLens = when {
45
- element.kotlinMetadata !is KotlinClassMetadata -> AnnotatedLens .InvalidElement ("""
46
- |Cannot use @Lenses on ${element.enclosingElement} .${element.simpleName} .
47
- |It can only be used on data classes.""" .trimMargin())
48
-
49
- (element.kotlinMetadata as KotlinClassMetadata ).data.classProto.isDataClass ->
50
+ private fun evalAnnotatedElement (element : Element ): AnnotatedLens .Element = when {
51
+ element.let { it.kotlinMetadata as ? KotlinClassMetadata }?.data?.classProto?.isDataClass == true ->
50
52
AnnotatedLens .Element (
51
53
element as TypeElement ,
52
- element.enclosedElements
53
- .filter { it.asType().kind == TypeKind .DECLARED }
54
- .map { it as VariableElement })
54
+ element.enclosedElements.firstOrNull { it.kind == ElementKind .CONSTRUCTOR }
55
+ ?.let { it as ExecutableElement }
56
+ ?.parameters ? : emptyList()
57
+ )
55
58
56
- else -> AnnotatedLens . InvalidElement ( " ${ element.enclosingElement} . ${element.simpleName} cannot be annotated with @Lenses " )
59
+ else -> knownError(opticsAnnotationError( element, lensesAnnotationName, lensesAnnotationTarget) )
57
60
}
58
61
62
+ private fun evalAnnotatedPrismElement (element : Element ): AnnotatedPrism .Element = when {
63
+ element.let { it.kotlinMetadata as ? KotlinClassMetadata }?.data?.classProto?.isSealed == true -> {
64
+ val (nameResolver, classProto) = element.kotlinMetadata.let { it as KotlinClassMetadata }.data
65
+
66
+ AnnotatedPrism .Element (
67
+ element as TypeElement ,
68
+ classProto.sealedSubclassFqNameList
69
+ .map(nameResolver::getString)
70
+ .map { it.replace(' /' , ' .' ) }
71
+ .mapNotNull(elementUtils::getTypeElement)
72
+ )
73
+ }
74
+
75
+ else -> knownError(opticsAnnotationError(element, prismsAnnotationName, prismsAnnotationTarget))
76
+ }
77
+
78
+ private fun opticsAnnotationError (element : Element , annotationName : String , targetName : String ): String = """
79
+ |Cannot use $annotationName on ${element.enclosingElement} .${element.simpleName} .
80
+ |It can only be used on $targetName .""" .trimMargin()
81
+
82
+ private val ProtoBuf .Class .isSealed
83
+ get() = modality == ProtoBuf .Modality .SEALED
84
+
59
85
}
0 commit comments