Introduce initial version of FIR Java type enhancement
Java type enhancement is performed by a special scope kind Java FIR dump was added for multiplatform tests to look at enhancements Overrides, J2K mapping, special cases does not work yet Related to KT-29937
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
public open class Annotated : R|java/lang/Object| {
|
||||
@R|org/jetbrains/annotations/NotNull|() public open operator function foo(@R|org/jetbrains/annotations/Nullable|() param: R|ft<java/lang/String?, java/lang/String?>|?): R|ft<java/lang/String, java/lang/String>|
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class Annotated {
|
||||
@NotNull
|
||||
public String foo(@Nullable String param) {
|
||||
if (param != null) return param;
|
||||
else return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class User : Annotated() {
|
||||
fun test() {
|
||||
val x = foo("123")
|
||||
val y = foo(null)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
FILE: jvm.kt
|
||||
public final class User : R|Annotated| {
|
||||
public constructor(): super<R|Annotated|>()
|
||||
|
||||
public final function test(): R|kotlin/Unit| {
|
||||
val x: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Annotated.foo|(String(123))
|
||||
val y: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Annotated.foo|(Null(null))
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
public open class Annotated : R|java/lang/Object| {
|
||||
@R|org/jetbrains/annotations/NotNull|() public open operator function foo(@R|org/jetbrains/annotations/Nullable|() param: R|ft<java/lang/String?, java/lang/String?>|?): R|ft<java/lang/String, java/lang/String>|
|
||||
|
||||
}
|
||||
public open class AnnotatedDerived : R|Annotated| {
|
||||
public open operator function foo(param: R|ft<java/lang/String?, java/lang/String?>|?): R|ft<java/lang/String, java/lang/String>|
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class Annotated {
|
||||
@NotNull
|
||||
public String foo(@Nullable String param) {
|
||||
if (param != null) return param;
|
||||
else return "";
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
public class AnnotatedDerived extends Annotated {
|
||||
public String foo(String param) {
|
||||
return super.foo(param);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class User : AnnotatedDerived() {
|
||||
fun test() {
|
||||
val x = foo("123")
|
||||
val y = foo(null)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
FILE: jvm.kt
|
||||
public final class User : R|AnnotatedDerived| {
|
||||
public constructor(): super<R|AnnotatedDerived|>()
|
||||
|
||||
public final function test(): R|kotlin/Unit| {
|
||||
val x: R|error: Not supported: FirImplicitTypeRefImpl| = <Ambiguity: foo, [/AnnotatedDerived.foo, /Annotated.foo]>#(String(123))
|
||||
val y: R|error: Not supported: FirImplicitTypeRefImpl| = <Ambiguity: foo, [/AnnotatedDerived.foo, /Annotated.foo]>#(Null(null))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
public open class Some : R|java/lang/Object| {
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<T> public open class A : R|java/lang/Object| {
|
||||
public open operator function foo(t: R|ft<T, T?>|!): R|ft<T, T?>|!
|
||||
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ FILE: simpleFakeOverride.kt
|
||||
public constructor(): super<R|A<Some>|>()
|
||||
|
||||
public final function test(): R|kotlin/Unit| {
|
||||
R|FakeOverride</A.foo: R|ft<T, T>|!>|(<Unresolved name: Some>#())
|
||||
R|FakeOverride</A.foo: R|ft<T, T?>|!>|(<Unresolved name: Some>#())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
public open class Some : R|java/lang/Object| {
|
||||
public open operator function foo(param: R|kotlin/Int|): R|kotlin/Boolean|
|
||||
|
||||
public open operator function bar(arr: R|kotlin/IntArray|): R|kotlin/Array<ft<java/lang/String, java/lang/String?>>|
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
public class Some {
|
||||
public boolean foo(int param) {
|
||||
return param > 0;
|
||||
}
|
||||
|
||||
public String[] bar(int[] arr) {
|
||||
String[] result = new String[arr.length];
|
||||
int i = 0;
|
||||
for (int elem: arr) {
|
||||
result[i++] = elem;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class A : Some() {
|
||||
fun test() {
|
||||
val res1 = foo(1)
|
||||
val res2 = foo(-1)
|
||||
val res3 = bar(intArrayOf(0, 2, -2))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
FILE: jvm.kt
|
||||
public final class A : R|Some| {
|
||||
public constructor(): super<R|Some|>()
|
||||
|
||||
public final function test(): R|kotlin/Unit| {
|
||||
val res1: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Some.foo|(Int(1))
|
||||
val res2: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Some.foo|(<Unresolved name: unaryMinus>#(Int(1)))
|
||||
val res3: R|error: Not supported: FirImplicitTypeRefImpl| = R|/Some.bar|(<Unresolved name: intArrayOf>#(Int(0), Int(2), <Unresolved name: unaryMinus>#(Int(2))))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
public open class A : R|java/lang/Object| {
|
||||
public open operator function foo(): R|ft<A, A?>|!
|
||||
|
||||
public open operator function bar(): R|ft<A, A?>|!
|
||||
|
||||
}
|
||||
@@ -12,15 +12,26 @@ import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.search.FileTypeIndex
|
||||
import org.jetbrains.kotlin.fir.FirRenderer
|
||||
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.dependenciesWithoutSelf
|
||||
import org.jetbrains.kotlin.fir.java.FirJavaModuleBasedSession
|
||||
import org.jetbrains.kotlin.fir.java.FirLibrarySession
|
||||
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
|
||||
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
|
||||
import org.jetbrains.kotlin.fir.java.declarations.FirJavaMethod
|
||||
import org.jetbrains.kotlin.fir.java.scopes.JavaClassEnhancementScope
|
||||
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirScopeProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.impl.FirCompositeSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.impl.FirProviderImpl
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.FirTotalResolveTransformer
|
||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.isLibraryClasses
|
||||
@@ -64,9 +75,11 @@ abstract class AbstractFirMultiModuleResolveTest : AbstractMultiModuleTest() {
|
||||
|
||||
private fun doFirResolveTest(dirPath: String) {
|
||||
val firFiles = mutableListOf<FirFile>()
|
||||
val sessions = mutableListOf<FirJavaModuleBasedSession>()
|
||||
val provider = FirProjectSessionProvider(project)
|
||||
for (module in project.allModules().drop(1)) {
|
||||
val session = createSession(module, provider)
|
||||
sessions += session
|
||||
|
||||
val builder = RawFirBuilder(session, stubMode = false)
|
||||
val psiManager = PsiManager.getInstance(project)
|
||||
@@ -112,5 +125,54 @@ abstract class AbstractFirMultiModuleResolveTest : AbstractMultiModuleTest() {
|
||||
val expectedPath = expectedTxtPath((file.psi as PsiFile).virtualFile)
|
||||
KotlinTestUtils.assertEqualsToFile(File(expectedPath), firFileDump)
|
||||
}
|
||||
val processedJavaClasses = mutableSetOf<FirJavaClass>()
|
||||
val javaFirDump = StringBuilder().also { builder ->
|
||||
val renderer = FirRenderer(builder)
|
||||
for (session in sessions) {
|
||||
val symbolProvider = session.service<FirSymbolProvider>() as FirCompositeSymbolProvider
|
||||
val javaProvider = symbolProvider.providers.filterIsInstance<JavaSymbolProvider>().first()
|
||||
for (javaClass in javaProvider.getJavaTopLevelClasses().sortedBy { it.name }) {
|
||||
if (javaClass !is FirJavaClass || javaClass in processedJavaClasses) continue
|
||||
val enhancementScope = session.service<FirScopeProvider>().getDeclaredMemberScope(javaClass, session).let {
|
||||
when (it) {
|
||||
is FirCompositeScope -> it.scopes.filterIsInstance<JavaClassEnhancementScope>().first()
|
||||
is JavaClassEnhancementScope -> it
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
if (enhancementScope == null) {
|
||||
javaClass.accept(renderer, null)
|
||||
} else {
|
||||
renderer.visitMemberDeclaration(javaClass)
|
||||
renderer.renderSupertypes(javaClass)
|
||||
renderer.renderInBraces {
|
||||
val renderedDeclarations = mutableListOf<FirDeclaration>()
|
||||
for (declaration in javaClass.declarations) {
|
||||
if (declaration in renderedDeclarations) continue
|
||||
if (declaration !is FirJavaMethod) {
|
||||
declaration.accept(renderer, null)
|
||||
renderer.newLine()
|
||||
renderedDeclarations += declaration
|
||||
} else {
|
||||
enhancementScope.processFunctionsByName(declaration.name) { symbol ->
|
||||
val enhanced = (symbol as? FirFunctionSymbol)?.fir
|
||||
if (enhanced != null && enhanced !in renderedDeclarations) {
|
||||
enhanced.accept(renderer, null)
|
||||
renderer.newLine()
|
||||
renderedDeclarations += enhanced
|
||||
}
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
processedJavaClasses += javaClass
|
||||
}
|
||||
}
|
||||
}.toString()
|
||||
if (javaFirDump.isNotEmpty()) {
|
||||
KotlinTestUtils.assertEqualsToFile(File("$dirPath/extraDump.java.txt"), javaFirDump)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
@@ -34,6 +34,16 @@ public class FirMultiModuleResolveTestGenerated extends AbstractFirMultiModuleRe
|
||||
runTest("idea/testData/fir/multiModule/basic/");
|
||||
}
|
||||
|
||||
@TestMetadata("basicWithAnnotatedJava")
|
||||
public void testBasicWithAnnotatedJava() throws Exception {
|
||||
runTest("idea/testData/fir/multiModule/basicWithAnnotatedJava/");
|
||||
}
|
||||
|
||||
@TestMetadata("basicWithAnnotatedOverriddenJava")
|
||||
public void testBasicWithAnnotatedOverriddenJava() throws Exception {
|
||||
runTest("idea/testData/fir/multiModule/basicWithAnnotatedOverriddenJava/");
|
||||
}
|
||||
|
||||
@TestMetadata("basicWithJava")
|
||||
public void testBasicWithJava() throws Exception {
|
||||
runTest("idea/testData/fir/multiModule/basicWithJava/");
|
||||
@@ -44,6 +54,11 @@ public class FirMultiModuleResolveTestGenerated extends AbstractFirMultiModuleRe
|
||||
runTest("idea/testData/fir/multiModule/basicWithJavaFakeOverride/");
|
||||
}
|
||||
|
||||
@TestMetadata("basicWithPrimitiveJava")
|
||||
public void testBasicWithPrimitiveJava() throws Exception {
|
||||
runTest("idea/testData/fir/multiModule/basicWithPrimitiveJava/");
|
||||
}
|
||||
|
||||
@TestMetadata("mppFakeOverrides")
|
||||
public void testMppFakeOverrides() throws Exception {
|
||||
runTest("idea/testData/fir/multiModule/mppFakeOverrides/");
|
||||
|
||||
Reference in New Issue
Block a user