[LL FIR, Java] fix resolve contract violation from java symbol provider

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-59133 fixed
This commit is contained in:
Ilya Kirillov
2023-06-07 14:56:56 +02:00
committed by Space Team
parent f590e88bdd
commit b8f15cbbb3
11 changed files with 114 additions and 1 deletions
@@ -47,3 +47,16 @@ internal class JavaElementDelegatingExpressionTypeSourceWithSmartPointer<TYPE :
return psi.type as TYPE
}
}
internal class JavaElementDelegatingTypeParameterBoundTypeSourceWithSmartPointer<TYPE : PsiType>(
override val psiPointer: SmartPsiElementPointer<out PsiTypeParameter>,
private val boundIndex: Int,
override val factory: JavaElementSourceFactory,
) : JavaElementDelegatingTypeSourceWithSmartPointer<PsiTypeParameter, TYPE>() {
override fun getType(psi: PsiTypeParameter): TYPE {
@Suppress("UNCHECKED_CAST")
return psi.bounds[boundIndex] as TYPE
}
}
@@ -33,6 +33,18 @@ class JavaElementSourceWithSmartPointerFactory(project: Project) : JavaElementSo
return JavaElementDelegatingMethodReturnTypeSourceWithSmartPointer(psiMethodSource.pointer, psiMethodSource.factory)
}
override fun <TYPE : PsiType> createTypeParameterUpperBoundTypeSource(
psiTypeParameterSource: JavaElementPsiSource<out PsiTypeParameter>,
boundIndex: Int
): JavaElementTypeSource<TYPE> {
require(psiTypeParameterSource is JavaElementPsiSourceWithSmartPointer)
return JavaElementDelegatingTypeParameterBoundTypeSourceWithSmartPointer(
psiTypeParameterSource.pointer,
boundIndex,
psiTypeParameterSource.factory
)
}
override fun <TYPE : PsiType> createExpressionTypeSource(psiExpressionSource: JavaElementPsiSource<out PsiExpression>): JavaElementTypeSource<TYPE> {
require(psiExpressionSource is JavaElementPsiSourceWithSmartPointer)
return JavaElementDelegatingExpressionTypeSourceWithSmartPointer(psiExpressionSource.pointer, psiExpressionSource.factory)
@@ -21,6 +21,12 @@ public class DiagnosticCompilerTestFirTestdataTestGenerated extends AbstractDiag
@TestMetadata("compiler/fir/analysis-tests/testData/resolve")
@TestDataPath("$PROJECT_ROOT")
public class Resolve {
@Test
@TestMetadata("accessJavaFromKotlinViaImport.kt")
public void testAccessJavaFromKotlinViaImport() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaImport.kt");
}
@Test
public void testAllFilesPresentInResolve() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
@@ -21,6 +21,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFirTestDataTestGenerated
@TestMetadata("compiler/fir/analysis-tests/testData/resolve")
@TestDataPath("$PROJECT_ROOT")
public class Resolve {
@Test
@TestMetadata("accessJavaFromKotlinViaImport.kt")
public void testAccessJavaFromKotlinViaImport() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaImport.kt");
}
@Test
public void testAllFilesPresentInResolve() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
@@ -25,6 +25,11 @@ public class LazyBodyIsNotTouchedTestGenerated extends AbstractLazyBodyIsNotTouc
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
@TestMetadata("accessJavaFromKotlinViaImport.kt")
public void testAccessJavaFromKotlinViaImport() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaImport.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/Unit| {
Q|InspectionProfileImpl|.R|/InspectionProfileImpl.INIT_INSPECTIONS| = Boolean(true)
}
FILE: NewInspectionProfile.kt
public abstract class NewInspectionProfile : R|kotlin/Any| {
public constructor(): R|NewInspectionProfile| {
super<R|kotlin/Any|>()
}
}
@@ -0,0 +1,21 @@
// FILE: useSite.kt
fun foo() {
InspectionProfileImpl.INIT_INSPECTIONS = true
}
// FILE: InspectionProfileImpl.java
public class InspectionProfileImpl extends NewInspectionProfile {
public static boolean INIT_INSPECTIONS;
public <T extends InspectionProfileEntry> T getUnwrappedTool() { }
}
// FILE: NewInspectionProfile.kt
import InspectionProfileImpl.INIT_INSPECTIONS
abstract class NewInspectionProfile
// FILE: InspectionProfileEntry.java
public abstract class InspectionProfileEntry {}
@@ -21,6 +21,12 @@ public class FirLightTreeDiagnosticsTestGenerated extends AbstractFirLightTreeDi
@TestMetadata("compiler/fir/analysis-tests/testData/resolve")
@TestDataPath("$PROJECT_ROOT")
public class Resolve {
@Test
@TestMetadata("accessJavaFromKotlinViaImport.kt")
public void testAccessJavaFromKotlinViaImport() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaImport.kt");
}
@Test
public void testAllFilesPresentInResolve() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
@@ -21,6 +21,12 @@ public class FirPsiDiagnosticTestGenerated extends AbstractFirPsiDiagnosticTest
@TestMetadata("compiler/fir/analysis-tests/testData/resolve")
@TestDataPath("$PROJECT_ROOT")
public class Resolve {
@Test
@TestMetadata("accessJavaFromKotlinViaImport.kt")
public void testAccessJavaFromKotlinViaImport() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/accessJavaFromKotlinViaImport.kt");
}
@Test
public void testAllFilesPresentInResolve() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.load.java.structure.impl;
import com.intellij.psi.PsiAnnotationOwner;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiTypeParameter;
import org.jetbrains.annotations.NotNull;
@@ -25,10 +26,14 @@ import org.jetbrains.kotlin.load.java.structure.JavaClassifierType;
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter;
import org.jetbrains.kotlin.load.java.structure.impl.source.JavaElementPsiSource;
import org.jetbrains.kotlin.load.java.structure.impl.source.JavaElementSourceFactory;
import org.jetbrains.kotlin.load.java.structure.impl.source.JavaElementTypeSource;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.name.SpecialNames;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import static org.jetbrains.kotlin.load.java.structure.impl.JavaElementCollectionFromPsiArrayUtil.classifierTypes;
@@ -51,7 +56,16 @@ public class JavaTypeParameterImpl extends JavaClassifierImpl<PsiTypeParameter>
@Override
@NotNull
public Collection<JavaClassifierType> getUpperBounds() {
return classifierTypes(getPsi().getExtendsList().getReferencedTypes(), getSourceFactory());
PsiClassType[] referencedTypes = getPsi().getExtendsList().getReferencedTypes();
if (referencedTypes.length == 0) return Collections.emptyList();
Collection<JavaClassifierType> result = new ArrayList<>(referencedTypes.length);
JavaElementSourceFactory sourceFactory = getSourceFactory();
for (int boundIndex = 0; boundIndex < referencedTypes.length; boundIndex++) {
JavaElementTypeSource<PsiClassType> source =
sourceFactory.createTypeParameterUpperBoundTypeSource(psiElementSource, boundIndex);
result.add(new JavaClassifierTypeImpl(source));
}
return result;
}
@Nullable
@@ -14,6 +14,11 @@ abstract class JavaElementSourceFactory {
abstract fun <TYPE : PsiType> createVariableReturnTypeSource(psiVariableSource: JavaElementPsiSource<out PsiVariable>): JavaElementTypeSource<TYPE>
abstract fun <TYPE : PsiType> createMethodReturnTypeSource(psiMethodSource: JavaElementPsiSource<out PsiMethod>): JavaElementTypeSource<TYPE>
abstract fun <TYPE : PsiType> createTypeParameterUpperBoundTypeSource(
psiTypeParameterSource: JavaElementPsiSource<out PsiTypeParameter>,
boundIndex: Int,
): JavaElementTypeSource<TYPE>
abstract fun <TYPE : PsiType> createExpressionTypeSource(psiExpressionSource: JavaElementPsiSource<out PsiExpression>): JavaElementTypeSource<TYPE>
companion object {
@@ -38,6 +43,14 @@ class JavaFixedElementSourceFactory : JavaElementSourceFactory() {
return createTypeSource(psiVariableSource.psi.type as TYPE)
}
override fun <TYPE : PsiType> createTypeParameterUpperBoundTypeSource(
psiTypeParameterSource: JavaElementPsiSource<out PsiTypeParameter>,
boundIndex: Int
): JavaElementTypeSource<TYPE> {
@Suppress("UNCHECKED_CAST")
return createTypeSource(psiTypeParameterSource.psi.bounds[boundIndex] as TYPE)
}
override fun <TYPE : PsiType> createExpressionTypeSource(psiExpressionSource: JavaElementPsiSource<out PsiExpression>): JavaElementTypeSource<TYPE> {
@Suppress("UNCHECKED_CAST")