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 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user