[go: nahoru, domu]

blob: eda347fab169b0ae151aeb28a51522e7a8928ae5 [file] [log] [blame]
/*
* Copyright 2021 The Android Open Source Project
*
* 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 androidx.room.compiler.processing.ksp
import androidx.room.compiler.processing.XType
import androidx.room.compiler.processing.ksp.synthetic.KspSyntheticPropertyMethodElement
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSDeclaration
import com.google.devtools.ksp.symbol.KSNode
import com.google.devtools.ksp.symbol.Origin
/**
* JvmType of a Kotlin type depends on where the type is declared.
*
* This resolver is used to resolve that type when necessary (computing TypeName).
* See [KSTypeVarianceResolver] for details.
*/
internal class KspJvmTypeResolver(
val scope: KspJvmTypeResolutionScope,
val delegate: KspType
) {
internal fun resolveJvmType(
env: KspProcessingEnv
): KspType {
if (!scope.needsWildcardResolution) {
return delegate
}
val wildcardMode = if (scope.suppressesWildcards) {
KSTypeVarianceResolver.WildcardMode.SUPPRESSED
} else {
KSTypeVarianceResolver.WildcardMode.PREFERRED
}
val declarationType = scope.findDeclarationType() as? KspType
return env.resolveWildcards(
ksType = delegate.ksType,
wildcardMode = wildcardMode,
// See KSTypeVarianceResolver#applyTypeVariance: "If the ksType is from the original
// declaration, declarationType should be null".
declarationType = if (declarationType == delegate) {
null
} else {
// use the jvm type of the declaration so that it also gets its jvm wildcards
// resolved.
declarationType?.jvmWildcardTypeOrSelf?.ksType
}
).let {
env.wrap(
ksType = it,
allowPrimitives = delegate.typeName.isPrimitive
)
}
}
}
/**
* Provides KSType resolution scope for parameter types.
*/
internal sealed class KspJvmTypeResolutionScope(
private val annotated: KSAnnotated,
private val container: KSDeclaration?
) {
/**
* Checks whether we need wildcard resolution at all. It is only necessary if either the method
* parameter is in kotlin or the containing class, which inherited the method, is in kotlin.
*/
val needsWildcardResolution: Boolean by lazy {
annotated.isInKotlinCode() || container?.isInKotlinCode() == true
}
/**
* Checks if the wildcards are suppressed by checking the hierarchy of the declaration to see if
* it has the @JvmSuppressWildcards annotation.
*/
val suppressesWildcards by lazy {
// suppress wildcards depend on the declaration site.
annotated.hasSuppressWildcardsAnnotationInHierarchy()
}
private fun KSAnnotated.isInKotlinCode(): Boolean {
// find the true origin by skipping synthetics.
var current: KSNode? = this
while (current != null) {
val origin = current.origin
if (origin != Origin.SYNTHETIC) {
return origin == Origin.KOTLIN || origin == Origin.KOTLIN_LIB
}
current = current.parent
}
return false
}
/**
* Finds the XType from the declaration if and only if this method is inherited from another
* class / interface.
*/
abstract fun findDeclarationType(): XType?
internal class MethodParameter(
private val kspExecutableElement: KspExecutableElement,
private val parameterIndex: Int,
annotated: KSAnnotated,
container: KSDeclaration?,
) : KspJvmTypeResolutionScope(annotated, container) {
override fun findDeclarationType(): XType? {
return if (kspExecutableElement is KspMethodElement) {
kspExecutableElement.executableType.parameterTypes.getOrNull(parameterIndex)
} else {
null
}
}
}
internal class PropertySetterParameter(
val declaration: KspSyntheticPropertyMethodElement
) : KspJvmTypeResolutionScope(
annotated = declaration.accessor,
container = declaration.field.enclosingElement.declaration
) {
override fun findDeclarationType(): XType? {
// We return the declaration from the setter, not the field because the setter parameter
// will have a different type in jvm (due to jvm wildcard resolution)
return declaration.field.syntheticSetter?.parameters?.firstOrNull()?.type
}
}
}