diff --git a/j2k/src/org/jetbrains/jet/j2k/ConstructorUtils.kt b/j2k/src/org/jetbrains/jet/j2k/ConstructorUtils.kt index 461241a9505..cc7c5258caf 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ConstructorUtils.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ConstructorUtils.kt @@ -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() +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()) - .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() + + override fun visitReferenceExpression(expression: PsiReferenceExpression) { + expression.getReferences() + .filter { it.getCanonicalText() == "this" } + .map { it.resolve() } + .filterIsInstance(javaClass()) + .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 } diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 7d599fd18fd..ccd79cf3430 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -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() 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) diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt index 9c2393a083b..a73498caf61 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ExpressionVisitor.kt @@ -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) {