Open ShawxingKwok opened 2 years ago
For example
abstract class Bar{
abstract fun foo()
}
Class Bar and function Bar::foo are both open in Ksp, but not in Kotlin reflection. I think Ksp had better keep the same with Kotlin reflection library on this feature.
sealed class / interface should be also abstract.
Here is my modification.
private val cache = ImmutableKSDeclarationInfoCache<Modifier>(false, false)
public val KSDeclaration.status: Modifier get() = cache.getOrPut {
when {
// consider that bug first: modifiers in the java @interface declaration contain ABSTRACT
this is KSClassDeclaration && classKind == ClassKind.ANNOTATION_CLASS -> Modifier.FINAL
// return directly if its modifiers contain any key modifier
Modifier.FINAL in modifiers || Modifier.JAVA_STATIC in modifiers -> Modifier.FINAL
Modifier.OPEN in modifiers || Modifier.JAVA_DEFAULT in modifiers -> Modifier.OPEN
Modifier.SEALED in modifiers || Modifier.ABSTRACT in modifiers -> Modifier.ABSTRACT
// situations below are property or function with no FINAL, OPEN or ABSTRACT
this is KSClassDeclaration ->
when (classKind) {
ClassKind.INTERFACE -> Modifier.ABSTRACT
ClassKind.CLASS ->
// default kotlin class
if (origin == Origin.KOTLIN || origin == Origin.KOTLIN_LIB)
Modifier.FINAL
else // default java class
Modifier.OPEN
// object, annotation, enum
else -> Modifier.FINAL
}
// this is property or function
else -> {
val parentKlass = parentDeclaration as? KSClassDeclaration
when (parentKlass?.classKind) {
// on top level
null -> Modifier.FINAL
ClassKind.INTERFACE -> when (this) {
// constant in java interface was considered above
// and here is from only kotlin
is KSPropertyDeclaration ->
if (Modifier.ABSTRACT in getter!!.modifiers)
Modifier.ABSTRACT
else
Modifier.OPEN
is KSFunctionDeclaration ->
// 'isAbstract' is realized in KSFunctionDeclarationImpl, but that part calls
// an internal function ktFunction.hasBody and can't be taken here.
if (isAbstract) Modifier.ABSTRACT
else Modifier.OPEN
else -> unexpectedError()
}
ClassKind.CLASS -> when {
parentKlass.status == Modifier.FINAL -> Modifier.FINAL
// situations below are in open or abstract class
// default kotlin property or function
origin == Origin.KOTLIN_LIB || origin == Origin.KOTLIN ->
if (Modifier.OVERRIDE in modifiers)
Modifier.OPEN
else
Modifier.FINAL
// java property
this is KSPropertyDeclaration -> Modifier.FINAL
// default java function
this is KSFunctionDeclaration -> Modifier.OPEN
else -> unexpectedError()
}
// in an object, annotation, or enum class
else -> Modifier.FINAL
}
}
}
}
private fun KSDeclaration._isMyOpen() = status == Modifier.OPEN
private fun KSDeclaration._isMyAbstract() = status == Modifier.ABSTRACT
private fun KSDeclaration._isFinal() = status == Modifier.FINAL
public fun KSClassDeclaration.isMyOpen(): Boolean = _isMyOpen()
public fun KSClassDeclaration.isMyAbstract(): Boolean = _isMyAbstract()
public fun KSClassDeclaration.isFinal(): Boolean = _isFinal()
public fun KSPropertyDeclaration.isMyOpen(): Boolean = _isMyOpen()
public fun KSPropertyDeclaration.isMyAbstract(): Boolean = _isMyAbstract()
public fun KSPropertyDeclaration.isFinal(): Boolean = _isFinal()
public fun KSFunctionDeclaration.isMyOpen(): Boolean = _isMyOpen()
public fun KSFunctionDeclaration.isMyAbstract(): Boolean = _isMyAbstract()
public fun KSFunctionDeclaration.isFinal(): Boolean = _isFinal()
And you can refer to my cache class.
/**
* Caches immutable KSDeclaration info of type [T] which is same in the same site. Local declarations
* themselves would be used as keys and cleared every round, but qualified names of others would be
* used as keys, which is, therefore, much more efficient.
* @param concurrent if enabled, the cache work would be synchronized, which is generally for
* complicated work.
* @param nullable if the result is nullable
*/
public class ImmutableKSDeclarationInfoCache<T>(
private val concurrent: Boolean,
private val nullable: Boolean
) {
private val unregisteredCache: MutableMap<Any, T> = mutableMapOf()
// saves local info and is cleared every round.
private val registeredCache: MutableMap<Any, T> = mutableMapOf<Any, T>().alsoRegister()
private val lock = object {}
context (KSDeclaration)
@Suppress("UNCHECKED_CAST")
public fun getOrPut(defaultValue: ()->T): T {
val (cache, key) =
when(val qualifiedName = qualifiedName?.asString()){
null -> registeredCache to this
else -> unregisteredCache to qualifiedName
}
fun getValue(): T = when{
!nullable -> cache.getOrPut(key, defaultValue)
key in cache -> cache[key] as T
else -> defaultValue().also{ cache[key] = it }
}
if (concurrent)
return synchronized(lock, ::getValue)
else
return getValue()
}
}
can you elaborate on the request?