Synthesized 'copy' in data classes cannot override anything since 1.3
Synthesized 'copy' introduces default values for parameters, which is prohibited for regular overrides. Report warning in language version 1.2-, error in 1.3+.
This commit is contained in:
@@ -394,6 +394,10 @@ public interface Errors {
|
||||
|
||||
DiagnosticFactory2<PsiElement, CallableMemberDescriptor, DeclarationDescriptor> DATA_CLASS_OVERRIDE_CONFLICT =
|
||||
DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory2<PsiElement, CallableMemberDescriptor, DeclarationDescriptor> DATA_CLASS_OVERRIDE_DEFAULT_VALUES_WARNING =
|
||||
DiagnosticFactory2.create(WARNING);
|
||||
DiagnosticFactory2<PsiElement, CallableMemberDescriptor, DeclarationDescriptor> DATA_CLASS_OVERRIDE_DEFAULT_VALUES_ERROR =
|
||||
DiagnosticFactory2.create(ERROR);
|
||||
|
||||
DiagnosticFactory1<KtDeclaration, CallableMemberDescriptor> CANNOT_INFER_VISIBILITY =
|
||||
DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
|
||||
+2
@@ -290,6 +290,8 @@ public class DefaultErrorMessages {
|
||||
MAP.put(VIRTUAL_MEMBER_HIDDEN, "''{0}'' hides member of supertype ''{2}'' and needs ''override'' modifier", NAME, NAME, NAME);
|
||||
|
||||
MAP.put(DATA_CLASS_OVERRIDE_CONFLICT, "Function ''{0}'' generated for the data class conflicts with member of supertype ''{1}''", NAME, NAME);
|
||||
MAP.put(DATA_CLASS_OVERRIDE_DEFAULT_VALUES_WARNING, "Function ''{0}'' generated for the data class has default values for parameters, and conflicts with member of supertype ''{1}''", NAME, NAME);
|
||||
MAP.put(DATA_CLASS_OVERRIDE_DEFAULT_VALUES_ERROR, "Function ''{0}'' generated for the data class has default values for parameters, and conflicts with member of supertype ''{1}''", NAME, NAME);
|
||||
|
||||
MAP.put(CANNOT_OVERRIDE_INVISIBLE_MEMBER, "''{0}'' has no access to ''{1}'', so it cannot override it", FQ_NAMES_IN_TYPES,
|
||||
FQ_NAMES_IN_TYPES);
|
||||
|
||||
@@ -22,6 +22,8 @@ import com.intellij.psi.PsiElement
|
||||
import com.intellij.util.SmartList
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.util.containers.SmartHashSet
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DELEGATION
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.FAKE_OVERRIDE
|
||||
@@ -41,7 +43,8 @@ import java.util.*
|
||||
|
||||
class OverrideResolver(
|
||||
private val trace: BindingTrace,
|
||||
private val overridesBackwardCompatibilityHelper: OverridesBackwardCompatibilityHelper
|
||||
private val overridesBackwardCompatibilityHelper: OverridesBackwardCompatibilityHelper,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
|
||||
fun check(c: TopDownAnalysisContext) {
|
||||
@@ -244,6 +247,9 @@ class OverrideResolver(
|
||||
if (DataClassDescriptorResolver.isComponentLike(declared.name)) {
|
||||
checkOverrideForComponentFunction(declared)
|
||||
}
|
||||
else if (declared.name == DataClassDescriptorResolver.COPY_METHOD_NAME) {
|
||||
checkOverrideForCopyFunction(declared)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -341,6 +347,20 @@ class OverrideResolver(
|
||||
})
|
||||
}
|
||||
|
||||
private fun checkOverrideForCopyFunction(copyFunction: CallableMemberDescriptor) {
|
||||
val overridden = copyFunction.overriddenDescriptors.firstOrNull()
|
||||
if (overridden != null) {
|
||||
val baseClassifier = overridden.containingDeclaration
|
||||
val dataModifier = findDataModifierForDataClass(copyFunction.containingDeclaration)
|
||||
if (languageVersionSettings.supportsFeature(LanguageFeature.ProhibitDataClassesOverridingCopy)) {
|
||||
trace.report(DATA_CLASS_OVERRIDE_DEFAULT_VALUES_ERROR.on(dataModifier, copyFunction, baseClassifier))
|
||||
}
|
||||
else {
|
||||
trace.report(DATA_CLASS_OVERRIDE_DEFAULT_VALUES_WARNING.on(dataModifier, copyFunction, baseClassifier))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkParameterOverridesForAllClasses(c: TopDownAnalysisContext) {
|
||||
for (classDescriptor in c.declaredClasses.values) {
|
||||
for (member in DescriptorUtils.getAllDescriptors(classDescriptor.defaultType.memberScope)) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// LANGUAGE_VERSION: 1.1
|
||||
|
||||
fun box(): String {
|
||||
val a: A = B(1)
|
||||
a.copy(1)
|
||||
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
// !LANGUAGE: +ProhibitDataClassesOverridingCopy
|
||||
|
||||
interface WithCopy<T> {
|
||||
fun copy(str: T): WithCopy<T>
|
||||
}
|
||||
|
||||
<!DATA_CLASS_OVERRIDE_DEFAULT_VALUES_ERROR!>data<!> class <!CONFLICTING_JVM_DECLARATIONS, CONFLICTING_JVM_DECLARATIONS!>Test(val str: String)<!> : WithCopy<String> {
|
||||
<!CONFLICTING_OVERLOADS!>override fun copy(str: String)<!> = Test(str)
|
||||
}
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
package
|
||||
|
||||
public final data class Test : WithCopy<kotlin.String> {
|
||||
public constructor Test(/*0*/ str: kotlin.String)
|
||||
public final val str: kotlin.String
|
||||
public final operator /*synthesized*/ fun component1(): kotlin.String
|
||||
public open override /*1*/ fun copy(/*0*/ str: kotlin.String): Test
|
||||
public final override /*1*/ /*synthesized*/ fun copy(/*0*/ str: kotlin.String = ...): Test
|
||||
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
|
||||
}
|
||||
|
||||
public interface WithCopy</*0*/ T> {
|
||||
public abstract fun copy(/*0*/ str: T): WithCopy<T>
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
// !LANGUAGE: +ProhibitDataClassesOverridingCopy
|
||||
|
||||
interface WithCopy<T> {
|
||||
fun copy(str: T): WithCopy<T>
|
||||
}
|
||||
|
||||
<!DATA_CLASS_OVERRIDE_DEFAULT_VALUES_ERROR!>data<!> class <!CONFLICTING_JVM_DECLARATIONS, CONFLICTING_JVM_DECLARATIONS, CONFLICTING_JVM_DECLARATIONS!>Test(val str: String)<!> : WithCopy<String> {
|
||||
<!CONFLICTING_OVERLOADS!>override fun copy(str: String = <!DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE!>this.str<!>)<!> = Test(str)
|
||||
}
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
package
|
||||
|
||||
public final data class Test : WithCopy<kotlin.String> {
|
||||
public constructor Test(/*0*/ str: kotlin.String)
|
||||
public final val str: kotlin.String
|
||||
public final operator /*synthesized*/ fun component1(): kotlin.String
|
||||
public open override /*1*/ fun copy(/*0*/ str: kotlin.String = ...): Test
|
||||
public final override /*1*/ /*synthesized*/ fun copy(/*0*/ str: kotlin.String = ...): Test
|
||||
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
|
||||
}
|
||||
|
||||
public interface WithCopy</*0*/ T> {
|
||||
public abstract fun copy(/*0*/ str: T): WithCopy<T>
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// !LANGUAGE: +ProhibitDataClassesOverridingCopy
|
||||
|
||||
interface WithCopy<T> {
|
||||
fun copy(str: T): WithCopy<T>
|
||||
}
|
||||
|
||||
data class Test(val str: String, val int: Int) : WithCopy<String> {
|
||||
override fun copy(str: String) = copy(str, int)
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package
|
||||
|
||||
public final data class Test : WithCopy<kotlin.String> {
|
||||
public constructor Test(/*0*/ str: kotlin.String, /*1*/ int: kotlin.Int)
|
||||
public final val int: kotlin.Int
|
||||
public final val str: kotlin.String
|
||||
public final operator /*synthesized*/ fun component1(): kotlin.String
|
||||
public final operator /*synthesized*/ fun component2(): kotlin.Int
|
||||
public open override /*1*/ fun copy(/*0*/ str: kotlin.String): Test
|
||||
public final /*synthesized*/ fun copy(/*0*/ str: kotlin.String = ..., /*1*/ int: kotlin.Int = ...): Test
|
||||
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
|
||||
}
|
||||
|
||||
public interface WithCopy</*0*/ T> {
|
||||
public abstract fun copy(/*0*/ str: T): WithCopy<T>
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// !LANGUAGE: -ProhibitDataClassesOverridingCopy
|
||||
|
||||
interface WithCopy<T> {
|
||||
fun copy(str: T): WithCopy<T>
|
||||
}
|
||||
|
||||
<!DATA_CLASS_OVERRIDE_DEFAULT_VALUES_WARNING!>data<!> class Test(val str: String): WithCopy<String>
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package
|
||||
|
||||
public final data class Test : WithCopy<kotlin.String> {
|
||||
public constructor Test(/*0*/ str: kotlin.String)
|
||||
public final val str: kotlin.String
|
||||
public final operator /*synthesized*/ fun component1(): kotlin.String
|
||||
public final override /*1*/ /*synthesized*/ fun copy(/*0*/ str: kotlin.String = ...): Test
|
||||
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
|
||||
}
|
||||
|
||||
public interface WithCopy</*0*/ T> {
|
||||
public abstract fun copy(/*0*/ str: T): WithCopy<T>
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// !LANGUAGE: +ProhibitDataClassesOverridingCopy
|
||||
|
||||
interface WithCopy<T> {
|
||||
fun copy(str: T): WithCopy<T>
|
||||
}
|
||||
|
||||
<!DATA_CLASS_OVERRIDE_DEFAULT_VALUES_ERROR!>data<!> class Test(val str: String): WithCopy<String>
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package
|
||||
|
||||
public final data class Test : WithCopy<kotlin.String> {
|
||||
public constructor Test(/*0*/ str: kotlin.String)
|
||||
public final val str: kotlin.String
|
||||
public final operator /*synthesized*/ fun component1(): kotlin.String
|
||||
public final override /*1*/ /*synthesized*/ fun copy(/*0*/ str: kotlin.String = ...): Test
|
||||
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
|
||||
}
|
||||
|
||||
public interface WithCopy</*0*/ T> {
|
||||
public abstract fun copy(/*0*/ str: T): WithCopy<T>
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -4828,12 +4828,42 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassExplicitlyOverridingCopyNoDefaults.kt")
|
||||
public void testDataClassExplicitlyOverridingCopyNoDefaults() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/dataClassExplicitlyOverridingCopyNoDefaults.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassExplicitlyOverridingCopyWithDefaults.kt")
|
||||
public void testDataClassExplicitlyOverridingCopyWithDefaults() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/dataClassExplicitlyOverridingCopyWithDefaults.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassNoName.kt")
|
||||
public void testDataClassNoName() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/dataClassNoName.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassNotOverridingCopy.kt")
|
||||
public void testDataClassNotOverridingCopy() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/dataClassNotOverridingCopy.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassOverridingCopy_lv12.kt")
|
||||
public void testDataClassOverridingCopy_lv12() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/dataClassOverridingCopy_lv12.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassOverridingCopy_lv13.kt")
|
||||
public void testDataClassOverridingCopy_lv13() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/dataClassOverridingCopy_lv13.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassVarargParam.kt")
|
||||
public void testDataClassVarargParam() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/dataClassVarargParam.kt");
|
||||
|
||||
+30
@@ -4828,12 +4828,42 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassExplicitlyOverridingCopyNoDefaults.kt")
|
||||
public void testDataClassExplicitlyOverridingCopyNoDefaults() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/dataClassExplicitlyOverridingCopyNoDefaults.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassExplicitlyOverridingCopyWithDefaults.kt")
|
||||
public void testDataClassExplicitlyOverridingCopyWithDefaults() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/dataClassExplicitlyOverridingCopyWithDefaults.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassNoName.kt")
|
||||
public void testDataClassNoName() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/dataClassNoName.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassNotOverridingCopy.kt")
|
||||
public void testDataClassNotOverridingCopy() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/dataClassNotOverridingCopy.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassOverridingCopy_lv12.kt")
|
||||
public void testDataClassOverridingCopy_lv12() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/dataClassOverridingCopy_lv12.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassOverridingCopy_lv13.kt")
|
||||
public void testDataClassOverridingCopy_lv13() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/dataClassOverridingCopy_lv13.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassVarargParam.kt")
|
||||
public void testDataClassVarargParam() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataClasses/dataClassVarargParam.kt");
|
||||
|
||||
@@ -65,6 +65,7 @@ enum class LanguageFeature(
|
||||
|
||||
RestrictionOfValReassignmentViaBackingField(KOTLIN_1_3),
|
||||
NestedClassesInEnumEntryShouldBeInner(KOTLIN_1_3),
|
||||
ProhibitDataClassesOverridingCopy(KOTLIN_1_3),
|
||||
RestrictionOfWrongAnnotationsWithUseSiteTargetsOnTypes(KOTLIN_1_3),
|
||||
|
||||
// Experimental features
|
||||
|
||||
Reference in New Issue
Block a user