Support JvmWildcard/JvmSuppressWildcard in ultra-light classes
The idea is reusing logic from KotlinTypeMapper for that
This commit is contained in:
@@ -1464,14 +1464,22 @@ public class KotlinTypeMapper {
|
||||
public String mapFieldSignature(@NotNull KotlinType backingFieldType, @NotNull PropertyDescriptor propertyDescriptor) {
|
||||
JvmSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.TYPE);
|
||||
|
||||
writeFieldSignature(backingFieldType, propertyDescriptor, sw);
|
||||
|
||||
return sw.makeJavaGenericSignature();
|
||||
}
|
||||
|
||||
public void writeFieldSignature(
|
||||
@NotNull KotlinType backingFieldType,
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
JvmSignatureWriter sw
|
||||
) {
|
||||
if (!propertyDescriptor.isVar()) {
|
||||
mapReturnType(propertyDescriptor, sw, backingFieldType);
|
||||
}
|
||||
else {
|
||||
writeParameterType(sw, backingFieldType, propertyDescriptor);
|
||||
}
|
||||
|
||||
return sw.makeJavaGenericSignature();
|
||||
}
|
||||
|
||||
public void writeFormalTypeParameters(@NotNull List<TypeParameterDescriptor> typeParameters, @NotNull JvmSignatureWriter sw) {
|
||||
@@ -1550,7 +1558,7 @@ public class KotlinTypeMapper {
|
||||
sw.writeParameterTypeEnd();
|
||||
}
|
||||
|
||||
private void writeParameterType(
|
||||
public void writeParameterType(
|
||||
@NotNull JvmSignatureWriter sw,
|
||||
@NotNull KotlinType type,
|
||||
@Nullable CallableDescriptor callableDescriptor
|
||||
|
||||
@@ -125,5 +125,5 @@ private fun AnnotationDescriptor?.suppressWildcardsMode(): Boolean? {
|
||||
return (this ?: return null).allValueArguments.values.firstOrNull()?.value as? Boolean ?: true
|
||||
}
|
||||
|
||||
private val JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmSuppressWildcards")
|
||||
private val JVM_WILDCARD_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmWildcard")
|
||||
val JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmSuppressWildcards")
|
||||
val JVM_WILDCARD_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmWildcard")
|
||||
|
||||
@@ -323,7 +323,7 @@ class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: Ult
|
||||
val wrapper = KtUltraLightMethod(method, ktFunction, support, this)
|
||||
addReceiverParameter(ktFunction, wrapper)
|
||||
for (parameter in ktFunction.valueParameters) {
|
||||
method.addParameter(KtUltraLightParameter(parameter.name.orEmpty(), parameter, support, wrapper, null))
|
||||
method.addParameter(KtUltraLightParameter(parameter.name.orEmpty(), parameter, support, wrapper, null, ktFunction))
|
||||
}
|
||||
val returnType: PsiType? by lazyPub {
|
||||
if (isConstructor) null
|
||||
@@ -333,11 +333,9 @@ class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: Ult
|
||||
return wrapper
|
||||
}
|
||||
|
||||
private fun addReceiverParameter(f: KtDeclaration, method: KtUltraLightMethod) {
|
||||
val receiver = (f as? KtCallableDeclaration)?.receiverTypeReference
|
||||
if (receiver != null) {
|
||||
method.delegate.addParameter(KtUltraLightParameter("\$self", f, support, method, receiver))
|
||||
}
|
||||
private fun addReceiverParameter(callable: KtCallableDeclaration, method: KtUltraLightMethod) {
|
||||
val receiver = callable.receiverTypeReference ?: return
|
||||
method.delegate.addParameter(KtUltraLightParameter("\$self", callable, support, method, receiver, callable))
|
||||
}
|
||||
|
||||
private fun methodReturnType(ktDeclaration: KtDeclaration, wrapper: KtUltraLightMethod): PsiType {
|
||||
@@ -434,7 +432,7 @@ class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: Ult
|
||||
return f.hasModifier(INTERNAL_KEYWORD)
|
||||
}
|
||||
|
||||
private fun propertyAccessors(declaration: KtNamedDeclaration, mutable: Boolean, onlyJvmStatic: Boolean): List<KtLightMethod> {
|
||||
private fun propertyAccessors(declaration: KtCallableDeclaration, mutable: Boolean, onlyJvmStatic: Boolean): List<KtLightMethod> {
|
||||
val propertyName = declaration.name
|
||||
if (declaration.hasModifier(CONST_KEYWORD) || propertyName == null) return emptyList()
|
||||
|
||||
@@ -478,7 +476,9 @@ class KtUltraLightClass(classOrObject: KtClassOrObject, private val support: Ult
|
||||
val setterWrapper = KtUltraLightMethod(setterPrototype, declaration, support, this)
|
||||
addReceiverParameter(declaration, setterWrapper)
|
||||
val parameterOrigin = ktSetter?.parameter ?: declaration
|
||||
setterPrototype.addParameter(KtUltraLightParameter(propertyName, parameterOrigin, support, setterWrapper, null))
|
||||
setterPrototype.addParameter(
|
||||
KtUltraLightParameter(propertyName, parameterOrigin, support, setterWrapper, null, declaration)
|
||||
)
|
||||
result.add(setterWrapper)
|
||||
}
|
||||
return result
|
||||
@@ -535,9 +535,14 @@ private class KtUltraLightField(
|
||||
|
||||
private val _type: PsiType by lazyPub {
|
||||
fun nonExistent() = JavaPsiFacade.getElementFactory(project).createTypeFromText("error.NonExistentClass", declaration)
|
||||
|
||||
val propertyDescriptor: PropertyDescriptor? by lazyPub {
|
||||
declaration.resolve() as? PropertyDescriptor
|
||||
}
|
||||
|
||||
when {
|
||||
declaration is KtProperty && declaration.hasDelegate() ->
|
||||
(declaration.resolve() as? PropertyDescriptor)
|
||||
propertyDescriptor
|
||||
?.let {
|
||||
val context = LightClassGenerationSupport.getInstance(project).analyze(declaration)
|
||||
PropertyCodegen.getDelegateTypeForProperty(declaration, it, context)
|
||||
@@ -548,14 +553,14 @@ private class KtUltraLightField(
|
||||
declaration is KtObjectDeclaration ->
|
||||
KtLightClassForSourceDeclaration.create(declaration)?.let { JavaPsiFacade.getElementFactory(project).createType(it) }
|
||||
?: nonExistent()
|
||||
else ->
|
||||
declaration.getKotlinType()?.let {
|
||||
val mode = when {
|
||||
(declaration.resolve() as? PropertyDescriptor)?.isVar == true -> TypeMappingMode.getOptimalModeForValueParameter(it)
|
||||
else -> TypeMappingMode.getOptimalModeForReturnType(it, false)
|
||||
}
|
||||
it.asPsiType(support, mode, this)
|
||||
} ?: PsiType.NULL
|
||||
else -> {
|
||||
val kotlinType = declaration.getKotlinType() ?: return@lazyPub PsiType.NULL
|
||||
val descriptor = propertyDescriptor ?: return@lazyPub PsiType.NULL
|
||||
|
||||
support.mapType(this) { typeMapper, sw ->
|
||||
typeMapper.writeFieldSignature(kotlinType, descriptor, sw)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -633,7 +638,8 @@ internal class KtUltraLightParameter(
|
||||
override val kotlinOrigin: KtDeclaration,
|
||||
private val support: UltraLightSupport,
|
||||
method: KtLightMethod,
|
||||
private val receiver: KtTypeReference?
|
||||
private val receiver: KtTypeReference?,
|
||||
private val containingFunction: KtCallableDeclaration
|
||||
) : org.jetbrains.kotlin.asJava.elements.LightParameter(
|
||||
name,
|
||||
PsiType.NULL,
|
||||
@@ -661,7 +667,11 @@ internal class KtUltraLightParameter(
|
||||
}
|
||||
}
|
||||
private val _type: PsiType by lazyPub {
|
||||
kotlinType?.let { it.asPsiType(support, TypeMappingMode.getOptimalModeForValueParameter(it), this) } ?: PsiType.NULL
|
||||
val kotlinType = kotlinType ?: return@lazyPub PsiType.NULL
|
||||
val containingDescriptor = containingFunction.resolve() as? CallableDescriptor ?: return@lazyPub PsiType.NULL
|
||||
support.mapType(this) { typeMapper, sw ->
|
||||
typeMapper.writeParameterType(sw, kotlinType, containingDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getType(): PsiType = _type
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
class Inv<E>
|
||||
class Out<out T>
|
||||
class OutPair<out Final, out Y>
|
||||
class In<in Z>
|
||||
|
||||
class Final
|
||||
open class Open
|
||||
|
||||
class Container {
|
||||
@JvmSuppressWildcards(true)
|
||||
fun deepOpen(x: Out<Out<Out<Open>>>) {}
|
||||
|
||||
|
||||
@JvmSuppressWildcards(false)
|
||||
fun bar(): Out<Open> = null!!
|
||||
|
||||
fun simpleOut(x: Out<@JvmWildcard Final>) {}
|
||||
fun simpleIn(x: In<@JvmWildcard Any?>) {}
|
||||
|
||||
fun falseTrueFalse(): @JvmSuppressWildcards(false) OutPair<Final, @JvmSuppressWildcards OutPair<Out<Final>, Out<@JvmSuppressWildcards(false) Final>>> = null!!
|
||||
fun combination(): @JvmSuppressWildcards OutPair<Open, @JvmWildcard OutPair<Open, @JvmWildcard Out<Open>>> = null!!
|
||||
|
||||
@JvmSuppressWildcards(false)
|
||||
fun foo(x: Boolean, y: Out<Int>): Int = 1
|
||||
|
||||
@JvmSuppressWildcards(true)
|
||||
fun bar(x: Boolean, y: In<Long>, z: @JvmSuppressWildcards(false) Long): Int = 1
|
||||
}
|
||||
|
||||
interface A<T> {
|
||||
@JvmSuppressWildcards(true)
|
||||
fun foo(): Out<T>
|
||||
}
|
||||
|
||||
interface B {
|
||||
@JvmSuppressWildcards(true)
|
||||
fun foo(): In<Open>
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
class Inv<E>
|
||||
class Out<out T>
|
||||
class OutPair<out Final, out Y>
|
||||
class In<in Z>
|
||||
|
||||
class Final
|
||||
open class Open
|
||||
|
||||
class Container {
|
||||
// The signatures are obtained from compiler/testData/writeSignature/declarationSiteVariance/wildcardOptimization
|
||||
fun openClassArgument(x: Out<Open>, y: In<Open>) {}
|
||||
fun finalClassArgument(x: Out<Final>, y: In<Final>) {}
|
||||
fun oneArgumentFinal(x: OutPair<Final, Open>) {}
|
||||
|
||||
fun arrayOfOutOpen(x: Array<Out<Open>>) {}
|
||||
fun arrayOfOutFinal(x: Array<Out<Final>>) {}
|
||||
fun outOfArrayOpen(x: Out<Array<Open>>) {}
|
||||
fun outOfArrayOutOpen(x: Out<Array<out Open>>) {}
|
||||
|
||||
fun deepOpen(x: Out<Out<Out<Open>>>) {}
|
||||
fun deepFinal(x: Out<Out<Out<Final>>>) {}
|
||||
|
||||
fun skipAllOutInvWildcards(): Inv<OutPair<Open, Out<Out<Open>>>> = null!!
|
||||
fun skipAllInvWildcards(): Inv<In<Out<Open>>> = null!!
|
||||
fun notDeepIn(): In<Final> = null!!
|
||||
fun skipWildcardsUntilIn0(): Out<In<Out<Open>>> = null!!
|
||||
fun skipWildcardsUntilIn1(): Out<In<Out<Final>>> = null!!
|
||||
fun skipWildcardsUntilIn2(): Out<In<OutPair<Final, Out<Open>>>> = null!!
|
||||
fun skipWildcardsUntilInProjection(): Inv<in Out<Open>> = null!!
|
||||
|
||||
fun outIn(x: Out<In<Final>>) {}
|
||||
fun outInAny(x: Out<In<Any?>>) {}
|
||||
|
||||
fun invInv(x: Out<Inv<Open>>) {}
|
||||
fun invOut(x: Out<Inv<out Open>>) {}
|
||||
fun invOutFinal(x: Out<Inv<out Final>>) {}
|
||||
fun invIn(x: Out<Inv<in Final>>) {}
|
||||
fun invInAny(x: Out<Inv<in Any>>) {}
|
||||
|
||||
fun inFinal(x: In<Final>) {}
|
||||
fun inAny(x: In<Any>) {}
|
||||
fun inOutFinal(x: In<Out<Final>>) {}
|
||||
|
||||
fun invOpen(x: Inv<Open>) {}
|
||||
fun invFinal(x: Inv<Final>) {}
|
||||
fun invOutOpen(x: Inv<Out<Open>>) {}
|
||||
fun invOutFinal(x: Inv<Out<Final>>) {}
|
||||
fun invInOutOpen(x: Inv<In<Out<Open>>>) {}
|
||||
fun invInOutFinal(x: Inv<In<Out<Final>>>) {}
|
||||
fun invOutProjectedOutFinal(x: Inv<out Out<Final>>) {}
|
||||
|
||||
fun <Q : Final> typeParameter(x: Out<Q>, y: In<Q>) {}
|
||||
}
|
||||
+13
-1
@@ -37,6 +37,8 @@ import org.jetbrains.kotlin.asJava.classes.lazyPub
|
||||
import org.jetbrains.kotlin.asJava.classes.shouldNotBeVisibleAsLightClass
|
||||
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
|
||||
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.state.JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.codegen.state.JVM_WILDCARD_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
@@ -52,6 +54,7 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
@@ -107,9 +110,18 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
|
||||
}
|
||||
|
||||
private fun findTooComplexDeclaration(declaration: KtDeclaration): PsiElement? {
|
||||
fun isNameOfUnsupportedJvmAnnotation(name: Name): Boolean {
|
||||
if (!name.asString().startsWith("Jvm")) return false
|
||||
if (name == JVM_STATIC_ANNOTATION_FQ_NAME.shortName()) return false
|
||||
if (name == JVM_SUPPRESS_WILDCARDS_ANNOTATION_FQ_NAME.shortName()) return false
|
||||
if (name == JVM_WILDCARD_ANNOTATION_FQ_NAME.shortName()) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun KtAnnotationEntry.seemsNonTrivial(): Boolean {
|
||||
val name = shortName
|
||||
return name == null || hasAlias(declaration, name) || name.asString().startsWith("Jvm") && name.asString() != "JvmStatic"
|
||||
return name == null || hasAlias(declaration, name) || isNameOfUnsupportedJvmAnnotation(name)
|
||||
}
|
||||
|
||||
if (declaration.hasExpectModifier() ||
|
||||
|
||||
+10
@@ -109,6 +109,11 @@ public class UltraLightClassLoadingTestGenerated extends AbstractUltraLightClass
|
||||
runTest("compiler/testData/asJava/ultraLightClasses/jvmOverloads.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmWildcardAnnotations.kt")
|
||||
public void testJvmWildcardAnnotations() throws Exception {
|
||||
runTest("compiler/testData/asJava/ultraLightClasses/jvmWildcardAnnotations.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lateinitProperty.kt")
|
||||
public void testLateinitProperty() throws Exception {
|
||||
runTest("compiler/testData/asJava/ultraLightClasses/lateinitProperty.kt");
|
||||
@@ -138,4 +143,9 @@ public class UltraLightClassLoadingTestGenerated extends AbstractUltraLightClass
|
||||
public void testTypeAliases() throws Exception {
|
||||
runTest("compiler/testData/asJava/ultraLightClasses/typeAliases.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("wildcardOptimization.kt")
|
||||
public void testWildcardOptimization() throws Exception {
|
||||
runTest("compiler/testData/asJava/ultraLightClasses/wildcardOptimization.kt");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user