[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
This commit is contained in:
Dmitrii Gridin
2023-06-12 14:17:10 +02:00
committed by Space Team
parent 5af8b9e819
commit 7631e90f12
13 changed files with 117 additions and 9 deletions
@@ -48,7 +48,6 @@ internal class JavaElementDelegatingExpressionTypeSourceWithSmartPointer<TYPE :
}
}
internal class JavaElementDelegatingTypeParameterBoundTypeSourceWithSmartPointer<TYPE : PsiType>(
override val psiPointer: SmartPsiElementPointer<out PsiTypeParameter>,
private val boundIndex: Int,
@@ -68,3 +67,11 @@ internal class JavaElementDelegatingSuperTypeSourceWithSmartPointer(
) : JavaElementDelegatingTypeSourceWithSmartPointer<PsiClass, PsiClassType>() {
override fun getType(psi: PsiClass): PsiClassType = psi.superTypes[superTypeIndex]
}
internal class JavaElementDelegatingPermittedTypeSourceWithSmartPointer(
override val psiPointer: SmartPsiElementPointer<out PsiClass>,
private val permittedTypeIndex: Int,
override val factory: JavaElementSourceFactory,
) : JavaElementDelegatingTypeSourceWithSmartPointer<PsiClass, PsiClassType>() {
override fun getType(psi: PsiClass): PsiClassType = psi.permitsListTypes[permittedTypeIndex]
}
@@ -61,4 +61,16 @@ class JavaElementSourceWithSmartPointerFactory(project: Project) : JavaElementSo
require(psiExpressionSource is JavaElementPsiSourceWithSmartPointer)
return JavaElementDelegatingExpressionTypeSourceWithSmartPointer(psiExpressionSource.pointer, psiExpressionSource.factory)
}
override fun createPermittedTypeSource(
psiTypeParameterSource: JavaElementPsiSource<out PsiClass>,
permittedTypeIndex: Int
): JavaElementTypeSource<PsiClassType> {
require(psiTypeParameterSource is JavaElementPsiSourceWithSmartPointer)
return JavaElementDelegatingPermittedTypeSourceWithSmartPointer(
psiTypeParameterSource.pointer,
permittedTypeIndex,
psiTypeParameterSource.factory,
)
}
}
@@ -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);
@@ -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);
@@ -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);
}
@@ -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|
}
@@ -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
}
@@ -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);
@@ -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);
@@ -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) {
@@ -23,7 +23,7 @@ private val FirSession.sealedClassInheritorsProvider: SealedClassInheritorsProvi
object SealedClassInheritorsProviderImpl : SealedClassInheritorsProvider() {
@OptIn(SealedClassInheritorsProviderInternals::class)
override fun getSealedClassInheritors(firClass: FirRegularClass): List<ClassId> {
return firClass.sealedInheritorsAttr ?: emptyList()
return firClass.sealedInheritorsAttr?.value ?: emptyList()
}
}
@@ -36,11 +36,17 @@ fun FirRegularClass.getSealedClassInheritors(session: FirSession): List<ClassId>
@OptIn(SealedClassInheritorsProviderInternals::class)
fun FirRegularClass.setSealedClassInheritors(inheritors: List<ClassId>) {
require(this.isSealed)
sealedInheritorsAttr = inheritors.sortedBy { it.asFqNameString() }
sealedInheritorsAttr = lazyOf(inheritors.sortedBy { it.asFqNameString() })
}
@OptIn(SealedClassInheritorsProviderInternals::class)
fun FirRegularClass.setSealedClassInheritors(inheritorComputer: () -> List<ClassId>) {
require(this.isSealed)
sealedInheritorsAttr = lazy { inheritorComputer().sortedBy { it.asFqNameString() } }
}
private object SealedClassInheritorsKey : FirDeclarationDataKey()
@SealedClassInheritorsProviderInternals
var FirRegularClass.sealedInheritorsAttr: List<ClassId>? by FirDeclarationDataRegistry.data(SealedClassInheritorsKey)
var FirRegularClass.sealedInheritorsAttr: Lazy<List<ClassId>>? by FirDeclarationDataRegistry.data(SealedClassInheritorsKey)
private set
@@ -69,7 +69,9 @@ class JavaClassImpl(psiClassSource: JavaElementPsiSource<PsiClass>) : JavaClassi
get() = JavaElementUtil.isSealed(this)
override val permittedTypes: Collection<JavaClassifierType>
get() = classifierTypes(psi.permitsListTypes, sourceFactory)
get() = psi.permitsListTypes.convertIndexed { index, _ ->
JavaClassifierTypeImpl(sourceFactory.createPermittedTypeSource(psiElementSource, index))
}
override val isRecord: Boolean
get() = psi.isRecord
@@ -26,6 +26,14 @@ abstract class JavaElementSourceFactory {
abstract fun <TYPE : PsiType> createExpressionTypeSource(psiExpressionSource: JavaElementPsiSource<out PsiExpression>): JavaElementTypeSource<TYPE>
/**
* @see com.intellij.psi.PsiClass.getPermitsListTypes
*/
abstract fun createPermittedTypeSource(
psiTypeParameterSource: JavaElementPsiSource<out PsiClass>,
permittedTypeIndex: Int,
): JavaElementTypeSource<PsiClassType>
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<out PsiClass>,
permittedTypeIndex: Int
): JavaElementTypeSource<PsiClassType> {
return createTypeSource(psiTypeParameterSource.psi.permitsListTypes[permittedTypeIndex])
}
override fun <TYPE : PsiType> createExpressionTypeSource(psiExpressionSource: JavaElementPsiSource<out PsiExpression>): JavaElementTypeSource<TYPE> {
@Suppress("UNCHECKED_CAST")
return createTypeSource(psiExpressionSource.psi.type as TYPE)