Java to Kotlin convertor: improving code related to primary constructors

This commit is contained in:
Valentin Kipyatkov
2014-05-30 17:34:48 +04:00
parent 1e39021bd3
commit aa8b968756
3 changed files with 56 additions and 69 deletions
@@ -22,57 +22,70 @@ import com.intellij.psi.PsiReferenceExpression
import com.intellij.psi.JavaRecursiveElementVisitor import com.intellij.psi.JavaRecursiveElementVisitor
import java.util.LinkedHashSet import java.util.LinkedHashSet
import com.intellij.psi.PsiReference import com.intellij.psi.PsiReference
import com.intellij.psi.PsiElement
fun isConstructorPrimary(constructor: PsiMethod): Boolean { fun PsiMethod.isPrimaryConstructor(): Boolean {
val parent = constructor.getParent() if (!isConstructor()) return false
if (parent is PsiClass) { val parent = getParent()
if (parent.getConstructors().size == 1) { if (parent !is PsiClass) return false
return true return parent.getPrimaryConstructor() == this
}
else {
val primary = getPrimaryConstructorForThisCase(parent)
//TODO: I do not understand code below
if (primary != null && primary.hashCode() == constructor.hashCode()) {
return true
}
}
}
return false
} }
fun getPrimaryConstructorForThisCase(psiClass: PsiClass): PsiMethod? { fun PsiClass.getPrimaryConstructor(): PsiMethod? {
class FindPrimaryConstructorVisitor() : JavaRecursiveElementVisitor() { val constructors = getConstructors()
private val resolvedConstructors = LinkedHashSet<PsiMethod>() return when (constructors.size) {
0 -> null
override fun visitReferenceExpression(expression: PsiReferenceExpression) { 1 -> constructors.single()
expression.getReferences()
.filter { it.getCanonicalText() == "this" } else -> {
.map { it.resolve() } // if there is more than one constructor then choose one invoked by all others
.filterIsInstance(javaClass<PsiMethod>()) class Visitor() : JavaRecursiveElementVisitor() {
.filterTo(resolvedConstructors) { it.isConstructor() } //TODO: skip all non-constructor members (optimization)
private val invokedConstructors = LinkedHashSet<PsiMethod>()
override fun visitReferenceExpression(expression: PsiReferenceExpression) {
expression.getReferences()
.filter { it.getCanonicalText() == "this" }
.map { it.resolve() }
.filterIsInstance(javaClass<PsiMethod>())
.filterTo(invokedConstructors) { it.isConstructor() }
}
val primaryConstructor: PsiMethod?
get() = if (invokedConstructors.size == 1) invokedConstructors.single() else null
}
val visitor = Visitor()
accept(visitor)
visitor.primaryConstructor
}
}
}
fun isInsidePrimaryConstructor(element: PsiElement): Boolean
= containingConstructor(element)?.isPrimaryConstructor() ?: false
fun isInsideSecondaryConstructor(element: PsiElement): Boolean
= !(containingConstructor(element)?.isPrimaryConstructor() ?: true)
fun containingConstructor(element: PsiElement): PsiMethod? {
var context = element.getContext()
while (context != null) {
val _context = context!!
if (_context is PsiMethod) {
return if (_context.isConstructor()) _context else null
} }
val result: PsiMethod? context = _context.getContext()
get() {
if (resolvedConstructors.isEmpty()) return null
//TODO: I do not understand code below
val first = resolvedConstructors.first()
return if (resolvedConstructors.all { it.hashCode() == first.hashCode() }) first else null
}
} }
return null
val visitor = FindPrimaryConstructorVisitor()
psiClass.accept(visitor)
return visitor.result
} }
fun isSuperConstructorRef(ref: PsiReference): Boolean { fun isSuperConstructorRef(ref: PsiReference): Boolean {
if (ref.getCanonicalText().equals("super")) { if (ref.getCanonicalText().equals("super")) {
val baseConstructor = ref.resolve() val target = ref.resolve()
if (baseConstructor is PsiMethod && baseConstructor.isConstructor()) { return target is PsiMethod && target.isConstructor()
return true
}
} }
return false return false
} }
+2 -2
View File
@@ -122,7 +122,7 @@ public class Converter(val project: Project, val settings: ConverterSettings) {
} }
} }
if (!psiClass.isEnum() && !psiClass.isInterface() && psiClass.getConstructors().size > 1 && getPrimaryConstructorForThisCase(psiClass) == null) { if (!psiClass.isEnum() && !psiClass.isInterface() && psiClass.getConstructors().size > 1 && psiClass.getPrimaryConstructor() == null) {
val finalOrWithEmptyInitializer = fields.filter { it.isVal() || it.initializer.toKotlin().isEmpty() } val finalOrWithEmptyInitializer = fields.filter { it.isVal() || it.initializer.toKotlin().isEmpty() }
val initializers = HashMap<String, String>() val initializers = HashMap<String, String>()
for (member in members) { for (member in members) {
@@ -243,7 +243,7 @@ public class Converter(val project: Project, val settings: ConverterSettings) {
if (method.isConstructor()) { if (method.isConstructor()) {
return Constructor(this, identifier, getComments(method), modifiers, returnType, typeParameterList, params, return Constructor(this, identifier, getComments(method), modifiers, returnType, typeParameterList, params,
Block(body.statements), isConstructorPrimary(method)) Block(body.statements), method.isPrimaryConstructor())
} }
return Function(this, identifier, getComments(method), modifiers, returnType, typeParameterList, params, body) return Function(this, identifier, getComments(method), modifiers, returnType, typeParameterList, params, body)
@@ -168,7 +168,7 @@ open class ExpressionVisitor(public val converter: Converter) : JavaElementVisit
val isNotConvertedClass = classReference != null && !converter.getClassIdentifiers().contains(classReference.getQualifiedName()) val isNotConvertedClass = classReference != null && !converter.getClassIdentifiers().contains(classReference.getQualifiedName())
val argumentList = expression.getArgumentList() val argumentList = expression.getArgumentList()
var arguments = argumentList?.getExpressions() ?: array() var arguments = argumentList?.getExpressions() ?: array()
if (constructor == null || isConstructorPrimary(constructor) || isNotConvertedClass) { if (constructor == null || constructor.isPrimaryConstructor() || isNotConvertedClass) {
return NewClassExpression(converter.convertElement(classReference), return NewClassExpression(converter.convertElement(classReference),
converter.convertArguments(expression), converter.convertArguments(expression),
converter.convertExpression(expression.getQualifier()), converter.convertExpression(expression.getQualifier()),
@@ -388,32 +388,6 @@ open class ExpressionVisitor(public val converter: Converter) : JavaElementVisit
return false return false
} }
private fun isInsideSecondaryConstructor(expression: PsiReferenceExpression): Boolean {
var context = expression.getContext()
while (context != null) {
val _context = context!!
if (_context is PsiMethod && _context.isConstructor()) {
return !isConstructorPrimary(_context)
}
context = _context.getContext()
}
return false
}
private fun isInsidePrimaryConstructor(expression: PsiExpression): Boolean {
var context = expression.getContext()
while (context != null) {
val _context = context!!
if (_context is PsiMethod && _context.isConstructor()) {
return isConstructorPrimary(_context)
}
context = _context.getContext()
}
return false
}
private fun getContainingClass(expression: PsiExpression): PsiClass? { private fun getContainingClass(expression: PsiExpression): PsiClass? {
var context = expression.getContext() var context = expression.getContext()
while (context != null) { while (context != null) {