New J2K: move helper functions to corresponding files & use better names for tree nodes files
This commit is contained in:
-1
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.nj2k.inference.common
|
||||
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.nj2k.inference.common.collectors.ConstraintsCollector
|
||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtImportDirective
|
||||
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.nj2k.conversions
|
||||
|
||||
import org.jetbrains.kotlin.nj2k.tree.JKElement
|
||||
|
||||
inline fun <reified T : JKElement> JKElement.parentOfType(): T? {
|
||||
return generateSequence(parent) { it.parent }.filterIsInstance<T>().firstOrNull()
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.nj2k.conversions
|
||||
|
||||
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||
import org.jetbrains.kotlin.nj2k.tree.*
|
||||
import org.jetbrains.kotlin.nj2k.tree.impl.*
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.nj2k.conversions
|
||||
|
||||
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||
import org.jetbrains.kotlin.nj2k.tree.*
|
||||
import org.jetbrains.kotlin.nj2k.tree.impl.JKKtConstructorImpl
|
||||
import org.jetbrains.kotlin.nj2k.tree.impl.JKStubExpressionImpl
|
||||
|
||||
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.nj2k.conversions
|
||||
|
||||
import com.intellij.psi.PsiEnumConstant
|
||||
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||
import org.jetbrains.kotlin.nj2k.symbols.*
|
||||
import org.jetbrains.kotlin.nj2k.tree.*
|
||||
import org.jetbrains.kotlin.nj2k.tree.impl.JKClassAccessExpressionImpl
|
||||
|
||||
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.nj2k.conversions
|
||||
|
||||
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||
import org.jetbrains.kotlin.nj2k.findUsages
|
||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||
import org.jetbrains.kotlin.nj2k.symbols.JKMethodSymbol
|
||||
import org.jetbrains.kotlin.nj2k.tree.*
|
||||
import org.jetbrains.kotlin.nj2k.tree.impl.JKBooleanLiteral
|
||||
|
||||
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.nj2k.conversions
|
||||
|
||||
import com.intellij.psi.PsiMember
|
||||
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||
import org.jetbrains.kotlin.nj2k.tree.*
|
||||
import org.jetbrains.kotlin.nj2k.tree.impl.psi
|
||||
import org.jetbrains.kotlin.nj2k.visibility
|
||||
|
||||
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.nj2k.conversions
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiMethod
|
||||
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||
import org.jetbrains.kotlin.nj2k.tree.*
|
||||
import org.jetbrains.kotlin.nj2k.tree.impl.JKOtherModifierElementImpl
|
||||
import org.jetbrains.kotlin.nj2k.tree.impl.psi
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.nj2k.conversions
|
||||
|
||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||
import org.jetbrains.kotlin.nj2k.tree.*
|
||||
|
||||
class RemoveWrongExtraModifiersForSingleFunctionsConversion : RecursiveApplicableConversionBase() {
|
||||
|
||||
-1
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.nj2k.conversions
|
||||
|
||||
import org.jetbrains.kotlin.nj2k.asStatement
|
||||
import org.jetbrains.kotlin.nj2k.copyTreeAndDetach
|
||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||
import org.jetbrains.kotlin.nj2k.tree.*
|
||||
import org.jetbrains.kotlin.nj2k.tree.impl.JKLabelTextImpl
|
||||
import org.jetbrains.kotlin.nj2k.tree.impl.JKLabeledStatementImpl
|
||||
|
||||
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.j2k.getContainingClass
|
||||
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||
import org.jetbrains.kotlin.nj2k.asQualifierWithThisAsSelector
|
||||
import org.jetbrains.kotlin.nj2k.copyTreeAndDetach
|
||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||
import org.jetbrains.kotlin.nj2k.symbols.JKClassSymbol
|
||||
import org.jetbrains.kotlin.nj2k.symbols.JKSymbol
|
||||
import org.jetbrains.kotlin.nj2k.tree.*
|
||||
|
||||
@@ -10,9 +10,9 @@ import com.intellij.psi.PsiMember
|
||||
import com.intellij.psi.PsiNamedElement
|
||||
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
|
||||
import org.jetbrains.kotlin.nj2k.JKSymbolProvider
|
||||
import org.jetbrains.kotlin.nj2k.parentOfType
|
||||
import org.jetbrains.kotlin.nj2k.tree.JKDeclaration
|
||||
import org.jetbrains.kotlin.nj2k.tree.JKFile
|
||||
import org.jetbrains.kotlin.nj2k.tree.parentOfType
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.nj2k.tree
|
||||
|
||||
import org.jetbrains.kotlin.j2k.ast.Nullability
|
||||
|
||||
interface JKOperator {
|
||||
val token: JKOperatorToken
|
||||
val precedence: Int
|
||||
}
|
||||
|
||||
interface JKOperatorToken {
|
||||
val text: String
|
||||
}
|
||||
|
||||
interface JKKtOperatorToken : JKOperatorToken {
|
||||
val operatorName: String
|
||||
}
|
||||
|
||||
interface JKQualifier
|
||||
|
||||
interface JKElement {
|
||||
val parent: JKElement?
|
||||
|
||||
fun detach(from: JKElement)
|
||||
|
||||
fun attach(to: JKElement)
|
||||
}
|
||||
|
||||
|
||||
interface JKBranchElement : JKElement {
|
||||
val children: List<Any>
|
||||
|
||||
val valid: Boolean
|
||||
fun invalidate()
|
||||
}
|
||||
|
||||
interface JKType {
|
||||
val nullability: Nullability
|
||||
}
|
||||
+3
-95
@@ -16,105 +16,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.nj2k.tree
|
||||
|
||||
import org.jetbrains.kotlin.j2k.ast.Nullability
|
||||
import org.jetbrains.kotlin.nj2k.symbols.JKClassSymbol
|
||||
import org.jetbrains.kotlin.nj2k.symbols.JKTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.nj2k.tree.impl.JKBranchElementBase
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import kotlin.jvm.internal.CallableReference
|
||||
import kotlin.reflect.KProperty0
|
||||
|
||||
interface JKOperator {
|
||||
val token: JKOperatorToken
|
||||
val precedence: Int
|
||||
}
|
||||
|
||||
interface JKOperatorToken {
|
||||
val text: String
|
||||
}
|
||||
|
||||
interface JKKtOperatorToken : JKOperatorToken {
|
||||
val operatorName: String
|
||||
}
|
||||
|
||||
interface JKQualifier
|
||||
|
||||
interface JKElement {
|
||||
val parent: JKElement?
|
||||
|
||||
fun detach(from: JKElement)
|
||||
|
||||
fun attach(to: JKElement)
|
||||
}
|
||||
|
||||
interface JKBranchElement : JKElement {
|
||||
val children: List<Any>
|
||||
|
||||
val valid: Boolean
|
||||
fun invalidate()
|
||||
}
|
||||
|
||||
interface JKType {
|
||||
val nullability: Nullability
|
||||
}
|
||||
|
||||
fun JKType.isNullable(): Boolean =
|
||||
nullability != Nullability.NotNull
|
||||
|
||||
interface JKWildCardType : JKType
|
||||
|
||||
interface JKVarianceTypeParameterType : JKWildCardType {
|
||||
val variance: Variance
|
||||
val boundType: JKType
|
||||
override val nullability: Nullability
|
||||
get() = Nullability.Default
|
||||
|
||||
enum class Variance {
|
||||
IN, OUT
|
||||
}
|
||||
}
|
||||
|
||||
interface JKTypeParameterType : JKType {
|
||||
val identifier: JKTypeParameterSymbol
|
||||
}
|
||||
|
||||
interface JKNoType : JKType
|
||||
|
||||
interface JKParametrizedType : JKType {
|
||||
val parameters: List<JKType>
|
||||
}
|
||||
|
||||
interface JKClassType : JKParametrizedType {
|
||||
val classReference: JKClassSymbol
|
||||
override val nullability: Nullability
|
||||
}
|
||||
|
||||
interface JKJavaPrimitiveType : JKType {
|
||||
val jvmPrimitiveType: JvmPrimitiveType
|
||||
override val nullability: Nullability
|
||||
get() = Nullability.NotNull
|
||||
}
|
||||
|
||||
interface JKJavaArrayType : JKType {
|
||||
val type: JKType
|
||||
}
|
||||
|
||||
interface JKStarProjectionType : JKWildCardType {
|
||||
override val nullability: Nullability
|
||||
get() = Nullability.NotNull
|
||||
}
|
||||
|
||||
interface JKJavaDisjunctionType : JKType {
|
||||
val disjunctions: List<JKType>
|
||||
}
|
||||
|
||||
inline fun <reified T> JKElement.getParentOfType(): T? {
|
||||
var p = parent
|
||||
while (true) {
|
||||
if (p is T || p == null)
|
||||
return p as? T
|
||||
p = p.parent
|
||||
}
|
||||
inline fun <reified T : JKElement> JKElement.parentOfType(): T? {
|
||||
return generateSequence(parent) { it.parent }.filterIsInstance<T>().firstOrNull()
|
||||
}
|
||||
|
||||
private fun <T : JKElement> KProperty0<Any>.detach(element: T) {
|
||||
@@ -126,6 +34,7 @@ private fun <T : JKElement> KProperty0<Any>.detach(element: T) {
|
||||
element.detach(boundReceiver)
|
||||
}
|
||||
|
||||
|
||||
fun <T : JKElement> KProperty0<T>.detached(): T =
|
||||
get().also { detach(it) }
|
||||
|
||||
@@ -138,7 +47,6 @@ fun <T : JKElement> T.detached(from: JKElement): T =
|
||||
fun <T : JKBranchElement> T.invalidated(): T =
|
||||
also { it.invalidate() }
|
||||
|
||||
|
||||
fun <R : JKTreeElement, T> applyRecursive(
|
||||
element: R,
|
||||
data: T,
|
||||
@@ -1,406 +1,58 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.nj2k.tree
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
|
||||
import org.jetbrains.kotlin.j2k.ast.Nullability
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.nj2k.JKSymbolProvider
|
||||
import org.jetbrains.kotlin.nj2k.kotlinTypeByName
|
||||
import org.jetbrains.kotlin.nj2k.symbols.*
|
||||
import org.jetbrains.kotlin.nj2k.tree.impl.*
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtTypeParameter
|
||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.nj2k.symbols.JKClassSymbol
|
||||
import org.jetbrains.kotlin.nj2k.symbols.JKTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.isNullable
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
fun JKExpression.type(symbolProvider: JKSymbolProvider): JKType? =
|
||||
when (this) {
|
||||
is JKLiteralExpression -> type.toJkType(symbolProvider)
|
||||
is JKOperatorExpression -> {
|
||||
val operator = operator
|
||||
when (operator) {
|
||||
is JKKtOperatorImpl -> operator.returnType
|
||||
is JKKtSpreadOperator -> (this as JKPrefixExpression).expression.type(symbolProvider)//TODO ger real type
|
||||
else -> error("Cannot get type of ${operator::class}, it should be first converted to KtOperator")
|
||||
}
|
||||
}
|
||||
is JKMethodCallExpression -> identifier.returnType
|
||||
is JKFieldAccessExpressionImpl -> identifier.fieldType
|
||||
is JKQualifiedExpressionImpl -> selector.type(symbolProvider)
|
||||
is JKKtThrowExpression -> kotlinTypeByName(KotlinBuiltIns.FQ_NAMES.nothing.asString(), symbolProvider)
|
||||
is JKClassAccessExpression ->
|
||||
JKClassTypeImpl(identifier, emptyList(), Nullability.NotNull)
|
||||
is JKJavaNewExpression -> JKClassTypeImpl(classSymbol)
|
||||
is JKKtIsExpression -> kotlinTypeByName(KotlinBuiltIns.FQ_NAMES._boolean.asString(), symbolProvider)
|
||||
is JKParenthesizedExpression -> expression.type(symbolProvider)
|
||||
is JKTypeCastExpression -> type.type
|
||||
is JKThisExpression -> null// TODO return actual type
|
||||
is JKSuperExpression -> null// TODO return actual type
|
||||
is JKStubExpression -> null
|
||||
is JKIfElseExpression -> thenBranch.type(symbolProvider)// TODO return actual type
|
||||
is JKArrayAccessExpression ->
|
||||
(expression.type(symbolProvider) as? JKParametrizedType)?.parameters?.lastOrNull()
|
||||
is JKClassLiteralExpression -> {
|
||||
val symbol = when (literalType) {
|
||||
JKClassLiteralExpression.LiteralType.KOTLIN_CLASS ->
|
||||
symbolProvider.provideClassSymbol(KotlinBuiltIns.FQ_NAMES.kClass.toSafe())
|
||||
JKClassLiteralExpression.LiteralType.JAVA_CLASS,
|
||||
JKClassLiteralExpression.LiteralType.JAVA_PRIMITIVE_CLASS, JKClassLiteralExpression.LiteralType.JAVA_VOID_TYPE ->
|
||||
symbolProvider.provideClassSymbol("java.lang.Class")
|
||||
}
|
||||
JKClassTypeImpl(symbol, listOf(classType.type), Nullability.NotNull)
|
||||
}
|
||||
is JKKtAnnotationArrayInitializerExpression -> JKNoTypeImpl //TODO
|
||||
is JKLambdaExpression -> returnType.type
|
||||
is JKLabeledStatement ->
|
||||
statement.safeAs<JKExpressionStatement>()?.expression?.type(symbolProvider)
|
||||
is JKMethodReferenceExpression -> JKNoTypeImpl //TODO
|
||||
else -> TODO(this::class.java.toString())
|
||||
}
|
||||
interface JKWildCardType : JKType
|
||||
|
||||
fun ClassId.toKtClassType(
|
||||
symbolProvider: JKSymbolProvider,
|
||||
nullability: Nullability = Nullability.Default
|
||||
): JKType =
|
||||
JKClassTypeImpl(symbolProvider.provideClassSymbol(asSingleFqName()), emptyList(), nullability)
|
||||
interface JKVarianceTypeParameterType : JKWildCardType {
|
||||
val variance: Variance
|
||||
val boundType: JKType
|
||||
override val nullability: Nullability
|
||||
get() = Nullability.Default
|
||||
|
||||
|
||||
fun PsiType.toJK(symbolProvider: JKSymbolProvider, nullability: Nullability = Nullability.Default): JKType {
|
||||
return when (this) {
|
||||
is PsiClassType -> {
|
||||
val target = resolve()
|
||||
val parameters = parameters.map { it.toJK(symbolProvider, nullability) }
|
||||
when (target) {
|
||||
null ->
|
||||
JKClassTypeImpl(JKUnresolvedClassSymbol(rawType().canonicalText), parameters, nullability)
|
||||
is PsiTypeParameter ->
|
||||
JKTypeParameterTypeImpl(symbolProvider.provideDirectSymbol(target) as JKTypeParameterSymbol)
|
||||
else -> {
|
||||
JKClassTypeImpl(
|
||||
target.let { symbolProvider.provideDirectSymbol(it) as JKClassSymbol },
|
||||
parameters,
|
||||
nullability
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
is PsiArrayType -> JKJavaArrayTypeImpl(componentType.toJK(symbolProvider, nullability), nullability)
|
||||
is PsiPrimitiveType -> JKJavaPrimitiveTypeImpl.KEYWORD_TO_INSTANCE[presentableText]
|
||||
?: error("Invalid primitive type $presentableText")
|
||||
is PsiDisjunctionType ->
|
||||
JKJavaDisjunctionTypeImpl(disjunctions.map { it.toJK(symbolProvider) })
|
||||
is PsiWildcardType ->
|
||||
when {
|
||||
isExtends ->
|
||||
JKVarianceTypeParameterTypeImpl(
|
||||
JKVarianceTypeParameterType.Variance.OUT,
|
||||
extendsBound.toJK(symbolProvider)
|
||||
)
|
||||
isSuper ->
|
||||
JKVarianceTypeParameterTypeImpl(
|
||||
JKVarianceTypeParameterType.Variance.IN,
|
||||
superBound.toJK(symbolProvider)
|
||||
)
|
||||
else -> JKStarProjectionTypeImpl()
|
||||
}
|
||||
is PsiCapturedWildcardType ->
|
||||
JKCapturedType(
|
||||
wildcard.toJK(symbolProvider, nullability) as JKWildCardType,
|
||||
nullability
|
||||
)
|
||||
else -> throw Exception("Invalid PSI ${this::class.java}")
|
||||
enum class Variance {
|
||||
IN, OUT
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun JKType.asTypeElement() =
|
||||
JKTypeElementImpl(this)
|
||||
|
||||
fun JKClassSymbol.asType(nullability: Nullability = Nullability.Default): JKClassType =
|
||||
JKClassTypeImpl(this, emptyList(), nullability)
|
||||
|
||||
fun JKType.isSubtypeOf(other: JKType, symbolProvider: JKSymbolProvider): Boolean =
|
||||
other.toKtType(symbolProvider)
|
||||
?.let { otherType -> this.toKtType(symbolProvider)?.isSubtypeOf(otherType) } == true
|
||||
|
||||
|
||||
fun KotlinType.toJK(symbolProvider: JKSymbolProvider): JKType {
|
||||
return when (val descriptor = constructor.declarationDescriptor) {
|
||||
is TypeParameterDescriptor ->
|
||||
JKTypeParameterTypeImpl(
|
||||
symbolProvider.provideDirectSymbol(descriptor.findPsi() as? KtTypeParameter ?: return JKNoTypeImpl) as JKTypeParameterSymbol
|
||||
)
|
||||
|
||||
else -> JKClassTypeImpl(
|
||||
symbolProvider.provideClassSymbol(getJetTypeFqName(false)),
|
||||
arguments.map { it.type.toJK(symbolProvider) },
|
||||
if (isNullable()) Nullability.Nullable else Nullability.NotNull
|
||||
)
|
||||
}
|
||||
interface JKTypeParameterType : JKType {
|
||||
val identifier: JKTypeParameterSymbol
|
||||
}
|
||||
|
||||
val PsiType.isKotlinFunctionalType: Boolean
|
||||
get() {
|
||||
val fqName = safeAs<PsiClassType>()?.resolve()?.getKotlinFqName() ?: return false
|
||||
return functionalTypeRegex.matches(fqName.asString())
|
||||
}
|
||||
interface JKNoType : JKType
|
||||
|
||||
|
||||
private val functionalTypeRegex = """(kotlin\.jvm\.functions|kotlin)\.Function[\d+]""".toRegex()
|
||||
|
||||
|
||||
fun KtTypeReference.toJK(symbolProvider: JKSymbolProvider): JKType? =
|
||||
analyze(BodyResolveMode.PARTIAL)
|
||||
.get(BindingContext.TYPE, this)
|
||||
?.toJK(symbolProvider)
|
||||
|
||||
|
||||
fun JKType.toKtType(symbolProvider: JKSymbolProvider): KotlinType? =
|
||||
when (this) {
|
||||
is JKClassType -> classReference.toKtType()
|
||||
is JKJavaPrimitiveType ->
|
||||
kotlinTypeByName(
|
||||
jvmPrimitiveType.primitiveType.typeFqName.asString(),
|
||||
symbolProvider
|
||||
).toKtType(symbolProvider)
|
||||
else -> null
|
||||
}
|
||||
|
||||
infix fun JKJavaPrimitiveType.isStrongerThan(other: JKJavaPrimitiveType) =
|
||||
jvmPrimitiveTypesPriority.getValue(this.jvmPrimitiveType.primitiveType) >
|
||||
jvmPrimitiveTypesPriority.getValue(other.jvmPrimitiveType.primitiveType)
|
||||
|
||||
private val jvmPrimitiveTypesPriority =
|
||||
mapOf(
|
||||
PrimitiveType.BOOLEAN to -1,
|
||||
PrimitiveType.CHAR to 0,
|
||||
PrimitiveType.BYTE to 1,
|
||||
PrimitiveType.SHORT to 2,
|
||||
PrimitiveType.INT to 3,
|
||||
PrimitiveType.LONG to 4,
|
||||
PrimitiveType.FLOAT to 5,
|
||||
PrimitiveType.DOUBLE to 6
|
||||
)
|
||||
|
||||
|
||||
fun JKClassSymbol.toKtType(): KotlinType? {
|
||||
val classDescriptor = when (this) {
|
||||
is JKMultiverseKtClassSymbol -> {
|
||||
val bindingContext = target.analyze()
|
||||
bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, target] as ClassDescriptor
|
||||
}
|
||||
is JKMultiverseClassSymbol ->
|
||||
target.getJavaClassDescriptor()
|
||||
is JKUniverseClassSymbol ->
|
||||
target.psi<PsiClass>()?.getJavaClassDescriptor()//TODO null in case of a fake package
|
||||
else -> TODO(this::class.java.toString())
|
||||
}
|
||||
return classDescriptor?.defaultType
|
||||
interface JKParametrizedType : JKType {
|
||||
val parameters: List<JKType>
|
||||
}
|
||||
|
||||
fun JKType.applyRecursive(transform: (JKType) -> JKType?): JKType =
|
||||
transform(this) ?: when (this) {
|
||||
is JKTypeParameterTypeImpl -> this
|
||||
is JKClassTypeImpl ->
|
||||
JKClassTypeImpl(
|
||||
classReference,
|
||||
parameters.map { it.applyRecursive(transform) },
|
||||
nullability
|
||||
)
|
||||
is JKNoType -> this
|
||||
is JKJavaVoidType -> this
|
||||
is JKJavaPrimitiveType -> this
|
||||
is JKJavaArrayType -> JKJavaArrayTypeImpl(type.applyRecursive(transform), nullability)
|
||||
is JKContextType -> JKContextType
|
||||
is JKJavaDisjunctionType ->
|
||||
JKJavaDisjunctionTypeImpl(disjunctions.map { it.applyRecursive(transform) }, nullability)
|
||||
is JKStarProjectionType -> this
|
||||
else -> TODO(this::class.toString())
|
||||
}
|
||||
|
||||
inline fun <reified T : JKType> T.updateNullability(newNullability: Nullability): T =
|
||||
if (nullability == newNullability) this
|
||||
else when (this) {
|
||||
is JKTypeParameterTypeImpl -> JKTypeParameterTypeImpl(identifier, newNullability)
|
||||
is JKClassTypeImpl -> JKClassTypeImpl(classReference, parameters, newNullability)
|
||||
is JKNoType -> this
|
||||
is JKJavaVoidType -> this
|
||||
is JKJavaPrimitiveType -> this
|
||||
is JKJavaArrayType -> JKJavaArrayTypeImpl(type, newNullability)
|
||||
is JKContextType -> JKContextType
|
||||
is JKJavaDisjunctionType -> this
|
||||
else -> TODO(this::class.toString())
|
||||
} as T
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : JKType> T.updateNullabilityRecursively(newNullability: Nullability): T =
|
||||
applyRecursive {
|
||||
when (it) {
|
||||
is JKTypeParameterTypeImpl -> JKTypeParameterTypeImpl(it.identifier, newNullability)
|
||||
is JKClassTypeImpl ->
|
||||
JKClassTypeImpl(
|
||||
it.classReference,
|
||||
it.parameters.map { it.updateNullabilityRecursively(newNullability) },
|
||||
newNullability
|
||||
)
|
||||
is JKJavaArrayType -> JKJavaArrayTypeImpl(it.type.updateNullabilityRecursively(newNullability), newNullability)
|
||||
else -> null
|
||||
}
|
||||
} as T
|
||||
|
||||
fun JKType.isStringType(): Boolean =
|
||||
(this as? JKClassType)?.classReference?.isStringType() == true
|
||||
|
||||
fun JKClassSymbol.isStringType(): Boolean =
|
||||
fqName == CommonClassNames.JAVA_LANG_STRING
|
||||
|| fqName == KotlinBuiltIns.FQ_NAMES.string.asString()
|
||||
|
||||
fun JKLiteralExpression.LiteralType.toPrimitiveType(): JKJavaPrimitiveType? =
|
||||
when (this) {
|
||||
JKLiteralExpression.LiteralType.CHAR -> JKJavaPrimitiveTypeImpl.CHAR
|
||||
JKLiteralExpression.LiteralType.BOOLEAN -> JKJavaPrimitiveTypeImpl.BOOLEAN
|
||||
JKLiteralExpression.LiteralType.INT -> JKJavaPrimitiveTypeImpl.INT
|
||||
JKLiteralExpression.LiteralType.LONG -> JKJavaPrimitiveTypeImpl.LONG
|
||||
JKLiteralExpression.LiteralType.FLOAT -> JKJavaPrimitiveTypeImpl.FLOAT
|
||||
JKLiteralExpression.LiteralType.DOUBLE -> JKJavaPrimitiveTypeImpl.DOUBLE
|
||||
JKLiteralExpression.LiteralType.STRING -> null
|
||||
JKLiteralExpression.LiteralType.NULL -> null
|
||||
}
|
||||
|
||||
fun JKJavaPrimitiveType.toLiteralType(): JKLiteralExpression.LiteralType? =
|
||||
when (this) {
|
||||
JKJavaPrimitiveTypeImpl.CHAR -> JKLiteralExpression.LiteralType.CHAR
|
||||
JKJavaPrimitiveTypeImpl.BOOLEAN -> JKLiteralExpression.LiteralType.BOOLEAN
|
||||
JKJavaPrimitiveTypeImpl.INT -> JKLiteralExpression.LiteralType.INT
|
||||
JKJavaPrimitiveTypeImpl.LONG -> JKLiteralExpression.LiteralType.LONG
|
||||
JKJavaPrimitiveTypeImpl.CHAR -> JKLiteralExpression.LiteralType.CHAR
|
||||
JKJavaPrimitiveTypeImpl.DOUBLE -> JKLiteralExpression.LiteralType.DOUBLE
|
||||
JKJavaPrimitiveTypeImpl.FLOAT -> JKLiteralExpression.LiteralType.FLOAT
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
fun JKType.asPrimitiveType(): JKJavaPrimitiveType? =
|
||||
if (this is JKJavaPrimitiveType) this
|
||||
else when ((this as? JKClassType)?.classReference?.fqName) {
|
||||
KotlinBuiltIns.FQ_NAMES._char.asString(), CommonClassNames.JAVA_LANG_CHARACTER -> JKJavaPrimitiveTypeImpl.CHAR
|
||||
KotlinBuiltIns.FQ_NAMES._boolean.asString(), CommonClassNames.JAVA_LANG_BOOLEAN -> JKJavaPrimitiveTypeImpl.BOOLEAN
|
||||
KotlinBuiltIns.FQ_NAMES._int.asString(), CommonClassNames.JAVA_LANG_INTEGER -> JKJavaPrimitiveTypeImpl.INT
|
||||
KotlinBuiltIns.FQ_NAMES._long.asString(), CommonClassNames.JAVA_LANG_LONG -> JKJavaPrimitiveTypeImpl.LONG
|
||||
KotlinBuiltIns.FQ_NAMES._float.asString(), CommonClassNames.JAVA_LANG_FLOAT -> JKJavaPrimitiveTypeImpl.FLOAT
|
||||
KotlinBuiltIns.FQ_NAMES._double.asString(), CommonClassNames.JAVA_LANG_DOUBLE -> JKJavaPrimitiveTypeImpl.DOUBLE
|
||||
KotlinBuiltIns.FQ_NAMES._byte.asString(), CommonClassNames.JAVA_LANG_BYTE -> JKJavaPrimitiveTypeImpl.BYTE
|
||||
KotlinBuiltIns.FQ_NAMES._short.asString(), CommonClassNames.JAVA_LANG_SHORT -> JKJavaPrimitiveTypeImpl.SHORT
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun JKJavaPrimitiveType.isNumberType() =
|
||||
this == JKJavaPrimitiveTypeImpl.INT ||
|
||||
this == JKJavaPrimitiveTypeImpl.LONG ||
|
||||
this == JKJavaPrimitiveTypeImpl.FLOAT ||
|
||||
this == JKJavaPrimitiveTypeImpl.DOUBLE
|
||||
|
||||
inline fun <reified T : JKType> T.addTypeParametersToRawProjectionType(typeParameter: JKType): T =
|
||||
if (this is JKClassType && parameters.isEmpty()) {
|
||||
val parametersCount = classReference.expectedTypeParametersCount()
|
||||
val typeParameters = List(parametersCount) { typeParameter }
|
||||
JKClassTypeImpl(
|
||||
classReference,
|
||||
typeParameters,
|
||||
nullability
|
||||
) as T
|
||||
} else this
|
||||
|
||||
fun JKClassSymbol.expectedTypeParametersCount(): Int =
|
||||
when (val resolvedClass = target) {
|
||||
is PsiClass -> resolvedClass.typeParameters.size
|
||||
is KtClass -> resolvedClass.typeParameters.size
|
||||
is JKClass -> resolvedClass.typeParameterList.typeParameters.size
|
||||
else -> 0
|
||||
}
|
||||
|
||||
|
||||
val primitiveTypes =
|
||||
listOf(
|
||||
JvmPrimitiveType.BOOLEAN,
|
||||
JvmPrimitiveType.CHAR,
|
||||
JvmPrimitiveType.BYTE,
|
||||
JvmPrimitiveType.SHORT,
|
||||
JvmPrimitiveType.INT,
|
||||
JvmPrimitiveType.FLOAT,
|
||||
JvmPrimitiveType.LONG,
|
||||
JvmPrimitiveType.DOUBLE
|
||||
)
|
||||
|
||||
fun JKType.arrayFqName(): String =
|
||||
if (this is JKJavaPrimitiveType)
|
||||
PrimitiveType.valueOf(jvmPrimitiveType.name).arrayTypeFqName.asString()
|
||||
else KotlinBuiltIns.FQ_NAMES.array.asString()
|
||||
|
||||
fun JKClassSymbol.isArrayType(): Boolean =
|
||||
fqName in
|
||||
JKJavaPrimitiveTypeImpl.KEYWORD_TO_INSTANCE.values
|
||||
.filterIsInstance<JKJavaPrimitiveType>()
|
||||
.map { PrimitiveType.valueOf(it.jvmPrimitiveType.name).arrayTypeFqName.asString() } +
|
||||
KotlinBuiltIns.FQ_NAMES.array.asString()
|
||||
|
||||
fun JKType.isArrayType() =
|
||||
when (this) {
|
||||
is JKClassType -> classReference.isArrayType()
|
||||
is JKJavaArrayType -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
|
||||
fun JKType.arrayInnerType(): JKType? =
|
||||
when (this) {
|
||||
is JKJavaArrayType -> type
|
||||
is JKClassType ->
|
||||
if (this.classReference.isArrayType()) this.parameters.singleOrNull()
|
||||
else null
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun JKClassSymbol.isInterface(): Boolean {
|
||||
val target = target
|
||||
return when (target) {
|
||||
is PsiClass -> target.isInterface
|
||||
is KtClass -> target.isInterface()
|
||||
is JKClass -> target.classKind == JKClass.ClassKind.INTERFACE
|
||||
else -> false
|
||||
}
|
||||
interface JKClassType : JKParametrizedType {
|
||||
val classReference: JKClassSymbol
|
||||
override val nullability: Nullability
|
||||
}
|
||||
|
||||
fun JKType.isInterface(): Boolean =
|
||||
(this as? JKClassType)?.classReference?.isInterface() ?: false
|
||||
interface JKJavaPrimitiveType : JKType {
|
||||
val jvmPrimitiveType: JvmPrimitiveType
|
||||
override val nullability: Nullability
|
||||
get() = Nullability.NotNull
|
||||
}
|
||||
|
||||
interface JKJavaArrayType : JKType {
|
||||
val type: JKType
|
||||
}
|
||||
|
||||
fun JKType.replaceJavaClassWithKotlinClassType(symbolProvider: JKSymbolProvider): JKType =
|
||||
applyRecursive { type ->
|
||||
if (type is JKClassType && type.classReference.fqName == "java.lang.Class") {
|
||||
JKClassTypeImpl(
|
||||
symbolProvider.provideClassSymbol(KotlinBuiltIns.FQ_NAMES.kClass.toSafe()),
|
||||
type.parameters.map { it.replaceJavaClassWithKotlinClassType(symbolProvider) },
|
||||
Nullability.NotNull
|
||||
)
|
||||
} else null
|
||||
}
|
||||
interface JKStarProjectionType : JKWildCardType {
|
||||
override val nullability: Nullability
|
||||
get() = Nullability.NotNull
|
||||
}
|
||||
|
||||
interface JKJavaDisjunctionType : JKType {
|
||||
val disjunctions: List<JKType>
|
||||
}
|
||||
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.nj2k.tree
|
||||
|
||||
import com.intellij.psi.*
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
|
||||
import org.jetbrains.kotlin.j2k.ast.Nullability
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.nj2k.JKSymbolProvider
|
||||
import org.jetbrains.kotlin.nj2k.kotlinTypeByName
|
||||
import org.jetbrains.kotlin.nj2k.symbols.*
|
||||
import org.jetbrains.kotlin.nj2k.tree.impl.*
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtTypeParameter
|
||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.isNullable
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
fun JKExpression.type(symbolProvider: JKSymbolProvider): JKType? =
|
||||
when (this) {
|
||||
is JKLiteralExpression -> type.toJkType(symbolProvider)
|
||||
is JKOperatorExpression -> {
|
||||
val operator = operator
|
||||
when (operator) {
|
||||
is JKKtOperatorImpl -> operator.returnType
|
||||
is JKKtSpreadOperator -> (this as JKPrefixExpression).expression.type(symbolProvider)//TODO ger real type
|
||||
else -> error("Cannot get type of ${operator::class}, it should be first converted to KtOperator")
|
||||
}
|
||||
}
|
||||
is JKMethodCallExpression -> identifier.returnType
|
||||
is JKFieldAccessExpressionImpl -> identifier.fieldType
|
||||
is JKQualifiedExpressionImpl -> selector.type(symbolProvider)
|
||||
is JKKtThrowExpression -> kotlinTypeByName(KotlinBuiltIns.FQ_NAMES.nothing.asString(), symbolProvider)
|
||||
is JKClassAccessExpression ->
|
||||
JKClassTypeImpl(identifier, emptyList(), Nullability.NotNull)
|
||||
is JKJavaNewExpression -> JKClassTypeImpl(classSymbol)
|
||||
is JKKtIsExpression -> kotlinTypeByName(KotlinBuiltIns.FQ_NAMES._boolean.asString(), symbolProvider)
|
||||
is JKParenthesizedExpression -> expression.type(symbolProvider)
|
||||
is JKTypeCastExpression -> type.type
|
||||
is JKThisExpression -> null// TODO return actual type
|
||||
is JKSuperExpression -> null// TODO return actual type
|
||||
is JKStubExpression -> null
|
||||
is JKIfElseExpression -> thenBranch.type(symbolProvider)// TODO return actual type
|
||||
is JKArrayAccessExpression ->
|
||||
(expression.type(symbolProvider) as? JKParametrizedType)?.parameters?.lastOrNull()
|
||||
is JKClassLiteralExpression -> {
|
||||
val symbol = when (literalType) {
|
||||
JKClassLiteralExpression.LiteralType.KOTLIN_CLASS ->
|
||||
symbolProvider.provideClassSymbol(KotlinBuiltIns.FQ_NAMES.kClass.toSafe())
|
||||
JKClassLiteralExpression.LiteralType.JAVA_CLASS,
|
||||
JKClassLiteralExpression.LiteralType.JAVA_PRIMITIVE_CLASS, JKClassLiteralExpression.LiteralType.JAVA_VOID_TYPE ->
|
||||
symbolProvider.provideClassSymbol("java.lang.Class")
|
||||
}
|
||||
JKClassTypeImpl(symbol, listOf(classType.type), Nullability.NotNull)
|
||||
}
|
||||
is JKKtAnnotationArrayInitializerExpression -> JKNoTypeImpl //TODO
|
||||
is JKLambdaExpression -> returnType.type
|
||||
is JKLabeledStatement ->
|
||||
statement.safeAs<JKExpressionStatement>()?.expression?.type(symbolProvider)
|
||||
is JKMethodReferenceExpression -> JKNoTypeImpl //TODO
|
||||
else -> TODO(this::class.java.toString())
|
||||
}
|
||||
|
||||
fun ClassId.toKtClassType(
|
||||
symbolProvider: JKSymbolProvider,
|
||||
nullability: Nullability = Nullability.Default
|
||||
): JKType =
|
||||
JKClassTypeImpl(symbolProvider.provideClassSymbol(asSingleFqName()), emptyList(), nullability)
|
||||
|
||||
|
||||
fun PsiType.toJK(symbolProvider: JKSymbolProvider, nullability: Nullability = Nullability.Default): JKType {
|
||||
return when (this) {
|
||||
is PsiClassType -> {
|
||||
val target = resolve()
|
||||
val parameters = parameters.map { it.toJK(symbolProvider, nullability) }
|
||||
when (target) {
|
||||
null ->
|
||||
JKClassTypeImpl(JKUnresolvedClassSymbol(rawType().canonicalText), parameters, nullability)
|
||||
is PsiTypeParameter ->
|
||||
JKTypeParameterTypeImpl(symbolProvider.provideDirectSymbol(target) as JKTypeParameterSymbol)
|
||||
else -> {
|
||||
JKClassTypeImpl(
|
||||
target.let { symbolProvider.provideDirectSymbol(it) as JKClassSymbol },
|
||||
parameters,
|
||||
nullability
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
is PsiArrayType -> JKJavaArrayTypeImpl(componentType.toJK(symbolProvider, nullability), nullability)
|
||||
is PsiPrimitiveType -> JKJavaPrimitiveTypeImpl.KEYWORD_TO_INSTANCE[presentableText]
|
||||
?: error("Invalid primitive type $presentableText")
|
||||
is PsiDisjunctionType ->
|
||||
JKJavaDisjunctionTypeImpl(disjunctions.map { it.toJK(symbolProvider) })
|
||||
is PsiWildcardType ->
|
||||
when {
|
||||
isExtends ->
|
||||
JKVarianceTypeParameterTypeImpl(
|
||||
JKVarianceTypeParameterType.Variance.OUT,
|
||||
extendsBound.toJK(symbolProvider)
|
||||
)
|
||||
isSuper ->
|
||||
JKVarianceTypeParameterTypeImpl(
|
||||
JKVarianceTypeParameterType.Variance.IN,
|
||||
superBound.toJK(symbolProvider)
|
||||
)
|
||||
else -> JKStarProjectionTypeImpl()
|
||||
}
|
||||
is PsiCapturedWildcardType ->
|
||||
JKCapturedType(
|
||||
wildcard.toJK(symbolProvider, nullability) as JKWildCardType,
|
||||
nullability
|
||||
)
|
||||
else -> throw Exception("Invalid PSI ${this::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun JKType.asTypeElement() =
|
||||
JKTypeElementImpl(this)
|
||||
|
||||
fun JKClassSymbol.asType(nullability: Nullability = Nullability.Default): JKClassType =
|
||||
JKClassTypeImpl(this, emptyList(), nullability)
|
||||
|
||||
fun JKType.isSubtypeOf(other: JKType, symbolProvider: JKSymbolProvider): Boolean =
|
||||
other.toKtType(symbolProvider)
|
||||
?.let { otherType -> this.toKtType(symbolProvider)?.isSubtypeOf(otherType) } == true
|
||||
|
||||
|
||||
fun KotlinType.toJK(symbolProvider: JKSymbolProvider): JKType {
|
||||
return when (val descriptor = constructor.declarationDescriptor) {
|
||||
is TypeParameterDescriptor ->
|
||||
JKTypeParameterTypeImpl(
|
||||
symbolProvider.provideDirectSymbol(descriptor.findPsi() as? KtTypeParameter ?: return JKNoTypeImpl) as JKTypeParameterSymbol
|
||||
)
|
||||
|
||||
else -> JKClassTypeImpl(
|
||||
symbolProvider.provideClassSymbol(getJetTypeFqName(false)),
|
||||
arguments.map { it.type.toJK(symbolProvider) },
|
||||
if (isNullable()) Nullability.Nullable else Nullability.NotNull
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val PsiType.isKotlinFunctionalType: Boolean
|
||||
get() {
|
||||
val fqName = safeAs<PsiClassType>()?.resolve()?.getKotlinFqName() ?: return false
|
||||
return functionalTypeRegex.matches(fqName.asString())
|
||||
}
|
||||
|
||||
|
||||
private val functionalTypeRegex = """(kotlin\.jvm\.functions|kotlin)\.Function[\d+]""".toRegex()
|
||||
|
||||
|
||||
fun KtTypeReference.toJK(symbolProvider: JKSymbolProvider): JKType? =
|
||||
analyze(BodyResolveMode.PARTIAL)
|
||||
.get(BindingContext.TYPE, this)
|
||||
?.toJK(symbolProvider)
|
||||
|
||||
|
||||
fun JKType.toKtType(symbolProvider: JKSymbolProvider): KotlinType? =
|
||||
when (this) {
|
||||
is JKClassType -> classReference.toKtType()
|
||||
is JKJavaPrimitiveType ->
|
||||
kotlinTypeByName(
|
||||
jvmPrimitiveType.primitiveType.typeFqName.asString(),
|
||||
symbolProvider
|
||||
).toKtType(symbolProvider)
|
||||
else -> null
|
||||
}
|
||||
|
||||
infix fun JKJavaPrimitiveType.isStrongerThan(other: JKJavaPrimitiveType) =
|
||||
jvmPrimitiveTypesPriority.getValue(this.jvmPrimitiveType.primitiveType) >
|
||||
jvmPrimitiveTypesPriority.getValue(other.jvmPrimitiveType.primitiveType)
|
||||
|
||||
private val jvmPrimitiveTypesPriority =
|
||||
mapOf(
|
||||
PrimitiveType.BOOLEAN to -1,
|
||||
PrimitiveType.CHAR to 0,
|
||||
PrimitiveType.BYTE to 1,
|
||||
PrimitiveType.SHORT to 2,
|
||||
PrimitiveType.INT to 3,
|
||||
PrimitiveType.LONG to 4,
|
||||
PrimitiveType.FLOAT to 5,
|
||||
PrimitiveType.DOUBLE to 6
|
||||
)
|
||||
|
||||
|
||||
fun JKClassSymbol.toKtType(): KotlinType? {
|
||||
val classDescriptor = when (this) {
|
||||
is JKMultiverseKtClassSymbol -> {
|
||||
val bindingContext = target.analyze()
|
||||
bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, target] as ClassDescriptor
|
||||
}
|
||||
is JKMultiverseClassSymbol ->
|
||||
target.getJavaClassDescriptor()
|
||||
is JKUniverseClassSymbol ->
|
||||
target.psi<PsiClass>()?.getJavaClassDescriptor()//TODO null in case of a fake package
|
||||
else -> TODO(this::class.java.toString())
|
||||
}
|
||||
return classDescriptor?.defaultType
|
||||
}
|
||||
|
||||
fun JKType.applyRecursive(transform: (JKType) -> JKType?): JKType =
|
||||
transform(this) ?: when (this) {
|
||||
is JKTypeParameterTypeImpl -> this
|
||||
is JKClassTypeImpl ->
|
||||
JKClassTypeImpl(
|
||||
classReference,
|
||||
parameters.map { it.applyRecursive(transform) },
|
||||
nullability
|
||||
)
|
||||
is JKNoType -> this
|
||||
is JKJavaVoidType -> this
|
||||
is JKJavaPrimitiveType -> this
|
||||
is JKJavaArrayType -> JKJavaArrayTypeImpl(type.applyRecursive(transform), nullability)
|
||||
is JKContextType -> JKContextType
|
||||
is JKJavaDisjunctionType ->
|
||||
JKJavaDisjunctionTypeImpl(disjunctions.map { it.applyRecursive(transform) }, nullability)
|
||||
is JKStarProjectionType -> this
|
||||
else -> TODO(this::class.toString())
|
||||
}
|
||||
|
||||
inline fun <reified T : JKType> T.updateNullability(newNullability: Nullability): T =
|
||||
if (nullability == newNullability) this
|
||||
else when (this) {
|
||||
is JKTypeParameterTypeImpl -> JKTypeParameterTypeImpl(identifier, newNullability)
|
||||
is JKClassTypeImpl -> JKClassTypeImpl(classReference, parameters, newNullability)
|
||||
is JKNoType -> this
|
||||
is JKJavaVoidType -> this
|
||||
is JKJavaPrimitiveType -> this
|
||||
is JKJavaArrayType -> JKJavaArrayTypeImpl(type, newNullability)
|
||||
is JKContextType -> JKContextType
|
||||
is JKJavaDisjunctionType -> this
|
||||
else -> TODO(this::class.toString())
|
||||
} as T
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : JKType> T.updateNullabilityRecursively(newNullability: Nullability): T =
|
||||
applyRecursive {
|
||||
when (it) {
|
||||
is JKTypeParameterTypeImpl -> JKTypeParameterTypeImpl(it.identifier, newNullability)
|
||||
is JKClassTypeImpl ->
|
||||
JKClassTypeImpl(
|
||||
it.classReference,
|
||||
it.parameters.map { it.updateNullabilityRecursively(newNullability) },
|
||||
newNullability
|
||||
)
|
||||
is JKJavaArrayType -> JKJavaArrayTypeImpl(it.type.updateNullabilityRecursively(newNullability), newNullability)
|
||||
else -> null
|
||||
}
|
||||
} as T
|
||||
|
||||
fun JKType.isStringType(): Boolean =
|
||||
(this as? JKClassType)?.classReference?.isStringType() == true
|
||||
|
||||
fun JKClassSymbol.isStringType(): Boolean =
|
||||
fqName == CommonClassNames.JAVA_LANG_STRING
|
||||
|| fqName == KotlinBuiltIns.FQ_NAMES.string.asString()
|
||||
|
||||
fun JKLiteralExpression.LiteralType.toPrimitiveType(): JKJavaPrimitiveType? =
|
||||
when (this) {
|
||||
JKLiteralExpression.LiteralType.CHAR -> JKJavaPrimitiveTypeImpl.CHAR
|
||||
JKLiteralExpression.LiteralType.BOOLEAN -> JKJavaPrimitiveTypeImpl.BOOLEAN
|
||||
JKLiteralExpression.LiteralType.INT -> JKJavaPrimitiveTypeImpl.INT
|
||||
JKLiteralExpression.LiteralType.LONG -> JKJavaPrimitiveTypeImpl.LONG
|
||||
JKLiteralExpression.LiteralType.FLOAT -> JKJavaPrimitiveTypeImpl.FLOAT
|
||||
JKLiteralExpression.LiteralType.DOUBLE -> JKJavaPrimitiveTypeImpl.DOUBLE
|
||||
JKLiteralExpression.LiteralType.STRING -> null
|
||||
JKLiteralExpression.LiteralType.NULL -> null
|
||||
}
|
||||
|
||||
fun JKJavaPrimitiveType.toLiteralType(): JKLiteralExpression.LiteralType? =
|
||||
when (this) {
|
||||
JKJavaPrimitiveTypeImpl.CHAR -> JKLiteralExpression.LiteralType.CHAR
|
||||
JKJavaPrimitiveTypeImpl.BOOLEAN -> JKLiteralExpression.LiteralType.BOOLEAN
|
||||
JKJavaPrimitiveTypeImpl.INT -> JKLiteralExpression.LiteralType.INT
|
||||
JKJavaPrimitiveTypeImpl.LONG -> JKLiteralExpression.LiteralType.LONG
|
||||
JKJavaPrimitiveTypeImpl.CHAR -> JKLiteralExpression.LiteralType.CHAR
|
||||
JKJavaPrimitiveTypeImpl.DOUBLE -> JKLiteralExpression.LiteralType.DOUBLE
|
||||
JKJavaPrimitiveTypeImpl.FLOAT -> JKLiteralExpression.LiteralType.FLOAT
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
fun JKType.asPrimitiveType(): JKJavaPrimitiveType? =
|
||||
if (this is JKJavaPrimitiveType) this
|
||||
else when ((this as? JKClassType)?.classReference?.fqName) {
|
||||
KotlinBuiltIns.FQ_NAMES._char.asString(), CommonClassNames.JAVA_LANG_CHARACTER -> JKJavaPrimitiveTypeImpl.CHAR
|
||||
KotlinBuiltIns.FQ_NAMES._boolean.asString(), CommonClassNames.JAVA_LANG_BOOLEAN -> JKJavaPrimitiveTypeImpl.BOOLEAN
|
||||
KotlinBuiltIns.FQ_NAMES._int.asString(), CommonClassNames.JAVA_LANG_INTEGER -> JKJavaPrimitiveTypeImpl.INT
|
||||
KotlinBuiltIns.FQ_NAMES._long.asString(), CommonClassNames.JAVA_LANG_LONG -> JKJavaPrimitiveTypeImpl.LONG
|
||||
KotlinBuiltIns.FQ_NAMES._float.asString(), CommonClassNames.JAVA_LANG_FLOAT -> JKJavaPrimitiveTypeImpl.FLOAT
|
||||
KotlinBuiltIns.FQ_NAMES._double.asString(), CommonClassNames.JAVA_LANG_DOUBLE -> JKJavaPrimitiveTypeImpl.DOUBLE
|
||||
KotlinBuiltIns.FQ_NAMES._byte.asString(), CommonClassNames.JAVA_LANG_BYTE -> JKJavaPrimitiveTypeImpl.BYTE
|
||||
KotlinBuiltIns.FQ_NAMES._short.asString(), CommonClassNames.JAVA_LANG_SHORT -> JKJavaPrimitiveTypeImpl.SHORT
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun JKJavaPrimitiveType.isNumberType() =
|
||||
this == JKJavaPrimitiveTypeImpl.INT ||
|
||||
this == JKJavaPrimitiveTypeImpl.LONG ||
|
||||
this == JKJavaPrimitiveTypeImpl.FLOAT ||
|
||||
this == JKJavaPrimitiveTypeImpl.DOUBLE
|
||||
|
||||
inline fun <reified T : JKType> T.addTypeParametersToRawProjectionType(typeParameter: JKType): T =
|
||||
if (this is JKClassType && parameters.isEmpty()) {
|
||||
val parametersCount = classReference.expectedTypeParametersCount()
|
||||
val typeParameters = List(parametersCount) { typeParameter }
|
||||
JKClassTypeImpl(
|
||||
classReference,
|
||||
typeParameters,
|
||||
nullability
|
||||
) as T
|
||||
} else this
|
||||
|
||||
fun JKClassSymbol.expectedTypeParametersCount(): Int =
|
||||
when (val resolvedClass = target) {
|
||||
is PsiClass -> resolvedClass.typeParameters.size
|
||||
is KtClass -> resolvedClass.typeParameters.size
|
||||
is JKClass -> resolvedClass.typeParameterList.typeParameters.size
|
||||
else -> 0
|
||||
}
|
||||
|
||||
|
||||
val primitiveTypes =
|
||||
listOf(
|
||||
JvmPrimitiveType.BOOLEAN,
|
||||
JvmPrimitiveType.CHAR,
|
||||
JvmPrimitiveType.BYTE,
|
||||
JvmPrimitiveType.SHORT,
|
||||
JvmPrimitiveType.INT,
|
||||
JvmPrimitiveType.FLOAT,
|
||||
JvmPrimitiveType.LONG,
|
||||
JvmPrimitiveType.DOUBLE
|
||||
)
|
||||
|
||||
fun JKType.arrayFqName(): String =
|
||||
if (this is JKJavaPrimitiveType)
|
||||
PrimitiveType.valueOf(jvmPrimitiveType.name).arrayTypeFqName.asString()
|
||||
else KotlinBuiltIns.FQ_NAMES.array.asString()
|
||||
|
||||
fun JKClassSymbol.isArrayType(): Boolean =
|
||||
fqName in
|
||||
JKJavaPrimitiveTypeImpl.KEYWORD_TO_INSTANCE.values
|
||||
.filterIsInstance<JKJavaPrimitiveType>()
|
||||
.map { PrimitiveType.valueOf(it.jvmPrimitiveType.name).arrayTypeFqName.asString() } +
|
||||
KotlinBuiltIns.FQ_NAMES.array.asString()
|
||||
|
||||
fun JKType.isArrayType() =
|
||||
when (this) {
|
||||
is JKClassType -> classReference.isArrayType()
|
||||
is JKJavaArrayType -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
|
||||
fun JKType.arrayInnerType(): JKType? =
|
||||
when (this) {
|
||||
is JKJavaArrayType -> type
|
||||
is JKClassType ->
|
||||
if (this.classReference.isArrayType()) this.parameters.singleOrNull()
|
||||
else null
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun JKClassSymbol.isInterface(): Boolean {
|
||||
val target = target
|
||||
return when (target) {
|
||||
is PsiClass -> target.isInterface
|
||||
is KtClass -> target.isInterface()
|
||||
is JKClass -> target.classKind == JKClass.ClassKind.INTERFACE
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun JKType.isInterface(): Boolean =
|
||||
(this as? JKClassType)?.classReference?.isInterface() ?: false
|
||||
|
||||
|
||||
fun JKType.replaceJavaClassWithKotlinClassType(symbolProvider: JKSymbolProvider): JKType =
|
||||
applyRecursive { type ->
|
||||
if (type is JKClassType && type.classReference.fqName == "java.lang.Class") {
|
||||
JKClassTypeImpl(
|
||||
symbolProvider.provideClassSymbol(KotlinBuiltIns.FQ_NAMES.kClass.toSafe()),
|
||||
type.parameters.map { it.replaceJavaClassWithKotlinClassType(symbolProvider) },
|
||||
Nullability.NotNull
|
||||
)
|
||||
} else null
|
||||
}
|
||||
@@ -5,9 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.nj2k
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.util.parentsOfType
|
||||
import org.jetbrains.kotlin.lexer.KtKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
@@ -19,11 +16,6 @@ fun <T> List<T>.replace(element: T, replacer: T): List<T> {
|
||||
return mutableList
|
||||
}
|
||||
|
||||
inline fun <reified T : PsiElement> PsiElement.parentOfType(): T? =
|
||||
PsiTreeUtil.getParentOfType(this, T::class.java)
|
||||
|
||||
inline fun <reified T : PsiElement> PsiElement.parentsOfType(): Sequence<T> = parentsOfType(T::class.java)
|
||||
|
||||
fun String.asGetterName() =
|
||||
takeIf { JvmAbi.isGetterName(it) }
|
||||
?.removePrefix("get")
|
||||
|
||||
Reference in New Issue
Block a user