New J2K: Hack around type nullability calculation
This commit is contained in:
committed by
Ilya Kirillov
parent
65e0694ba1
commit
63fd2439bf
@@ -12,7 +12,8 @@ import org.jetbrains.kotlin.j2k.tree.JKElement
|
|||||||
data class ConversionContext(
|
data class ConversionContext(
|
||||||
val symbolProvider: JKSymbolProvider,
|
val symbolProvider: JKSymbolProvider,
|
||||||
val converter: NewJavaToKotlinConverter,
|
val converter: NewJavaToKotlinConverter,
|
||||||
val backAnnotator: (JKElement) -> PsiElement?
|
val backAnnotator: (JKElement) -> PsiElement?,
|
||||||
|
val inConversionContext: (PsiElement) -> Boolean
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val project: Project get() = converter.project
|
val project: Project get() = converter.project
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ object ConversionsRunner {
|
|||||||
|
|
||||||
private fun createConversions(context: ConversionContext) = listOf(
|
private fun createConversions(context: ConversionContext) = listOf(
|
||||||
ModalityConversion(context),
|
ModalityConversion(context),
|
||||||
FieldToPropertyConversion(),
|
|
||||||
TypeMappingConversion(context),
|
TypeMappingConversion(context),
|
||||||
|
FieldToPropertyConversion(),
|
||||||
AssignmentAsExpressionToAlsoConversion(context),
|
AssignmentAsExpressionToAlsoConversion(context),
|
||||||
AssignmentStatementValCreationConversion(context),
|
AssignmentStatementValCreationConversion(context),
|
||||||
AssignmentStatementOperatorConversion(),
|
AssignmentStatementOperatorConversion(),
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ package org.jetbrains.kotlin.j2k
|
|||||||
import com.intellij.openapi.progress.EmptyProgressIndicator
|
import com.intellij.openapi.progress.EmptyProgressIndicator
|
||||||
import com.intellij.openapi.progress.ProgressIndicator
|
import com.intellij.openapi.progress.ProgressIndicator
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiJavaFile
|
import com.intellij.psi.PsiJavaFile
|
||||||
|
import org.jetbrains.kotlin.j2k.tree.JKElement
|
||||||
import org.jetbrains.kotlin.j2k.tree.JKTreeElement
|
import org.jetbrains.kotlin.j2k.tree.JKTreeElement
|
||||||
import org.jetbrains.kotlin.j2k.tree.prettyDebugPrintTree
|
import org.jetbrains.kotlin.j2k.tree.prettyDebugPrintTree
|
||||||
|
|
||||||
@@ -47,8 +49,10 @@ class NewJavaToKotlinConverter(
|
|||||||
|
|
||||||
val context = ConversionContext(
|
val context = ConversionContext(
|
||||||
symbolProvider,
|
symbolProvider,
|
||||||
this
|
this,
|
||||||
) { treeBuilder.backAnnotation[it] }
|
{ it: JKElement -> treeBuilder.backAnnotation[it] },
|
||||||
|
{ it: PsiElement -> it.containingFile in files }
|
||||||
|
)
|
||||||
|
|
||||||
ConversionsRunner.doApply(fileTrees, context)
|
ConversionsRunner.doApply(fileTrees, context)
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,10 @@
|
|||||||
package org.jetbrains.kotlin.j2k.conversions
|
package org.jetbrains.kotlin.j2k.conversions
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiMethod
|
||||||
|
import com.intellij.psi.PsiVariable
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.j2k.ConversionContext
|
import org.jetbrains.kotlin.j2k.*
|
||||||
import org.jetbrains.kotlin.j2k.ast.Nullability
|
import org.jetbrains.kotlin.j2k.ast.Nullability
|
||||||
import org.jetbrains.kotlin.j2k.tree.*
|
import org.jetbrains.kotlin.j2k.tree.*
|
||||||
import org.jetbrains.kotlin.j2k.tree.impl.JKClassSymbol
|
import org.jetbrains.kotlin.j2k.tree.impl.JKClassSymbol
|
||||||
@@ -21,6 +23,18 @@ import org.jetbrains.kotlin.psi.KtClassOrObject
|
|||||||
|
|
||||||
class TypeMappingConversion(val context: ConversionContext) : RecursiveApplicableConversionBase() {
|
class TypeMappingConversion(val context: ConversionContext) : RecursiveApplicableConversionBase() {
|
||||||
|
|
||||||
|
private val typeFlavorCalculator = TypeFlavorCalculator(object : TypeFlavorConverterFacade {
|
||||||
|
override val referenceSearcher: ReferenceSearcher
|
||||||
|
get() = context.converter.converterServices.oldServices.referenceSearcher
|
||||||
|
override val javaDataFlowAnalyzerFacade: JavaDataFlowAnalyzerFacade
|
||||||
|
get() = context.converter.converterServices.oldServices.javaDataFlowAnalyzerFacade
|
||||||
|
override val resolverForConverter: ResolverForConverter
|
||||||
|
get() = context.converter.converterServices.oldServices.resolverForConverter
|
||||||
|
|
||||||
|
override fun inConversionScope(element: PsiElement): Boolean = context.inConversionContext(element)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
override fun applyToElement(element: JKTreeElement): JKTreeElement {
|
override fun applyToElement(element: JKTreeElement): JKTreeElement {
|
||||||
return if (element is JKTypeElement) {
|
return if (element is JKTypeElement) {
|
||||||
val type = element.type
|
val type = element.type
|
||||||
@@ -50,12 +64,22 @@ class TypeMappingConversion(val context: ConversionContext) : RecursiveApplicabl
|
|||||||
return JKClassTypeImpl(context.symbolProvider.provideDirectSymbol(newTarget) as JKClassSymbol, parameters, nullability)
|
return JKClassTypeImpl(context.symbolProvider.provideDirectSymbol(newTarget) as JKClassSymbol, parameters, nullability)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun calculateNullability(typeElement: JKTypeElement): Nullability {
|
||||||
|
val parent = typeElement.parent
|
||||||
|
return when (parent) {
|
||||||
|
is JKJavaMethod -> typeFlavorCalculator.methodNullability(context.backAnnotator(typeElement)!!.parent as PsiMethod)
|
||||||
|
is JKJavaField -> typeFlavorCalculator.variableNullability(context.backAnnotator(typeElement)!!.parent as PsiVariable)
|
||||||
|
is JKLocalVariable -> typeFlavorCalculator.variableNullability(context.backAnnotator(typeElement)!!.parent as PsiVariable)
|
||||||
|
else -> Nullability.Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun mapClassType(type: JKClassType, typeElement: JKTypeElement): JKTypeElement {
|
private fun mapClassType(type: JKClassType, typeElement: JKTypeElement): JKTypeElement {
|
||||||
val fqNameStr = (type.classReference as? JKClassSymbol)?.fqName ?: return typeElement
|
val fqNameStr = (type.classReference as? JKClassSymbol)?.fqName ?: return typeElement
|
||||||
|
|
||||||
val newFqName = JavaToKotlinClassMap.mapJavaToKotlin(FqName(fqNameStr)) ?: return typeElement
|
val newFqName = JavaToKotlinClassMap.mapJavaToKotlin(FqName(fqNameStr)) ?: return typeElement
|
||||||
|
|
||||||
return classTypeByFqName(context.backAnnotator(typeElement), newFqName, type.parameters, type.nullability)?.let {
|
return classTypeByFqName(context.backAnnotator(typeElement), newFqName, type.parameters, calculateNullability(typeElement))?.let {
|
||||||
JKTypeElementImpl(it)
|
JKTypeElementImpl(it)
|
||||||
} ?: typeElement
|
} ?: typeElement
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,14 +40,26 @@ interface JavaDataFlowAnalyzerFacade {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class TypeConverter(val converter: Converter) {
|
class TypeConverter(val converter: Converter) {
|
||||||
private val typesBeingConverted = HashSet<PsiType>()
|
private val typesBeingConverted = HashSet<PsiType>()
|
||||||
|
|
||||||
|
private val typeFlavorCalculator = TypeFlavorCalculator(object : TypeFlavorConverterFacade {
|
||||||
|
override val referenceSearcher: ReferenceSearcher
|
||||||
|
get() = converter.referenceSearcher
|
||||||
|
override val javaDataFlowAnalyzerFacade: JavaDataFlowAnalyzerFacade
|
||||||
|
get() = converter.services.javaDataFlowAnalyzerFacade
|
||||||
|
override val resolverForConverter: ResolverForConverter
|
||||||
|
get() = converter.services.resolverForConverter
|
||||||
|
|
||||||
|
override fun inConversionScope(element: PsiElement): Boolean = converter.inConversionScope(element)
|
||||||
|
})
|
||||||
|
|
||||||
fun convertType(
|
fun convertType(
|
||||||
type: PsiType?,
|
type: PsiType?,
|
||||||
nullability: Nullability = Nullability.Default,
|
nullability: Nullability = Nullability.Default,
|
||||||
mutability: Mutability = Mutability.Default,
|
mutability: Mutability = Mutability.Default,
|
||||||
inAnnotationType: Boolean = false
|
inAnnotationType: Boolean = false
|
||||||
): Type {
|
): Type {
|
||||||
if (type == null) return ErrorType().assignNoPrototype()
|
if (type == null) return ErrorType().assignNoPrototype()
|
||||||
|
|
||||||
@@ -66,23 +78,60 @@ class TypeConverter(val converter: Converter) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun convertTypes(types: Array<PsiType>): List<Type>
|
fun convertTypes(types: Array<PsiType>): List<Type> = types.map { convertType(it) }
|
||||||
= types.map { convertType(it) }
|
|
||||||
|
|
||||||
fun convertVariableType(variable: PsiVariable): Type {
|
fun convertVariableType(variable: PsiVariable): Type {
|
||||||
val result = if (variable.isMainMethodParameter()) {
|
val result = if (variable.isMainMethodParameter()) {
|
||||||
ArrayType(ClassType(ReferenceElement(Identifier.withNoPrototype("String"), listOf()).assignNoPrototype(), Nullability.NotNull, converter.settings).assignNoPrototype(),
|
ArrayType(
|
||||||
Nullability.NotNull,
|
ClassType(
|
||||||
converter.settings).assignNoPrototype()
|
ReferenceElement(Identifier.withNoPrototype("String"), listOf()).assignNoPrototype(),
|
||||||
}
|
Nullability.NotNull,
|
||||||
else {
|
converter.settings
|
||||||
convertType(variable.type, variableNullability(variable), variableMutability(variable))
|
).assignNoPrototype(),
|
||||||
|
Nullability.NotNull,
|
||||||
|
converter.settings
|
||||||
|
).assignNoPrototype()
|
||||||
|
} else {
|
||||||
|
convertType(
|
||||||
|
variable.type,
|
||||||
|
typeFlavorCalculator.variableNullability(variable),
|
||||||
|
typeFlavorCalculator.variableMutability(variable)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return result.assignPrototype(variable.typeElement, CommentsAndSpacesInheritance.NO_SPACES)
|
return result.assignPrototype(variable.typeElement, CommentsAndSpacesInheritance.NO_SPACES)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun convertMethodReturnType(method: PsiMethod): Type
|
fun convertMethodReturnType(method: PsiMethod): Type = convertType(
|
||||||
= convertType(method.returnType, methodNullability(method), methodMutability(method)).assignPrototype(method.returnTypeElement)
|
method.returnType,
|
||||||
|
typeFlavorCalculator.methodNullability(method),
|
||||||
|
typeFlavorCalculator.methodMutability(method)
|
||||||
|
).assignPrototype(method.returnTypeElement)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fun methodMutability(method: PsiMethod): Mutability = typeFlavorCalculator.methodMutability(method)
|
||||||
|
|
||||||
|
fun variableNullability(variable: PsiVariable): Nullability = typeFlavorCalculator.variableNullability(variable)
|
||||||
|
|
||||||
|
fun variableReferenceNullability(variable: PsiVariable, reference: PsiReferenceExpression): Nullability
|
||||||
|
= typeFlavorCalculator.variableReferenceNullability(variable, reference)
|
||||||
|
|
||||||
|
fun methodNullability(method: PsiMethod): Nullability
|
||||||
|
= typeFlavorCalculator.methodNullability(method)
|
||||||
|
|
||||||
|
fun variableMutability(variable: PsiVariable): Mutability
|
||||||
|
= typeFlavorCalculator.variableMutability(variable)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TypeFlavorConverterFacade {
|
||||||
|
val referenceSearcher: ReferenceSearcher
|
||||||
|
val javaDataFlowAnalyzerFacade: JavaDataFlowAnalyzerFacade
|
||||||
|
val resolverForConverter: ResolverForConverter
|
||||||
|
fun inConversionScope(element: PsiElement): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeFlavorCalculator(val converter: TypeFlavorConverterFacade) {
|
||||||
|
|
||||||
fun variableNullability(variable: PsiVariable): Nullability
|
fun variableNullability(variable: PsiVariable): Nullability
|
||||||
= nullabilityFlavor.forVariableType(variable, true)
|
= nullabilityFlavor.forVariableType(variable, true)
|
||||||
@@ -99,8 +148,6 @@ class TypeConverter(val converter: Converter) {
|
|||||||
fun methodMutability(method: PsiMethod): Mutability
|
fun methodMutability(method: PsiMethod): Mutability
|
||||||
= mutabilityFlavor.forMethodReturnType(method)
|
= mutabilityFlavor.forMethodReturnType(method)
|
||||||
|
|
||||||
private fun PsiVariable.isMainMethodParameter() = this is PsiParameter && (declarationScope as? PsiMethod)?.isMainMethod() ?: false
|
|
||||||
|
|
||||||
private fun searchScope(element: PsiElement): PsiElement? {
|
private fun searchScope(element: PsiElement): PsiElement? {
|
||||||
return when(element) {
|
return when(element) {
|
||||||
is PsiParameter -> element.declarationScope
|
is PsiParameter -> element.declarationScope
|
||||||
@@ -250,14 +297,14 @@ class TypeConverter(val converter: Converter) {
|
|||||||
private val nullabilityFlavor = object : TypeFlavor<Nullability>(Nullability.Default) {
|
private val nullabilityFlavor = object : TypeFlavor<Nullability>(Nullability.Default) {
|
||||||
fun forVariableReference(variable: PsiVariable, reference: PsiReferenceExpression): Nullability {
|
fun forVariableReference(variable: PsiVariable, reference: PsiReferenceExpression): Nullability {
|
||||||
assert(reference.resolve() == variable)
|
assert(reference.resolve() == variable)
|
||||||
val dataFlowUtil = converter.services.javaDataFlowAnalyzerFacade
|
val dataFlowUtil = converter.javaDataFlowAnalyzerFacade
|
||||||
|
|
||||||
return dataFlowUtil.variableNullability(variable, reference).takeIf { it != default } ?:
|
return dataFlowUtil.variableNullability(variable, reference).takeIf { it != default } ?:
|
||||||
variableNullability(variable)
|
variableNullability(variable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fromDataFlowForMethod(method: PsiMethod): Nullability =
|
override fun fromDataFlowForMethod(method: PsiMethod): Nullability =
|
||||||
converter.services.javaDataFlowAnalyzerFacade.methodNullability(method)
|
converter.javaDataFlowAnalyzerFacade.methodNullability(method)
|
||||||
|
|
||||||
override val forEnumConstant: Nullability
|
override val forEnumConstant: Nullability
|
||||||
get() = Nullability.NotNull
|
get() = Nullability.NotNull
|
||||||
@@ -293,7 +340,7 @@ class TypeConverter(val converter: Converter) {
|
|||||||
return Nullability.Nullable
|
return Nullability.Nullable
|
||||||
}
|
}
|
||||||
|
|
||||||
if (variable.isMainMethodParameter() ) {
|
if (variable.isMainMethodParameter()) {
|
||||||
return Nullability.NotNull
|
return Nullability.NotNull
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,7 +466,7 @@ class TypeConverter(val converter: Converter) {
|
|||||||
override fun fromAnnotations(owner: PsiModifierListOwner): Mutability {
|
override fun fromAnnotations(owner: PsiModifierListOwner): Mutability {
|
||||||
if (owner is KtLightElement<*, *>) {
|
if (owner is KtLightElement<*, *>) {
|
||||||
val jetDeclaration = owner.kotlinOrigin as? KtCallableDeclaration ?: return Mutability.Default
|
val jetDeclaration = owner.kotlinOrigin as? KtCallableDeclaration ?: return Mutability.Default
|
||||||
val descriptor = converter.services.resolverForConverter.resolveToDescriptor(jetDeclaration) as? CallableDescriptor ?: return Mutability.Default
|
val descriptor = converter.resolverForConverter.resolveToDescriptor(jetDeclaration) as? CallableDescriptor ?: return Mutability.Default
|
||||||
val type = descriptor.returnType ?: return Mutability.Default
|
val type = descriptor.returnType ?: return Mutability.Default
|
||||||
val classDescriptor = TypeUtils.getClassDescriptor(type) ?: return Mutability.Default
|
val classDescriptor = TypeUtils.getClassDescriptor(type) ?: return Mutability.Default
|
||||||
return if (DescriptorUtils.getFqName(classDescriptor).asString() in mutableKotlinClasses)
|
return if (DescriptorUtils.getFqName(classDescriptor).asString() in mutableKotlinClasses)
|
||||||
@@ -520,3 +567,5 @@ private val typeConversionMap: Map<String, String> = mapOf(
|
|||||||
CommonClassNames.JAVA_LANG_DOUBLE to "double",
|
CommonClassNames.JAVA_LANG_DOUBLE to "double",
|
||||||
CommonClassNames.JAVA_LANG_CHARACTER to "char"
|
CommonClassNames.JAVA_LANG_CHARACTER to "char"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun PsiVariable.isMainMethodParameter() = this is PsiParameter && (declarationScope as? PsiMethod)?.isMainMethod() ?: false
|
||||||
Reference in New Issue
Block a user