Correct descriptor shape for @JvmRecord annotated classes
This commit adds relevant functions: hashCode, toString, equals (if the class is not a data class) And supertype j.l.Record It only affects descriptor contents, i.e. works for FE ^KT-43677 In Progress
This commit is contained in:
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.resolve.jvm
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.AdditionalClassPartsProvider
|
||||
import org.jetbrains.kotlin.resolve.FunctionsFromAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.isJvmRecord
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class JvmAdditionalClassPartsProvider : AdditionalClassPartsProvider {
|
||||
override fun generateAdditionalMethods(
|
||||
thisDescriptor: ClassDescriptor,
|
||||
result: MutableCollection<SimpleFunctionDescriptor>,
|
||||
name: Name,
|
||||
location: LookupLocation,
|
||||
fromSupertypes: Collection<SimpleFunctionDescriptor>
|
||||
) {
|
||||
if (thisDescriptor.isJvmRecord()) {
|
||||
FunctionsFromAny.addFunctionFromAnyIfNeeded(thisDescriptor, result, name, fromSupertypes)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAdditionalSupertypes(
|
||||
thisDescriptor: ClassDescriptor,
|
||||
existingSupertypes: List<KotlinType>
|
||||
): List<KotlinType> {
|
||||
if (thisDescriptor.isJvmRecord() && existingSupertypes.none(::isJavaLangRecordType)) {
|
||||
thisDescriptor.module.resolveTopLevelClass(JAVA_LANG_RECORD_FQ_NAME, NoLookupLocation.FOR_DEFAULT_IMPORTS)?.defaultType?.let {
|
||||
return listOf(it)
|
||||
}
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isJavaLangRecordType(it: KotlinType) =
|
||||
KotlinBuiltIns.isConstructedFromGivenClass(it, JAVA_LANG_RECORD_FQ_NAME)
|
||||
+1
@@ -110,6 +110,7 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase(
|
||||
container.useImpl<JvmPlatformOverloadsSpecificityComparator>()
|
||||
container.useImpl<JvmDefaultSuperCallChecker>()
|
||||
container.useImpl<JvmSamConversionOracle>()
|
||||
container.useImpl<JvmAdditionalClassPartsProvider>()
|
||||
container.useInstance(FunctionWithBigAritySupport.LanguageVersionDependent)
|
||||
container.useInstance(GenericArrayClassLiteralSupport.Enabled)
|
||||
container.useInstance(JavaActualAnnotationArgumentExtractor())
|
||||
|
||||
@@ -92,6 +92,7 @@ public class DescriptorResolver {
|
||||
private final DeclarationReturnTypeSanitizer declarationReturnTypeSanitizer;
|
||||
private final DataFlowValueFactory dataFlowValueFactory;
|
||||
private final Iterable<DeclarationSignatureAnonymousTypeTransformer> anonymousTypeTransformers;
|
||||
private final AdditionalClassPartsProvider additionalClassPartsProvider;
|
||||
|
||||
public DescriptorResolver(
|
||||
@NotNull AnnotationResolver annotationResolver,
|
||||
@@ -111,7 +112,8 @@ public class DescriptorResolver {
|
||||
@NotNull TypeApproximator approximator,
|
||||
@NotNull DeclarationReturnTypeSanitizer declarationReturnTypeSanitizer,
|
||||
@NotNull DataFlowValueFactory dataFlowValueFactory,
|
||||
@NotNull Iterable<DeclarationSignatureAnonymousTypeTransformer> anonymousTypeTransformers
|
||||
@NotNull Iterable<DeclarationSignatureAnonymousTypeTransformer> anonymousTypeTransformers,
|
||||
@NotNull AdditionalClassPartsProvider additionalClassPartsProvider
|
||||
) {
|
||||
this.annotationResolver = annotationResolver;
|
||||
this.builtIns = builtIns;
|
||||
@@ -131,6 +133,7 @@ public class DescriptorResolver {
|
||||
this.declarationReturnTypeSanitizer = declarationReturnTypeSanitizer;
|
||||
this.dataFlowValueFactory = dataFlowValueFactory;
|
||||
this.anonymousTypeTransformers = anonymousTypeTransformers;
|
||||
this.additionalClassPartsProvider = additionalClassPartsProvider;
|
||||
}
|
||||
|
||||
public List<KotlinType> resolveSupertypes(
|
||||
@@ -156,6 +159,7 @@ public class DescriptorResolver {
|
||||
}
|
||||
|
||||
syntheticResolveExtension.addSyntheticSupertypes(classDescriptor, supertypes);
|
||||
supertypes.addAll(additionalClassPartsProvider.getAdditionalSupertypes(classDescriptor, supertypes));
|
||||
|
||||
if (supertypes.isEmpty()) {
|
||||
addValidSupertype(supertypes, getDefaultSupertype(classDescriptor));
|
||||
|
||||
@@ -19,10 +19,29 @@ object FunctionsFromAny {
|
||||
val HASH_CODE_METHOD_NAME = Name.identifier("hashCode")
|
||||
val TO_STRING_METHOD_NAME = Name.identifier("toString")
|
||||
|
||||
fun addFunctionFromAnyIfNeeded(
|
||||
thisDescriptor: ClassDescriptor,
|
||||
result: MutableCollection<SimpleFunctionDescriptor>,
|
||||
name: Name,
|
||||
fromSupertypes: Collection<SimpleFunctionDescriptor>,
|
||||
) {
|
||||
if (shouldAddEquals(name, result, fromSupertypes)) {
|
||||
result.add(createEqualsFunctionDescriptor(thisDescriptor))
|
||||
}
|
||||
|
||||
if (shouldAddHashCode(name, result, fromSupertypes)) {
|
||||
result.add(createHashCodeFunctionDescriptor(thisDescriptor))
|
||||
}
|
||||
|
||||
if (shouldAddToString(name, result, fromSupertypes)) {
|
||||
result.add(createToStringFunctionDescriptor(thisDescriptor))
|
||||
}
|
||||
}
|
||||
|
||||
fun shouldAddEquals(
|
||||
name: Name,
|
||||
declaredFunctions: Collection<SimpleFunctionDescriptor>,
|
||||
fromSupertypes: List<SimpleFunctionDescriptor>
|
||||
fromSupertypes: Collection<SimpleFunctionDescriptor>
|
||||
): Boolean {
|
||||
return name == EQUALS_METHOD_NAME && shouldAddFunctionFromAny(
|
||||
declaredFunctions,
|
||||
@@ -36,7 +55,7 @@ object FunctionsFromAny {
|
||||
fun shouldAddHashCode(
|
||||
name: Name,
|
||||
declaredFunctions: Collection<SimpleFunctionDescriptor>,
|
||||
fromSupertypes: List<SimpleFunctionDescriptor>
|
||||
fromSupertypes: Collection<SimpleFunctionDescriptor>
|
||||
): Boolean {
|
||||
return name == HASH_CODE_METHOD_NAME && shouldAddFunctionFromAny(
|
||||
declaredFunctions,
|
||||
@@ -49,7 +68,7 @@ object FunctionsFromAny {
|
||||
fun shouldAddToString(
|
||||
name: Name,
|
||||
declaredFunctions: Collection<SimpleFunctionDescriptor>,
|
||||
fromSupertypes: List<SimpleFunctionDescriptor>
|
||||
fromSupertypes: Collection<SimpleFunctionDescriptor>
|
||||
): Boolean {
|
||||
return name == TO_STRING_METHOD_NAME && shouldAddFunctionFromAny(
|
||||
declaredFunctions,
|
||||
@@ -90,8 +109,8 @@ object FunctionsFromAny {
|
||||
}
|
||||
|
||||
private fun shouldAddFunctionFromAny(
|
||||
declaredFunctions: Collection <SimpleFunctionDescriptor>,
|
||||
fromSupertypes: List<SimpleFunctionDescriptor>,
|
||||
declaredFunctions: Collection<SimpleFunctionDescriptor>,
|
||||
fromSupertypes: Collection<SimpleFunctionDescriptor>,
|
||||
checkParameters: (FunctionDescriptor) -> Boolean
|
||||
): Boolean {
|
||||
// Add 'equals', 'hashCode', 'toString' iff there is no such declared member AND there is no such final member in supertypes
|
||||
|
||||
@@ -47,4 +47,5 @@ interface LazyClassContext {
|
||||
val wrappedTypeFactory: WrappedTypeFactory
|
||||
val kotlinTypeChecker: NewKotlinTypeChecker
|
||||
val samConversionResolver: SamConversionResolver
|
||||
val additionalClassPartsProvider: AdditionalClassPartsProvider
|
||||
}
|
||||
|
||||
@@ -86,6 +86,8 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext {
|
||||
private PlatformDiagnosticSuppressor platformDiagnosticSuppressor;
|
||||
private SamConversionResolver samConversionResolver;
|
||||
|
||||
private AdditionalClassPartsProvider additionalClassPartsProvider;
|
||||
|
||||
private final SyntheticResolveExtension syntheticResolveExtension;
|
||||
|
||||
private final NewKotlinTypeChecker kotlinTypeChecker;
|
||||
@@ -157,6 +159,11 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext {
|
||||
this.samConversionResolver = samConversionResolver;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setAdditionalClassPartsProvider(@NotNull AdditionalClassPartsProvider additionalClassPartsProvider) {
|
||||
this.additionalClassPartsProvider = additionalClassPartsProvider;
|
||||
}
|
||||
|
||||
// Only calls from injectors expected
|
||||
@Deprecated
|
||||
public ResolveSession(
|
||||
@@ -500,4 +507,10 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext {
|
||||
public SamConversionResolver getSamConversionResolver() {
|
||||
return samConversionResolver;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AdditionalClassPartsProvider getAdditionalClassPartsProvider() {
|
||||
return additionalClassPartsProvider;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-20
@@ -250,6 +250,9 @@ open class LazyClassMemberScope(
|
||||
generateDataClassMethods(result, name, location, fromSupertypes)
|
||||
generateFunctionsFromAnyForInlineClass(result, name, fromSupertypes)
|
||||
c.syntheticResolveExtension.generateSyntheticMethods(thisDescriptor, name, trace.bindingContext, fromSupertypes, result)
|
||||
|
||||
c.additionalClassPartsProvider.generateAdditionalMethods(thisDescriptor, result, name, location, fromSupertypes)
|
||||
|
||||
generateFakeOverrides(name, fromSupertypes, result, SimpleFunctionDescriptor::class.java)
|
||||
}
|
||||
|
||||
@@ -259,7 +262,7 @@ open class LazyClassMemberScope(
|
||||
fromSupertypes: List<SimpleFunctionDescriptor>
|
||||
) {
|
||||
if (!thisDescriptor.isInlineClass()) return
|
||||
addFunctionFromAnyIfNeeded(result, name, fromSupertypes)
|
||||
FunctionsFromAny.addFunctionFromAnyIfNeeded(thisDescriptor, result, name, fromSupertypes)
|
||||
}
|
||||
|
||||
private fun generateDataClassMethods(
|
||||
@@ -309,25 +312,7 @@ open class LazyClassMemberScope(
|
||||
}
|
||||
|
||||
if (c.languageVersionSettings.supportsFeature(LanguageFeature.DataClassInheritance)) {
|
||||
addFunctionFromAnyIfNeeded(result, name, fromSupertypes)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addFunctionFromAnyIfNeeded(
|
||||
result: MutableCollection<SimpleFunctionDescriptor>,
|
||||
name: Name,
|
||||
fromSupertypes: List<SimpleFunctionDescriptor>
|
||||
) {
|
||||
if (FunctionsFromAny.shouldAddEquals(name, result, fromSupertypes)) {
|
||||
result.add(FunctionsFromAny.createEqualsFunctionDescriptor(thisDescriptor))
|
||||
}
|
||||
|
||||
if (FunctionsFromAny.shouldAddHashCode(name, result, fromSupertypes)) {
|
||||
result.add(FunctionsFromAny.createHashCodeFunctionDescriptor(thisDescriptor))
|
||||
}
|
||||
|
||||
if (FunctionsFromAny.shouldAddToString(name, result, fromSupertypes)) {
|
||||
result.add(FunctionsFromAny.createToStringFunctionDescriptor(thisDescriptor))
|
||||
FunctionsFromAny.addFunctionFromAnyIfNeeded(thisDescriptor, result, name, fromSupertypes)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-3
@@ -69,7 +69,8 @@ class LocalClassifierAnalyzer(
|
||||
private val delegationFilter: DelegationFilter,
|
||||
private val wrappedTypeFactory: WrappedTypeFactory,
|
||||
private val kotlinTypeChecker: NewKotlinTypeChecker,
|
||||
private val samConversionResolver: SamConversionResolver
|
||||
private val samConversionResolver: SamConversionResolver,
|
||||
private val additionalClassPartsProvider: AdditionalClassPartsProvider,
|
||||
) {
|
||||
fun processClassOrObject(
|
||||
scope: LexicalWritableScope?,
|
||||
@@ -104,7 +105,8 @@ class LocalClassifierAnalyzer(
|
||||
delegationFilter,
|
||||
wrappedTypeFactory,
|
||||
kotlinTypeChecker,
|
||||
samConversionResolver
|
||||
samConversionResolver,
|
||||
additionalClassPartsProvider,
|
||||
),
|
||||
analyzerServices
|
||||
)
|
||||
@@ -134,7 +136,8 @@ class LocalClassDescriptorHolder(
|
||||
val delegationFilter: DelegationFilter,
|
||||
val wrappedTypeFactory: WrappedTypeFactory,
|
||||
val kotlinTypeChecker: NewKotlinTypeChecker,
|
||||
val samConversionResolver: SamConversionResolver
|
||||
val samConversionResolver: SamConversionResolver,
|
||||
val additionalClassPartsProvider: AdditionalClassPartsProvider,
|
||||
) {
|
||||
// We do not need to synchronize here, because this code is used strictly from one thread
|
||||
private var classDescriptor: ClassDescriptor? = null
|
||||
@@ -176,6 +179,8 @@ class LocalClassDescriptorHolder(
|
||||
override val wrappedTypeFactory: WrappedTypeFactory = this@LocalClassDescriptorHolder.wrappedTypeFactory
|
||||
override val kotlinTypeChecker: NewKotlinTypeChecker = this@LocalClassDescriptorHolder.kotlinTypeChecker
|
||||
override val samConversionResolver: SamConversionResolver = this@LocalClassDescriptorHolder.samConversionResolver
|
||||
override val additionalClassPartsProvider: AdditionalClassPartsProvider =
|
||||
this@LocalClassDescriptorHolder.additionalClassPartsProvider
|
||||
},
|
||||
containingDeclaration,
|
||||
classOrObject.nameAsSafeName,
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// !LANGUAGE: +JvmRecordSupport
|
||||
|
||||
@JvmRecord
|
||||
class BasicRecord(val x: String)
|
||||
|
||||
@JvmRecord
|
||||
data class BasicDataRecord(val x: String)
|
||||
|
||||
@JvmRecord
|
||||
class BasicRecordWithSuperClass(val x: String) : Record()
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package
|
||||
|
||||
@kotlin.jvm.JvmRecord public final data class BasicDataRecord : java.lang.Record {
|
||||
public constructor BasicDataRecord(/*0*/ x: kotlin.String)
|
||||
public final val x: kotlin.String
|
||||
public final operator /*synthesized*/ fun component1(): kotlin.String
|
||||
public final /*synthesized*/ fun copy(/*0*/ x: kotlin.String = ...): BasicDataRecord
|
||||
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
@kotlin.jvm.JvmRecord public final class BasicRecord : java.lang.Record {
|
||||
public constructor BasicRecord(/*0*/ x: kotlin.String)
|
||||
public final val x: kotlin.String
|
||||
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
@kotlin.jvm.JvmRecord public final class BasicRecordWithSuperClass : java.lang.Record {
|
||||
public constructor BasicRecordWithSuperClass(/*0*/ x: kotlin.String)
|
||||
public final val x: kotlin.String
|
||||
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
|
||||
}
|
||||
+5
@@ -50,6 +50,11 @@ public class DiagnosticsWithJdk15TestGenerated extends AbstractDiagnosticsWithJd
|
||||
runTest("compiler/testData/diagnostics/testsWithJava15/jvmRecord/disabledFeature.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmRecordDescriptorStructure.kt")
|
||||
public void testJvmRecordDescriptorStructure() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithJava15/jvmRecord/jvmRecordDescriptorStructure.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleRecords.kt")
|
||||
public void testSimpleRecords() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithJava15/jvmRecord/simpleRecords.kt");
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.resolve
|
||||
|
||||
import org.jetbrains.kotlin.container.DefaultImplementation
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
@DefaultImplementation(impl = AdditionalClassPartsProvider.Default::class)
|
||||
interface AdditionalClassPartsProvider {
|
||||
fun generateAdditionalMethods(
|
||||
thisDescriptor: ClassDescriptor,
|
||||
result: MutableCollection<SimpleFunctionDescriptor>,
|
||||
name: Name,
|
||||
location: LookupLocation,
|
||||
fromSupertypes: Collection<SimpleFunctionDescriptor>
|
||||
)
|
||||
|
||||
fun getAdditionalSupertypes(
|
||||
thisDescriptor: ClassDescriptor,
|
||||
existingSupertypes: List<KotlinType>
|
||||
): List<KotlinType>
|
||||
|
||||
object Default : AdditionalClassPartsProvider {
|
||||
override fun generateAdditionalMethods(
|
||||
thisDescriptor: ClassDescriptor,
|
||||
result: MutableCollection<SimpleFunctionDescriptor>,
|
||||
name: Name,
|
||||
location: LookupLocation,
|
||||
fromSupertypes: Collection<SimpleFunctionDescriptor>
|
||||
) {}
|
||||
|
||||
override fun getAdditionalSupertypes(
|
||||
thisDescriptor: ClassDescriptor,
|
||||
existingSupertypes: List<KotlinType>
|
||||
): List<KotlinType> = emptyList()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user