Java to Kotlin converter: generate nullable type for private non-initialized fields

This commit is contained in:
Valentin Kipyatkov
2014-06-26 14:58:57 +04:00
parent f8e4ecfa94
commit 44c706eb3e
8 changed files with 41 additions and 32 deletions
@@ -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))
}
+3 -24
View File
@@ -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) {
+24
View File
@@ -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)
+2 -2
View File
@@ -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
}
+2 -2
View File
@@ -1,3 +1,3 @@
class C {
private val f: Foo = 0
}
private val f: Foo? = null
}