JVM_IR KT-45103 optimize direct invoke for lambdas and callable refs

This commit is contained in:
Dmitry Petrov
2021-04-26 17:17:25 +03:00
committed by teamcityserver
parent bfb1a06f3d
commit 851980e36f
124 changed files with 1340 additions and 324 deletions
@@ -8,9 +8,7 @@ package org.jetbrains.kotlin.asJava
import com.intellij.openapi.util.io.FileUtil
import com.intellij.psi.PsiClass
import junit.framework.TestCase
import org.jetbrains.kotlin.asJava.PsiClassRenderer.renderClass
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
import java.util.regex.Pattern
@@ -22,6 +20,7 @@ object LightClassTestCommon {
testDataFile: File,
findLightClass: (String) -> PsiClass?,
normalizeText: (String) -> String,
membersFilter: PsiClassRenderer.MembersFilter = PsiClassRenderer.MembersFilter.DEFAULT
): String {
val text = FileUtil.loadFile(testDataFile, true)
val matcher = SUBJECT_FQ_NAME_PATTERN.matcher(text)
@@ -30,15 +29,20 @@ object LightClassTestCommon {
val lightClass = findLightClass(fqName)
return actualText(fqName, lightClass, normalizeText)
return actualText(fqName, lightClass, normalizeText, membersFilter)
}
private fun actualText(fqName: String?, lightClass: PsiClass?, normalizeText: (String) -> String): String {
private fun actualText(
fqName: String?,
lightClass: PsiClass?,
normalizeText: (String) -> String,
membersFilter: PsiClassRenderer.MembersFilter
): String {
if (lightClass == null) {
return NOT_GENERATED_DIRECTIVE
}
TestCase.assertTrue("Not a light class: $lightClass ($fqName)", lightClass is KtLightClass)
return normalizeText(lightClass.renderClass(renderInner = true))
return normalizeText(PsiClassRenderer.renderClass(lightClass, renderInner = true, membersFilter = membersFilter))
}
// Actual text for light class is generated with ClsElementImpl.appendMirrorText() that can find empty DefaultImpl inner class in stubs
@@ -14,11 +14,67 @@ import org.jetbrains.kotlin.load.kotlin.NON_EXISTENT_CLASS_NAME
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
fun PsiClass.renderClass() = PsiClassRenderer.renderClass(this)
object PsiClassRenderer {
class PsiClassRenderer private constructor(
private val renderInner: Boolean,
private val membersFilter: MembersFilter
) {
var extendedTypeRenderer = false
interface MembersFilter {
fun includeEnumConstant(psiEnumConstant: PsiEnumConstant): Boolean = true
fun includeField(psiField: PsiField): Boolean = true
fun includeMethod(psiMethod: PsiMethod): Boolean = true
fun includeClass(psiClass: PsiClass): Boolean = true
companion object {
val DEFAULT = object : MembersFilter {}
}
}
companion object {
var extendedTypeRenderer = false
fun renderClass(
psiClass: PsiClass,
renderInner: Boolean = false,
membersFilter: MembersFilter = MembersFilter.DEFAULT
): String =
PsiClassRenderer(renderInner, membersFilter).renderClass(psiClass)
}
private fun renderClass(psiClass: PsiClass): String =
buildString {
val classWord = when {
psiClass.isAnnotationType -> "@interface"
psiClass.isInterface -> "interface"
psiClass.isEnum -> "enum"
else -> "class"
}
append(psiClass.renderModifiers())
append("$classWord ")
append("${psiClass.name} /* ${psiClass.qualifiedName}*/")
append(psiClass.typeParameters.renderTypeParams())
append(psiClass.extendsList.renderRefList("extends"))
append(psiClass.implementsList.renderRefList("implements"))
appendLine(" {")
if (psiClass.isEnum) {
append(
psiClass.fields
.filterIsInstance<PsiEnumConstant>()
.filter { membersFilter.includeEnumConstant(it) }
.joinToString(",\n") { it.renderEnumConstant() }.prependDefaultIndent()
)
append(";\n\n")
}
append(psiClass.renderMembers())
append("}")
}
private fun PsiType.renderType() = StringBuffer().also { renderType(it) }.toString()
private fun PsiType.renderType(sb: StringBuffer) {
@@ -126,69 +182,41 @@ object PsiClassRenderer {
return "$typeParams $name$paramTypes"
}
private fun PsiEnumConstant.renderEnumConstant(renderInner: Boolean): String {
private fun PsiEnumConstant.renderEnumConstant(): String {
val initializingClass = initializingClass ?: return name
return buildString {
appendLine("$name {")
append(initializingClass.renderMembers(renderInner))
append(initializingClass.renderMembers())
append("}")
}
}
fun PsiClass.renderClass(renderInner: Boolean = false): String {
val classWord = when {
isAnnotationType -> "@interface"
isInterface -> "interface"
isEnum -> "enum"
else -> "class"
}
return buildString {
append(renderModifiers())
append("$classWord ")
append("$name /* $qualifiedName*/")
append(typeParameters.renderTypeParams())
append(extendsList.renderRefList("extends"))
append(implementsList.renderRefList("implements"))
appendLine(" {")
if (isEnum) {
append(
fields
.filterIsInstance<PsiEnumConstant>()
.joinToString(",\n") { it.renderEnumConstant(renderInner) }.prependDefaultIndent()
)
append(";\n\n")
}
append(renderMembers(renderInner))
append("}")
}
}
private fun PsiClass.renderMembers(renderInner: Boolean): String {
private fun PsiClass.renderMembers(): String {
return buildString {
appendSorted(
fields
.filterNot { it is PsiEnumConstant }
.filter { membersFilter.includeField(it) }
.map { it.renderVar().prependDefaultIndent() + ";\n\n" }
)
appendSorted(
methods
.filter { membersFilter.includeMethod(it) }
.map { it.renderMethod().prependDefaultIndent() + "\n\n" }
)
appendSorted(
innerClasses.map {
appendLine()
if (renderInner)
it.renderClass(renderInner)
else
"class ${it.name} ...\n\n".prependDefaultIndent()
}
innerClasses
.filter { membersFilter.includeClass(it) }
.map {
appendLine()
if (renderInner)
renderClass(it, renderInner)
else
"class ${it.name} ...\n\n".prependDefaultIndent()
}
)
}
}