Support loading Java records
^KT-43677 In Progress
This commit is contained in:
+3
-4
@@ -23,19 +23,18 @@ import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaElement
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaField
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMember
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaElementImpl
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaFieldImpl
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaMethodImpl
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
||||
|
||||
class LazyResolveBasedCache(resolveSession: ResolveSession) : AbstractJavaResolverCache(resolveSession) {
|
||||
|
||||
override fun recordMethod(method: JavaMethod, descriptor: SimpleFunctionDescriptor) {
|
||||
BindingContextUtils.recordFunctionDeclarationToDescriptor(trace, (method as? JavaMethodImpl)?.psi ?: return, descriptor)
|
||||
override fun recordMethod(member: JavaMember, descriptor: SimpleFunctionDescriptor) {
|
||||
BindingContextUtils.recordFunctionDeclarationToDescriptor(trace, (member as? JavaElementImpl<*>)?.psi ?: return, descriptor)
|
||||
}
|
||||
|
||||
override fun recordConstructor(element: JavaElement, descriptor: ConstructorDescriptor) {
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ import org.jetbrains.kotlin.name.Name;
|
||||
@NotNull Kind kind,
|
||||
@NotNull JavaMethodDescriptor declaration
|
||||
) {
|
||||
super(containingDeclaration, original, declaration.getAnnotations(), declaration.getName(), kind, declaration.getSource());
|
||||
super(containingDeclaration, original, declaration.getAnnotations(), declaration.getName(), kind, declaration.getSource(), false);
|
||||
this.declaration = declaration;
|
||||
setParameterNamesStatus(declaration.hasStableParameterNames(), declaration.hasSynthesizedParameterNames());
|
||||
}
|
||||
|
||||
+2
-1
@@ -88,7 +88,8 @@ public class SignaturesPropagationData {
|
||||
Annotations.Companion.getEMPTY(),
|
||||
method.getName(),
|
||||
//TODO: what to do?
|
||||
SourceElement.NO_SOURCE
|
||||
SourceElement.NO_SOURCE,
|
||||
false
|
||||
);
|
||||
autoMethodDescriptor.initialize(
|
||||
null,
|
||||
|
||||
+74
-28
@@ -27,6 +27,8 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.incremental.record
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
@@ -113,20 +115,37 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
|
||||
}
|
||||
|
||||
private fun syntheticPropertyInClassNotCached(ownerClass: ClassDescriptor, name: Name): SyntheticPropertyHolder {
|
||||
val forBean = syntheticPropertyHolderForBeanConvention(name, ownerClass)
|
||||
if (forBean.descriptor != null) return forBean
|
||||
|
||||
fun result(descriptor: PropertyDescriptor?, getterNames: List<Name>, setterName: Name? = null): SyntheticPropertyHolder {
|
||||
if (lookupTracker === LookupTracker.DO_NOTHING) {
|
||||
return if (descriptor == null) SyntheticPropertyHolder.EMPTY else SyntheticPropertyHolder(descriptor, emptyList())
|
||||
}
|
||||
if (!ownerClass.isRecord()) return forBean
|
||||
|
||||
val names = ArrayList<Name>(getterNames.size + (setterName?.let { 1 } ?: 0))
|
||||
val propertyForComponent = syntheticPropertyDescriptorForRecordComponent(name, ownerClass)
|
||||
|
||||
names.addAll(getterNames)
|
||||
names.addIfNotNull(setterName)
|
||||
return createSyntheticPropertyHolder(propertyForComponent, forBean.lookedNames, name)
|
||||
}
|
||||
|
||||
return SyntheticPropertyHolder(descriptor, names)
|
||||
private fun createSyntheticPropertyHolder(
|
||||
descriptor: PropertyDescriptor?,
|
||||
lookedNames: List<Name>,
|
||||
additionalName: Name? = null
|
||||
): SyntheticPropertyHolder {
|
||||
if (lookupTracker === LookupTracker.DO_NOTHING) {
|
||||
return if (descriptor == null) SyntheticPropertyHolder.EMPTY else SyntheticPropertyHolder(descriptor, emptyList())
|
||||
}
|
||||
|
||||
val names = ArrayList<Name>(lookedNames.size + (additionalName?.let { 1 } ?: 0))
|
||||
|
||||
names.addAll(lookedNames)
|
||||
names.addIfNotNull(additionalName)
|
||||
|
||||
return SyntheticPropertyHolder(descriptor, names)
|
||||
}
|
||||
|
||||
private fun syntheticPropertyHolderForBeanConvention(
|
||||
name: Name,
|
||||
ownerClass: ClassDescriptor
|
||||
): SyntheticPropertyHolder {
|
||||
if (name.isSpecial) return SyntheticPropertyHolder.EMPTY
|
||||
|
||||
val identifier = name.identifier
|
||||
@@ -142,7 +161,7 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
|
||||
.flatMap { memberScope.getContributedFunctions(it, NoLookupLocation.FROM_SYNTHETIC_SCOPE) }
|
||||
.singleOrNull {
|
||||
it.hasJavaOriginInHierarchy() && isGoodGetMethod(it)
|
||||
} ?: return result(null, possibleGetMethodNames)
|
||||
} ?: return createSyntheticPropertyHolder(null, possibleGetMethodNames)
|
||||
|
||||
|
||||
val setMethodName = setMethodName(getMethod.name)
|
||||
@@ -152,7 +171,25 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
|
||||
val propertyType = getMethod.returnType!!
|
||||
|
||||
val descriptor = MyPropertyDescriptor.create(ownerClass, getMethod.original, setMethod?.original, name, propertyType)
|
||||
return result(descriptor, possibleGetMethodNames, setMethodName)
|
||||
return createSyntheticPropertyHolder(descriptor, possibleGetMethodNames, setMethodName)
|
||||
}
|
||||
|
||||
private fun syntheticPropertyDescriptorForRecordComponent(
|
||||
name: Name,
|
||||
ownerClass: ClassDescriptor
|
||||
): PropertyDescriptor? {
|
||||
val componentLikeMethod =
|
||||
ownerClass.unsubstitutedMemberScope
|
||||
.getContributedFunctions(name, NoLookupLocation.FROM_SYNTHETIC_SCOPE)
|
||||
.singleOrNull(this::isGoodGetMethod) ?: return null
|
||||
|
||||
if (componentLikeMethod !is JavaMethodDescriptor || !componentLikeMethod.isForRecordComponent) {
|
||||
return null
|
||||
}
|
||||
|
||||
val propertyType = componentLikeMethod.returnType!!
|
||||
|
||||
return MyPropertyDescriptor.create(ownerClass, componentLikeMethod.original, null, name, propertyType)
|
||||
}
|
||||
|
||||
private fun isGoodGetMethod(descriptor: FunctionDescriptor): Boolean {
|
||||
@@ -249,8 +286,14 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
|
||||
if (classifier is ClassDescriptor) {
|
||||
for (descriptor in classifier.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS)) {
|
||||
if (descriptor is FunctionDescriptor) {
|
||||
val propertyName = SyntheticJavaPropertyDescriptor.propertyNameByGetMethodName(descriptor.getName()) ?: continue
|
||||
addIfNotNull(syntheticPropertyInClass(Pair(classifier, propertyName)).descriptor)
|
||||
val propertyName = SyntheticJavaPropertyDescriptor.propertyNameByGetMethodName(descriptor.getName())
|
||||
if (propertyName != null) {
|
||||
addIfNotNull(syntheticPropertyInClass(Pair(classifier, propertyName)).descriptor)
|
||||
}
|
||||
|
||||
if (classifier.isRecord()) {
|
||||
addIfNotNull(syntheticPropertyInClass(Pair(classifier, descriptor.name)).descriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -258,6 +301,9 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
|
||||
}
|
||||
}
|
||||
|
||||
private fun ClassifierDescriptor.isRecord() =
|
||||
this is JavaClassDescriptor && isRecord
|
||||
|
||||
private fun SmartList<PropertyDescriptor>?.add(property: PropertyDescriptor?): SmartList<PropertyDescriptor>? {
|
||||
if (property == null) return this
|
||||
val list = if (this != null) this else SmartList()
|
||||
@@ -280,15 +326,15 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
|
||||
}
|
||||
|
||||
private class MyPropertyDescriptor(
|
||||
containingDeclaration: DeclarationDescriptor,
|
||||
original: PropertyDescriptor?,
|
||||
annotations: Annotations,
|
||||
modality: Modality,
|
||||
visibility: DescriptorVisibility,
|
||||
isVar: Boolean,
|
||||
name: Name,
|
||||
kind: CallableMemberDescriptor.Kind,
|
||||
source: SourceElement
|
||||
containingDeclaration: DeclarationDescriptor,
|
||||
original: PropertyDescriptor?,
|
||||
annotations: Annotations,
|
||||
modality: Modality,
|
||||
visibility: DescriptorVisibility,
|
||||
isVar: Boolean,
|
||||
name: Name,
|
||||
kind: CallableMemberDescriptor.Kind,
|
||||
source: SourceElement
|
||||
) : SyntheticJavaPropertyDescriptor, PropertyDescriptorImpl(
|
||||
containingDeclaration, original, annotations, modality, visibility, isVar, name, kind, source,
|
||||
/* lateInit = */ false, /* isConst = */ false, /* isExpect = */ false, /* isActual = */ false, /* isExternal = */ false,
|
||||
@@ -374,13 +420,13 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
|
||||
}
|
||||
|
||||
override fun createSubstitutedCopy(
|
||||
newOwner: DeclarationDescriptor,
|
||||
newModality: Modality,
|
||||
newVisibility: DescriptorVisibility,
|
||||
original: PropertyDescriptor?,
|
||||
kind: CallableMemberDescriptor.Kind,
|
||||
newName: Name,
|
||||
source: SourceElement
|
||||
newOwner: DeclarationDescriptor,
|
||||
newModality: Modality,
|
||||
newVisibility: DescriptorVisibility,
|
||||
original: PropertyDescriptor?,
|
||||
kind: CallableMemberDescriptor.Kind,
|
||||
newName: Name,
|
||||
source: SourceElement
|
||||
): PropertyDescriptorImpl {
|
||||
return MyPropertyDescriptor(newOwner, this, annotations, newModality, newVisibility, isVar, newName, kind, this.source).apply {
|
||||
getMethod = this@MyPropertyDescriptor.getMethod
|
||||
|
||||
+3
-3
@@ -24,12 +24,12 @@ import org.jetbrains.kotlin.load.java.components.AbstractJavaResolverCache
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaElement
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaField
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMember
|
||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
||||
|
||||
class StubJavaResolverCache(resolveSession: ResolveSession) : AbstractJavaResolverCache(resolveSession) {
|
||||
|
||||
override fun recordMethod(method: JavaMethod, descriptor: SimpleFunctionDescriptor) {}
|
||||
override fun recordMethod(member: JavaMember, descriptor: SimpleFunctionDescriptor) {}
|
||||
|
||||
override fun recordConstructor(element: JavaElement, descriptor: ConstructorDescriptor) {}
|
||||
|
||||
@@ -37,4 +37,4 @@ class StubJavaResolverCache(resolveSession: ResolveSession) : AbstractJavaResolv
|
||||
|
||||
override fun recordClass(javaClass: JavaClass, descriptor: ClassDescriptor) {}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -157,9 +157,12 @@ class MockKotlinClassifier(override val classId: ClassId,
|
||||
override val isInterface get() = shouldNotBeCalled()
|
||||
override val isAnnotationType get() = shouldNotBeCalled()
|
||||
override val isEnum get() = shouldNotBeCalled()
|
||||
override val isRecord get() = shouldNotBeCalled()
|
||||
override val methods get() = shouldNotBeCalled()
|
||||
override val fields get() = shouldNotBeCalled()
|
||||
override val constructors get() = shouldNotBeCalled()
|
||||
override val recordComponents get() = shouldNotBeCalled()
|
||||
|
||||
override fun hasDefaultConstructor() = shouldNotBeCalled()
|
||||
override val annotations get() = shouldNotBeCalled()
|
||||
override val isDeprecatedInJavaDoc get() = shouldNotBeCalled()
|
||||
|
||||
+3
@@ -65,6 +65,9 @@ class FakeSymbolBasedClass(
|
||||
|
||||
override val isEnum: Boolean get() = false
|
||||
|
||||
override val isRecord: Boolean get() = false
|
||||
|
||||
override val recordComponents: Collection<JavaRecordComponent> get() = emptyList()
|
||||
override val lightClassOriginKind: LightClassOriginKind? get() = null
|
||||
|
||||
override val methods: Collection<JavaMethod> get() = emptyList()
|
||||
|
||||
+6
@@ -133,6 +133,12 @@ class SymbolBasedClass(
|
||||
.filter { it.kind == ElementKind.CONSTRUCTOR }
|
||||
.map { SymbolBasedConstructor(it as ExecutableElement, this, javac) }
|
||||
|
||||
override val isRecord: Boolean
|
||||
get() = false
|
||||
|
||||
override val recordComponents: Collection<JavaRecordComponent>
|
||||
get() = emptyList()
|
||||
|
||||
override fun hasDefaultConstructor() = false // default constructors are explicit in symbols
|
||||
|
||||
override val innerClassNames: Collection<Name>
|
||||
|
||||
@@ -114,6 +114,10 @@ class TreeBasedClass(
|
||||
override val isEnum: Boolean
|
||||
get() = tree.modifiers.flags and Flags.ENUM.toLong() != 0L
|
||||
|
||||
// TODO: Support
|
||||
override val isRecord: Boolean
|
||||
get() = false
|
||||
|
||||
override val lightClassOriginKind: LightClassOriginKind?
|
||||
get() = null
|
||||
|
||||
@@ -134,6 +138,9 @@ class TreeBasedClass(
|
||||
TreeBasedConstructor(constructor as JCTree.JCMethodDecl, compilationUnit, this, javac)
|
||||
}
|
||||
|
||||
override val recordComponents: Collection<JavaRecordComponent>
|
||||
get() = emptyList()
|
||||
|
||||
override fun hasDefaultConstructor() = !isInterface && constructors.isEmpty()
|
||||
|
||||
override val innerClassNames: Collection<Name>
|
||||
|
||||
+10
@@ -59,6 +59,9 @@ class JavaClassImpl(psiClass: PsiClass) : JavaClassifierImpl<PsiClass>(psiClass)
|
||||
override val isEnum: Boolean
|
||||
get() = psi.isEnum
|
||||
|
||||
override val isRecord: Boolean
|
||||
get() = psi.isRecord
|
||||
|
||||
override val outerClass: JavaClassImpl?
|
||||
get() {
|
||||
val outer = psi.containingClass
|
||||
@@ -100,6 +103,13 @@ class JavaClassImpl(psiClass: PsiClass) : JavaClassifierImpl<PsiClass>(psiClass)
|
||||
return constructors(psi.constructors.filter { method -> method.isConstructor })
|
||||
}
|
||||
|
||||
override val recordComponents: Collection<JavaRecordComponent>
|
||||
get() {
|
||||
assertNotLightClass()
|
||||
|
||||
return psi.recordComponents.convert(::JavaRecordComponentImpl)
|
||||
}
|
||||
|
||||
override fun hasDefaultConstructor() = !isInterface && constructors.isEmpty()
|
||||
|
||||
override val isAbstract: Boolean
|
||||
|
||||
+2
-2
@@ -24,14 +24,14 @@ import org.jetbrains.kotlin.load.java.NULLABILITY_ANNOTATIONS
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
private inline fun <Psi, Java> Array<Psi>.convert(factory: (Psi) -> Java): List<Java> =
|
||||
inline fun <Psi, Java> Array<Psi>.convert(factory: (Psi) -> Java): List<Java> =
|
||||
when (size) {
|
||||
0 -> emptyList()
|
||||
1 -> listOf(factory(first()))
|
||||
else -> map(factory)
|
||||
}
|
||||
|
||||
private fun <Psi, Java> Collection<Psi>.convert(factory: (Psi) -> Java): List<Java> =
|
||||
fun <Psi, Java> Collection<Psi>.convert(factory: (Psi) -> Java): List<Java> =
|
||||
when (size) {
|
||||
0 -> emptyList()
|
||||
1 -> listOf(factory(first()))
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.load.java.structure.impl
|
||||
|
||||
import com.intellij.psi.PsiRecordComponent
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaRecordComponent
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaType
|
||||
|
||||
class JavaRecordComponentImpl(psiRecordComponent: PsiRecordComponent) : JavaMemberImpl<PsiRecordComponent>(psiRecordComponent), JavaRecordComponent {
|
||||
override val type: JavaType
|
||||
get() = JavaTypeImpl.create(psi.type)
|
||||
|
||||
override val isVararg: Boolean
|
||||
get() = psi.isVarArgs
|
||||
}
|
||||
+15
@@ -47,6 +47,8 @@ class BinaryJavaClass(
|
||||
override val methods = arrayListOf<JavaMethod>()
|
||||
override val fields = arrayListOf<JavaField>()
|
||||
override val constructors = arrayListOf<JavaConstructor>()
|
||||
override val recordComponents = arrayListOf<JavaRecordComponent>()
|
||||
|
||||
override fun hasDefaultConstructor() = false // never: all constructors explicit in bytecode
|
||||
|
||||
override val annotationsByFqName by buildLazyValueForMap()
|
||||
@@ -63,6 +65,9 @@ class BinaryJavaClass(
|
||||
override val isInterface get() = isSet(Opcodes.ACC_INTERFACE)
|
||||
override val isAnnotationType get() = isSet(Opcodes.ACC_ANNOTATION)
|
||||
override val isEnum get() = isSet(Opcodes.ACC_ENUM)
|
||||
|
||||
override val isRecord get() = isSet(Opcodes.ACC_RECORD)
|
||||
|
||||
override val lightClassOriginKind: LightClassOriginKind? get() = null
|
||||
|
||||
override fun isFromSourceCodeInScope(scope: SearchScope): Boolean = false
|
||||
@@ -184,6 +189,16 @@ class BinaryJavaClass(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun visitRecordComponent(name: String, descriptor: String, signature: String?): RecordComponentVisitor? {
|
||||
val type = signatureParser.parseTypeString(StringCharacterIterator(signature ?: descriptor), context)
|
||||
// TODO: Read isVararg properly
|
||||
val isVararg = false
|
||||
recordComponents.add(BinaryJavaRecordComponent(Name.identifier(name), this, type, isVararg))
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* All the int-like values (including Char/Boolean) come in visitor as Integer instances
|
||||
*/
|
||||
|
||||
+16
@@ -64,6 +64,22 @@ class BinaryJavaValueParameter(
|
||||
}
|
||||
}
|
||||
|
||||
class BinaryJavaRecordComponent(
|
||||
override val name: Name,
|
||||
override val containingClass: JavaClass,
|
||||
override val type: JavaType,
|
||||
override val isVararg: Boolean,
|
||||
) : JavaRecordComponent, BinaryJavaModifierListOwner {
|
||||
override val annotations: Collection<JavaAnnotation>
|
||||
get() = emptyList()
|
||||
|
||||
override val access: Int
|
||||
get() = 0
|
||||
|
||||
override val annotationsByFqName: Map<FqName?, JavaAnnotation>
|
||||
get() = emptyMap()
|
||||
}
|
||||
|
||||
fun isNotTopLevelClass(classContent: ByteArray): Boolean {
|
||||
var isNotTopLevelClass = false
|
||||
ClassReader(classContent).accept(
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// FILE: MyRecord.java
|
||||
public record MyRecord(int x, CharSequence y) {
|
||||
|
||||
}
|
||||
|
||||
// FILE: main.kt
|
||||
|
||||
fun foo(mr: MyRecord) {
|
||||
MyRecord(1, "")
|
||||
|
||||
mr.x()
|
||||
mr.y()
|
||||
|
||||
mr.x
|
||||
mr.y
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package
|
||||
|
||||
public fun foo(/*0*/ mr: MyRecord): kotlin.Unit
|
||||
|
||||
/*record*/ public final class MyRecord : java.lang.Record {
|
||||
public constructor MyRecord(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.CharSequence!)
|
||||
public abstract override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public abstract override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public abstract override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
/*record component*/ public open fun x(): kotlin.Int
|
||||
/*record component*/ public open fun y(): kotlin.CharSequence!
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package test
|
||||
|
||||
public final class GenericRecord</*0*/ T : kotlin.Any!, /*1*/ E : kotlin.Any!> : java.lang.Record {
|
||||
public constructor GenericRecord</*0*/ T : kotlin.Any!, /*1*/ E : kotlin.Any!>(/*0*/ x: T!, /*1*/ y: E!)
|
||||
private final val x: T!
|
||||
private final val y: E!
|
||||
public open fun x(): T!
|
||||
public open fun y(): E!
|
||||
public open fun y(/*0*/ p0: E!): E!
|
||||
public open fun z(): kotlin.Double
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package test
|
||||
|
||||
/*record*/ public final class GenericRecord</*0*/ T : kotlin.Any!, /*1*/ E : kotlin.Any!> : java.lang.Record {
|
||||
public constructor GenericRecord</*0*/ T : kotlin.Any!, /*1*/ E : kotlin.Any!>(/*0*/ x: T!, /*1*/ y: E!)
|
||||
private final val x: T!
|
||||
private final val y: E!
|
||||
/*record component*/ public open fun x(): T!
|
||||
/*record component*/ public open fun y(): E!
|
||||
public open fun y(/*0*/ p0: E!): E!
|
||||
public open fun z(): kotlin.Double
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package test;
|
||||
public record GenericRecord<T, E>(T x, E y) {
|
||||
public E y() { return y; }
|
||||
public E y(E n) { return y; }
|
||||
public double z() { return 0.0; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package test
|
||||
|
||||
/*record*/ public final class GenericRecord</*0*/ T : kotlin.Any!, /*1*/ E : kotlin.Any!> : java.lang.Record {
|
||||
public constructor GenericRecord</*0*/ T : kotlin.Any!, /*1*/ E : kotlin.Any!>(/*0*/ x: T!, /*1*/ y: E!)
|
||||
/*record component*/ public open fun x(): T!
|
||||
/*record component*/ public open fun y(): E!
|
||||
public open fun y(/*0*/ n: E!): E!
|
||||
public open fun z(): kotlin.Double
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package test
|
||||
|
||||
public final class SimpleRecord : java.lang.Record {
|
||||
public constructor SimpleRecord(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.CharSequence!)
|
||||
private final val x: kotlin.Int
|
||||
private final val y: kotlin.CharSequence!
|
||||
public open fun x(): kotlin.Int
|
||||
public open fun y(): kotlin.CharSequence!
|
||||
public open fun y(/*0*/ p0: kotlin.Int): kotlin.CharSequence!
|
||||
public open fun z(): kotlin.Double
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package test
|
||||
|
||||
/*record*/ public final class SimpleRecord : java.lang.Record {
|
||||
public constructor SimpleRecord(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.CharSequence!)
|
||||
private final val x: kotlin.Int
|
||||
private final val y: kotlin.CharSequence!
|
||||
/*record component*/ public open fun x(): kotlin.Int
|
||||
/*record component*/ public open fun y(): kotlin.CharSequence!
|
||||
public open fun y(/*0*/ p0: kotlin.Int): kotlin.CharSequence!
|
||||
public open fun z(): kotlin.Double
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package test;
|
||||
public record SimpleRecord(int x, CharSequence y) {
|
||||
public CharSequence y() { return y; }
|
||||
public CharSequence y(int n) { return y; }
|
||||
public double z() { return 0.0; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package test
|
||||
|
||||
/*record*/ public final class SimpleRecord : java.lang.Record {
|
||||
public constructor SimpleRecord(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.CharSequence!)
|
||||
/*record component*/ public open fun x(): kotlin.Int
|
||||
/*record component*/ public open fun y(): kotlin.CharSequence!
|
||||
public open fun y(/*0*/ n: kotlin.Int): kotlin.CharSequence!
|
||||
public open fun z(): kotlin.Double
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* 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 org.jetbrains.kotlin.checkers
|
||||
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
|
||||
abstract class AbstractDiagnosticsWithJdk15Test : AbstractDiagnosticsTest() {
|
||||
|
||||
override fun getTestJdkKind(files: List<TestFile>): TestJdkKind {
|
||||
return TestJdkKind.FULL_JDK_15
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.compiler
|
||||
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractLoadJava15Test : AbstractLoadJavaTest() {
|
||||
override fun getJdkKind(): TestJdkKind = TestJdkKind.FULL_JDK_15
|
||||
override fun getJdkHomeForJavac(): File = KotlinTestUtils.getJdk15Home()
|
||||
override fun getAdditionalJavacArgs(): List<String> = ADDITIONAL_JAVAC_ARGS_FOR_15
|
||||
}
|
||||
|
||||
val ADDITIONAL_JAVAC_ARGS_FOR_15 = listOf("--release", "15", "--enable-preview")
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.compiler
|
||||
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractLoadJava15WithPsiClassReadingTest : AbstractLoadJavaWithPsiClassReadingTest() {
|
||||
override fun getJdkKind(): TestJdkKind = TestJdkKind.FULL_JDK_15
|
||||
override fun getJdkHomeForJavac(): File = KotlinTestUtils.getJdk15Home()
|
||||
override fun getAdditionalJavacArgs(): List<String> = ADDITIONAL_JAVAC_ARGS_FOR_15
|
||||
}
|
||||
+24
-2
@@ -9,6 +9,7 @@ import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import junit.framework.ComparisonFailure;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult;
|
||||
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettingsKt;
|
||||
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
|
||||
@@ -299,7 +300,19 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
|
||||
Pair<PackageViewDescriptor, BindingContext> javaPackageAndContext = compileJavaAndLoadTestPackageAndBindingContextFromBinary(
|
||||
srcFiles, compiledDir, ConfigurationKind.ALL
|
||||
);
|
||||
checkJavaPackage(getExpectedFile(javaFileName.replaceFirst("\\.java$", ".txt")), javaPackageAndContext.first, javaPackageAndContext.second, configuration);
|
||||
|
||||
|
||||
|
||||
checkJavaPackage(getExpectedFile(
|
||||
useTxtSuffixIfFileExists(javaFileName.replaceFirst("\\.java$", ".txt"), "compiled")
|
||||
), javaPackageAndContext.first, javaPackageAndContext.second, configuration);
|
||||
}
|
||||
|
||||
public static String useTxtSuffixIfFileExists(String name, String suffix) {
|
||||
File differentResultFile = KotlinTestUtils.replaceExtension(new File(name), suffix + ".txt");
|
||||
if (differentResultFile.exists()) return differentResultFile.getPath();
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -308,12 +321,21 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
|
||||
@NotNull File outDir,
|
||||
@NotNull ConfigurationKind configurationKind
|
||||
) throws IOException {
|
||||
compileJavaWithAnnotationsJar(javaFiles, outDir);
|
||||
compileJavaWithAnnotationsJar(javaFiles, outDir, getAdditionalJavacArgs(), getJdkHomeForJavac());
|
||||
return loadTestPackageAndBindingContextFromJavaRoot(outDir, getTestRootDisposable(), getJdkKind(), configurationKind, true,
|
||||
usePsiClassFilesReading(), useJavacWrapper(), null,
|
||||
getExtraClasspath(), this::configureEnvironment);
|
||||
}
|
||||
|
||||
protected List<String> getAdditionalJavacArgs() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected File getJdkHomeForJavac() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void checkJavaPackage(
|
||||
File txtFile,
|
||||
PackageViewDescriptor javaPackage,
|
||||
|
||||
+14
-2
@@ -142,7 +142,12 @@ public class LoadDescriptorUtil {
|
||||
return Pair.create(packageView, analysisResult.getBindingContext());
|
||||
}
|
||||
|
||||
public static void compileJavaWithAnnotationsJar(@NotNull Collection<File> javaFiles, @NotNull File outDir) throws IOException {
|
||||
public static void compileJavaWithAnnotationsJar(
|
||||
@NotNull Collection<File> javaFiles,
|
||||
@NotNull File outDir,
|
||||
@NotNull List<String> additionalArgs,
|
||||
@Nullable File customJdkHomeForJavac
|
||||
) throws IOException {
|
||||
List<String> args = new ArrayList<>(Arrays.asList(
|
||||
"-sourcepath", "compiler/testData/loadJava/include",
|
||||
"-d", outDir.getPath())
|
||||
@@ -170,7 +175,14 @@ public class LoadDescriptorUtil {
|
||||
args.add("-classpath");
|
||||
args.add(classpath.stream().map(File::getPath).collect(Collectors.joining(File.pathSeparator)));
|
||||
|
||||
KotlinTestUtils.compileJavaFiles(javaFiles, args);
|
||||
args.addAll(additionalArgs);
|
||||
|
||||
if (customJdkHomeForJavac != null) {
|
||||
KotlinTestUtils.compileJavaFilesExternally(javaFiles, args, customJdkHomeForJavac);
|
||||
}
|
||||
else {
|
||||
KotlinTestUtils.compileJavaFiles(javaFiles, args);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -680,6 +680,10 @@ public class KotlinTestUtils {
|
||||
}
|
||||
|
||||
public static boolean compileJavaFilesExternallyWithJava9(@NotNull Collection<File> files, @NotNull List<String> options) {
|
||||
return compileJavaFilesExternally(files, options, getJdk9Home());
|
||||
}
|
||||
|
||||
public static boolean compileJavaFilesExternally(@NotNull Collection<File> files, @NotNull List<String> options, @NotNull File jdkHome) {
|
||||
List<String> command = new ArrayList<>();
|
||||
command.add(new File(jdkHome, "bin/javac").getPath());
|
||||
command.addAll(options);
|
||||
|
||||
+20
-1
@@ -27,6 +27,8 @@ import org.jetbrains.kotlin.contracts.description.*;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.SubpackagesScope;
|
||||
import org.jetbrains.kotlin.jvm.compiler.ExpectedLoadErrorsUtil;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.platform.TargetPlatformKt;
|
||||
import org.jetbrains.kotlin.renderer.*;
|
||||
@@ -193,7 +195,24 @@ public class RecursiveDescriptorComparator {
|
||||
boolean isPrimaryConstructor = conf.checkPrimaryConstructors &&
|
||||
descriptor instanceof ConstructorDescriptor && ((ConstructorDescriptor) descriptor).isPrimary();
|
||||
|
||||
printer.print(isPrimaryConstructor ? "/*primary*/ " : "", conf.renderer.render(descriptor));
|
||||
boolean isRecord = descriptor instanceof JavaClassDescriptor && ((JavaClassDescriptor) descriptor).isRecord();
|
||||
boolean isRecordComponent = descriptor instanceof JavaMethodDescriptor && ((JavaMethodDescriptor) descriptor).isForRecordComponent();
|
||||
|
||||
StringBuilder prefix = new StringBuilder();
|
||||
|
||||
if (isPrimaryConstructor) {
|
||||
prefix.append("/*primary*/ ");
|
||||
}
|
||||
|
||||
if (isRecord) {
|
||||
prefix.append("/*record*/ ");
|
||||
}
|
||||
|
||||
if (isRecordComponent) {
|
||||
prefix.append("/*record component*/ ");
|
||||
}
|
||||
|
||||
printer.print(prefix.toString(), conf.renderer.render(descriptor));
|
||||
|
||||
if (descriptor instanceof FunctionDescriptor && conf.checkFunctionContracts) {
|
||||
printEffectsIfAny((FunctionDescriptor) descriptor, printer);
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.checkers;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("compiler/testData/diagnostics/testsWithJava15")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class DiagnosticsWithJdk15TestGenerated extends AbstractDiagnosticsWithJdk15Test {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInTestsWithJava15() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJava15"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleRecords.kt")
|
||||
public void testSimpleRecords() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithJava15/simpleRecords.kt");
|
||||
}
|
||||
}
|
||||
@@ -123,6 +123,10 @@ fun main(args: Array<String>) {
|
||||
model("diagnostics/testsWithJava9")
|
||||
}
|
||||
|
||||
testClass<AbstractDiagnosticsWithJdk15Test> {
|
||||
model("diagnostics/testsWithJava15")
|
||||
}
|
||||
|
||||
testClass<AbstractDiagnosticsWithUnsignedTypes> {
|
||||
model("diagnostics/testsWithUnsignedTypes")
|
||||
}
|
||||
@@ -309,6 +313,15 @@ fun main(args: Array<String>) {
|
||||
model("loadJava/compiledJava", extension = "java", testMethod = "doTestCompiledJava")
|
||||
}
|
||||
|
||||
testClass<AbstractLoadJava15Test> {
|
||||
model("loadJava15", extension = "java", testMethod = "doTestCompiledJava", testClassName = "CompiledJava")
|
||||
model("loadJava15", extension = "java", testMethod = "doTestSourceJava", testClassName = "SourceJava")
|
||||
}
|
||||
|
||||
testClass<AbstractLoadJava15WithPsiClassReadingTest> {
|
||||
model("loadJava15", extension = "java", testMethod = "doTestCompiledJava")
|
||||
}
|
||||
|
||||
testClass<AbstractCompileJavaAgainstKotlinTest> {
|
||||
model(
|
||||
"compileJavaAgainstKotlin",
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.compiler;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class LoadJava15TestGenerated extends AbstractLoadJava15Test {
|
||||
@TestMetadata("compiler/testData/loadJava15")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class CompiledJava extends AbstractLoadJava15Test {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTestCompiledJava, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInCompiledJava() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/loadJava15"), Pattern.compile("^(.+)\\.java$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("GenericRecord.java")
|
||||
public void testGenericRecord() throws Exception {
|
||||
runTest("compiler/testData/loadJava15/GenericRecord.java");
|
||||
}
|
||||
|
||||
@TestMetadata("SimpleRecord.java")
|
||||
public void testSimpleRecord() throws Exception {
|
||||
runTest("compiler/testData/loadJava15/SimpleRecord.java");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/loadJava15")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class SourceJava extends AbstractLoadJava15Test {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTestSourceJava, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInSourceJava() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/loadJava15"), Pattern.compile("^(.+)\\.java$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("GenericRecord.java")
|
||||
public void testGenericRecord() throws Exception {
|
||||
runTest("compiler/testData/loadJava15/GenericRecord.java");
|
||||
}
|
||||
|
||||
@TestMetadata("SimpleRecord.java")
|
||||
public void testSimpleRecord() throws Exception {
|
||||
runTest("compiler/testData/loadJava15/SimpleRecord.java");
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.jvm.compiler;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("compiler/testData/loadJava15")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class LoadJava15WithPsiClassReadingTestGenerated extends AbstractLoadJava15WithPsiClassReadingTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTestCompiledJava, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInLoadJava15() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/loadJava15"), Pattern.compile("^(.+)\\.java$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("GenericRecord.java")
|
||||
public void testGenericRecord() throws Exception {
|
||||
runTest("compiler/testData/loadJava15/GenericRecord.java");
|
||||
}
|
||||
|
||||
@TestMetadata("SimpleRecord.java")
|
||||
public void testSimpleRecord() throws Exception {
|
||||
runTest("compiler/testData/loadJava15/SimpleRecord.java");
|
||||
}
|
||||
}
|
||||
@@ -85,11 +85,13 @@ interface JavaClass : JavaClassifier, JavaTypeParameterListOwner, JavaModifierLi
|
||||
val isInterface: Boolean
|
||||
val isAnnotationType: Boolean
|
||||
val isEnum: Boolean
|
||||
val isRecord: Boolean
|
||||
val lightClassOriginKind: LightClassOriginKind?
|
||||
|
||||
val methods: Collection<JavaMethod>
|
||||
val fields: Collection<JavaField>
|
||||
val constructors: Collection<JavaConstructor>
|
||||
val recordComponents: Collection<JavaRecordComponent>
|
||||
fun hasDefaultConstructor(): Boolean
|
||||
}
|
||||
|
||||
@@ -133,6 +135,11 @@ interface JavaValueParameter : JavaAnnotationOwner {
|
||||
val isVararg: Boolean
|
||||
}
|
||||
|
||||
interface JavaRecordComponent : JavaMember {
|
||||
val type: JavaType
|
||||
val isVararg: Boolean
|
||||
}
|
||||
|
||||
interface JavaTypeParameter : JavaClassifier {
|
||||
val upperBounds: Collection<JavaClassifierType>
|
||||
}
|
||||
|
||||
+4
-6
@@ -22,10 +22,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaElement;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaField;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod;
|
||||
import org.jetbrains.kotlin.load.java.structure.*;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
|
||||
public interface JavaResolverCache {
|
||||
@@ -37,7 +34,7 @@ public interface JavaResolverCache {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordMethod(@NotNull JavaMethod method, @NotNull SimpleFunctionDescriptor descriptor) {
|
||||
public void recordMethod(@NotNull JavaMember member, @NotNull SimpleFunctionDescriptor descriptor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,7 +53,8 @@ public interface JavaResolverCache {
|
||||
@Nullable
|
||||
ClassDescriptor getClassResolvedFromSource(@NotNull FqName fqName);
|
||||
|
||||
void recordMethod(@NotNull JavaMethod method, @NotNull SimpleFunctionDescriptor descriptor);
|
||||
// It's a JavaMethod or JavaRecordComponent
|
||||
void recordMethod(@NotNull JavaMember member, @NotNull SimpleFunctionDescriptor descriptor);
|
||||
|
||||
void recordConstructor(@NotNull JavaElement element, @NotNull ConstructorDescriptor descriptor);
|
||||
|
||||
|
||||
+1
@@ -19,4 +19,5 @@ package org.jetbrains.kotlin.load.java.descriptors;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
|
||||
public interface JavaClassDescriptor extends ClassDescriptor {
|
||||
boolean isRecord();
|
||||
}
|
||||
|
||||
+13
-4
@@ -60,6 +60,7 @@ public class JavaMethodDescriptor extends SimpleFunctionDescriptorImpl implement
|
||||
}
|
||||
|
||||
private ParameterNamesStatus parameterNamesStatus = null;
|
||||
private final boolean isForRecordComponent;
|
||||
|
||||
protected JavaMethodDescriptor(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@@ -67,9 +68,11 @@ public class JavaMethodDescriptor extends SimpleFunctionDescriptorImpl implement
|
||||
@NotNull Annotations annotations,
|
||||
@NotNull Name name,
|
||||
@NotNull Kind kind,
|
||||
@NotNull SourceElement source
|
||||
@NotNull SourceElement source,
|
||||
boolean isForRecordComponent
|
||||
) {
|
||||
super(containingDeclaration, original, annotations, name, kind, source);
|
||||
this.isForRecordComponent = isForRecordComponent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -77,9 +80,10 @@ public class JavaMethodDescriptor extends SimpleFunctionDescriptorImpl implement
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@NotNull Annotations annotations,
|
||||
@NotNull Name name,
|
||||
@NotNull SourceElement source
|
||||
@NotNull SourceElement source,
|
||||
boolean isForRecordComponent
|
||||
) {
|
||||
return new JavaMethodDescriptor(containingDeclaration, null, annotations, name, Kind.DECLARATION, source);
|
||||
return new JavaMethodDescriptor(containingDeclaration, null, annotations, name, Kind.DECLARATION, source, isForRecordComponent);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -118,6 +122,10 @@ public class JavaMethodDescriptor extends SimpleFunctionDescriptorImpl implement
|
||||
this.parameterNamesStatus = ParameterNamesStatus.get(hasStableParameterNames, hasSynthesizedParameterNames);
|
||||
}
|
||||
|
||||
public boolean isForRecordComponent() {
|
||||
return isForRecordComponent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected JavaMethodDescriptor createSubstitutedCopy(
|
||||
@@ -134,7 +142,8 @@ public class JavaMethodDescriptor extends SimpleFunctionDescriptorImpl implement
|
||||
annotations,
|
||||
newName != null ? newName : getName(),
|
||||
kind,
|
||||
source
|
||||
source,
|
||||
isForRecordComponent
|
||||
);
|
||||
result.setParameterNamesStatus(hasStableParameterNames(), hasSynthesizedParameterNames());
|
||||
return result;
|
||||
|
||||
+10
@@ -26,12 +26,18 @@ interface DeclaredMemberIndex {
|
||||
fun findFieldByName(name: Name): JavaField?
|
||||
fun getFieldNames(): Set<Name>
|
||||
|
||||
fun getRecordComponentNames(): Set<Name>
|
||||
fun findRecordComponentByName(name: Name): JavaRecordComponent?
|
||||
|
||||
object Empty : DeclaredMemberIndex {
|
||||
override fun findMethodsByName(name: Name) = listOf<JavaMethod>()
|
||||
override fun getMethodNames() = emptySet<Name>()
|
||||
|
||||
override fun findFieldByName(name: Name): JavaField? = null
|
||||
override fun getFieldNames() = emptySet<Name>()
|
||||
|
||||
override fun getRecordComponentNames(): Set<Name> = emptySet()
|
||||
override fun findRecordComponentByName(name: Name): JavaRecordComponent? = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,11 +51,15 @@ open class ClassDeclaredMemberIndex(
|
||||
|
||||
private val methods = jClass.methods.asSequence().filter(methodFilter).groupBy { m -> m.name }
|
||||
private val fields = jClass.fields.asSequence().filter(memberFilter).associateBy { m -> m.name }
|
||||
private val components = jClass.recordComponents.filter(memberFilter).associateBy { it.name }
|
||||
|
||||
override fun findMethodsByName(name: Name): Collection<JavaMethod> = methods[name] ?: listOf()
|
||||
override fun getMethodNames(): Set<Name> = jClass.methods.asSequence().filter(methodFilter).mapTo(mutableSetOf(), JavaMethod::name)
|
||||
|
||||
override fun findFieldByName(name: Name): JavaField? = fields[name]
|
||||
override fun getFieldNames(): Set<Name> = jClass.fields.asSequence().filter(memberFilter).mapTo(mutableSetOf(), JavaField::name)
|
||||
|
||||
override fun getRecordComponentNames(): Set<Name> = components.keys
|
||||
override fun findRecordComponentByName(name: Name): JavaRecordComponent? = components[name]
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -84,6 +84,8 @@ class LazyJavaClassDescriptor(
|
||||
override fun getKind() = kind
|
||||
override fun getModality() = modality
|
||||
|
||||
override fun isRecord(): Boolean = jClass.isRecord
|
||||
|
||||
// To workaround a problem with Scala compatibility (KT-9700),
|
||||
// we consider private visibility of a Java top level class as package private
|
||||
// Shortly: Scala plugin introduces special kind of "private in package" classes
|
||||
|
||||
+94
-5
@@ -39,10 +39,7 @@ import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.lazy.childForMethod
|
||||
import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.toAttributes
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaArrayType
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaConstructor
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaMethod
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -79,23 +76,79 @@ class LazyJavaClassMemberScope(
|
||||
it.memberScope.getFunctionNames()
|
||||
}.apply {
|
||||
addAll(declaredMemberIndex().getMethodNames())
|
||||
addAll(declaredMemberIndex().getRecordComponentNames())
|
||||
addAll(computeClassNames(kindFilter, nameFilter))
|
||||
}
|
||||
|
||||
internal val constructors = c.storageManager.createLazyValue {
|
||||
val constructors = jClass.constructors
|
||||
val result = ArrayList<JavaClassConstructorDescriptor>(constructors.size)
|
||||
val result = ArrayList<ClassConstructorDescriptor>(constructors.size)
|
||||
for (constructor in constructors) {
|
||||
val descriptor = resolveConstructor(constructor)
|
||||
result.add(descriptor)
|
||||
}
|
||||
|
||||
if (jClass.isRecord) {
|
||||
val defaultConstructor = createDefaultRecordConstructor()
|
||||
val jvmDescriptor = defaultConstructor.computeJvmDescriptor(withReturnType = false)
|
||||
|
||||
if (result.none { it.computeJvmDescriptor(withReturnType = false) == jvmDescriptor }) {
|
||||
result.add(defaultConstructor)
|
||||
c.components.javaResolverCache.recordConstructor(jClass, defaultConstructor)
|
||||
}
|
||||
}
|
||||
|
||||
c.components.signatureEnhancement.enhanceSignatures(
|
||||
c,
|
||||
result.ifEmpty { listOfNotNull(createDefaultConstructor()) }
|
||||
).toList()
|
||||
}
|
||||
|
||||
private fun createDefaultRecordConstructor(): ClassConstructorDescriptor {
|
||||
val classDescriptor = ownerDescriptor
|
||||
val constructorDescriptor = JavaClassConstructorDescriptor.createJavaConstructor(
|
||||
classDescriptor, Annotations.EMPTY, /* isPrimary = */ true, c.components.sourceElementFactory.source(jClass)
|
||||
)
|
||||
val valueParameters = createRecordConstructorParameters(constructorDescriptor)
|
||||
constructorDescriptor.setHasSynthesizedParameterNames(false)
|
||||
|
||||
constructorDescriptor.initialize(valueParameters, getConstructorVisibility(classDescriptor))
|
||||
constructorDescriptor.setHasStableParameterNames(false)
|
||||
constructorDescriptor.returnType = classDescriptor.defaultType
|
||||
return constructorDescriptor
|
||||
}
|
||||
|
||||
private fun createRecordConstructorParameters(constructor: ClassConstructorDescriptorImpl): List<ValueParameterDescriptor> {
|
||||
val components = jClass.recordComponents
|
||||
val result = ArrayList<ValueParameterDescriptor>(components.size)
|
||||
|
||||
val attr = TypeUsage.COMMON.toAttributes(isForAnnotationParameter = false)
|
||||
|
||||
for ((index, component) in components.withIndex()) {
|
||||
val parameterType = c.typeResolver.transformJavaType(component.type, attr)
|
||||
val varargElementType =
|
||||
if (component.isVararg) c.components.module.builtIns.getArrayElementType(parameterType) else null
|
||||
|
||||
result.add(
|
||||
ValueParameterDescriptorImpl(
|
||||
constructor,
|
||||
null,
|
||||
index,
|
||||
Annotations.EMPTY,
|
||||
component.name,
|
||||
parameterType,
|
||||
/* deeclaresDefaultValue = */false,
|
||||
/* isCrossinline = */ false,
|
||||
/* isNoinline = */ false,
|
||||
varargElementType,
|
||||
c.components.sourceElementFactory.source(component)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun JavaMethodDescriptor.isVisibleAsFunction(): Boolean {
|
||||
if (jClass.isAnnotationType) return false
|
||||
return isVisibleAsFunctionInCurrentClass(this)
|
||||
@@ -439,6 +492,42 @@ class LazyJavaClassMemberScope(
|
||||
}
|
||||
}
|
||||
|
||||
override fun computeImplicitlyDeclaredFunctions(result: MutableCollection<SimpleFunctionDescriptor>, name: Name) {
|
||||
if (jClass.isRecord && declaredMemberIndex().findRecordComponentByName(name) != null && result.none { it.valueParameters.isEmpty() }) {
|
||||
result.add(resolveRecordComponentToFunctionDescriptor(declaredMemberIndex().findRecordComponentByName(name)!!))
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveRecordComponentToFunctionDescriptor(recordComponent: JavaRecordComponent): JavaMethodDescriptor {
|
||||
val annotations = c.resolveAnnotations(recordComponent)
|
||||
val functionDescriptorImpl = JavaMethodDescriptor.createJavaMethod(
|
||||
ownerDescriptor, annotations, recordComponent.name, c.components.sourceElementFactory.source(recordComponent), true
|
||||
)
|
||||
|
||||
val returnTypeAttrs = TypeUsage.COMMON.toAttributes(isForAnnotationParameter = false)
|
||||
val returnType = c.typeResolver.transformJavaType(recordComponent.type, returnTypeAttrs)
|
||||
|
||||
functionDescriptorImpl.initialize(
|
||||
null,
|
||||
getDispatchReceiverParameter(),
|
||||
emptyList(),
|
||||
emptyList(),
|
||||
returnType,
|
||||
// Those functions are generated as open in bytecode
|
||||
// Actually, it should not be important because the class is final anyway, but leaving them open is convenient for consistency
|
||||
Modality.convertFromFlags(abstract = false, open = true),
|
||||
DescriptorVisibilities.PUBLIC,
|
||||
null,
|
||||
)
|
||||
|
||||
functionDescriptorImpl.setParameterNamesStatus(false, false)
|
||||
|
||||
c.components.javaResolverCache.recordMethod(recordComponent, functionDescriptorImpl)
|
||||
|
||||
return functionDescriptorImpl
|
||||
}
|
||||
|
||||
|
||||
override fun computeNonDeclaredProperties(name: Name, result: MutableCollection<PropertyDescriptor>) {
|
||||
if (jClass.isAnnotationType) {
|
||||
computeAnnotationProperties(name, result)
|
||||
|
||||
+8
-1
@@ -82,6 +82,10 @@ abstract class LazyJavaScope(
|
||||
// Fake overrides, values()/valueOf(), etc.
|
||||
protected abstract fun computeNonDeclaredFunctions(result: MutableCollection<SimpleFunctionDescriptor>, name: Name)
|
||||
|
||||
// It has a similar semantics to computeNonDeclaredFunctions, but it's being called just once per class
|
||||
// While computeNonDeclaredFunctions is being called once per scope instance (once per KotlinTypeRefiner)
|
||||
protected open fun computeImplicitlyDeclaredFunctions(result: MutableCollection<SimpleFunctionDescriptor>, name: Name) {}
|
||||
|
||||
protected abstract fun getDispatchReceiverParameter(): ReceiverParameterDescriptor?
|
||||
|
||||
private val declaredFunctions: MemoizedFunctionToNotNull<Name, Collection<SimpleFunctionDescriptor>> =
|
||||
@@ -98,6 +102,8 @@ abstract class LazyJavaScope(
|
||||
result.add(descriptor)
|
||||
}
|
||||
|
||||
computeImplicitlyDeclaredFunctions(result, name)
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
@@ -154,7 +160,8 @@ abstract class LazyJavaScope(
|
||||
protected fun resolveMethodToFunctionDescriptor(method: JavaMethod): JavaMethodDescriptor {
|
||||
val annotations = c.resolveAnnotations(method)
|
||||
val functionDescriptorImpl = JavaMethodDescriptor.createJavaMethod(
|
||||
ownerDescriptor, annotations, method.name, c.components.sourceElementFactory.source(method)
|
||||
ownerDescriptor, annotations, method.name, c.components.sourceElementFactory.source(method),
|
||||
declaredMemberIndex().findRecordComponentByName(method.name) != null && method.valueParameters.isEmpty()
|
||||
)
|
||||
|
||||
val c = c.childForMethod(functionDescriptorImpl, method)
|
||||
|
||||
+8
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.descriptors.runtime.structure
|
||||
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClassifierType
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaRecordComponent
|
||||
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -96,6 +97,9 @@ class ReflectJavaClass(
|
||||
.map(::ReflectJavaConstructor)
|
||||
.toList()
|
||||
|
||||
override val recordComponents: Collection<JavaRecordComponent>
|
||||
get() = emptyList()
|
||||
|
||||
override fun hasDefaultConstructor() = false // any default constructor is returned by constructors
|
||||
|
||||
override val lightClassOriginKind: LightClassOriginKind?
|
||||
@@ -114,6 +118,10 @@ class ReflectJavaClass(
|
||||
override val isEnum: Boolean
|
||||
get() = klass.isEnum
|
||||
|
||||
// TODO: Support reflect
|
||||
override val isRecord: Boolean
|
||||
get() = false
|
||||
|
||||
override fun equals(other: Any?) = other is ReflectJavaClass && klass == other.klass
|
||||
|
||||
override fun hashCode() = klass.hashCode()
|
||||
|
||||
+1
-1
@@ -125,7 +125,7 @@ abstract class AbstractJvmRuntimeDescriptorLoaderTest : TestCaseWithTmpdir() {
|
||||
},
|
||||
""
|
||||
)
|
||||
LoadDescriptorUtil.compileJavaWithAnnotationsJar(sources, tmpdir)
|
||||
LoadDescriptorUtil.compileJavaWithAnnotationsJar(sources, tmpdir, emptyList(), null)
|
||||
}
|
||||
fileName.endsWith(".kt") -> {
|
||||
val environment = KotlinTestUtils.createEnvironmentWithJdkAndNullabilityAnnotationsFromIdea(
|
||||
|
||||
Reference in New Issue
Block a user