Prohibit irrelevant fields in @JvmRecord classes
^KT-43677 In Progress
This commit is contained in:
+30
-7
@@ -7,17 +7,13 @@ package org.jetbrains.kotlin.resolve.jvm.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.isFinalClass
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtModifierList
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
@@ -72,6 +68,16 @@ object JvmRecordApplicabilityChecker : DeclarationChecker {
|
||||
return
|
||||
}
|
||||
|
||||
if (descriptor.isInner) {
|
||||
val modifierOrName =
|
||||
declaration.modifierList?.getModifier(KtTokens.INNER_KEYWORD)
|
||||
?: declaration.nameIdentifier
|
||||
?: declaration
|
||||
|
||||
context.trace.report(ErrorsJvm.INNER_JVM_RECORD.on(modifierOrName))
|
||||
return
|
||||
}
|
||||
|
||||
if (DescriptorUtils.isLocal(descriptor)) {
|
||||
context.trace.report(ErrorsJvm.LOCAL_JVM_RECORD.on(reportOn))
|
||||
return
|
||||
@@ -100,6 +106,23 @@ object JvmRecordApplicabilityChecker : DeclarationChecker {
|
||||
}
|
||||
}
|
||||
|
||||
for (member in declaration.declarations) {
|
||||
if (member !is KtProperty) continue
|
||||
|
||||
val propertyDescriptor = context.trace[BindingContext.DECLARATION_TO_DESCRIPTOR, member] as? PropertyDescriptor ?: continue
|
||||
if (context.trace.bindingContext[BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor] != true && member.delegate == null) continue
|
||||
|
||||
context.trace.report(ErrorsJvm.FIELD_IN_JVM_RECORD.on(member))
|
||||
return
|
||||
}
|
||||
|
||||
for (superTypeEntry in declaration.superTypeListEntries) {
|
||||
if (superTypeEntry !is KtDelegatedSuperTypeEntry) continue
|
||||
|
||||
context.trace.report(ErrorsJvm.DELEGATION_BY_IN_JVM_RECORD.on(superTypeEntry))
|
||||
return
|
||||
}
|
||||
|
||||
for (supertype in descriptor.typeConstructor.supertypes) {
|
||||
val classDescriptor = supertype.constructor.declarationDescriptor as? ClassDescriptor ?: continue
|
||||
if (classDescriptor.kind == ClassKind.INTERFACE || classDescriptor.fqNameSafe == JAVA_LANG_RECORD_FQ_NAME) continue
|
||||
|
||||
+3
@@ -160,6 +160,9 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
|
||||
MAP.put(JVM_RECORD_NOT_LAST_VARARG_PARAMETER, "Only the last constructor parameter of @JvmRecord may be a vararg");
|
||||
MAP.put(JVM_RECORD_EXTENDS_CLASS, "Record cannot inherit an other class but java.lang.Record" , RENDER_TYPE);
|
||||
MAP.put(JVM_RECORD_REQUIRES_JDK15, "Using @JvmRecords requires at least JDK 15");
|
||||
MAP.put(INNER_JVM_RECORD, "@JvmRecord class should not be inner");
|
||||
MAP.put(FIELD_IN_JVM_RECORD, "It's not allowed to have non-constructor properties with backing filed in @JvmRecord class");
|
||||
MAP.put(DELEGATION_BY_IN_JVM_RECORD, "Delegation is not allowed for @JvmRecord classes");
|
||||
|
||||
String MESSAGE_FOR_CONCURRENT_HASH_MAP_CONTAINS =
|
||||
"Method 'contains' from ConcurrentHashMap may have unexpected semantics: it calls 'containsValue' instead of 'containsKey'. " +
|
||||
|
||||
@@ -123,6 +123,9 @@ public interface ErrorsJvm {
|
||||
DiagnosticFactory0<PsiElement> JVM_RECORD_NOT_LAST_VARARG_PARAMETER = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, KotlinType> JVM_RECORD_EXTENDS_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> JVM_RECORD_REQUIRES_JDK15 = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> INNER_JVM_RECORD = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> FIELD_IN_JVM_RECORD = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> DELEGATION_BY_IN_JVM_RECORD = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<KtDeclaration> NON_JVM_DEFAULT_OVERRIDES_JAVA_DEFAULT = DiagnosticFactory0.create(WARNING, DECLARATION_SIGNATURE);
|
||||
|
||||
|
||||
@@ -46,3 +46,8 @@ fun main() {
|
||||
<!LOCAL_JVM_RECORD!>@JvmRecord<!>
|
||||
class Local
|
||||
}
|
||||
|
||||
class Outer {
|
||||
@JvmRecord
|
||||
<!INNER_JVM_RECORD!>inner<!> class Inner(val name: String)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// !LANGUAGE: +JvmRecordSupport
|
||||
// SKIP_TXT
|
||||
|
||||
interface I
|
||||
|
||||
val i: I = object : I {}
|
||||
|
||||
@JvmRecord
|
||||
class MyRec1(val name: String) : <!DELEGATION_BY_IN_JVM_RECORD!>I by i<!>
|
||||
|
||||
@JvmRecord
|
||||
class MyRec2(val name: String) {
|
||||
<!FIELD_IN_JVM_RECORD!>val x: Int = 0<!>
|
||||
}
|
||||
|
||||
@JvmRecord
|
||||
class MyRec3(val name: String) {
|
||||
<!FIELD_IN_JVM_RECORD!>val y: String
|
||||
get() = field + "1"<!>
|
||||
|
||||
init {
|
||||
y = ""
|
||||
}
|
||||
}
|
||||
|
||||
@JvmRecord
|
||||
class MyRec4(val name: String) {
|
||||
<!FIELD_IN_JVM_RECORD!>val z: Int by lazy { 1 }<!>
|
||||
}
|
||||
|
||||
@JvmRecord
|
||||
class MyRec5(val name: String) {
|
||||
val w: String get() = name + "1"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+5
@@ -50,6 +50,11 @@ public class DiagnosticsWithJdk15TestGenerated extends AbstractDiagnosticsWithJd
|
||||
runTest("compiler/testData/diagnostics/testsWithJava15/jvmRecord/disabledFeature.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("irrelevantFields.kt")
|
||||
public void testIrrelevantFields() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithJava15/jvmRecord/irrelevantFields.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("jvmRecordDescriptorStructure.kt")
|
||||
public void testJvmRecordDescriptorStructure() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithJava15/jvmRecord/jvmRecordDescriptorStructure.kt");
|
||||
|
||||
Reference in New Issue
Block a user