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(
|
||||
val symbolProvider: JKSymbolProvider,
|
||||
val converter: NewJavaToKotlinConverter,
|
||||
val backAnnotator: (JKElement) -> PsiElement?
|
||||
val backAnnotator: (JKElement) -> PsiElement?,
|
||||
val inConversionContext: (PsiElement) -> Boolean
|
||||
) {
|
||||
|
||||
val project: Project get() = converter.project
|
||||
|
||||
@@ -23,8 +23,8 @@ object ConversionsRunner {
|
||||
|
||||
private fun createConversions(context: ConversionContext) = listOf(
|
||||
ModalityConversion(context),
|
||||
FieldToPropertyConversion(),
|
||||
TypeMappingConversion(context),
|
||||
FieldToPropertyConversion(),
|
||||
AssignmentAsExpressionToAlsoConversion(context),
|
||||
AssignmentStatementValCreationConversion(context),
|
||||
AssignmentStatementOperatorConversion(),
|
||||
|
||||
@@ -19,7 +19,9 @@ package org.jetbrains.kotlin.j2k
|
||||
import com.intellij.openapi.progress.EmptyProgressIndicator
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
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.prettyDebugPrintTree
|
||||
|
||||
@@ -47,8 +49,10 @@ class NewJavaToKotlinConverter(
|
||||
|
||||
val context = ConversionContext(
|
||||
symbolProvider,
|
||||
this
|
||||
) { treeBuilder.backAnnotation[it] }
|
||||
this,
|
||||
{ it: JKElement -> treeBuilder.backAnnotation[it] },
|
||||
{ it: PsiElement -> it.containingFile in files }
|
||||
)
|
||||
|
||||
ConversionsRunner.doApply(fileTrees, context)
|
||||
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
package org.jetbrains.kotlin.j2k.conversions
|
||||
|
||||
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.j2k.ConversionContext
|
||||
import org.jetbrains.kotlin.j2k.*
|
||||
import org.jetbrains.kotlin.j2k.ast.Nullability
|
||||
import org.jetbrains.kotlin.j2k.tree.*
|
||||
import org.jetbrains.kotlin.j2k.tree.impl.JKClassSymbol
|
||||
@@ -21,6 +23,18 @@ import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
|
||||
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 {
|
||||
return if (element is JKTypeElement) {
|
||||
val type = element.type
|
||||
@@ -50,12 +64,22 @@ class TypeMappingConversion(val context: ConversionContext) : RecursiveApplicabl
|
||||
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 {
|
||||
val fqNameStr = (type.classReference as? JKClassSymbol)?.fqName ?: 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)
|
||||
} ?: typeElement
|
||||
}
|
||||
|
||||
@@ -40,14 +40,26 @@ interface JavaDataFlowAnalyzerFacade {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TypeConverter(val converter: Converter) {
|
||||
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(
|
||||
type: PsiType?,
|
||||
nullability: Nullability = Nullability.Default,
|
||||
mutability: Mutability = Mutability.Default,
|
||||
inAnnotationType: Boolean = false
|
||||
type: PsiType?,
|
||||
nullability: Nullability = Nullability.Default,
|
||||
mutability: Mutability = Mutability.Default,
|
||||
inAnnotationType: Boolean = false
|
||||
): Type {
|
||||
if (type == null) return ErrorType().assignNoPrototype()
|
||||
|
||||
@@ -66,23 +78,60 @@ class TypeConverter(val converter: Converter) {
|
||||
}
|
||||
}
|
||||
|
||||
fun convertTypes(types: Array<PsiType>): List<Type>
|
||||
= types.map { convertType(it) }
|
||||
fun convertTypes(types: Array<PsiType>): List<Type> = types.map { convertType(it) }
|
||||
|
||||
|
||||
fun convertVariableType(variable: PsiVariable): Type {
|
||||
val result = if (variable.isMainMethodParameter()) {
|
||||
ArrayType(ClassType(ReferenceElement(Identifier.withNoPrototype("String"), listOf()).assignNoPrototype(), Nullability.NotNull, converter.settings).assignNoPrototype(),
|
||||
Nullability.NotNull,
|
||||
converter.settings).assignNoPrototype()
|
||||
}
|
||||
else {
|
||||
convertType(variable.type, variableNullability(variable), variableMutability(variable))
|
||||
ArrayType(
|
||||
ClassType(
|
||||
ReferenceElement(Identifier.withNoPrototype("String"), listOf()).assignNoPrototype(),
|
||||
Nullability.NotNull,
|
||||
converter.settings
|
||||
).assignNoPrototype(),
|
||||
Nullability.NotNull,
|
||||
converter.settings
|
||||
).assignNoPrototype()
|
||||
} else {
|
||||
convertType(
|
||||
variable.type,
|
||||
typeFlavorCalculator.variableNullability(variable),
|
||||
typeFlavorCalculator.variableMutability(variable)
|
||||
)
|
||||
}
|
||||
return result.assignPrototype(variable.typeElement, CommentsAndSpacesInheritance.NO_SPACES)
|
||||
}
|
||||
|
||||
fun convertMethodReturnType(method: PsiMethod): Type
|
||||
= convertType(method.returnType, methodNullability(method), methodMutability(method)).assignPrototype(method.returnTypeElement)
|
||||
fun convertMethodReturnType(method: PsiMethod): Type = convertType(
|
||||
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
|
||||
= nullabilityFlavor.forVariableType(variable, true)
|
||||
@@ -99,8 +148,6 @@ class TypeConverter(val converter: Converter) {
|
||||
fun methodMutability(method: PsiMethod): Mutability
|
||||
= mutabilityFlavor.forMethodReturnType(method)
|
||||
|
||||
private fun PsiVariable.isMainMethodParameter() = this is PsiParameter && (declarationScope as? PsiMethod)?.isMainMethod() ?: false
|
||||
|
||||
private fun searchScope(element: PsiElement): PsiElement? {
|
||||
return when(element) {
|
||||
is PsiParameter -> element.declarationScope
|
||||
@@ -250,14 +297,14 @@ class TypeConverter(val converter: Converter) {
|
||||
private val nullabilityFlavor = object : TypeFlavor<Nullability>(Nullability.Default) {
|
||||
fun forVariableReference(variable: PsiVariable, reference: PsiReferenceExpression): Nullability {
|
||||
assert(reference.resolve() == variable)
|
||||
val dataFlowUtil = converter.services.javaDataFlowAnalyzerFacade
|
||||
val dataFlowUtil = converter.javaDataFlowAnalyzerFacade
|
||||
|
||||
return dataFlowUtil.variableNullability(variable, reference).takeIf { it != default } ?:
|
||||
variableNullability(variable)
|
||||
}
|
||||
|
||||
override fun fromDataFlowForMethod(method: PsiMethod): Nullability =
|
||||
converter.services.javaDataFlowAnalyzerFacade.methodNullability(method)
|
||||
converter.javaDataFlowAnalyzerFacade.methodNullability(method)
|
||||
|
||||
override val forEnumConstant: Nullability
|
||||
get() = Nullability.NotNull
|
||||
@@ -293,7 +340,7 @@ class TypeConverter(val converter: Converter) {
|
||||
return Nullability.Nullable
|
||||
}
|
||||
|
||||
if (variable.isMainMethodParameter() ) {
|
||||
if (variable.isMainMethodParameter()) {
|
||||
return Nullability.NotNull
|
||||
}
|
||||
|
||||
@@ -419,7 +466,7 @@ class TypeConverter(val converter: Converter) {
|
||||
override fun fromAnnotations(owner: PsiModifierListOwner): Mutability {
|
||||
if (owner is KtLightElement<*, *>) {
|
||||
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 classDescriptor = TypeUtils.getClassDescriptor(type) ?: return Mutability.Default
|
||||
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_CHARACTER to "char"
|
||||
)
|
||||
|
||||
private fun PsiVariable.isMainMethodParameter() = this is PsiParameter && (declarationScope as? PsiMethod)?.isMainMethod() ?: false
|
||||
Reference in New Issue
Block a user