diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java index f0d7729ebea..ac8fbc620a7 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java @@ -33559,6 +33559,18 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.kt"); } + @Test + @TestMetadata("simpleRecordsDefaultConstructor.kt") + public void testSimpleRecordsDefaultConstructor() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsDefaultConstructor.kt"); + } + + @Test + @TestMetadata("simpleRecordsWithSecondaryConstructor.kt") + public void testSimpleRecordsWithSecondaryConstructor() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsWithSecondaryConstructor.kt"); + } + @Test @TestMetadata("supertypesCheck.kt") public void testSupertypesCheck() throws Exception { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java index 45b5e488fea..515f018c1b1 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java @@ -33559,6 +33559,18 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.kt"); } + @Test + @TestMetadata("simpleRecordsDefaultConstructor.kt") + public void testSimpleRecordsDefaultConstructor() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsDefaultConstructor.kt"); + } + + @Test + @TestMetadata("simpleRecordsWithSecondaryConstructor.kt") + public void testSimpleRecordsWithSecondaryConstructor() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsWithSecondaryConstructor.kt"); + } + @Test @TestMetadata("supertypesCheck.kt") public void testSupertypesCheck() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java index 33d9aa72a2f..31a721facce 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java @@ -33559,6 +33559,18 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.kt"); } + @Test + @TestMetadata("simpleRecordsDefaultConstructor.kt") + public void testSimpleRecordsDefaultConstructor() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsDefaultConstructor.kt"); + } + + @Test + @TestMetadata("simpleRecordsWithSecondaryConstructor.kt") + public void testSimpleRecordsWithSecondaryConstructor() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsWithSecondaryConstructor.kt"); + } + @Test @TestMetadata("supertypesCheck.kt") public void testSupertypesCheck() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java index a056c73e438..142adad5b9f 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java @@ -33673,6 +33673,18 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.kt"); } + @Test + @TestMetadata("simpleRecordsDefaultConstructor.kt") + public void testSimpleRecordsDefaultConstructor() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsDefaultConstructor.kt"); + } + + @Test + @TestMetadata("simpleRecordsWithSecondaryConstructor.kt") + public void testSimpleRecordsWithSecondaryConstructor() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsWithSecondaryConstructor.kt"); + } + @Test @TestMetadata("supertypesCheck.kt") public void testSupertypesCheck() throws Exception { diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt index 937e846319d..1313b7c77eb 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/FirJavaFacade.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.java +import com.intellij.psi.impl.light.LightRecordCanonicalConstructor import org.jetbrains.kotlin.* import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.descriptors.ClassKind @@ -320,6 +321,7 @@ abstract class FirJavaFacade( if (javaClassDeclaredConstructors.isEmpty() && javaClass.classKind == ClassKind.CLASS + && !javaClass.isRecord && javaClass.hasDefaultConstructor() ) { declarations += convertJavaConstructorToFir( @@ -441,39 +443,46 @@ abstract class FirJavaFacade( } } - destination += buildJavaConstructor { - source = javaClass.toSourceElement(KtFakeSourceElementKind.ImplicitJavaRecordConstructor) - this.moduleData = moduleData - isFromSource = javaClass.isFromSource + /** + * It is possible that JavaClass already has a synthetic primary constructor ([LightRecordCanonicalConstructor]) + * Such behavior depends on a platform version and psi providers + * (e.g., in IntelliJ plugin Java class can have additional declarations) + */ + if (destination.none { it is FirJavaConstructor && it.isPrimary }) { + destination += buildJavaConstructor { + source = javaClass.toSourceElement(KtFakeSourceElementKind.ImplicitJavaRecordConstructor) + this.moduleData = moduleData + isFromSource = javaClass.isFromSource - val constructorId = CallableId(classId, classId.shortClassName) - symbol = FirConstructorSymbol(constructorId) - status = FirResolvedDeclarationStatusImpl( - Visibilities.Public, - Modality.FINAL, - EffectiveVisibility.Public - ) - visibility = Visibilities.Public - isPrimary = true - returnTypeRef = classType.toFirResolvedTypeRef() - dispatchReceiverType = null - typeParameters += classTypeParameters.toRefs() - annotationBuilder = { emptyList() } + val constructorId = CallableId(classId, classId.shortClassName) + symbol = FirConstructorSymbol(constructorId) + status = FirResolvedDeclarationStatusImpl( + Visibilities.Public, + Modality.FINAL, + EffectiveVisibility.Public + ) + visibility = Visibilities.Public + isPrimary = true + returnTypeRef = classType.toFirResolvedTypeRef() + dispatchReceiverType = null + typeParameters += classTypeParameters.toRefs() + annotationBuilder = { emptyList() } - javaClass.recordComponents.mapTo(valueParameters) { component -> - buildJavaValueParameter { - containingFunctionSymbol = this@buildJavaConstructor.symbol - source = component.toSourceElement(KtFakeSourceElementKind.ImplicitRecordConstructorParameter) - this.moduleData = moduleData - isFromSource = component.isFromSource - returnTypeRef = component.type.toFirJavaTypeRef(session, javaTypeParameterStack) - name = component.name - isVararg = component.isVararg - annotationBuilder = { emptyList() } + javaClass.recordComponents.mapTo(valueParameters) { component -> + buildJavaValueParameter { + containingFunctionSymbol = this@buildJavaConstructor.symbol + source = component.toSourceElement(KtFakeSourceElementKind.ImplicitRecordConstructorParameter) + this.moduleData = moduleData + isFromSource = component.isFromSource + returnTypeRef = component.type.toFirJavaTypeRef(session, javaTypeParameterStack) + name = component.name + isVararg = component.isVararg + annotationBuilder = { emptyList() } + } } + }.apply { + containingClassForStaticMemberAttr = classType.lookupTag } - }.apply { - containingClassForStaticMemberAttr = classType.lookupTag } } @@ -636,7 +645,7 @@ abstract class FirJavaFacade( hasStableParameterNames = false } this.visibility = visibility - isPrimary = javaConstructor == null + isPrimary = javaConstructor == null || source?.psi is LightRecordCanonicalConstructor returnTypeRef = buildResolvedTypeRef { type = ownerClassBuilder.buildSelfTypeRef() } diff --git a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsDefaultConstructor.kt b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsDefaultConstructor.kt new file mode 100644 index 00000000000..e910362e3a8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsDefaultConstructor.kt @@ -0,0 +1,12 @@ +// FIR_IDENTICAL +// LANGUAGE: +JvmRecordSupport + +// FILE: MyRecord.java +public record MyRecord(String str) {} + +// FILE: main.kt + +fun foo() { + MyRecord("") // OK + MyRecord() // error +} diff --git a/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsWithSecondaryConstructor.kt b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsWithSecondaryConstructor.kt new file mode 100644 index 00000000000..13a83106505 --- /dev/null +++ b/compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsWithSecondaryConstructor.kt @@ -0,0 +1,16 @@ +// FIR_IDENTICAL +// LANGUAGE: +JvmRecordSupport + +// FILE: MyRecord.java +public record MyRecord(String string, int number) { + public MyRecord(Long number, String string) { + this(string, 4) + } +} + +// FILE: main.kt + +fun foo(mr: MyRecord) { + MyRecord("", 1) + MyRecord(4L, "") +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 3a35cd1b7a9..8d9537e5861 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -34517,6 +34517,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecords.kt"); } + @Test + @TestMetadata("simpleRecordsDefaultConstructor.kt") + public void testSimpleRecordsDefaultConstructor() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsDefaultConstructor.kt"); + } + + @Test + @TestMetadata("simpleRecordsWithSecondaryConstructor.kt") + public void testSimpleRecordsWithSecondaryConstructor() throws Exception { + runTest("compiler/testData/diagnostics/tests/testsWithJava17/jvmRecord/simpleRecordsWithSecondaryConstructor.kt"); + } + @Test @TestMetadata("supertypesCheck.kt") public void testSupertypesCheck() throws Exception {