New J2K: Cache resolving by fqNames

This commit is contained in:
Ilya Kirillov
2019-02-03 16:56:54 +03:00
committed by Ilya Kirillov
parent ea6cb716e5
commit c111f1c52f
6 changed files with 56 additions and 64 deletions
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class JKSymbolProvider { class JKSymbolProvider {
val symbolsByFqName = mutableMapOf<String, JKSymbol>()
val symbolsByPsi = mutableMapOf<PsiElement, JKSymbol>() val symbolsByPsi = mutableMapOf<PsiElement, JKSymbol>()
val symbolsByJK = mutableMapOf<JKDeclaration, JKSymbol>() val symbolsByJK = mutableMapOf<JKDeclaration, JKSymbol>()
@@ -89,30 +90,50 @@ class JKSymbolProvider {
JKUniverseMethodSymbol(this).also { it.target = jk } JKUniverseMethodSymbol(this).also { it.target = jk }
} as JKMethodSymbol } as JKMethodSymbol
internal inline fun <reified T : JKSymbol> provideByFqName(classId: ClassId, context: PsiElement = symbolsByPsi.keys.first()): T { internal inline fun <reified T : JKSymbol> provideByFqName(
return resolveFqName(classId, context)?.let(::provideDirectSymbol).safeAs<T>() ?: when { classId: ClassId,
isAssignable<T, JKUnresolvedMethod>() -> JKUnresolvedMethod(classId.asSingleFqName().asString().replace('/', '.')) multiResolve: Boolean = false,
isAssignable<T, JKUnresolvedField>() -> JKUnresolvedField(classId.asSingleFqName().asString().replace('/', '.'), this) context: PsiElement = symbolsByPsi.keys.first()
else -> JKUnresolvedClassSymbol(classId.asSingleFqName().asString().replace('/', '.')) ): T {
val fqName = classId.asSingleFqName().asString().replace('/', '.')
if (fqName in symbolsByFqName) {
return symbolsByFqName[fqName] as T
}
val resolved =
if (multiResolve) multiResolveFqName(classId, context).firstOrNull()
else resolveFqName(classId, context)
val symbol = resolved?.let(::provideDirectSymbol).safeAs<T>()
return symbol ?: when {
isAssignable<T, JKUnresolvedMethod>() -> JKUnresolvedMethod(fqName)
isAssignable<T, JKUnresolvedField>() -> JKUnresolvedField(fqName, this)
else -> JKUnresolvedClassSymbol(fqName)
} as T } as T
} }
internal inline fun <reified T : JKSymbol> provideByFqNameMulti(fqName: String, context: PsiElement = symbolsByPsi.keys.first()): T { @Deprecated("", ReplaceWith("provideByFqName(fqName, true, context)"))
return multiResolveFqName(ClassId.fromString(fqName), context).firstOrNull()?.let(::provideDirectSymbol).safeAs<T>() ?: when { internal inline fun <reified T : JKSymbol> provideByFqNameMulti(fqName: String, context: PsiElement = symbolsByPsi.keys.first()): T =
isAssignable<T, JKUnresolvedMethod>() -> JKUnresolvedMethod(fqName.replace('/', '.')) provideByFqName(ClassId.fromString(fqName), true, context)
isAssignable<T, JKUnresolvedField>() -> JKUnresolvedField(fqName.replace('/', '.'), this)
else -> JKUnresolvedClassSymbol(fqName.replace('/', '.'))
} as T
}
internal inline fun <reified T : JKSymbol> provideByFqName(fqName: String, context: PsiElement = symbolsByPsi.keys.first()): T = internal inline fun <reified T : JKSymbol> provideByFqName(
provideByFqName(ClassId.fromString(fqName), context) fqName: String,
multiResolve: Boolean = false,
context: PsiElement = symbolsByPsi.keys.first()
): T =
provideByFqName(ClassId.fromString(fqName), multiResolve, context)
internal inline fun <reified T : JKSymbol> provideByFqName(fqName: FqName, context: PsiElement = symbolsByPsi.keys.first()): T = internal inline fun <reified T : JKSymbol> provideByFqName(
provideByFqName(fqName.asString(), context) fqName: FqName,
multiResolve: Boolean = false,
context: PsiElement = symbolsByPsi.keys.first()
): T =
provideByFqName(fqName.asString(), multiResolve, context)
internal inline fun <reified T : JKSymbol> provideByFqName(fqName: FqNameUnsafe, context: PsiElement = symbolsByPsi.keys.first()): T = internal inline fun <reified T : JKSymbol> provideByFqName(
provideByFqName(fqName.asString(), context) fqName: FqNameUnsafe,
multiResolve: Boolean = false,
context: PsiElement = symbolsByPsi.keys.first()
): T =
provideByFqName(fqName.asString(), multiResolve, context)
private inner class ElementVisitor : JavaElementVisitor() { private inner class ElementVisitor : JavaElementVisitor() {
@@ -23,20 +23,13 @@ class BlockToRunConversion(private val context: ConversionContext) : RecursiveAp
val parentDeclaration = element.parentOfType<JKDeclaration>() ?: return recurse(element) val parentDeclaration = element.parentOfType<JKDeclaration>() ?: return recurse(element)
val psiContext = parentDeclaration.psi ?: return recurse(element) val psiContext = parentDeclaration.psi ?: return recurse(element)
val unitType =
context.symbolProvider.provideDirectSymbol(
resolveFqName(ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.unit.toSafe()), psiContext)!!
)
val runSymbol = context.symbolProvider.provideDirectSymbol(
multiResolveFqName(ClassId.fromString("kotlin/run"), psiContext).first()
)
element.invalidate() element.invalidate()
val lambda = JKLambdaExpressionImpl( val lambda = JKLambdaExpressionImpl(
JKBlockStatementImpl(element.block), JKBlockStatementImpl(element.block),
emptyList() emptyList()
) )
val call = JKKtCallExpressionImpl(runSymbol as JKMethodSymbol, JKExpressionListImpl(listOf(lambda))) val call = JKKtCallExpressionImpl(context.symbolProvider.provideByFqName("kotlin.run", true), JKExpressionListImpl(listOf(lambda)))
return recurse(JKExpressionStatementImpl(call)) return recurse(JKExpressionStatementImpl(call))
} }
@@ -22,26 +22,19 @@ import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.math.BigInteger import java.math.BigInteger
fun kotlinTypeByName(name: String, symbolProvider: JKSymbolProvider, nullability: Nullability = Nullability.Nullable): JKClassType { fun kotlinTypeByName(name: String, symbolProvider: JKSymbolProvider, nullability: Nullability = Nullability.Nullable): JKClassType =
val symbol = JKClassTypeImpl(
symbolProvider.provideDirectSymbol( symbolProvider.provideByFqName(name),
resolveFqName(ClassId.fromString(name), symbolProvider.symbolsByPsi.keys.first())!! emptyList(),
) as JKClassSymbol nullability
return JKClassTypeImpl(symbol, emptyList(), nullability) )
}
private fun JKType.classSymbol(symbolProvider: JKSymbolProvider) = private fun JKType.classSymbol(symbolProvider: JKSymbolProvider) =
when (this) { when (this) {
is JKClassType -> classReference is JKClassType -> classReference
is JKJavaPrimitiveType -> { is JKJavaPrimitiveType ->
val psiClass = resolveFqName( symbolProvider.provideByFqName(jvmPrimitiveType.primitiveType.typeFqName.asString())
ClassId.fromString(jvmPrimitiveType.primitiveType.typeFqName.asString()),
symbolProvider.symbolsByPsi.keys.first()
)
psiClass?.let { klass ->
symbolProvider.provideDirectSymbol(klass) as? JKClassSymbol
}
}
else -> null else -> null
} }
@@ -285,14 +278,7 @@ fun useExpression(
body: JKStatement, body: JKStatement,
symbolProvider: JKSymbolProvider symbolProvider: JKSymbolProvider
): JKExpression { ): JKExpression {
val useSymbol = val useSymbol = symbolProvider.provideByFqName<JKMethodSymbol>("kotlin.io.use")
symbolProvider
.provideDirectSymbol(
resolveFqName(
ClassId.fromString("kotlin.io.use"),
symbolProvider.symbolsByPsi.keys.first()
)!!
) as JKMethodSymbol
val lambdaParameter = val lambdaParameter =
JKParameterImpl(JKTypeElementImpl(JKNoTypeImpl), variableIdentifier) JKParameterImpl(JKTypeElementImpl(JKNoTypeImpl), variableIdentifier)
@@ -229,9 +229,7 @@ class JKBooleanLiteral(val value: Boolean) : JKLiteralExpression, JKElementBase(
fun JKLiteralExpression.LiteralType.toJkType(symbolProvider: JKSymbolProvider): JKType { fun JKLiteralExpression.LiteralType.toJkType(symbolProvider: JKSymbolProvider): JKType {
fun defaultTypeByName(name: String) = fun defaultTypeByName(name: String) =
JKClassTypeImpl( JKClassTypeImpl(
symbolProvider.provideDirectSymbol( symbolProvider.provideByFqName("kotlin.$name"), emptyList(), Nullability.NotNull
resolveFqName(ClassId.fromString("kotlin.$name"), symbolProvider.symbolsByPsi.keys.first())!!
) as JKClassSymbol, emptyList(), Nullability.NotNull
) )
return when (this) { return when (this) {
@@ -213,11 +213,7 @@ class JKUnresolvedField(override val target: String, private val symbolProvider:
get() { get() {
val resolvedType = (target as? PsiReferenceExpressionImpl)?.type val resolvedType = (target as? PsiReferenceExpressionImpl)?.type
if (resolvedType != null) return resolvedType.toJK(symbolProvider) if (resolvedType != null) return resolvedType.toJK(symbolProvider)
return JKClassTypeImpl(symbolProvider.provideByFqName("kotlin.Nothing"), emptyList())
val nothingSymbol = (symbolProvider.provideDirectSymbol(
resolveFqName(ClassId.fromString("kotlin.Nothing"), symbolProvider.symbolsByPsi.keys.first())!!
) as JKClassSymbol)
return JKClassTypeImpl(nothingSymbol, emptyList())
} }
override val declaredIn: JKSymbol override val declaredIn: JKSymbol
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
@@ -67,12 +67,10 @@ fun JKExpression.type(symbolProvider: JKSymbolProvider): JKType? =
fun ClassId.toKtClassType( fun ClassId.toKtClassType(
symbolProvider: JKSymbolProvider, symbolProvider: JKSymbolProvider,
nullability: Nullability = Nullability.Default, nullability: Nullability = Nullability.Default
context: PsiElement = symbolProvider.symbolsByPsi.keys.first() ): JKType =
): JKType { JKClassTypeImpl(symbolProvider.provideByFqName(this), emptyList(), nullability)
val typeSymbol = symbolProvider.provideDirectSymbol(resolveFqName(this, context)!!) as JKClassSymbol
return JKClassTypeImpl(typeSymbol, emptyList(), nullability)
}
fun PsiType.toJK(symbolProvider: JKSymbolProvider, nullability: Nullability = Nullability.Default): JKType { fun PsiType.toJK(symbolProvider: JKSymbolProvider, nullability: Nullability = Nullability.Default): JKType {
return when (this) { return when (this) {