Java to Kotlin converter: generate nullable type for private non-initialized fields
This commit is contained in:
@@ -116,7 +116,7 @@ class ConstructorConverter(private val converter: Converter) {
|
||||
val (field, `type`) = parameterToField[parameter]!!
|
||||
Parameter(field.declarationIdentifier(),
|
||||
`type`,
|
||||
if (converter.isVal(field)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var,
|
||||
if (isVal(field)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var,
|
||||
converter.convertAnnotations(parameter) + converter.convertAnnotations(field),
|
||||
converter.convertModifiers(field).filter { it in ACCESS_MODIFIERS }).assignPrototypes(listOf(parameter, field), CommentsAndSpacesInheritance(blankLinesBefore = false))
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.util.*
|
||||
import com.intellij.psi.CommonClassNames.*
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions.*
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.util.PsiUtil
|
||||
|
||||
public trait ConversionScope {
|
||||
public fun contains(element: PsiElement): Boolean
|
||||
@@ -235,14 +234,15 @@ public class Converter private(val project: Project, val settings: ConverterSett
|
||||
val typeToDeclare = variableTypeToDeclare(field,
|
||||
settings.specifyFieldTypeByDefault || modifiers.isPublic || modifiers.isProtected,
|
||||
isVal && modifiers.isPrivate)
|
||||
val initializer = convertExpression(field.getInitializer(), field.getType())
|
||||
Field(name,
|
||||
annotations,
|
||||
modifiers,
|
||||
typeToDeclare ?: typeConverter.convertVariableType(field),
|
||||
convertExpression(field.getInitializer(), field.getType()),
|
||||
initializer,
|
||||
isVal,
|
||||
typeToDeclare != null,
|
||||
field.hasWriteAccesses(field.getContainingClass()))
|
||||
initializer.isEmpty && shouldGenerateDefaultInitializer(field))
|
||||
}
|
||||
return converted.assignPrototype(field)
|
||||
}
|
||||
@@ -264,27 +264,6 @@ public class Converter private(val project: Project, val settings: ConverterSett
|
||||
return if (convertedType == initializerType) null else convertedType
|
||||
}
|
||||
|
||||
fun isVal(field: PsiField): Boolean {
|
||||
if (field.hasModifierProperty(PsiModifier.FINAL)) return true
|
||||
if (!field.hasModifierProperty(PsiModifier.PRIVATE)) return false
|
||||
val containingClass = field.getContainingClass() ?: return false
|
||||
val writes = findVariableUsages(field, containingClass).filter { PsiUtil.isAccessedForWriting(it) }
|
||||
if (writes.size == 0) return true
|
||||
if (writes.size > 1) return false
|
||||
val write = writes.single()
|
||||
val parent = write.getParent()
|
||||
if (parent is PsiAssignmentExpression &&
|
||||
parent.getOperationSign().getTokenType() == JavaTokenType.EQ &&
|
||||
isQualifierEmptyOrThis(write)) {
|
||||
val constructor = write.getContainingConstructor()
|
||||
return constructor != null &&
|
||||
constructor.getContainingClass() == containingClass &&
|
||||
parent.getParent() is PsiExpressionStatement &&
|
||||
parent.getParent()?.getParent() == constructor.getBody()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun convertMethod(method: PsiMethod, membersToRemove: MutableSet<PsiMember>): Member {
|
||||
return withMethodReturnType(method.getReturnType()).doConvertMethod(method, membersToRemove).assignPrototype(method)
|
||||
}
|
||||
|
||||
@@ -120,6 +120,12 @@ class TypeConverter(val settings: ConverterSettings, val conversionScope: Conver
|
||||
return nullability
|
||||
}
|
||||
|
||||
if (nullability == Nullability.Default) {
|
||||
if (variable is PsiField && variable.hasModifierProperty(PsiModifier.PRIVATE) && shouldGenerateDefaultInitializer(variable)) {
|
||||
return Nullability.Nullable
|
||||
}
|
||||
}
|
||||
|
||||
if (nullability == Nullability.Default) {
|
||||
val scope = searchScope(variable)
|
||||
if (scope != null) {
|
||||
|
||||
@@ -69,6 +69,30 @@ fun getDefaultInitializer(field: Field): Expression {
|
||||
return result.assignNoPrototype()
|
||||
}
|
||||
|
||||
fun isVal(field: PsiField): Boolean {
|
||||
if (field.hasModifierProperty(PsiModifier.FINAL)) return true
|
||||
if (!field.hasModifierProperty(PsiModifier.PRIVATE)) return false
|
||||
val containingClass = field.getContainingClass() ?: return false
|
||||
val writes = findVariableUsages(field, containingClass).filter { PsiUtil.isAccessedForWriting(it) }
|
||||
if (writes.size == 0) return true
|
||||
if (writes.size > 1) return false
|
||||
val write = writes.single()
|
||||
val parent = write.getParent()
|
||||
if (parent is PsiAssignmentExpression &&
|
||||
parent.getOperationSign().getTokenType() == JavaTokenType.EQ &&
|
||||
isQualifierEmptyOrThis(write)) {
|
||||
val constructor = write.getContainingConstructor()
|
||||
return constructor != null &&
|
||||
constructor.getContainingClass() == containingClass &&
|
||||
parent.getParent() is PsiExpressionStatement &&
|
||||
parent.getParent()?.getParent() == constructor.getBody()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun shouldGenerateDefaultInitializer(field: PsiField)
|
||||
= field.getInitializer() == null && !(isVal(field) && field.hasWriteAccesses(field.getContainingClass()))
|
||||
|
||||
fun isQualifierEmptyOrThis(ref: PsiReferenceExpression): Boolean {
|
||||
val qualifier = ref.getQualifierExpression()
|
||||
return qualifier == null || (qualifier is PsiThisExpression && qualifier.getQualifier() == null)
|
||||
|
||||
@@ -26,7 +26,7 @@ class Field(
|
||||
val initializer: Element,
|
||||
val isVal: Boolean,
|
||||
val explicitType: Boolean,
|
||||
private val hasWriteAccesses: Boolean
|
||||
private val defaultInitializer: Boolean
|
||||
) : Member(annotations, modifiers) {
|
||||
|
||||
override fun generateCode(builder: CodeBuilder) {
|
||||
@@ -40,7 +40,7 @@ class Field(
|
||||
}
|
||||
|
||||
var initializerToUse = initializer
|
||||
if (initializerToUse.isEmpty && !(isVal && hasWriteAccesses)) {
|
||||
if (initializerToUse.isEmpty && defaultInitializer) {
|
||||
initializerToUse = getDefaultInitializer(this)
|
||||
}
|
||||
if (!initializerToUse.isEmpty) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
enum class E {
|
||||
I
|
||||
private val name: String = 0
|
||||
private val name: String? = null
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
class Base {
|
||||
private val myFirst: String = 0
|
||||
private val myFirst: String? = null
|
||||
}
|
||||
|
||||
class Child : Base() {
|
||||
private val mySecond: String = 0
|
||||
private val mySecond: String? = null
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
class C {
|
||||
private val f: Foo = 0
|
||||
}
|
||||
private val f: Foo? = null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user