Java to Kotlin convertor: improving code related to primary constructors
This commit is contained in:
@@ -22,57 +22,70 @@ import com.intellij.psi.PsiReferenceExpression
|
||||
import com.intellij.psi.JavaRecursiveElementVisitor
|
||||
import java.util.LinkedHashSet
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.PsiElement
|
||||
|
||||
fun isConstructorPrimary(constructor: PsiMethod): Boolean {
|
||||
val parent = constructor.getParent()
|
||||
if (parent is PsiClass) {
|
||||
if (parent.getConstructors().size == 1) {
|
||||
return true
|
||||
}
|
||||
else {
|
||||
val primary = getPrimaryConstructorForThisCase(parent)
|
||||
//TODO: I do not understand code below
|
||||
if (primary != null && primary.hashCode() == constructor.hashCode()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
fun PsiMethod.isPrimaryConstructor(): Boolean {
|
||||
if (!isConstructor()) return false
|
||||
val parent = getParent()
|
||||
if (parent !is PsiClass) return false
|
||||
return parent.getPrimaryConstructor() == this
|
||||
}
|
||||
|
||||
fun getPrimaryConstructorForThisCase(psiClass: PsiClass): PsiMethod? {
|
||||
class FindPrimaryConstructorVisitor() : JavaRecursiveElementVisitor() {
|
||||
private val resolvedConstructors = LinkedHashSet<PsiMethod>()
|
||||
fun PsiClass.getPrimaryConstructor(): PsiMethod? {
|
||||
val constructors = getConstructors()
|
||||
return when (constructors.size) {
|
||||
0 -> null
|
||||
|
||||
override fun visitReferenceExpression(expression: PsiReferenceExpression) {
|
||||
expression.getReferences()
|
||||
.filter { it.getCanonicalText() == "this" }
|
||||
.map { it.resolve() }
|
||||
.filterIsInstance(javaClass<PsiMethod>())
|
||||
.filterTo(resolvedConstructors) { it.isConstructor() }
|
||||
1 -> constructors.single()
|
||||
|
||||
else -> {
|
||||
// if there is more than one constructor then choose one invoked by all others
|
||||
class Visitor() : JavaRecursiveElementVisitor() {
|
||||
//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?
|
||||
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
|
||||
}
|
||||
context = _context.getContext()
|
||||
}
|
||||
|
||||
val visitor = FindPrimaryConstructorVisitor()
|
||||
psiClass.accept(visitor)
|
||||
return visitor.result
|
||||
return null
|
||||
}
|
||||
|
||||
fun isSuperConstructorRef(ref: PsiReference): Boolean {
|
||||
if (ref.getCanonicalText().equals("super")) {
|
||||
val baseConstructor = ref.resolve()
|
||||
if (baseConstructor is PsiMethod && baseConstructor.isConstructor()) {
|
||||
return true
|
||||
}
|
||||
val target = ref.resolve()
|
||||
return target is PsiMethod && target.isConstructor()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -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 initializers = HashMap<String, String>()
|
||||
for (member in members) {
|
||||
@@ -243,7 +243,7 @@ public class Converter(val project: Project, val settings: ConverterSettings) {
|
||||
|
||||
if (method.isConstructor()) {
|
||||
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)
|
||||
|
||||
@@ -168,7 +168,7 @@ open class ExpressionVisitor(public val converter: Converter) : JavaElementVisit
|
||||
val isNotConvertedClass = classReference != null && !converter.getClassIdentifiers().contains(classReference.getQualifiedName())
|
||||
val argumentList = expression.getArgumentList()
|
||||
var arguments = argumentList?.getExpressions() ?: array()
|
||||
if (constructor == null || isConstructorPrimary(constructor) || isNotConvertedClass) {
|
||||
if (constructor == null || constructor.isPrimaryConstructor() || isNotConvertedClass) {
|
||||
return NewClassExpression(converter.convertElement(classReference),
|
||||
converter.convertArguments(expression),
|
||||
converter.convertExpression(expression.getQualifier()),
|
||||
@@ -388,32 +388,6 @@ open class ExpressionVisitor(public val converter: Converter) : JavaElementVisit
|
||||
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? {
|
||||
var context = expression.getContext()
|
||||
while (context != null) {
|
||||
|
||||
Reference in New Issue
Block a user