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

com.airbnb.epoxy.processor.resourcescanning.ResourceScanner.kt Maven / Gradle / Ivy

package com.airbnb.epoxy.processor.resourcescanning

import androidx.room.compiler.processing.XAnnotation
import androidx.room.compiler.processing.XElement
import androidx.room.compiler.processing.XProcessingEnv
import androidx.room.compiler.processing.XTypeElement
import com.squareup.javapoet.ClassName
import kotlin.reflect.KClass

abstract class ResourceScanner(val environmentProvider: () -> XProcessingEnv) {
    val rClassNames: List
        get() = mutableRClasses.toList()

    private val mutableRClasses = mutableSetOf()

    /**
     * Returns the [ResourceValue] that is used as an annotation value of the given [XElement]
     */
    fun getResourceValue(
        annotation: KClass,
        element: XElement,
        property: String,
    ): ResourceValue? {
        // The annotation box class doesn't allow us to query properties by name, so we get an
        // XAnnotation which has that information.
        val xAnnotation = element.getXAnnotation(annotation) ?: return null

        val value = (
            xAnnotation.annotationValues
                .firstOrNull { it.name == property }
                ?.value as? Int
            )
            ?: return null

        return getResourceValue(annotation, element, property, value)
    }

    private fun XElement.getXAnnotation(
        annotation: KClass
    ): XAnnotation? {
        return getAllAnnotations().firstOrNull {
            // optimization to not resolve full annotation for fqn unless the simple name matches
            it.name == annotation.simpleName && it.qualifiedName == annotation.qualifiedName
        }
    }

    /**
     * Returns the [ResourceValue] that is used as an annotation value of the given [XElement]
     */
    fun getResourceValue(
        annotation: KClass,
        element: XElement,
        property: String,
        value: Int
    ): ResourceValue {
        return getResourceValueInternal(annotation, element, property, value).also { resourceValue ->
            resourceValue?.className?.let { mutableRClasses.add(it) }
        } ?: ResourceValue(value)
    }

    /**
     * Returns the list of [ResourceValue] that is used as an annotation value of the given [XElement]
     */
    fun getResourceValueList(
        annotation: KClass,
        element: XElement,
        property: String,
    ): List? {
        val xAnnotation = element.getXAnnotation(annotation) ?: return null

        val values = (
            xAnnotation.annotationValues
                .firstOrNull { it.name == property }
                ?.asIntList()
            )
            ?: return null

        return getResourceValueListInternal(annotation, element, property, values).also { list ->
            list.forEach { resourceValue ->
                resourceValue.rClass?.let { mutableRClasses.add(it) }
            }
        }
    }

    protected abstract fun getResourceValueListInternal(
        annotation: KClass,
        element: XElement,
        property: String,
        values: List,
    ): List

    protected abstract fun getResourceValueInternal(
        annotation: KClass,
        element: XElement,
        property: String,
        value: Int
    ): ResourceValue?

    /**
     * Returns a list of layout resources whose name contains the given layout as a prefix.
     */
    fun getAlternateLayouts(layout: ResourceValue): List {
        val layoutClassName = layout.className ?: return emptyList()

        val rLayoutClassElement: XTypeElement =
            environmentProvider().requireTypeElement(layoutClassName)
        val target = layout.resourceName + "_"

        return rLayoutClassElement
            .getDeclaredFields()
            .map { it.name }
            .filter {
                it.startsWith(target)
            }
            .map {
                ResourceValue(
                    layout.className,
                    it,
                    value = 0 // Don't care about this for our use case
                )
            }
    }

    abstract fun getImports(classElement: XTypeElement): List
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy