diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionContext.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionContext.kt index 7bd17d22846..554b25fbc15 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionContext.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionContext.kt @@ -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 diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt index a4c21a95926..227fb6cc5a9 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/ConversionsRunner.kt @@ -23,8 +23,8 @@ object ConversionsRunner { private fun createConversions(context: ConversionContext) = listOf( ModalityConversion(context), - FieldToPropertyConversion(), TypeMappingConversion(context), + FieldToPropertyConversion(), AssignmentAsExpressionToAlsoConversion(context), AssignmentStatementValCreationConversion(context), AssignmentStatementOperatorConversion(), diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/NewJavaToKotlinConverter.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/NewJavaToKotlinConverter.kt index 64a88eca066..6c99482a723 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/NewJavaToKotlinConverter.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/NewJavaToKotlinConverter.kt @@ -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) diff --git a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/TypeMappingConversion.kt b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/TypeMappingConversion.kt index c05f4da9dbc..6e0896da5d7 100644 --- a/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/TypeMappingConversion.kt +++ b/j2k/newSrc/org/jetbrains/kotlin/j2k/conversions/TypeMappingConversion.kt @@ -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 } diff --git a/j2k/src/org/jetbrains/kotlin/j2k/TypeConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/TypeConverter.kt index f2b30d66cfb..f43d453e729 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/TypeConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/TypeConverter.kt @@ -40,14 +40,26 @@ interface JavaDataFlowAnalyzerFacade { } } + class TypeConverter(val converter: Converter) { private val typesBeingConverted = HashSet() + 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): List - = types.map { convertType(it) } + fun convertTypes(types: Array): List = 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.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 = 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 \ No newline at end of file