All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dropbox.kaiken.processor.InjectableCodeGenerator.kt Maven / Gradle / Ivy

package com.dropbox.kaiken.processor

import com.dropbox.kaiken.annotation.Injectable
import com.google.auto.service.AutoService
import com.squareup.anvil.annotations.ExperimentalAnvilApi
import com.squareup.anvil.compiler.api.AnvilContext
import com.squareup.anvil.compiler.api.CodeGenerator
import com.squareup.anvil.compiler.api.GeneratedFile
import com.squareup.anvil.compiler.api.createGeneratedFile
import com.squareup.anvil.compiler.internal.asClassName
import com.squareup.anvil.compiler.internal.classesAndInnerClass
import com.squareup.anvil.compiler.internal.hasAnnotation
import com.squareup.anvil.compiler.internal.safePackageString
import com.squareup.kotlinpoet.javapoet.KotlinPoetJavaPoetPreview
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.resolveClassByFqName
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.calls.callUtil.createLookupLocation
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import java.io.File

@ExperimentalStdlibApi
@ExperimentalAnvilApi
@AutoService(CodeGenerator::class)
class InjectableCodeGenerator : CodeGenerator {

    internal enum class ClassType {
        ACTIVITY, FRAGMENT, INVALID
    }

    @KotlinPoetJavaPoetPreview
    override fun generateCode(
        codeGenDir: File,
        module: ModuleDescriptor,
        projectFiles: Collection,
    ): Collection {
        return projectFiles.classesAndInnerClass(module).filter { clazz ->
            clazz.hasAnnotation(FqName("com.dropbox.kaiken.annotation.Injectable"), module)
        }.map(mapper(module, codeGenDir)).toList()
    }

    private fun mapper(
        module: ModuleDescriptor,
        codeGenDir: File
    ): (KtClassOrObject) -> GeneratedFile =
        { clazz: KtClassOrObject ->
            var classType = ClassType.INVALID
            val descriptor: ClassDescriptor? =
                module.resolveClassByFqName(
                    clazz.fqName!!,
                    checkNotNull(clazz.createLookupLocation())
                )

            checkNotNull(descriptor).getAllSuperClassifiers().forEach {
                if (it.isFragment()) {
                    validateFragment(descriptor, clazz)
                    classType = ClassType.FRAGMENT
                } else if (it.isAndroidActivity()) {
                    validateActivity(descriptor, clazz)
                    classType = ClassType.ACTIVITY
                }
            }
            check(classType != ClassType.INVALID) {
                "Only Android Activities or Fragments can be annotated with" +
                    " ${Injectable::class.java.simpleName}"
            }
            val className = clazz.asClassName()
            val packageName =
                (clazz as KtClass).fqName!!.parent().safePackageString(dotPrefix = true)

            val fileSpec = if (classType == ClassType.ACTIVITY)
                generateActivityFileSpec(
                    packageName,
                    "${className.simpleName}Injector",
                    className
                ) else
                generateFragmentFileSpec(
                    packageName,
                    "${className.simpleName}Injector",
                    className,
                    true
                )
            createGeneratedFile(
                codeGenDir = codeGenDir,
                packageName = packageName,
                fileName = "${className.simpleName}Injector",
                content = fileSpec.toString()
            )
        }

    override fun isApplicable(context: AnvilContext): Boolean = !context.disableComponentMerging
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy