860653f01fc0151e757fef3550b6c4120046d7ba
1 package ru.fredboy.cavedroid.ksp.processor
3 import com.google.devtools.ksp.processing.*
4 import com.google.devtools.ksp.symbol.KSAnnotated
5 import com.google.devtools.ksp.symbol.KSClassDeclaration
6 import com.google.devtools.ksp.symbol.KSType
7 import com.squareup.kotlinpoet.*
8 import com.squareup.kotlinpoet.ksp.toClassName
9 import com.squareup.kotlinpoet.ksp.writeTo
10 import ru.fredboy.cavedroid.ksp.annotations.GenerateMapMultibindingsModule
12 class GenerateMapMultibindingsSymbolProcessor(
13 private val codeGenerator: CodeGenerator,
14 private val logger: KSPLogger,
15 ) : SymbolProcessor {
17 private fun generateModule(
18 annotationName: String,
19 interfaceName: ClassName,
20 moduleName: ClassName,
21 classes: List<KSClassDeclaration>
22 ): FileSpec? {
23 if (classes.isEmpty()) {
24 return null
25 }
27 val bindings = classes.map { decl ->
28 val stringKey = decl.annotations.first { declAnn ->
29 declAnn.shortName.getShortName() == annotationName
30 }.arguments.firstOrNull { arg ->
31 arg.name!!.getShortName() == "stringKey"
32 }?.value as? String ?: run {
33 logger.error("@${annotationName} must include stringKey parameter for key selection in generated module")
34 throw IllegalArgumentException()
35 }
37 val clazz = decl.toClassName()
39 FunSpec.builder("bind${clazz.simpleName}")
40 .addAnnotation(ClassName("dagger", "Binds"))
41 .addAnnotation(ClassName("dagger.multibindings", "IntoMap"))
42 .addAnnotation(
43 AnnotationSpec.builder(ClassName("dagger.multibindings", "StringKey"))
44 .addMember("\"$stringKey\"")
45 .build()
46 )
47 .addParameter(ParameterSpec("impl", clazz))
48 .returns(interfaceName)
49 .addCode("return impl")
50 .build()
51 }
53 val moduleObject = TypeSpec.objectBuilder(moduleName)
54 .addAnnotation(ClassName("dagger", "Module"))
55 .addAnnotation(
56 AnnotationSpec.builder(ClassName("javax.annotation.processing", "Generated"))
57 .addMember("value = [%S]", this::class.qualifiedName!!)
58 .build()
59 )
60 .addFunctions(bindings)
61 .build()
63 return FileSpec.builder(moduleName)
64 .addType(moduleObject)
65 .build()
67 }
69 private fun processAnnotation(resolver: Resolver, annotation: KSClassDeclaration) {
70 val args = annotation.annotations.first {
71 it.shortName.getShortName() == "GenerateMapMultibindingsModule"
72 }.arguments.takeIf { it.size == 3 } ?: run {
73 logger.error("GenerateMapMultibindingsModule should have 3 arguments")
74 throw IllegalArgumentException()
75 }
77 val interfaceName = args.first { it.name?.getShortName() == "interfaceClass" }.value as KSType
78 val modulePackage = args.first { it.name?.getShortName() == "modulePackage" }.value as String
79 val moduleName = args.first { it.name?.getShortName() == "moduleName" }.value as String
81 val moduleClassName = ClassName(modulePackage, moduleName)
82 val elements = resolver.getSymbolsWithAnnotation(annotation.qualifiedName!!.asString())
83 .filterIsInstance<KSClassDeclaration>()
84 .toList()
86 logger.info("Found elements: ${elements.joinToString()}")
88 generateModule(
89 annotationName = annotation.qualifiedName!!.getShortName(),
90 interfaceName = interfaceName.toClassName(),
91 moduleName = moduleClassName,
92 classes = elements
93 )?.writeTo(codeGenerator, Dependencies(true))
94 }
96 override fun process(resolver: Resolver): List<KSAnnotated> {
97 val annotations = resolver.getAnnotatedClasses(GenerateMapMultibindingsModule::class.qualifiedName!!, logger)
98 logger.info("Found annotations: ${annotations.joinToString { it.qualifiedName!!.asString() }}")
99 annotations.forEach { processAnnotation(resolver, it) }
100 return emptyList()
101 }
103 }