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");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user