diff --git a/j2k/src/org/jetbrains/jet/j2k/ClassBodyConverter.kt b/j2k/src/org/jetbrains/jet/j2k/ClassBodyConverter.kt new file mode 100644 index 00000000000..efc27184492 --- /dev/null +++ b/j2k/src/org/jetbrains/jet/j2k/ClassBodyConverter.kt @@ -0,0 +1,104 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.j2k + +import com.intellij.psi.PsiClass +import java.util.HashSet +import com.intellij.psi.PsiMember +import java.util.LinkedHashMap +import com.intellij.psi.PsiAnnotationMethod +import java.util.ArrayList +import com.intellij.psi.PsiModifier +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiField +import com.intellij.psi.PsiClassInitializer +import org.jetbrains.jet.j2k.ast.* + +class ClassBodyConverter(private val psiClass: PsiClass, + private val converter: Converter, + private val constructorConverter: ConstructorConverter?) { + public fun convertBody(): ClassBody { + val membersToRemove = HashSet() + val convertedMembers = LinkedHashMap() + for (element in psiClass.getChildren()) { + if (element is PsiMember) { + if (element is PsiAnnotationMethod) continue // converted in convertAnnotationType() + + val converted = converter.convertMember(element, membersToRemove, constructorConverter) + if (converted != null && !converted.isEmpty) { + convertedMembers.put(element, converted) + } + } + } + + for (member in membersToRemove) { + convertedMembers.remove(member) + } + + val useClassObject = shouldGenerateClassObject(convertedMembers) + + val members = ArrayList() + val classObjectMembers = ArrayList() + val factoryFunctions = ArrayList() + var primaryConstructorSignature: PrimaryConstructorSignature? = null + for ((psiMember, member) in convertedMembers) { + if (member is PrimaryConstructor) { + assert(primaryConstructorSignature == null) + primaryConstructorSignature = member.signature() + val initializer = member.initializer() + if (initializer != null) { + members.add(initializer) + } + } + else if (member is FactoryFunction) { + factoryFunctions.add(member) + } + else if (useClassObject + && (if (member is Class) shouldGenerateIntoClassObject(member) else psiMember.hasModifierProperty(PsiModifier.STATIC))) { + classObjectMembers.add(member) + } + else { + members.add(member) + } + } + + val lBrace = LBrace().assignPrototype(psiClass.getLBrace()) + val rBrace = RBrace().assignPrototype(psiClass.getRBrace()) + return ClassBody(primaryConstructorSignature, members, classObjectMembers, factoryFunctions, lBrace, rBrace) + } + + // do not convert private static methods into class object if possible + private fun shouldGenerateClassObject(convertedMembers: Map): Boolean { + if (psiClass.isEnum()) return false + + if (convertedMembers.values().any { it is Class && shouldGenerateIntoClassObject(it) }) return true + + val members = convertedMembers.keySet().filter { !it.isConstructor() } + val classObjectMembers = members.filter { it !is PsiClass && it.hasModifierProperty(PsiModifier.STATIC) } + val nestedClasses = members.filterIsInstance(javaClass()).filter { it.hasModifierProperty(PsiModifier.STATIC) } + if (classObjectMembers.all { it is PsiMethod && it.hasModifierProperty(PsiModifier.PRIVATE) }) { + return nestedClasses.any { nestedClass -> classObjectMembers.any { converter.referenceSearcher.findMethodCalls(it as PsiMethod, nestedClass).isNotEmpty() } } + } + else { + return true + } + } + + // we generate nested classes with factory functions into class object as a workaround until secondary constructors supported by Kotlin + private fun shouldGenerateIntoClassObject(nestedClass: Class) + = !nestedClass.modifiers.contains(Modifier.INNER) && nestedClass.body.factoryFunctions.isNotEmpty() +} \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index cd8a73010ba..5ee0915d671 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -72,7 +72,8 @@ public class Converter private(val project: Project, class object { private val LOG = Logger.getInstance("#org.jetbrains.jet.j2k.Converter") - public fun create(project: Project, settings: ConverterSettings, conversionScope: ConversionScope, referenceSearcher: ReferenceSearcher, postProcessor: PostProcessor?): Converter { + public fun create(project: Project, settings: ConverterSettings, conversionScope: ConversionScope, + referenceSearcher: ReferenceSearcher, postProcessor: PostProcessor?): Converter { val state = State(null, { ExpressionVisitor(it) }, { StatementVisitor(it) }, null, null, null) return Converter(project, settings, conversionScope, referenceSearcher, postProcessor, state) } @@ -184,81 +185,11 @@ public class Converter private(val project: Project, } fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody { - return AnonymousClassBody(convertBody(anonymousClass, null), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false).assignPrototype(anonymousClass) + return AnonymousClassBody(ClassBodyConverter(anonymousClass, this, null).convertBody(), + anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false).assignPrototype(anonymousClass) } - private fun convertBody(psiClass: PsiClass, constructorConverter: ConstructorConverter?): ClassBody { - val membersToRemove = HashSet() - val convertedMembers = LinkedHashMap() - for (element in psiClass.getChildren()) { - if (element is PsiMember) { - if (element is PsiAnnotationMethod) continue // converted in convertAnnotationType() - - val converted = convertMember(element, membersToRemove, constructorConverter) - if (converted != null && !converted.isEmpty) { - convertedMembers.put(element, converted) - } - } - } - - for (member in membersToRemove) { - convertedMembers.remove(member) - } - - val useClassObject = shouldGenerateClassObject(psiClass, convertedMembers) - - val members = ArrayList() - val classObjectMembers = ArrayList() - val factoryFunctions = ArrayList() - var primaryConstructorSignature: PrimaryConstructorSignature? = null - for ((psiMember, member) in convertedMembers) { - if (member is PrimaryConstructor) { - assert(primaryConstructorSignature == null) - primaryConstructorSignature = member.signature() - val initializer = member.initializer() - if (initializer != null) { - members.add(initializer) - } - } - else if (member is FactoryFunction) { - factoryFunctions.add(member) - } - else if (useClassObject - && (if (member is Class) shouldGenerateIntoClassObject(member) else psiMember.hasModifierProperty(PsiModifier.STATIC))) { - classObjectMembers.add(member) - } - else { - members.add(member) - } - } - - val lBrace = LBrace().assignPrototype(psiClass.getLBrace()) - val rBrace = RBrace().assignPrototype(psiClass.getRBrace()) - return ClassBody(primaryConstructorSignature, members, classObjectMembers, factoryFunctions, lBrace, rBrace) - } - - // do not convert private static methods into class object if possible - private fun shouldGenerateClassObject(psiClass: PsiClass, convertedMembers: Map): Boolean { - if (psiClass.isEnum()) return false - - if (convertedMembers.values().any { it is Class && shouldGenerateIntoClassObject(it) }) return true - - val members = convertedMembers.keySet().filter { !it.isConstructor() } - val classObjectMembers = members.filter { it !is PsiClass && it.hasModifierProperty(PsiModifier.STATIC) } - val nestedClasses = members.filterIsInstance(javaClass()).filter { it.hasModifierProperty(PsiModifier.STATIC) } - if (classObjectMembers.all { it is PsiMethod && it.hasModifierProperty(PsiModifier.PRIVATE) }) { - return nestedClasses.any { nestedClass -> classObjectMembers.any { referenceSearcher.findMethodCalls(it as PsiMethod, nestedClass).isNotEmpty() } } - } - else { - return true - } - } - - // we generate nested classes with factory functions into class object as a workaround until secondary constructors supported by Kotlin - private fun shouldGenerateIntoClassObject(nestedClass: Class) - = !nestedClass.modifiers.contains(Modifier.INNER) && nestedClass.body.factoryFunctions.isNotEmpty() - - private fun convertMember(member: PsiMember, membersToRemove: MutableSet, constructorConverter: ConstructorConverter?): Member? = when (member) { + fun convertMember(member: PsiMember, membersToRemove: MutableSet, constructorConverter: ConstructorConverter?): Member? = when (member) { is PsiMethod -> convertMethod(member, membersToRemove, constructorConverter) is PsiField -> convertField(member) is PsiClass -> convertClass(member) @@ -282,7 +213,7 @@ public class Converter private(val project: Project, val name = psiClass.declarationIdentifier() val constructorConverter = ConstructorConverter(psiClass, this) - var classBody = convertBody(psiClass, constructorConverter) + var classBody = ClassBodyConverter(psiClass, this, constructorConverter).convertBody() classBody = constructorConverter.postProcessConstructors(classBody) return when { @@ -328,7 +259,7 @@ public class Converter private(val project: Project, val constructorSignature = PrimaryConstructorSignature(Annotations.Empty, Modifiers.Empty, parameterList).assignNoPrototype() // to convert fields and nested types - they are not allowed in Kotlin but we convert them and let user refactor code - var classBody = convertBody(psiClass, null) + var classBody = ClassBodyConverter(psiClass, this, null).convertBody() classBody = ClassBody(constructorSignature, classBody.members, classBody.classObjectMembers, listOf(), classBody.lBrace, classBody.rBrace) val annotationAnnotation = Annotation(Identifier("annotation").assignNoPrototype(), listOf(), false, false).assignNoPrototype() @@ -376,7 +307,7 @@ public class Converter private(val project: Project, return converted.assignPrototype(field) } - fun variableTypeToDeclare(variable: PsiVariable, specifyAlways: Boolean, canChangeType: Boolean): Type? { + private fun variableTypeToDeclare(variable: PsiVariable, specifyAlways: Boolean, canChangeType: Boolean): Type? { fun convertType() = typeConverter.convertVariableType(variable) if (specifyAlways) return convertType()