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

tagan.lang-ksp.1.5.1.source-code.kspUtils.kt Maven / Gradle / Ivy

Go to download

Yatagan is a Dependency Injection framework, specializing on runtime performance and build speed. Supports code generation (apt/kapt/ksp) or reflection.

The newest version!
/*
 * Copyright 2022 Yandex LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.yandex.yatagan.lang.ksp

import com.google.devtools.ksp.getDeclaredFunctions
import com.google.devtools.ksp.getVisibility
import com.google.devtools.ksp.isConstructor
import com.google.devtools.ksp.isPrivate
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.symbol.ClassKind
import com.google.devtools.ksp.symbol.FunctionKind
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSAnnotation
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSDeclaration
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.google.devtools.ksp.symbol.KSName
import com.google.devtools.ksp.symbol.KSNode
import com.google.devtools.ksp.symbol.KSPropertyDeclaration
import com.google.devtools.ksp.symbol.KSType
import com.google.devtools.ksp.symbol.KSTypeAlias
import com.google.devtools.ksp.symbol.Modifier
import com.google.devtools.ksp.symbol.Origin
import com.google.devtools.ksp.symbol.Visibility
import com.yandex.yatagan.lang.Parameter


internal fun  KSAnnotation.hasType(clazz: Class): Boolean {
    return shortName.getShortName() == clazz.simpleName &&
            annotationType.resolve().declaration.qualifiedName?.asString() ==
            clazz.canonicalName
}

internal operator fun KSAnnotation.get(name: String): Any? {
    return arguments.find { (it.name?.asString() ?: "value") == name }?.value
}

internal inline fun  KSAnnotated.isAnnotationPresent(): Boolean =
    isAnnotationPresent(T::class.java)

internal fun  KSAnnotated.isAnnotationPresent(clazz: Class): Boolean =
    annotations.any { it.hasType(clazz) }

internal fun KSPropertyDeclaration.isKotlinFieldInObject(): Boolean {
    return Modifier.CONST in modifiers || isAnnotationPresent()
}

internal fun KSPropertyDeclaration.isLateInit(): Boolean {
    return Modifier.LATEINIT in modifiers
}

internal fun KSDeclaration.isPublicOrInternal() = when (getVisibility()) {
    Visibility.PUBLIC, Visibility.INTERNAL -> true
    else -> false
}

internal val KSNode.isFromJava
    get() = when (origin) {
        Origin.JAVA, Origin.JAVA_LIB -> true
        else -> false
    }

internal val KSNode.isFromKotlin
    get() = when (origin) {
        Origin.KOTLIN, Origin.KOTLIN_LIB -> true
        else -> false
    }

internal fun KSType.resolveAliasIfNeeded(): KSType = when (val declaration = declaration) {
    is KSTypeAlias -> declaration.type.resolve().resolveAliasIfNeeded()
    else -> this
}

internal fun KSType.classDeclaration(): KSClassDeclaration? = when (val declaration = declaration) {
    is KSTypeAlias -> declaration.type.resolve().classDeclaration()
    else -> declaration as? KSClassDeclaration
}

internal fun KSType.isRaw(): Boolean {
    return Utils.resolver.isJavaRawType(this)
}

internal fun KSClassDeclaration.getCompanionObject(): KSClassDeclaration? =
    declarations.filterIsInstance().find(KSClassDeclaration::isCompanionObject)

private fun KSFunctionDeclaration.isFromObject(): Boolean = when(simpleName.asString()) {
    "clone" -> Utils.resolver.mapToJvmSignature(this) == "()Ljava/lang/Object;"
    "equals" -> Utils.resolver.mapToJvmSignature(this) == "(Ljava/lang/Object;)Z"
    "finalize" -> Utils.resolver.mapToJvmSignature(this) == "()V"
    "getClass" -> Utils.resolver.mapToJvmSignature(this) == "()Ljava/lang/Class;"
    "hashCode" -> Utils.resolver.mapToJvmSignature(this) == "()I"
    "notify" -> Utils.resolver.mapToJvmSignature(this) == "()V"
    "notifyAll" -> Utils.resolver.mapToJvmSignature(this) == "()V"
    "toString" -> Utils.resolver.mapToJvmSignature(this) == "()Ljava/lang/String;"
    "wait" -> when(Utils.resolver.mapToJvmSignature(this)) {
       "()V", "(J)V", "(JI)V" -> true
       else -> false
    }
    else -> false
}

internal fun KSClassDeclaration.allNonPrivateFunctions(): Sequence =
    getAllFunctions()
        .filter {
            !it.isConstructor() && !it.isPrivate() && !it.isFromObject()
        } + getDeclaredFunctions().filter {
        // Include static functions.
        it.functionKind == FunctionKind.STATIC && !it.isPrivate()
    }

internal fun KSClassDeclaration.allNonPrivateProperties(): Sequence {
    return getAllProperties().filter { !it.isPrivate() && !it.isKotlinFieldInObject() }
}

internal fun KSClassDeclaration.getSuperclass(): KSType? {
    return superTypes
        .map { it.resolve().resolveAliasIfNeeded() }
        .find { (it.declaration as? KSClassDeclaration)?.classKind == ClassKind.CLASS }
}

internal fun parametersSequenceFor(
    declaration: KSFunctionDeclaration,
    jvmMethodSignature: JvmMethodSignature,
    containing: KSType?,
) = sequence {
    val parameters = declaration.parameters
    val types = containing?.let { declaration.asMemberOf(it).parameterTypes }
    for (i in parameters.indices) {
        val parameter = parameters[i]
        yield(
            KspParameterImpl(
                impl = parameter,
                jvmSignatureSupplier = { jvmMethodSignature.parameterTypesSignatures?.get(i) },
                refinedTypeRef = parameter.type.run {
                    types?.get(i)?.let { replaceType(it) } ?: this
                },
            )
        )
    }
}

internal fun Resolver.getKotlinClassByName(qualifiedName: KSName, forceMutable: Boolean): KSClassDeclaration? {
    // TODO: Remove this workaround when this is available in the public api.
    // https://github.com/google/ksp/pull/1201
    var name = mapJavaNameToKotlin(qualifiedName) ?: qualifiedName
    if (forceMutable) {
        val mutable = mapKotlinClassMutabilityMapping(name.asString())
        if (mutable != null) {
            name = getKSNameFromString(mutable)
        }
    }
    return getClassDeclarationByName(name)
}

private fun mapKotlinClassMutabilityMapping(maybeReadOnly: String) = when(maybeReadOnly) {
    // based on info from `org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap`.
    "kotlin.collections.Iterable" -> "kotlin.collections.MutableIterable"
    "kotlin.collections.Iterator" -> "kotlin.collections.MutableIterator"
    "kotlin.collections.Collection" -> "kotlin.collections.MutableCollection"
    "kotlin.collections.List" -> "kotlin.collections.MutableList"
    "kotlin.collections.Set" -> "kotlin.collections.MutableSet"
    "kotlin.collections.ListIterator" -> "kotlin.collections.MutableListIterator"
    "kotlin.collections.Map" -> "kotlin.collections.MutableMap"
    "kotlin.collections.Map.Entry" -> "kotlin.collections.MutableMap.MutableEntry"
    else -> null
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy