From 7631e90f123a5cfad83c7e25cb07e10a6104ea0d Mon Sep 17 00:00:00 2001 From: Dmitrii Gridin Date: Mon, 12 Jun 2023 14:17:10 +0200 Subject: [PATCH] [LL FIR, Java] fix resolve contract violation from java symbol provider from permits To create a smart psi type pointer, IJ Platform uses resolve We cannot use resolve from JavaSymbolProvider, as it may lead to resolve contract violation ^KT-59243 Fixed --- ...entDelegatingTypeSourceWithSmartPointer.kt | 9 ++++++- ...avaElementSourceWithSmartPointerFactory.kt | 12 ++++++++++ ...cCompilerTestFirTestdataTestGenerated.java | 6 +++++ ...osticCompilerFirTestDataTestGenerated.java | 6 +++++ .../LazyBodyIsNotTouchedTestGenerated.java | 5 ++++ ...romKotlinViaStaticImportAndPermits.fir.txt | 11 +++++++++ ...JavaFromKotlinViaStaticImportAndPermits.kt | 24 +++++++++++++++++++ .../FirLightTreeDiagnosticsTestGenerated.java | 6 +++++ .../FirPsiDiagnosticTestGenerated.java | 6 +++++ .../kotlin/fir/java/FirJavaFacade.kt | 10 ++++---- .../fir/declarations/SealedClassInheritors.kt | 12 +++++++--- .../load/java/structure/impl/JavaClassImpl.kt | 4 +++- .../impl/source/JavaElementSourceFactory.kt | 15 ++++++++++++ 13 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImportAndPermits.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImportAndPermits.kt diff --git a/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/java/source/JavaElementDelegatingTypeSourceWithSmartPointer.kt b/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/java/source/JavaElementDelegatingTypeSourceWithSmartPointer.kt index 1553c08b977..245e757fe7e 100644 --- a/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/java/source/JavaElementDelegatingTypeSourceWithSmartPointer.kt +++ b/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/java/source/JavaElementDelegatingTypeSourceWithSmartPointer.kt @@ -48,7 +48,6 @@ internal class JavaElementDelegatingExpressionTypeSourceWithSmartPointer( override val psiPointer: SmartPsiElementPointer, private val boundIndex: Int, @@ -68,3 +67,11 @@ internal class JavaElementDelegatingSuperTypeSourceWithSmartPointer( ) : JavaElementDelegatingTypeSourceWithSmartPointer() { override fun getType(psi: PsiClass): PsiClassType = psi.superTypes[superTypeIndex] } + +internal class JavaElementDelegatingPermittedTypeSourceWithSmartPointer( + override val psiPointer: SmartPsiElementPointer, + private val permittedTypeIndex: Int, + override val factory: JavaElementSourceFactory, +) : JavaElementDelegatingTypeSourceWithSmartPointer() { + override fun getType(psi: PsiClass): PsiClassType = psi.permitsListTypes[permittedTypeIndex] +} diff --git a/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/java/source/JavaElementSourceWithSmartPointerFactory.kt b/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/java/source/JavaElementSourceWithSmartPointerFactory.kt index 060bd5755b9..35a4cdc7926 100644 --- a/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/java/source/JavaElementSourceWithSmartPointerFactory.kt +++ b/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/java/source/JavaElementSourceWithSmartPointerFactory.kt @@ -61,4 +61,16 @@ class JavaElementSourceWithSmartPointerFactory(project: Project) : JavaElementSo require(psiExpressionSource is JavaElementPsiSourceWithSmartPointer) return JavaElementDelegatingExpressionTypeSourceWithSmartPointer(psiExpressionSource.pointer, psiExpressionSource.factory) } + + override fun createPermittedTypeSource( + psiTypeParameterSource: JavaElementPsiSource, + permittedTypeIndex: Int + ): JavaElementTypeSource { + require(psiTypeParameterSource is JavaElementPsiSourceWithSmartPointer) + return JavaElementDelegatingPermittedTypeSourceWithSmartPointer( + psiTypeParameterSource.pointer, + permittedTypeIndex, + psiTypeParameterSource.factory, + ) + } } \ No newline at end of file diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFirTestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFirTestdataTestGenerated.java index 7eab0910551..806e87a335a 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFirTestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFirTestdataTestGenerated.java @@ -39,6 +39,12 @@ public class DiagnosticCompilerTestFirTestdataTestGenerated extends AbstractDiag runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImport2.kt"); } + @Test + @TestMetadata("accessJavaFromKotlinViaStaticImportAndPermits.kt") + public void testAccessJavaFromKotlinViaStaticImportAndPermits() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImportAndPermits.kt"); + } + @Test public void testAllFilesPresentInResolve() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve"), Pattern.compile("^([^.]+)\\.kt$"), null, true); diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated.java index 2a42e3f5267..f370eef0a9c 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated.java @@ -39,6 +39,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImport2.kt"); } + @Test + @TestMetadata("accessJavaFromKotlinViaStaticImportAndPermits.kt") + public void testAccessJavaFromKotlinViaStaticImportAndPermits() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImportAndPermits.kt"); + } + @Test public void testAllFilesPresentInResolve() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve"), Pattern.compile("^([^.]+)\\.kt$"), null, true); diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTestGenerated.java index 9482efb0c52..7af38c62cb6 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTestGenerated.java @@ -40,6 +40,11 @@ public class LazyBodyIsNotTouchedTestGenerated extends AbstractLazyBodyIsNotTouc runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImport2.kt"); } + @TestMetadata("accessJavaFromKotlinViaStaticImportAndPermits.kt") + public void testAccessJavaFromKotlinViaStaticImportAndPermits() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImportAndPermits.kt"); + } + public void testAllFilesPresentInResolve() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve"), Pattern.compile("^([^.]+)\\.kt$"), null, true); } diff --git a/compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImportAndPermits.fir.txt b/compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImportAndPermits.fir.txt new file mode 100644 index 00000000000..ad57860018b --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImportAndPermits.fir.txt @@ -0,0 +1,11 @@ +FILE: useSite.kt + public final fun foo(): R|kotlin/Int| { + ^foo Int(4) + } +FILE: KotlinInterface.kt + public abstract interface KotlinInterface : R|kotlin/Any| { + public abstract var selectedOptions: R|kotlin/Int| + public get(): R|kotlin/Int| + public set(value: R|kotlin/Int|): R|kotlin/Unit| + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImportAndPermits.kt b/compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImportAndPermits.kt new file mode 100644 index 00000000000..6266211b6af --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImportAndPermits.kt @@ -0,0 +1,24 @@ +// FILE: useSite.kt + +import InspectionProfileImpl.INIT_INSPECTIONS + +fun foo(): Int = 4 + +// FILE: InspectionProfileImpl.java +import static Configuration.StaticConfigurationClass + +public abstract sealed class InspectionProfileImpl permits StaticConfigurationClass { + public static boolean INIT_INSPECTIONS; +} + +// FILE: Configuration.java +public class Configuration implements KotlinInterface { + public static class StaticConfigurationClass { + + } +} + +// FILE: KotlinInterface.kt +interface KotlinInterface { + var selectedOptions: Int +} diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java index 12b8f64c735..3988308ef7d 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeDiagnosticsTestGenerated.java @@ -39,6 +39,12 @@ public class FirLightTreeDiagnosticsTestGenerated extends AbstractFirLightTreeDi runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImport2.kt"); } + @Test + @TestMetadata("accessJavaFromKotlinViaStaticImportAndPermits.kt") + public void testAccessJavaFromKotlinViaStaticImportAndPermits() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImportAndPermits.kt"); + } + @Test public void testAllFilesPresentInResolve() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve"), Pattern.compile("^([^.]+)\\.kt$"), null, true); diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java index abd9585ad60..f4b54ee7d24 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiDiagnosticTestGenerated.java @@ -39,6 +39,12 @@ public class FirPsiDiagnosticTestGenerated extends AbstractFirPsiDiagnosticTest runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImport2.kt"); } + @Test + @TestMetadata("accessJavaFromKotlinViaStaticImportAndPermits.kt") + public void testAccessJavaFromKotlinViaStaticImportAndPermits() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaStaticImportAndPermits.kt"); + } + @Test public void testAllFilesPresentInResolve() throws Exception { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve"), Pattern.compile("^([^.]+)\\.kt$"), null, true); 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 55d0c832cdc..248bb631056 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 @@ -381,11 +381,13 @@ abstract class FirJavaFacade( } }.apply { if (modality == Modality.SEALED) { - val inheritors = javaClass.permittedTypes.mapNotNull { classifierType -> - val classifier = classifierType.classifier as? JavaClass - classifier?.let { JavaToKotlinClassMap.mapJavaToKotlin(it.fqName!!) } + val permittedTypes = javaClass.permittedTypes + setSealedClassInheritors { + permittedTypes.mapNotNull { classifierType -> + val classifier = classifierType.classifier as? JavaClass + classifier?.let { JavaToKotlinClassMap.mapJavaToKotlin(it.fqName!!) } + } } - setSealedClassInheritors(inheritors) } if (classIsAnnotation) { diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/SealedClassInheritors.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/SealedClassInheritors.kt index d437dc49f9f..7fa0d86e5d8 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/SealedClassInheritors.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/SealedClassInheritors.kt @@ -23,7 +23,7 @@ private val FirSession.sealedClassInheritorsProvider: SealedClassInheritorsProvi object SealedClassInheritorsProviderImpl : SealedClassInheritorsProvider() { @OptIn(SealedClassInheritorsProviderInternals::class) override fun getSealedClassInheritors(firClass: FirRegularClass): List { - return firClass.sealedInheritorsAttr ?: emptyList() + return firClass.sealedInheritorsAttr?.value ?: emptyList() } } @@ -36,11 +36,17 @@ fun FirRegularClass.getSealedClassInheritors(session: FirSession): List @OptIn(SealedClassInheritorsProviderInternals::class) fun FirRegularClass.setSealedClassInheritors(inheritors: List) { require(this.isSealed) - sealedInheritorsAttr = inheritors.sortedBy { it.asFqNameString() } + sealedInheritorsAttr = lazyOf(inheritors.sortedBy { it.asFqNameString() }) +} + +@OptIn(SealedClassInheritorsProviderInternals::class) +fun FirRegularClass.setSealedClassInheritors(inheritorComputer: () -> List) { + require(this.isSealed) + sealedInheritorsAttr = lazy { inheritorComputer().sortedBy { it.asFqNameString() } } } private object SealedClassInheritorsKey : FirDeclarationDataKey() @SealedClassInheritorsProviderInternals -var FirRegularClass.sealedInheritorsAttr: List? by FirDeclarationDataRegistry.data(SealedClassInheritorsKey) +var FirRegularClass.sealedInheritorsAttr: Lazy>? by FirDeclarationDataRegistry.data(SealedClassInheritorsKey) private set diff --git a/compiler/resolution.common.jvm/src/org/jetbrains/kotlin/load/java/structure/impl/JavaClassImpl.kt b/compiler/resolution.common.jvm/src/org/jetbrains/kotlin/load/java/structure/impl/JavaClassImpl.kt index 8d5a13b988e..d3ff5de7b67 100644 --- a/compiler/resolution.common.jvm/src/org/jetbrains/kotlin/load/java/structure/impl/JavaClassImpl.kt +++ b/compiler/resolution.common.jvm/src/org/jetbrains/kotlin/load/java/structure/impl/JavaClassImpl.kt @@ -69,7 +69,9 @@ class JavaClassImpl(psiClassSource: JavaElementPsiSource) : JavaClassi get() = JavaElementUtil.isSealed(this) override val permittedTypes: Collection - get() = classifierTypes(psi.permitsListTypes, sourceFactory) + get() = psi.permitsListTypes.convertIndexed { index, _ -> + JavaClassifierTypeImpl(sourceFactory.createPermittedTypeSource(psiElementSource, index)) + } override val isRecord: Boolean get() = psi.isRecord diff --git a/compiler/resolution.common.jvm/src/org/jetbrains/kotlin/load/java/structure/impl/source/JavaElementSourceFactory.kt b/compiler/resolution.common.jvm/src/org/jetbrains/kotlin/load/java/structure/impl/source/JavaElementSourceFactory.kt index 8a5e6a82fea..80df889c406 100644 --- a/compiler/resolution.common.jvm/src/org/jetbrains/kotlin/load/java/structure/impl/source/JavaElementSourceFactory.kt +++ b/compiler/resolution.common.jvm/src/org/jetbrains/kotlin/load/java/structure/impl/source/JavaElementSourceFactory.kt @@ -26,6 +26,14 @@ abstract class JavaElementSourceFactory { abstract fun createExpressionTypeSource(psiExpressionSource: JavaElementPsiSource): JavaElementTypeSource + /** + * @see com.intellij.psi.PsiClass.getPermitsListTypes + */ + abstract fun createPermittedTypeSource( + psiTypeParameterSource: JavaElementPsiSource, + permittedTypeIndex: Int, + ): JavaElementTypeSource + companion object { @JvmStatic fun getInstance(project: Project): JavaElementSourceFactory { @@ -63,6 +71,13 @@ class JavaFixedElementSourceFactory : JavaElementSourceFactory() { return createTypeSource(psiTypeParameterSource.psi.superTypes[superTypeIndex]) } + override fun createPermittedTypeSource( + psiTypeParameterSource: JavaElementPsiSource, + permittedTypeIndex: Int + ): JavaElementTypeSource { + return createTypeSource(psiTypeParameterSource.psi.permitsListTypes[permittedTypeIndex]) + } + override fun createExpressionTypeSource(psiExpressionSource: JavaElementPsiSource): JavaElementTypeSource { @Suppress("UNCHECKED_CAST") return createTypeSource(psiExpressionSource.psi.type as TYPE)