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

se.ansman.dagger.auto.compiler.common.ksp.KSAnnotations.kt Maven / Gradle / Ivy

package se.ansman.dagger.auto.compiler.common.ksp

import com.google.devtools.ksp.isDefault
import com.google.devtools.ksp.symbol.ClassKind
import com.google.devtools.ksp.symbol.KSAnnotation
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSName
import com.google.devtools.ksp.symbol.KSType
import com.squareup.kotlinpoet.AnnotationSpec
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.ksp.toClassName
import se.ansman.dagger.auto.compiler.common.applyEachIndexed
import se.ansman.dagger.auto.compiler.common.ksp.processing.unwrapTypeAlias
import java.util.Locale

/**
 * A version of `toAnnotationSpec` that fixes char arguments.
 *
 * Can be removed in favor for `toAnnotationSpec` after 1.12
 */
fun KSAnnotation.toAnnotationSpecFixed(): AnnotationSpec =
    AnnotationSpec
        .builder(annotationType.resolve().unwrapTypeAlias().toClassName())
        .applyEachIndexed(arguments) { i, argument ->
            if (argument.isDefault()) {
                return@applyEachIndexed
            }
            addMember(
                CodeBlock.builder()
                    .apply {
                        val name = argument.name!!.getShortName()
                        if (i > 0 || name != "value") {
                            add("%N = ", name)
                        }
                    }
                    .addAnnotationValue(argument.value!!)
                    .build()
            )
        }
        .build()

private fun CodeBlock.Builder.addAnnotationValue(value: Any): CodeBlock.Builder =
    when (value) {
        is List<*> -> {
            add("[")
            value.forEachIndexed { index, innerValue ->
                if (index > 0) add(", ")
                addAnnotationValue(innerValue!!)
            }
            add("]")
        }

        is KSType -> {
            val unwrapped = value.unwrapTypeAlias()
            if ((unwrapped.declaration as KSClassDeclaration).classKind == ClassKind.ENUM_ENTRY) {
                val parent = unwrapped.declaration.parentDeclaration as KSClassDeclaration
                val entry = unwrapped.declaration.simpleName.getShortName()
                add("%T.%L", parent.toClassName(), entry)
            } else {
                add("%T::class", unwrapped.toClassName())
            }
        }

        is KSName -> add("%T.%L", ClassName.bestGuess(value.getQualifier()), value.getShortName())
        is KSAnnotation -> add("%L", value.toAnnotationSpecFixed())
        else -> add(memberForValue(value))
    }

private fun memberForValue(value: Any) = when (value) {
    is Class<*> -> CodeBlock.of("%T::class", value)
    is Enum<*> -> CodeBlock.of("%T.%L", value.javaClass, value.name)
    is String -> CodeBlock.of("%S", value)
    is Char -> CodeBlock.of("'%L'", value.literalWithoutSingleQuotes())
    is Float -> CodeBlock.of("%Lf", value)
    else -> CodeBlock.of("%L", value)
}

private fun Char.literalWithoutSingleQuotes(): String =
    when (this) {
        '\b' -> "\\b" /* \u0008: backspace (BS) */
        '\t' -> "\\t" /* \u0009: horizontal tab (HT) */
        '\n' -> "\\n" /* \u000a: linefeed (LF) */
        '\u000c' -> "\\u000c" /* \u000c: form feed (FF) */
        '\r' -> "\\r" /* \u000d: carriage return (CR) */
        '\'' -> "\\'" /* \u0027: single quote (') */
        '\\' -> "\\\\" /* \u005c: backslash (\) */
        else -> if (isISOControl()) String.format(Locale.ROOT, "\\u%04x", code) else toString()
    }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy