From 8b5f169dd870b753438c5322f9337dd746d0b0b4 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 18 Jun 2014 16:57:15 +0400 Subject: [PATCH] Java to Kotlin converter: new way of preserving comments and blank lines implemented (not completely though) --- .../org/jetbrains/jet/j2k/CommentConverter.kt | 62 ----- .../jetbrains/jet/j2k/CommentsAndSpaces.kt | 174 +++++++++++++ j2k/src/org/jetbrains/jet/j2k/Converter.kt | 228 ++++++++---------- .../org/jetbrains/jet/j2k/MainMethodUtils.kt | 2 +- .../org/jetbrains/jet/j2k/ast/Annotation.kt | 16 +- .../jet/j2k/ast/AnonymousClassBody.kt | 6 +- .../ArrayWithoutInitializationExpression.kt | 16 +- j2k/src/org/jetbrains/jet/j2k/ast/Block.kt | 40 +-- j2k/src/org/jetbrains/jet/j2k/ast/Class.kt | 40 ++- .../org/jetbrains/jet/j2k/ast/ClassBody.kt | 64 +++++ .../org/jetbrains/jet/j2k/ast/Constructors.kt | 31 ++- .../jet/j2k/ast/DummyStringExpression.kt | 4 +- j2k/src/org/jetbrains/jet/j2k/ast/Element.kt | 42 +++- j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt | 24 +- .../org/jetbrains/jet/j2k/ast/EnumConstant.kt | 13 +- .../org/jetbrains/jet/j2k/ast/Expression.kt | 4 +- .../jetbrains/jet/j2k/ast/ExpressionList.kt | 6 +- .../org/jetbrains/jet/j2k/ast/Expressions.kt | 61 ++--- j2k/src/org/jetbrains/jet/j2k/ast/Field.kt | 16 +- j2k/src/org/jetbrains/jet/j2k/ast/File.kt | 12 +- j2k/src/org/jetbrains/jet/j2k/ast/Function.kt | 20 +- .../org/jetbrains/jet/j2k/ast/Identifier.kt | 9 +- j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt | 32 +-- .../org/jetbrains/jet/j2k/ast/Initializer.kt | 8 +- .../jetbrains/jet/j2k/ast/LocalVariable.kt | 12 +- j2k/src/org/jetbrains/jet/j2k/ast/Members.kt | 70 ------ .../jet/j2k/ast/MethodCallExpression.kt | 12 +- j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt | 2 +- .../jet/j2k/ast/NewClassExpression.kt | 14 +- .../org/jetbrains/jet/j2k/ast/Parameter.kt | 8 +- .../jetbrains/jet/j2k/ast/ParameterList.kt | 7 +- .../jetbrains/jet/j2k/ast/ReferenceElement.kt | 4 +- .../org/jetbrains/jet/j2k/ast/Statements.kt | 62 +++-- j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt | 7 +- .../org/jetbrains/jet/j2k/ast/TypeElement.kt | 4 +- .../jetbrains/jet/j2k/ast/TypeParameters.kt | 20 +- j2k/src/org/jetbrains/jet/j2k/ast/Types.kt | 34 +-- j2k/src/org/jetbrains/jet/j2k/ast/Util.kt | 61 +---- .../org/jetbrains/jet/j2k/ast/WhiteSpace.kt | 46 ---- .../jet/j2k/visitors/ElementVisitor.kt | 14 +- .../jet/j2k/visitors/StatementVisitor.kt | 25 +- .../JavaToKotlinConverterTestGenerated.java | 16 +- j2k/tests/testData/ast/comments/Comments.kt | 30 +++ j2k/tests/testData/ast/comments/comments.java | 26 ++ .../testData/ast/comments/comments.kt.todo | 25 ++ .../ast/constructors/withManyDefaultParams.kt | 1 - .../ast/formatting/nonStaticMembers.kt | 1 - .../nonStaticMembersWithComments.kt | 1 - .../staticAndNonStaticMembersWithComments.kt | 7 +- .../formatting/staticMembersWithComments.kt | 5 +- j2k/tests/testData/ast/issues/kt-836.kt | 1 - j2k/tests/testData/ast/issues/kt-837.kt | 1 - 52 files changed, 756 insertions(+), 690 deletions(-) delete mode 100644 j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt create mode 100644 j2k/src/org/jetbrains/jet/j2k/CommentsAndSpaces.kt create mode 100644 j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt delete mode 100644 j2k/src/org/jetbrains/jet/j2k/ast/Members.kt delete mode 100644 j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt create mode 100644 j2k/tests/testData/ast/comments/Comments.kt create mode 100644 j2k/tests/testData/ast/comments/comments.java create mode 100644 j2k/tests/testData/ast/comments/comments.kt.todo diff --git a/j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt b/j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt deleted file mode 100644 index ce9f22c79cf..00000000000 --- a/j2k/src/org/jetbrains/jet/j2k/CommentConverter.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.* -import java.util.ArrayList -import org.jetbrains.jet.j2k.ast.Element - -class CommentConverter(private val topElement: PsiElement?) { - private enum class CommentPlacement { - Before - SameLineBefore - SameLineAfter - After - } - - private class CommentInfo(val comment: PsiComment) { - val startOffset: Int - val endOffset: Int - var isAttached = false - - { - val range = comment.getTextRange()!! - startOffset = range.getStartOffset() - endOffset = range.getEndOffset() - } - } - - private val allComments: List = run { - val list = ArrayList() - topElement?.accept(object : JavaRecursiveElementVisitor(){ - override fun visitComment(comment: PsiComment) { - list.add(CommentInfo(comment)) - } - }) - list - } - - /* - public fun toKotlin(elementToKotlin: () -> String, originalElements: List): String { - - } - */ - - class object { - val Dummy: CommentConverter = CommentConverter(null) - } -} diff --git a/j2k/src/org/jetbrains/jet/j2k/CommentsAndSpaces.kt b/j2k/src/org/jetbrains/jet/j2k/CommentsAndSpaces.kt new file mode 100644 index 00000000000..7d306d1d5a3 --- /dev/null +++ b/j2k/src/org/jetbrains/jet/j2k/CommentsAndSpaces.kt @@ -0,0 +1,174 @@ +/* + * 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.* +import java.util.HashSet +import org.jetbrains.jet.lang.psi.psiUtil.isAncestor +import java.util.ArrayList +import org.jetbrains.jet.j2k.ast.PrototypeInfo + +class CommentsAndSpaces(private val topElement: PsiElement?) { + private val commentsAndSpacesUsed = HashSet() + + public fun wrapElement(elementToKotlin: () -> String, prototypes: List): String { + if (prototypes.isEmpty() || topElement == null) return elementToKotlin() + + val prefix = StringBuilder() + val postfix = StringBuilder() + for ((element, inheritBlankLinesBefore) in prototypes) { + assert(element !is PsiComment) + assert(element !is PsiWhiteSpace) + assert(topElement.isAncestor(element)) + prefix.collectPrefix(element, inheritBlankLinesBefore) + postfix.collectPostfix(element) + } + + return prefix.toString() + elementToKotlin() + postfix.toString() + } + + private fun StringBuilder.collectPrefix(element: PsiElement, allowBlankLinesBefore: Boolean) { + val atStart = ArrayList(2).addCommentsAndSpacesAtStart(element) + + val before = ArrayList(2).addCommentsAndSpacesBefore(element) + if (before.isNotEmpty()) { + val last = before.last() + if (last is PsiWhiteSpace) { + if (allowBlankLinesBefore) { + val blankLines = last.newLinesCount() - 1 + if (blankLines > 0) { + append("\n") // insert at maximum one blank line + commentsAndSpacesUsed.add(last) + } + } + before.remove(before.size - 1) + } + } + + if (before.isEmpty() && atStart.isEmpty()) return + + for (e in before.reverse() + atStart) { + append(e.getText()) + commentsAndSpacesUsed.add(e) + } + } + + private fun StringBuilder.collectPostfix(element: PsiElement) { + val atEnd = ArrayList(2).addCommentsAndSpacesAtEnd(element) + + val after = ArrayList(2).addCommentsAndSpacesAfter(element) + if (after.isNotEmpty()) { + val last = after.last() + if (last is PsiWhiteSpace) { + after.remove(after.size - 1) + } + } + + if (after.isEmpty() && atEnd.isEmpty()) return + + for (e in atEnd.reverse() + after) { + append(e.getText()) + commentsAndSpacesUsed.add(e) + } + } + + private fun MutableList.addCommentsAndSpacesBefore(element: PsiElement): MutableList { + if (element == topElement) return this + + val prev = element.getPrevSibling() + if (prev != null) { + if (prev.isCommentOrSpace()) { + if (prev !in commentsAndSpacesUsed) { + add(prev) + addCommentsAndSpacesBefore(prev) + } + } + else if (prev.isEmptyElement()){ + addCommentsAndSpacesBefore(prev) + } + } + else { + addCommentsAndSpacesBefore(element.getParent()!!) + } + return this + } + + private fun MutableList.addCommentsAndSpacesAfter(element: PsiElement): MutableList { + if (element == topElement) return this + + val next = element.getNextSibling() + if (next != null) { + if (next.isCommentOrSpace()) { + if (next is PsiWhiteSpace && next.hasNewLines()) return this // do not attach anything on next line after element + if (next !in commentsAndSpacesUsed) { + add(next) + addCommentsAndSpacesAfter(next) + } + } + else if (next.isEmptyElement()){ + addCommentsAndSpacesAfter(next) + } + } + else { + addCommentsAndSpacesAfter(element.getParent()!!) + } + return this + } + + private fun MutableList.addCommentsAndSpacesAtStart(element: PsiElement): MutableList { + var child = element.getFirstChild() + while(child != null) { + if (child!!.isCommentOrSpace()) { + if (child !in commentsAndSpacesUsed) add(child!!) else break + } + else if (!child!!.isEmptyElement()) { + addCommentsAndSpacesAtStart(child!!) + break + } + child = child!!.getNextSibling() + } + return this + } + + private fun MutableList.addCommentsAndSpacesAtEnd(element: PsiElement): MutableList { + var child = element.getLastChild() + while(child != null) { + if (child!!.isCommentOrSpace()) { + if (child !in commentsAndSpacesUsed) add(child!!) else break + } + else if (!child!!.isEmptyElement()) { + addCommentsAndSpacesAtEnd(child!!) + break + } + child = child!!.getPrevSibling() + } + return this + } + + private fun PsiElement.isCommentOrSpace() = this is PsiComment || this is PsiWhiteSpace + + private fun PsiElement.isEmptyElement() = getFirstChild() == null && getTextLength() == 0 + + private fun PsiWhiteSpace.newLinesCount() = getText()!!.count { it == '\n' } //TODO: this is not correct!! + + private fun PsiWhiteSpace.hasNewLines() = getText()!!.any { it == '\n' || it == '\r' } + + class object { + val None: CommentsAndSpaces = CommentsAndSpaces(null) + } +} + diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 6cbc279c55e..c23b8512880 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -60,7 +60,7 @@ public class Converter private(val project: Project, val settings: ConverterSett = Converter(project, settings, conversionScope, State(typeConverter, state.methodReturnType, state.expressionVisitorFactory, factory)) public fun elementToKotlin(element: PsiElement): String - = convertTopElement(element)?.toKotlin(CommentConverter(element)) ?: "" + = convertTopElement(element)?.toKotlin(CommentsAndSpaces(element)) ?: "" private fun convertTopElement(element: PsiElement?): Element? = when(element) { is PsiJavaFile -> convertFile(element) @@ -69,12 +69,10 @@ public class Converter private(val project: Project, val settings: ConverterSett is PsiField -> convertField(element) is PsiStatement -> convertStatement(element) is PsiExpression -> convertExpression(element) - is PsiComment -> Comment(element.getText()!!/*, listOf(element)*/) is PsiImportList -> convertImportList(element) is PsiImportStatementBase -> convertImport(element, false) is PsiAnnotation -> convertAnnotation(element, false) - is PsiPackageStatement -> PackageStatement(quoteKeywords(element.getPackageName() ?: "")) - is PsiWhiteSpace -> WhiteSpace(element.getText()!!) + is PsiPackageStatement -> PackageStatement(quoteKeywords(element.getPackageName() ?: "")).assignPrototype(element) else -> null } @@ -93,45 +91,42 @@ public class Converter private(val project: Project, val settings: ConverterSett typeConverter.importList = null if (typeConverter.importsToAdd.isNotEmpty()) { val importList = convertedChildren.filterIsInstance(javaClass()).first() - val newImportList = ImportList(importList.imports + typeConverter.importsToAdd) + val newImportList = ImportList(importList.imports + typeConverter.importsToAdd).assignPrototypesFrom(importList) convertedChildren = convertedChildren.map { if (it == importList) newImportList else it } } - return File(FileMemberList(convertedChildren), createMainFunction(javaFile)) + return File(convertedChildren, createMainFunction(javaFile)).assignPrototype(javaFile) } fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody { - return AnonymousClassBody(convertClassBody(anonymousClass), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false) + return AnonymousClassBody(convertBody(anonymousClass), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false).assignPrototype(anonymousClass) } - private fun convertClassBody(psiClass: PsiClass): ClassBody { + private fun convertBody(psiClass: PsiClass): ClassBody { val membersToRemove = HashSet() - val convertedElements = LinkedHashMap() - var inBody = false - val lBrace = psiClass.getLBrace() + val convertedMembers = LinkedHashMap() for (element in psiClass.getChildren()) { - if (element == lBrace) inBody = true - if (inBody) { - convertedElements.put(element, convertMember(element, membersToRemove)) + if (element is PsiMember) { + val converted = convertMember(element, membersToRemove) + if (!converted.isEmpty) { + convertedMembers.put(element, converted) + } } } for (member in membersToRemove) { - convertedElements.remove(member) + convertedMembers.remove(member) } - val membersMap = splitIntoMembers(convertedElements) - - val constructors = membersMap.values().filter { it.member is Constructor } - val primaryConstructor = constructors.map { it.member }.filterIsInstance(javaClass()).firstOrNull() - val secondaryConstructors = constructors.filter { it.member is SecondaryConstructor } + val primaryConstructor = convertedMembers.values().filterIsInstance(javaClass()).firstOrNull() + val secondaryConstructors = convertedMembers.values().filterIsInstance(javaClass()) // do not convert private static methods into class object if possible val useClassObject = if (psiClass.isEnum()) { false } else { - val members = membersMap.keySet().filter { it !is PsiMethod || !it.isConstructor() } + val members = convertedMembers.keySet().filter { it !is PsiMethod || !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) }) { @@ -142,10 +137,10 @@ public class Converter private(val project: Project, val settings: ConverterSett } } - val normalMembers = ArrayList() - val classObjectMembers = ArrayList() - for ((psiMember, member) in membersMap) { - if (member.member is Constructor) continue + val normalMembers = ArrayList() + val classObjectMembers = ArrayList() + for ((psiMember, member) in convertedMembers) { + if (member is Constructor) continue if (useClassObject && psiMember !is PsiClass && psiMember.hasModifierProperty(PsiModifier.STATIC)) { classObjectMembers.add(member) } @@ -154,51 +149,17 @@ public class Converter private(val project: Project, val settings: ConverterSett } } - return ClassBody(primaryConstructor, - secondaryConstructors.toMemberList(), - normalMembers.toMemberList(), - classObjectMembers.toMemberList()) - + val lBrace = LBrace().assignPrototype(psiClass.getLBrace()) + val rBrace = RBrace().assignPrototype(psiClass.getRBrace()) + return ClassBody(primaryConstructor, secondaryConstructors, normalMembers, classObjectMembers, lBrace, rBrace) } - private fun List.toMemberList() = MemberList(flatMap { it.elements }) - - private fun splitIntoMembers(elements: Map): Map { - val result = LinkedHashMap() - var currentGroup = ArrayList() - var lastMember: PsiMember? = null - for ((psiElement, element) in elements) { - currentGroup.add(element) - if (element is Member) { - result.put(psiElement as PsiMember, MemberWithComments(element, currentGroup)) - currentGroup = ArrayList() - lastMember = psiElement - } - } - if (lastMember != null) { - (result[lastMember]!!.elements as MutableList).addAll(currentGroup) - } - return result - } - - private fun convertMember(element: PsiElement, membersToRemove: MutableSet): Element = when(element) { - is PsiMethod -> convertMethod(element, membersToRemove) - is PsiField -> convertField(element) - is PsiClass -> convertClass(element) - is PsiClassInitializer -> convertInitializer(element) - else -> convertElement(element) - } - - private fun getComments(member: PsiMember): MemberComments { - var relevantChildren = member.getChildren().toList() - if (member is PsiClass) { - val leftBraceIndex = relevantChildren.indexOf(member.getLBrace()) - relevantChildren = relevantChildren.subList(0, leftBraceIndex) - } - val whiteSpacesAndComments = relevantChildren - .filter { it is PsiWhiteSpace || it is PsiComment } - .map { convertElement(it) } - return MemberComments(whiteSpacesAndComments) + private fun convertMember(member: PsiMember, membersToRemove: MutableSet): Member = when(member) { + is PsiMethod -> convertMethod(member, membersToRemove) + is PsiField -> convertField(member) + is PsiClass -> convertClass(member) + is PsiClassInitializer -> convertInitializer(member) + else -> throw IllegalArgumentException("Unknown member: $member") } private fun convertClass(psiClass: PsiClass): Class { @@ -207,13 +168,13 @@ public class Converter private(val project: Project, val settings: ConverterSett val typeParameters = convertTypeParameterList(psiClass.getTypeParameterList()) val implementsTypes = convertToNotNullableTypes(psiClass.getImplementsListTypes()) val extendsTypes = convertToNotNullableTypes(psiClass.getExtendsListTypes()) - val name = Identifier(psiClass.getName()!!) - var classBody = convertClassBody(psiClass) + val name = psiClass.declarationIdentifier() + var classBody = convertBody(psiClass) - when { - psiClass.isInterface() -> return Trait(name, getComments(psiClass), annotations, modifiers, typeParameters, extendsTypes, listOf(), implementsTypes, classBody) + return when { + psiClass.isInterface() -> Trait(name, annotations, modifiers, typeParameters, extendsTypes, listOf(), implementsTypes, classBody) - psiClass.isEnum() -> return Enum(name, getComments(psiClass), annotations, modifiers, typeParameters, listOf(), listOf(), implementsTypes, classBody) + psiClass.isEnum() -> Enum(name, annotations, modifiers, typeParameters, listOf(), listOf(), implementsTypes, classBody) else -> { if (psiClass.getPrimaryConstructor() == null && psiClass.getConstructors().size > 1) { @@ -240,19 +201,17 @@ public class Converter private(val project: Project, val settings: ConverterSett modifiers.add(Modifier.INNER) } - return Class(name, getComments(psiClass), annotations, modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, classBody) + Class(name, annotations, modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, classBody) } - } + }.assignPrototype(psiClass) } private fun generateArtificialPrimaryConstructor(className: Identifier, classBody: ClassBody): ClassBody { assert(classBody.primaryConstructor == null) - val finalOrWithEmptyInitializerFields = classBody.normalMembers.members.filterIsInstance(javaClass()).filter { it.isVal || it.initializer.isEmpty } + val finalOrWithEmptyInitializerFields = classBody.normalMembers.filterIsInstance(javaClass()).filter { it.isVal || it.initializer.isEmpty } val initializers = HashMap() - for (constructor in classBody.secondaryConstructors.members) { - constructor as SecondaryConstructor - + for (constructor in classBody.secondaryConstructors) { for (field in finalOrWithEmptyInitializerFields) { initializers.put(field, getDefaultInitializer(field)) } @@ -290,7 +249,7 @@ public class Converter private(val project: Project, val settings: ConverterSett true, settings) newStatements.add(0, DeclarationStatement(listOf(localVar))) - constructor.block = Block(newStatements) + constructor.block = Block(newStatements, LBrace(), RBrace()) } //TODO: comments? @@ -299,39 +258,40 @@ public class Converter private(val project: Project, val settings: ConverterSett Parameter(field.identifier, field.`type`, varValModifier, field.annotations, field.modifiers.filter { ACCESS_MODIFIERS.contains(it) }) } - val primaryConstructor = PrimaryConstructor(this, MemberComments.Empty, Annotations.Empty, setOf(Modifier.PRIVATE), ParameterList(parameters), Block.Empty) - val updatedMembers = MemberList(classBody.normalMembers.elements.filter { !finalOrWithEmptyInitializerFields.contains(it) }) - return ClassBody(primaryConstructor, classBody.secondaryConstructors, updatedMembers, classBody.classObjectMembers) + val primaryConstructor = PrimaryConstructor(this, Annotations.Empty, setOf(Modifier.PRIVATE), ParameterList(parameters), Block.Empty) + val updatedMembers = classBody.normalMembers.filter { !finalOrWithEmptyInitializerFields.contains(it) } + return ClassBody(primaryConstructor, classBody.secondaryConstructors, updatedMembers, classBody.classObjectMembers, classBody.lBrace, classBody.rBrace) } private fun convertInitializer(initializer: PsiClassInitializer): Initializer { - return Initializer(convertBlock(initializer.getBody()), convertModifiers(initializer)) + return Initializer(convertBlock(initializer.getBody()), convertModifiers(initializer)).assignPrototype(initializer) } private fun convertField(field: PsiField): Field { val annotations = convertAnnotations(field) val modifiers = convertModifiers(field) - if (field is PsiEnumConstant) { - return EnumConstant(Identifier(field.getName()!!), - getComments(field), - annotations, - modifiers, - typeConverter.convertType(field.getType(), Nullability.NotNull), - convertElement(field.getArgumentList())) + val name = field.declarationIdentifier() + val converted = if (field is PsiEnumConstant) { + EnumConstant(name, + annotations, + modifiers, + typeConverter.convertType(field.getType(), Nullability.NotNull), + convertElement(field.getArgumentList())) } - - return Field(Identifier(field.getName()!!), - getComments(field), - annotations, - modifiers, - typeConverter.convertVariableType(field), - convertExpression(field.getInitializer(), field.getType()), - field.hasModifierProperty(PsiModifier.FINAL), - field.hasWriteAccesses(field.getContainingClass())) + else { + Field(name, + annotations, + modifiers, + typeConverter.convertVariableType(field), + convertExpression(field.getInitializer(), field.getType()), + field.hasModifierProperty(PsiModifier.FINAL), + field.hasWriteAccesses(field.getContainingClass())) + } + return converted.assignPrototype(field) } private fun convertMethod(method: PsiMethod, membersToRemove: MutableSet): Function { - return withMethodReturnType(method.getReturnType()).doConvertMethod(method, membersToRemove) + return withMethodReturnType(method.getReturnType()).doConvertMethod(method, membersToRemove).assignPrototype(method) } private fun doConvertMethod(method: PsiMethod, membersToRemove: MutableSet): Function { @@ -340,15 +300,13 @@ public class Converter private(val project: Project, val settings: ConverterSett val annotations = convertAnnotations(method) + convertThrows(method) val modifiers = convertModifiers(method) - val comments = getComments(method) - if (method.isConstructor()) { if (method.isPrimaryConstructor()) { - return convertPrimaryConstructor(method, annotations, modifiers, comments, membersToRemove) + return convertPrimaryConstructor(method, annotations, modifiers, membersToRemove) } else { val params = convertParameterList(method.getParameterList()) - return SecondaryConstructor(this, comments, annotations, modifiers, params, convertBlock(method.getBody())) + return SecondaryConstructor(this, annotations, modifiers, params, convertBlock(method.getBody())) } } else { @@ -387,7 +345,7 @@ public class Converter private(val project: Project, val settings: ConverterSett val typeParameterList = convertTypeParameterList(method.getTypeParameterList()) val block = convertBlock(method.getBody()) - return Function(this, Identifier(method.getName()), comments, annotations, modifiers, returnType, typeParameterList, params, block, containingClass?.isInterface() ?: false) + return Function(this, method.declarationIdentifier(), annotations, modifiers, returnType, typeParameterList, params, block, containingClass?.isInterface() ?: false) } } @@ -429,7 +387,6 @@ public class Converter private(val project: Project, val settings: ConverterSett private fun convertPrimaryConstructor(constructor: PsiMethod, annotations: Annotations, modifiers: Set, - comments: MemberComments, membersToRemove: MutableSet): PrimaryConstructor { val params = constructor.getParameterList().getParameters() val parameterToField = HashMap>() @@ -468,20 +425,20 @@ public class Converter private(val project: Project, val settings: ConverterSett Block.Empty } - val parameterList = ParameterList(params.map { - if (!parameterToField.containsKey(it)) { - convertParameter(it) + val parameterList = ParameterList(params.map { parameter -> + if (!parameterToField.containsKey(parameter)) { + convertParameter(parameter) } else { - val (field, `type`) = parameterToField[it]!! - Parameter(Identifier(field.getName()!!), + val (field, `type`) = parameterToField[parameter]!! + Parameter(field.declarationIdentifier(), `type`, if (field.hasModifierProperty(PsiModifier.FINAL)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var, - convertAnnotations(it) + convertAnnotations(field), - convertModifiers(field).filter { ACCESS_MODIFIERS.contains(it) }) + convertAnnotations(parameter) + convertAnnotations(field), + convertModifiers(field).filter { ACCESS_MODIFIERS.contains(it) }).assignPrototypes(listOf(parameter, field), inheritBlankLinesBefore = false) } }) - return PrimaryConstructor(this, comments, annotations, modifiers, parameterList, block) + return PrimaryConstructor(this, annotations, modifiers, parameterList, block).assignPrototype(constructor) } private fun findBackingFieldForConstructorParameter(parameter: PsiParameter, constructor: PsiMethod): Pair? { @@ -518,9 +475,9 @@ public class Converter private(val project: Project, val settings: ConverterSett fun convertBlock(block: PsiCodeBlock?, notEmpty: Boolean = true, statementFilter: (PsiStatement) -> Boolean = {true}): Block { if (block == null) return Block.Empty - val filteredChildren = block.getChildren().filter { it !is PsiStatement || statementFilter(it) } - val statementList = StatementList(filteredChildren.map { if (it is PsiStatement) convertStatement(it) else convertElement(it) }) - return Block(statementList, notEmpty) + val lBrace = LBrace().assignPrototype(block.getLBrace()) + val rBrace = RBrace().assignPrototype(block.getRBrace()) + return Block(block.getStatements().filter(statementFilter).map { convertStatement(it) }, lBrace, rBrace, notEmpty).assignPrototype(block) } fun convertStatement(statement: PsiStatement?): Statement { @@ -528,7 +485,7 @@ public class Converter private(val project: Project, val settings: ConverterSett statementVisitor.reset() statement.accept(statementVisitor) - return statementVisitor.result + return statementVisitor.result.assignPrototype(statement) } fun convertExpressions(expressions: Array): List @@ -539,7 +496,7 @@ public class Converter private(val project: Project, val settings: ConverterSett expressionVisitor.reset() expression.accept(expressionVisitor) - return expressionVisitor.result + return expressionVisitor.result.assignPrototype(expression) } fun convertElement(element: PsiElement?): Element { @@ -547,17 +504,17 @@ public class Converter private(val project: Project, val settings: ConverterSett val elementVisitor = ElementVisitor(this) element.accept(elementVisitor) - return elementVisitor.result + return elementVisitor.result.assignPrototype(element) } fun convertTypeElement(element: PsiTypeElement?): TypeElement - = TypeElement(if (element == null) Type.Empty else typeConverter.convertType(element.getType())) + = TypeElement(if (element == null) Type.Empty else typeConverter.convertType(element.getType())).assignPrototype(element) private fun convertToNotNullableTypes(types: Array): List = types.map { typeConverter.convertType(it, Nullability.NotNull) } fun convertParameterList(parameterList: PsiParameterList): ParameterList - = ParameterList(parameterList.getParameters().map { convertParameter(it) }) + = ParameterList(parameterList.getParameters().map { convertParameter(it) }).assignPrototype(parameterList) fun convertParameter(parameter: PsiParameter, nullability: Nullability = Nullability.Default, @@ -568,7 +525,7 @@ public class Converter private(val project: Project, val settings: ConverterSett Nullability.NotNull -> `type` = `type`.toNotNullType() Nullability.Nullable -> `type` = `type`.toNullableType() } - return Parameter(Identifier(parameter.getName()!!), `type`, varValModifier, convertAnnotations(parameter), modifiers) + return Parameter(parameter.declarationIdentifier(), `type`, varValModifier, convertAnnotations(parameter), modifiers).assignPrototype(parameter) } fun convertExpression(argument: PsiExpression?, expectedType: PsiType?): Expression { @@ -596,13 +553,13 @@ public class Converter private(val project: Project, val settings: ConverterSett } - return expression + return expression.assignPrototype(argument) } fun convertIdentifier(identifier: PsiIdentifier?): Identifier { if (identifier == null) return Identifier.Empty - return Identifier(identifier.getText()!!) + return Identifier(identifier.getText()!!).assignPrototype(identifier) } fun convertModifiers(owner: PsiModifierListOwner): MutableSet @@ -641,11 +598,12 @@ public class Converter private(val project: Project, val settings: ConverterSett private fun convertAnnotation(annotation: PsiAnnotation, brackets: Boolean): Annotation? { val qualifiedName = annotation.getQualifiedName() if (qualifiedName == CommonClassNames.JAVA_LANG_DEPRECATED && annotation.getParameterList().getAttributes().isEmpty()) { - return Annotation(Identifier("deprecated"), listOf(null to LiteralExpression("\"\"")), brackets) //TODO: insert comment + return Annotation(Identifier("deprecated"), listOf(null to LiteralExpression("\"\"")), brackets).assignPrototype(annotation) //TODO: insert comment } - val name = Identifier((annotation.getNameReferenceElement() ?: return null).getText()!!) - val annotationClass = annotation.getNameReferenceElement()?.resolve() as? PsiClass + val nameRef = annotation.getNameReferenceElement() + val name = Identifier((nameRef ?: return null).getText()!!).assignPrototype(nameRef) + val annotationClass = nameRef!!.resolve() as? PsiClass val lastMethod = annotationClass?.getMethods()?.lastOrNull() val arguments = annotation.getParameterList().getAttributes().flatMap { val method = annotationClass?.findMethodsByName(it.getName() ?: "value", false)?.firstOrNull() @@ -659,7 +617,7 @@ public class Converter private(val project: Project, val settings: ConverterSett attrValues.map { attrName to it } } - return Annotation(name, arguments, brackets) + return Annotation(name, arguments, brackets).assignPrototype(annotation) } private fun convertAttributeValue(value: PsiAnnotationMemberValue?, expectedType: PsiType?, isVararg: Boolean, isUnnamed: Boolean): List { @@ -689,11 +647,13 @@ public class Converter private(val project: Project, val settings: ConverterSett } private fun convertThrows(method: PsiMethod): Annotations { - val types = method.getThrowsList().getReferencedTypes() + val throwsList = method.getThrowsList() + val types = throwsList.getReferencedTypes() if (types.isEmpty()) return Annotations.Empty - return Annotations(listOf(Annotation(Identifier("throws"), - types.map { null to MethodCallExpression.buildNotNull(null, "javaClass", listOf(), listOf(typeConverter.convertType(it, Nullability.NotNull))) }, - false)), + val annotation = Annotation(Identifier("throws"), + types.map { null to MethodCallExpression.buildNotNull(null, "javaClass", listOf(), listOf(typeConverter.convertType(it, Nullability.NotNull))) }, + false) + return Annotations(listOf(annotation.assignPrototype(throwsList)), true) } diff --git a/j2k/src/org/jetbrains/jet/j2k/MainMethodUtils.kt b/j2k/src/org/jetbrains/jet/j2k/MainMethodUtils.kt index efbb1142f45..c508d8dd507 100644 --- a/j2k/src/org/jetbrains/jet/j2k/MainMethodUtils.kt +++ b/j2k/src/org/jetbrains/jet/j2k/MainMethodUtils.kt @@ -38,7 +38,7 @@ fun createMainFunction(file: PsiFile): String { } if (classNamesWithMains.size() > 0) { - var className = classNamesWithMains.get(0).first + var className = classNamesWithMains[0].first return MessageFormat.format("fun main(args : Array) = {0}.main(args as Array?)", className) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt index 5345c90d6ff..a96ed874910 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Annotation.kt @@ -16,31 +16,31 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class Annotation(val name: Identifier, val arguments: List>, val brackets: Boolean) : Element() { private fun surroundWithBrackets(text: String) = if (brackets) "[$text]" else text - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { if (arguments.isEmpty()) { - return surroundWithBrackets(name.toKotlin(commentConverter)) + return surroundWithBrackets(name.toKotlin(commentsAndSpaces)) } val argsText = arguments.map { if (it.first != null) - it.first!!.toKotlin(commentConverter) + " = " + it.second.toKotlin(commentConverter) + it.first!!.toKotlin(commentsAndSpaces) + " = " + it.second.toKotlin(commentsAndSpaces) else - it.second.toKotlin(commentConverter) + it.second.toKotlin(commentsAndSpaces) }.makeString(", ") - return surroundWithBrackets(name.toKotlin(commentConverter) + "(" + argsText + ")") + return surroundWithBrackets(name.toKotlin(commentsAndSpaces) + "(" + argsText + ")") } } class Annotations(val annotations: List, val newLines: Boolean) : Element() { private val br = if (newLines) "\n" else " " - override fun toKotlinImpl(commentConverter: CommentConverter): String { - return if (annotations.isNotEmpty()) annotations.map { it.toKotlin(commentConverter) }.makeString(br) + br else "" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + return if (annotations.isNotEmpty()) annotations.map { it.toKotlin(commentsAndSpaces) }.makeString(br) + br else "" } fun plus(other: Annotations) = Annotations(annotations + other.annotations, newLines || other.newLines) diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt index d2606aaba63..8ea24070061 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClassBody.kt @@ -16,9 +16,9 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class AnonymousClassBody(body: ClassBody, val extendsTrait: Boolean) -: Class(Identifier(""), MemberComments.Empty, Annotations.Empty, setOf(), TypeParameterList.Empty, listOf(), listOf(), listOf(), body) { - override fun toKotlinImpl(commentConverter: CommentConverter) = body.toKotlin(null, commentConverter) +: Class(Identifier.Empty, Annotations.Empty, setOf(), TypeParameterList.Empty, listOf(), listOf(), listOf(), body) { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = body.toKotlin(null, commentsAndSpaces) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt index 96eb2a3c8ee..30519ce89bc 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ArrayWithoutInitializationExpression.kt @@ -16,26 +16,26 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces -open class ArrayWithoutInitializationExpression(val `type`: ArrayType, val expressions: List) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { +class ArrayWithoutInitializationExpression(val `type`: ArrayType, val expressions: List) : Expression() { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { fun getConstructorName(`type`: ArrayType, hasInit: Boolean): String { return when (`type`.elementType) { is PrimitiveType -> - `type`.toNotNullType().toKotlin(commentConverter) + `type`.toNotNullType().toKotlin(commentsAndSpaces) is ArrayType -> if (hasInit) - `type`.toNotNullType().toKotlin(commentConverter) + `type`.toNotNullType().toKotlin(commentsAndSpaces) else - "arrayOfNulls<" + `type`.elementType.toKotlin(commentConverter) + ">" + "arrayOfNulls<" + `type`.elementType.toKotlin(commentsAndSpaces) + ">" else -> - "arrayOfNulls<" + `type`.elementType.toKotlin(commentConverter) + ">" + "arrayOfNulls<" + `type`.elementType.toKotlin(commentsAndSpaces) + ">" } } fun oneDim(`type`: ArrayType, size: Expression, init: String = ""): String { - return getConstructorName(`type`, !init.isEmpty()) + "(" + size.toKotlin(commentConverter) + init.withPrefix(", ") + ")" + return getConstructorName(`type`, !init.isEmpty()) + "(" + size.toKotlin(commentsAndSpaces) + init.withPrefix(", ") + ")" } fun constructInnerType(hostType: ArrayType, expressions: List): String { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt index ebccce581b1..1a85bf35949 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Block.kt @@ -16,33 +16,33 @@ package org.jetbrains.jet.j2k.ast -import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentConverter - -fun Block(statements: List, notEmpty: Boolean = false): Block { - val elements = ArrayList() - elements.add(WhiteSpace.NewLine) - elements.addAll(statements) - elements.add(WhiteSpace.NewLine) - return Block(StatementList(elements), notEmpty) -} - -class Block(val statementList: StatementList, val notEmpty: Boolean = false) : Statement() { - val statements: List = statementList.statements - +import org.jetbrains.jet.j2k.CommentsAndSpaces +class Block(val statements: List, val lBrace: LBrace, val rBrace: RBrace, val notEmpty: Boolean = false) : Statement() { override val isEmpty: Boolean get() = !notEmpty && statements.all { it.isEmpty } - override fun toKotlinImpl(commentConverter: CommentConverter): String { - if (!isEmpty) { - return "{${statementList.toKotlin(commentConverter)}}" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + if (statements.all { it.isEmpty }) { + return if (isEmpty) "" else lBrace.toKotlin(commentsAndSpaces) + rBrace.toKotlin(commentsAndSpaces) } - - return "" + return lBrace.toKotlin(commentsAndSpaces) + + "\n" + + statements.toKotlin(commentsAndSpaces, "\n") + + "\n" + + rBrace.toKotlin(commentsAndSpaces) } class object { - val Empty = Block(StatementList(listOf())) + val Empty = Block(listOf(), LBrace(), RBrace()) } } + +// we use LBrace and RBrace elements to better handle comments around them +class LBrace() : Element() { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "{" +} + +class RBrace() : Element() { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "}" +} diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt index c9b80664aca..7ca280e905a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt @@ -17,11 +17,10 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces open class Class( val name: Identifier, - comments: MemberComments, annotations: Annotations, modifiers: Set, val typeParameterList: TypeParameterList, @@ -29,37 +28,36 @@ open class Class( val baseClassParams: List, val implementsTypes: List, val body: ClassBody -) : Member(comments, annotations, modifiers) { +) : Member(annotations, modifiers) { - override fun toKotlinImpl(commentConverter: CommentConverter): String = - commentsToKotlin(commentConverter) + - annotations.toKotlin(commentConverter) + + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = + annotations.toKotlin(commentsAndSpaces) + modifiersToKotlin() + - keyword + " " + name.toKotlin(commentConverter) + - typeParameterList.toKotlin(commentConverter) + - primaryConstructorSignatureToKotlin(commentConverter) + - implementTypesToKotlin(commentConverter) + - typeParameterList.whereToKotlin(commentConverter).withPrefix(" ") + - body.toKotlin(this, commentConverter) + keyword + " " + name.toKotlin(commentsAndSpaces) + + typeParameterList.toKotlin(commentsAndSpaces) + + primaryConstructorSignatureToKotlin(commentsAndSpaces) + + implementTypesToKotlin(commentsAndSpaces) + + typeParameterList.whereToKotlin(commentsAndSpaces).withPrefix(" ") + + body.toKotlin(this, commentsAndSpaces) protected open val keyword: String get() = "class" - protected open fun primaryConstructorSignatureToKotlin(commentConverter: CommentConverter): String - = body.primaryConstructor?.signatureToKotlin(commentConverter) ?: "()" + protected open fun primaryConstructorSignatureToKotlin(commentsAndSpaces: CommentsAndSpaces): String + = body.primaryConstructor?.signatureToKotlin(commentsAndSpaces) ?: "()" - private fun baseClassSignatureWithParams(commentConverter: CommentConverter): List { + private fun baseClassSignatureWithParams(commentsAndSpaces: CommentsAndSpaces): List { if (keyword.equals("class") && extendsTypes.size() == 1) { - val baseParams = baseClassParams.toKotlin(commentConverter, ", ") - return arrayListOf(extendsTypes[0].toKotlin(commentConverter) + "(" + baseParams + ")") + val baseParams = baseClassParams.toKotlin(commentsAndSpaces, ", ") + return arrayListOf(extendsTypes[0].toKotlin(commentsAndSpaces) + "(" + baseParams + ")") } - return extendsTypes.map { it.toKotlin(commentConverter) } + return extendsTypes.map { it.toKotlin(commentsAndSpaces) } } - protected fun implementTypesToKotlin(commentConverter: CommentConverter): String { + protected fun implementTypesToKotlin(commentsAndSpaces: CommentsAndSpaces): String { val allTypes = ArrayList() - allTypes.addAll(baseClassSignatureWithParams(commentConverter)) - allTypes.addAll(implementsTypes.map { it.toKotlin(commentConverter) }) + allTypes.addAll(baseClassSignatureWithParams(commentsAndSpaces)) + allTypes.addAll(implementsTypes.map { it.toKotlin(commentsAndSpaces) }) return if (allTypes.size() == 0) "" else diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt new file mode 100644 index 00000000000..05b5bdfe2db --- /dev/null +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ClassBody.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2010-2013 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.ast + +import org.jetbrains.jet.j2k.CommentsAndSpaces + +abstract class Member(val annotations: Annotations, val modifiers: Set) : Element() + +class ClassBody ( + val primaryConstructor: PrimaryConstructor?, + val secondaryConstructors: List, + val normalMembers: List, + val classObjectMembers: List, + val lBrace: LBrace, + val rBrace: RBrace) { + + fun toKotlin(containingClass: Class?, commentsAndSpaces: CommentsAndSpaces): String { + val builder = StringBuilder() + builder.append(normalMembers.toKotlin(commentsAndSpaces, "\n")) + + val primaryConstructor = primaryConstructorBodyToKotlin(commentsAndSpaces) + if (primaryConstructor.isNotEmpty() && builder.length() > 0) { + builder.append("\n\n") // blank line before constructor body + } + builder.append(primaryConstructor) + + val classObject = classObjectToKotlin(containingClass, commentsAndSpaces) + if (classObject.isNotEmpty() && builder.length() > 0) { + builder.append("\n\n") // blank line before class object + } + builder.append(classObject) + + return if (builder.length() > 0) + " " + lBrace.toKotlin(commentsAndSpaces) + "\n" + builder + "\n" + rBrace.toKotlin(commentsAndSpaces) + else + "" + } + + private fun primaryConstructorBodyToKotlin(commentsAndSpaces: CommentsAndSpaces): String { + val constructor = primaryConstructor + if (constructor == null || constructor.block?.isEmpty ?: true) return "" + return constructor.bodyToKotlin(commentsAndSpaces) + } + + private fun classObjectToKotlin(containingClass: Class?, commentsAndSpaces: CommentsAndSpaces): String { + if (secondaryConstructors.isEmpty() && classObjectMembers.isEmpty()) return "" + val factoryFunctions = secondaryConstructors.map { it.toFactoryFunction(containingClass) } + return "class object {\n" + (factoryFunctions + classObjectMembers).toKotlin(commentsAndSpaces, "\n") + "\n}" + } +} diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt index 2f6c3287922..2a0964dd8ca 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Constructors.kt @@ -19,52 +19,51 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.Converter import java.util.HashSet import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces abstract class Constructor( converter: Converter, - comments: MemberComments, annotations: Annotations, modifiers: Set, parameterList: ParameterList, block: Block -) : Function(converter, Identifier.Empty, comments, annotations, modifiers, Type.Empty, TypeParameterList.Empty, parameterList, block, false) +) : Function(converter, Identifier.Empty, annotations, modifiers, Type.Empty, TypeParameterList.Empty, parameterList, block, false) class PrimaryConstructor(converter: Converter, - comments: MemberComments, annotations: Annotations, modifiers: Set, parameterList: ParameterList, block: Block) - : Constructor(converter, comments, annotations, modifiers, parameterList, block) { + : Constructor(converter, annotations, modifiers, parameterList, block) { - public fun signatureToKotlin(commentConverter: CommentConverter): String { + public fun signatureToKotlin(commentsAndSpaces: CommentsAndSpaces): String { val accessModifier = modifiers.accessModifier() val modifiersString = if (accessModifier != null && accessModifier != Modifier.PUBLIC) " " + accessModifier.toKotlin() else "" - return modifiersString + "(" + parameterList.toKotlin(commentConverter) + ")" + return modifiersString + "(" + parameterList.toKotlin(commentsAndSpaces) + ")" } - public fun bodyToKotlin(commentConverter: CommentConverter): String = block!!.toKotlin(commentConverter) + public fun bodyToKotlin(commentsAndSpaces: CommentsAndSpaces): String = block!!.toKotlin(commentsAndSpaces) } class SecondaryConstructor(converter: Converter, - comments: MemberComments, annotations: Annotations, modifiers: Set, parameterList: ParameterList, block: Block) - : Constructor(converter, comments, annotations, modifiers, parameterList, block) { + : Constructor(converter, annotations, modifiers, parameterList, block) { - public fun toInitFunction(containingClass: Class): Function { + public fun toFactoryFunction(containingClass: Class?): Function { val modifiers = HashSet(modifiers) val statements = ArrayList(block?.statements ?: listOf()) statements.add(ReturnStatement(tempValIdentifier)) - val block = Block(statements) + val block = Block(statements, block?.lBrace ?: LBrace(), block?.rBrace ?: RBrace()) val typeParameters = ArrayList() - typeParameters.addAll(containingClass.typeParameterList.parameters) - return Function(converter, Identifier("create"), comments, annotations, modifiers, - ClassType(containingClass.name, typeParameters, Nullability.NotNull, converter.settings), - TypeParameterList(typeParameters), parameterList, block, false) + if (containingClass != null) { + typeParameters.addAll(containingClass.typeParameterList.parameters) + } + return Function(converter, Identifier("create"), annotations, modifiers, + ClassType(containingClass?.name ?: Identifier.Empty, typeParameters, Nullability.NotNull, converter.settings), + TypeParameterList(typeParameters), parameterList, block, false).assignPrototypesFrom(this) } class object { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt index 248b9bbf902..dbd7c03f1fe 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/DummyStringExpression.kt @@ -16,8 +16,8 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class DummyStringExpression(val string: String) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = string + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = string } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt index 83cee59e7de..2a61fc6a7e6 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Element.kt @@ -16,21 +16,47 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces +import com.intellij.psi.PsiElement + +fun TElement.assignPrototype(prototype: PsiElement?): TElement { + assignPrototypeInfos(if (prototype != null) listOf(PrototypeInfo(prototype, true)) else listOf()) + return this +} + +fun TElement.assignPrototypes(prototypes: List, inheritBlankLinesBefore: Boolean): TElement { + assignPrototypeInfos(prototypes.map { PrototypeInfo(it, inheritBlankLinesBefore) }) + return this +} + +fun TElement.assignPrototypesFrom(element: Element): TElement { + assignPrototypeInfos(element.prototypes) + return this +} + +data class PrototypeInfo(val element: PsiElement, val inheritBlankLinesBefore: Boolean) abstract class Element { - public fun toKotlin(commentConverter: CommentConverter): String = toKotlinImpl(commentConverter) + public var prototypes: List = listOf() + private set - protected abstract fun toKotlinImpl(commentConverter: CommentConverter): String + public fun assignPrototypeInfos(prototypes: List) { + this.prototypes = prototypes + } + + public fun toKotlin(commentsAndSpaces: CommentsAndSpaces): String { + return if (isEmpty) // do not insert comment and spaces for empty elements to avoid multiple blank lines + "" + else + commentsAndSpaces.wrapElement({ toKotlinImpl(commentsAndSpaces) }, prototypes) + } + + protected abstract fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String public open val isEmpty: Boolean get() = false object Empty : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "" override val isEmpty: Boolean get() = true } } - -class Comment(val text: String) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter) = text -} diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt index 1bf0f80eb70..baa37ee79a7 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt @@ -16,11 +16,10 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class Enum( name: Identifier, - comments: MemberComments, annotations: Annotations, modifiers: Set, typeParameterList: TypeParameterList, @@ -28,20 +27,19 @@ class Enum( baseClassParams: List, implementsTypes: List, body: ClassBody -) : Class(name, comments, annotations, modifiers, typeParameterList, +) : Class(name, annotations, modifiers, typeParameterList, extendsTypes, baseClassParams, implementsTypes, body) { - override fun primaryConstructorSignatureToKotlin(commentConverter: CommentConverter): String - = body.primaryConstructor?.signatureToKotlin(commentConverter) ?: "" + override fun primaryConstructorSignatureToKotlin(commentsAndSpaces: CommentsAndSpaces): String + = body.primaryConstructor?.signatureToKotlin(commentsAndSpaces) ?: "" - override fun toKotlinImpl(commentConverter: CommentConverter): String { - return commentsToKotlin(commentConverter) + - annotations.toKotlin(commentConverter) + + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + return annotations.toKotlin(commentsAndSpaces) + modifiersToKotlin() + - "enum class " + name.toKotlin(commentConverter) + - primaryConstructorSignatureToKotlin(commentConverter) + - typeParameterList.toKotlin(commentConverter) + - implementTypesToKotlin(commentConverter) + - body.toKotlin(this, commentConverter) + "enum class " + name.toKotlin(commentsAndSpaces) + + primaryConstructorSignatureToKotlin(commentsAndSpaces) + + typeParameterList.toKotlin(commentsAndSpaces) + + implementTypesToKotlin(commentsAndSpaces) + + body.toKotlin(this, commentsAndSpaces) } } \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt index d38ac5675f3..0c70faebecf 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/EnumConstant.kt @@ -16,23 +16,22 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class EnumConstant( identifier: Identifier, - members: MemberComments, annotations: Annotations, modifiers: Set, `type`: Type, params: Element -) : Field(identifier, members, annotations, modifiers, `type`.toNotNullType(), params, true, false) { +) : Field(identifier, annotations, modifiers, `type`.toNotNullType(), params, true, false) { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - if (initializer.toKotlin(commentConverter).isEmpty()) { - return annotations.toKotlin(commentConverter) + identifier.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + if (initializer.toKotlin(commentsAndSpaces).isEmpty()) { + return annotations.toKotlin(commentsAndSpaces) + identifier.toKotlin(commentsAndSpaces) } - return annotations.toKotlin(commentConverter) + identifier.toKotlin(commentConverter) + " : " + `type`.toKotlin(commentConverter) + "(" + initializer.toKotlin(commentConverter) + ")" + return annotations.toKotlin(commentsAndSpaces) + identifier.toKotlin(commentsAndSpaces) + " : " + `type`.toKotlin(commentsAndSpaces) + "(" + initializer.toKotlin(commentsAndSpaces) + ")" } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt index 2aeba61b327..b8f65aa4fee 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expression.kt @@ -16,14 +16,14 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces abstract class Expression() : Statement() { open val isNullable: Boolean get() = false object Empty : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "" override val isEmpty: Boolean get() = true } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt index 082acb95d3b..6c1a9ba657a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt @@ -16,10 +16,10 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces -open class ExpressionList(val expressions: List) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = expressions.map { it.toKotlin(commentConverter) }.makeString(", ") +class ExpressionList(val expressions: List) : Expression() { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = expressions.map { it.toKotlin(commentsAndSpaces) }.makeString(", ") override val isEmpty: Boolean get() = expressions.isEmpty() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt index 699e727752d..3baccc78413 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Expressions.kt @@ -17,114 +17,115 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.lang.types.expressions.OperatorConventions -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class ArrayAccessExpression(val expression: Expression, val index: Expression, val lvalue: Boolean) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expression, commentConverter) + + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expression, commentsAndSpaces) + (if (!lvalue && expression.isNullable) "!!" else "") + - "[" + index.toKotlin(commentConverter) + "]" + "[" + index.toKotlin(commentsAndSpaces) + "]" } class AssignmentExpression(val left: Expression, val right: Expression, val op: String) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(left, commentConverter) + " " + op + " " + operandToKotlin(right, commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(left, commentsAndSpaces) + " " + op + " " + operandToKotlin(right, commentsAndSpaces) } class BangBangExpression(val expr: Expression) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expr, commentConverter) + "!!" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expr, commentsAndSpaces) + "!!" } class BinaryExpression(val left: Expression, val right: Expression, val op: String) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(left, commentConverter, false) + " " + op + " " + operandToKotlin(right, commentConverter, true) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(left, commentsAndSpaces, false) + " " + op + " " + operandToKotlin(right, commentsAndSpaces, true) } class IsOperator(val expression: Expression, val typeElement: TypeElement) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expression, commentConverter) + " is " + typeElement.`type`.toNotNullType().toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expression, commentsAndSpaces) + " is " + typeElement.`type`.toNotNullType().toKotlin(commentsAndSpaces) } class TypeCastExpression(val `type`: Type, val expression: Expression) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expression, commentConverter) + " as " + `type`.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expression, commentsAndSpaces) + " as " + `type`.toKotlin(commentsAndSpaces) } class LiteralExpression(val literalText: String) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = literalText + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = literalText } class ParenthesizedExpression(val expression: Expression) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "(" + expression.toKotlin(commentConverter) + ")" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "(" + expression.toKotlin(commentsAndSpaces) + ")" } class PrefixOperator(val op: String, val expression: Expression) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = op + operandToKotlin(expression, commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = op + operandToKotlin(expression, commentsAndSpaces) override val isNullable: Boolean get() = expression.isNullable } class PostfixOperator(val op: String, val expression: Expression) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = operandToKotlin(expression, commentConverter) + op + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = operandToKotlin(expression, commentsAndSpaces) + op } class ThisExpression(val identifier: Identifier) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "this" + identifier.withPrefix("@", commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "this" + identifier.withPrefix("@", commentsAndSpaces) } class SuperExpression(val identifier: Identifier) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "super" + identifier.withPrefix("@", commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "super" + identifier.withPrefix("@", commentsAndSpaces) } class QualifiedExpression(val qualifier: Expression, val identifier: Expression) : Expression() { override val isNullable: Boolean get() = identifier.isNullable - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { if (!qualifier.isEmpty) { - return operandToKotlin(qualifier, commentConverter) + (if (qualifier.isNullable) "!!." else ".") + identifier.toKotlin(commentConverter) + return operandToKotlin(qualifier, commentsAndSpaces) + (if (qualifier.isNullable) "!!." else ".") + identifier.toKotlin(commentsAndSpaces) } - return identifier.toKotlin(commentConverter) + return identifier.toKotlin(commentsAndSpaces) } } class PolyadicExpression(val expressions: List, val token: String) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - val expressionsWithConversions = expressions.map { it.toKotlin(commentConverter) } + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + val expressionsWithConversions = expressions.map { it.toKotlin(commentsAndSpaces) } return expressionsWithConversions.makeString(" " + token + " ") } } -class LambdaExpression(val arguments: String?, val statementList: StatementList) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - val statementsText = statementList.toKotlin(commentConverter).trim() - if (arguments != null) { +class LambdaExpression(val arguments: String?, val block: Block) : Expression() { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + val statementsText = block.statements.toKotlin(commentsAndSpaces, "\n").trim() + val innerBody = if (arguments != null) { val br = if (statementsText.indexOf('\n') < 0 && statementsText.indexOf('\r') < 0) " " else "\n" - return "{ $arguments ->$br$statementsText }" + "$arguments ->$br$statementsText" } else { - return "{ $statementsText }" + statementsText } + return block.lBrace.toKotlin(commentsAndSpaces) + " " + innerBody + " " + block.rBrace.toKotlin(commentsAndSpaces) } } class StarExpression(val methodCall: MethodCallExpression) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "*" + methodCall.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "*" + methodCall.toKotlin(commentsAndSpaces) } fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List, needExplicitType: Boolean) : MethodCallExpression { val elementType = arrayType.elementType val createArrayFunction = if (elementType is PrimitiveType) - (elementType.toNotNullType().toKotlin(CommentConverter.Dummy) + "Array").decapitalize() + (elementType.toNotNullType().toKotlin(CommentsAndSpaces.None) + "Array").decapitalize() else if (needExplicitType) - arrayType.toNotNullType().toKotlin(CommentConverter.Dummy).decapitalize() + arrayType.toNotNullType().toKotlin(CommentsAndSpaces.None).decapitalize() else "array" val doubleOrFloatTypes = setOf("double", "float", "java.lang.double", "java.lang.float") - val afterReplace = arrayType.toNotNullType().toKotlin(CommentConverter.Dummy).replace("Array", "").toLowerCase().replace(">", "").replace("<", "").replace("?", "") + val afterReplace = arrayType.toNotNullType().toKotlin(CommentsAndSpaces.None).replace("Array", "").toLowerCase().replace(">", "").replace("<", "").replace("?", "") fun explicitConvertIfNeeded(initializer: Expression): Expression { if (doubleOrFloatTypes.contains(afterReplace)) { if (initializer is LiteralExpression) { - if (!initializer.toKotlin(CommentConverter.Dummy).contains(".")) { + if (!initializer.toKotlin(CommentsAndSpaces.None).contains(".")) { return LiteralExpression(initializer.literalText + ".0") } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt index 3498fabfd9c..20f27b093fa 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Field.kt @@ -21,27 +21,25 @@ import java.util.ArrayList open class Field( val identifier: Identifier, - comments: MemberComments, annotations: Annotations, modifiers: Set, val `type`: Type, val initializer: Element, val isVal: Boolean, private val hasWriteAccesses: Boolean -) : Member(comments, annotations, modifiers) { +) : Member(annotations, modifiers) { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - val declaration = commentsToKotlin(commentConverter) + - annotations.toKotlin(commentConverter) + + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + val declaration = annotations.toKotlin(commentsAndSpaces) + modifiersToKotlin() + (if (isVal) "val " else "var ") + - identifier.toKotlin(commentConverter) + + identifier.toKotlin(commentsAndSpaces) + " : " + - `type`.toKotlin(commentConverter) + `type`.toKotlin(commentsAndSpaces) return if (initializer.isEmpty) - declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this).toKotlin(commentConverter)) + declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this).toKotlin(commentsAndSpaces)) else - declaration + " = " + initializer.toKotlin(commentConverter) + declaration + " = " + initializer.toKotlin(commentsAndSpaces) } private fun modifiersToKotlin(): String { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/File.kt b/j2k/src/org/jetbrains/jet/j2k/ast/File.kt index d1175ca8806..e4173edd52c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/File.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/File.kt @@ -16,20 +16,18 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter - -class FileMemberList(elements: List) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NewLine, false) +import org.jetbrains.jet.j2k.CommentsAndSpaces class PackageStatement(val packageName: String) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = "package " + packageName + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "package " + packageName } class File( - val body: FileMemberList, + val elements: List, val mainFunction: String ) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - return body.toKotlin(commentConverter) + mainFunction + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + return elements.toKotlin(commentsAndSpaces, "\n") + mainFunction } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt index 6020b9777a4..3298a2ffd84 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Function.kt @@ -18,12 +18,11 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList import org.jetbrains.jet.j2k.Converter -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces open class Function( val converter: Converter, val name: Identifier, - comments: MemberComments, annotations: Annotations, modifiers: Set, val `type`: Type, @@ -31,7 +30,7 @@ open class Function( val parameterList: ParameterList, var block: Block?, val isInTrait: Boolean -) : Member(comments, annotations, modifiers) { +) : Member(annotations, modifiers) { private fun modifiersToKotlin(): String { val resultingModifiers = ArrayList() @@ -56,14 +55,13 @@ open class Function( return resultingModifiers.toKotlin() } - override fun toKotlinImpl(commentConverter: CommentConverter): String { - return commentsToKotlin(commentConverter) + - annotations.toKotlin(commentConverter) + + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + return annotations.toKotlin(commentsAndSpaces) + modifiersToKotlin() + - "fun ${typeParameterList.toKotlin(commentConverter).withSuffix(" ")}${name.toKotlin(commentConverter)}" + - "(${parameterList.toKotlin(commentConverter)})" + - (if (!`type`.isUnit()) " : " + `type`.toKotlin(commentConverter) + " " else " ") + - typeParameterList.whereToKotlin(commentConverter) + - block?.toKotlin(commentConverter) + "fun ${typeParameterList.toKotlin(commentsAndSpaces).withSuffix(" ")}${name.toKotlin(commentsAndSpaces)}" + + "(${parameterList.toKotlin(commentsAndSpaces)})" + + (if (!`type`.isUnit()) " : " + `type`.toKotlin(commentsAndSpaces) + " " else " ") + + typeParameterList.whereToKotlin(commentsAndSpaces) + + block?.toKotlin(commentsAndSpaces) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt index 9e229d17ca7..4361838b0b6 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Identifier.kt @@ -16,8 +16,13 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces +import com.intellij.psi.PsiNameIdentifierOwner +fun PsiNameIdentifierOwner.declarationIdentifier(): Identifier { + val name = getName() + return if (name != null) Identifier(name, false).assignPrototype(getNameIdentifier()!!) else Identifier.Empty +} class Identifier( val name: String, @@ -36,7 +41,7 @@ class Identifier( return name } - override fun toKotlinImpl(commentConverter: CommentConverter): String = toKotlin() + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = toKotlin() private fun quote(str: String): String = "`" + str + "`" diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt index 82f85682e0e..50007b9a8c7 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Imports.kt @@ -25,35 +25,39 @@ import com.intellij.psi.PsiJavaCodeReferenceElement import org.jetbrains.jet.asJava.KotlinLightClassForPackage class Import(val name: String) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "import " + name + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "import " + name } class ImportList(public val imports: List) : Element() { override val isEmpty: Boolean get() = imports.isEmpty() - override fun toKotlinImpl(commentConverter: CommentConverter) = imports.toKotlin(commentConverter, "\n") + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = imports.toKotlin(commentsAndSpaces, "\n") } public fun Converter.convertImportList(importList: PsiImportList): ImportList = - ImportList(importList.getAllImportStatements().map { convertImport(it, true) }.filterNotNull()) + ImportList(importList.getAllImportStatements().map { convertImport(it, true) }.filterNotNull()).assignPrototype(importList) public fun Converter.convertImport(anImport: PsiImportStatementBase, filter: Boolean): Import? { - val reference = anImport.getImportReference() - if (reference == null) return null - val qualifiedName = quoteKeywords(reference.getQualifiedName()!!) - if (anImport.isOnDemand()) { - return Import(qualifiedName + ".*") - } - else { - return if (filter) { - val filteredName = filterImport(qualifiedName, reference) - if (filteredName != null) Import(filteredName) else null + fun doConvert(): Import? { + val reference = anImport.getImportReference() + if (reference == null) return null + val qualifiedName = quoteKeywords(reference.getQualifiedName()!!) + if (anImport.isOnDemand()) { + return Import(qualifiedName + ".*") } else { - Import(qualifiedName) + return if (filter) { + val filteredName = filterImport(qualifiedName, reference) + if (filteredName != null) Import(filteredName) else null + } + else { + Import(qualifiedName) + } } } + + return doConvert()?.assignPrototype(anImport) } private fun filterImport(name: String, ref: PsiJavaCodeReferenceElement): String? { diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt index ca90d460077..3386c36a33a 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Initializer.kt @@ -16,10 +16,10 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces -class Initializer(val block: Block, modifiers: Set) : Member(MemberComments.Empty, Annotations.Empty, modifiers) { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - return block.toKotlin(commentConverter) +class Initializer(val block: Block, modifiers: Set) : Member(Annotations.Empty, modifiers) { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + return block.toKotlin(commentsAndSpaces) } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt index a98f47ba5b4..ba225477abc 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/LocalVariable.kt @@ -17,7 +17,7 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.ConverterSettings -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class LocalVariable( private val identifier: Identifier, @@ -29,17 +29,17 @@ class LocalVariable( private val settings: ConverterSettings ) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - val start = annotations.toKotlin(commentConverter) + if (isVal) "val" else "var" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + val start = annotations.toKotlin(commentsAndSpaces) + if (isVal) "val" else "var" return if (initializer.isEmpty) { - "$start ${identifier.toKotlin(commentConverter)} : ${typeCalculator().toKotlin(commentConverter)}" + "$start ${identifier.toKotlin(commentsAndSpaces)} : ${typeCalculator().toKotlin(commentsAndSpaces)}" } else { val shouldSpecifyType = settings.specifyLocalVariableTypeByDefault if (shouldSpecifyType) - "$start ${identifier.toKotlin(commentConverter)} : ${typeCalculator().toKotlin(commentConverter)} = ${initializer.toKotlin(commentConverter)}" + "$start ${identifier.toKotlin(commentsAndSpaces)} : ${typeCalculator().toKotlin(commentsAndSpaces)} = ${initializer.toKotlin(commentsAndSpaces)}" else - "$start ${identifier.toKotlin(commentConverter)} = ${initializer.toKotlin(commentConverter)}" + "$start ${identifier.toKotlin(commentsAndSpaces)} = ${initializer.toKotlin(commentsAndSpaces)}" } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt deleted file mode 100644 index 846a6b39498..00000000000 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2010-2013 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.ast - -import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentConverter - -class MemberComments(elements: List) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NoSpace) { - class object { - val Empty = MemberComments(ArrayList()) - } -} - -abstract class Member(val comments: MemberComments, val annotations: Annotations, val modifiers: Set) : Element() { - fun commentsToKotlin(commentConverter: CommentConverter): String = comments.toKotlin(commentConverter) -} - -//member itself and all the elements before it in the code (comments, whitespaces) -class MemberWithComments(val member: Member, val elements: List) - -class MemberList(elements: List) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NewLine) { - val members: List - get() = elements.filter { it is Member }.map { it as Member } -} - -class ClassBody ( - val primaryConstructor: PrimaryConstructor?, - val secondaryConstructors: MemberList, - val normalMembers: MemberList, - val classObjectMembers: MemberList) { - - fun toKotlin(containingClass: Class?, commentConverter: CommentConverter): String { - val innerBody = normalMembers.toKotlin(commentConverter) + - primaryConstructorBodyToKotlin(commentConverter) + - classObjectToKotlin(containingClass, commentConverter) - return if (innerBody.trim().isNotEmpty()) " {" + innerBody + "}" else "" - } - - private fun primaryConstructorBodyToKotlin(commentConverter: CommentConverter): String { - val constructor = primaryConstructor - if (constructor != null && !(constructor.block?.isEmpty ?: true)) { - return "\n" + constructor.bodyToKotlin(commentConverter) + "\n" - } - return "" - } - - private fun classObjectToKotlin(containingClass: Class?, commentConverter: CommentConverter): String { - val secondaryConstructorsAsStaticInitFunctions = secondaryConstructorsAsStaticInitFunctions(containingClass) - if (secondaryConstructorsAsStaticInitFunctions.isEmpty() && classObjectMembers.isEmpty()) return "" - return "\nclass object {${secondaryConstructorsAsStaticInitFunctions.toKotlin(commentConverter)}${classObjectMembers.toKotlin(commentConverter)}}" - } - - private fun secondaryConstructorsAsStaticInitFunctions(containingClass: Class?): MemberList { - return MemberList(secondaryConstructors.elements.map { if (it is SecondaryConstructor && containingClass != null) it.toInitFunction(containingClass) else it }) - } -} diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt index 30795dd45a0..4cdeb67142f 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/MethodCallExpression.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class MethodCallExpression( val methodExpression: Expression, @@ -26,15 +26,15 @@ class MethodCallExpression( val lambdaArgument: LambdaExpression? = null ) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { val builder = StringBuilder() - builder.append(operandToKotlin(methodExpression, commentConverter)) - builder.append(typeArguments.toKotlin(commentConverter, ", ", "<", ">")) + builder.append(operandToKotlin(methodExpression, commentsAndSpaces)) + builder.append(typeArguments.toKotlin(commentsAndSpaces, ", ", "<", ">")) if (arguments.isNotEmpty() || lambdaArgument == null) { - builder.append("(").append(arguments.map { it.toKotlin(commentConverter) }.makeString(", ")).append(")") + builder.append("(").append(arguments.map { it.toKotlin(commentsAndSpaces) }.makeString(", ")).append(")") } if (lambdaArgument != null) { - builder.append(lambdaArgument.toKotlin(commentConverter)) + builder.append(lambdaArgument.toKotlin(commentsAndSpaces)) } return builder.toString() } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt index 59511daa58c..9baec7f14fd 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Modifier.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces enum class Modifier(val name: String) { PUBLIC: Modifier("public") diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt b/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt index e931089712f..0ffc786bfa8 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/NewClassExpression.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class NewClassExpression( val name: Element, @@ -25,18 +25,18 @@ class NewClassExpression( val anonymousClass: AnonymousClassBody? = null ) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { val callOperator = if (qualifier.isNullable) "!!." else "." - val qualifier = if (qualifier.isEmpty) "" else qualifier.toKotlin(commentConverter) + callOperator - val appliedArguments = arguments.toKotlin(commentConverter, ", ") + val qualifier = if (qualifier.isEmpty) "" else qualifier.toKotlin(commentsAndSpaces) + callOperator + val appliedArguments = arguments.toKotlin(commentsAndSpaces, ", ") return if (anonymousClass != null) { if (anonymousClass.extendsTrait) - "object : " + qualifier + name.toKotlin(commentConverter) + anonymousClass.toKotlin(commentConverter) + "object : " + qualifier + name.toKotlin(commentsAndSpaces) + anonymousClass.toKotlin(commentsAndSpaces) else - "object : " + qualifier + name.toKotlin(commentConverter) + "(" + appliedArguments + ")" + anonymousClass.toKotlin(commentConverter) + "object : " + qualifier + name.toKotlin(commentsAndSpaces) + "(" + appliedArguments + ")" + anonymousClass.toKotlin(commentsAndSpaces) } else{ - qualifier + name.toKotlin(commentConverter) + "(" + appliedArguments + ")" + qualifier + name.toKotlin(commentsAndSpaces) + "(" + appliedArguments + ")" } } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt index 2c1692907df..83d4ad89d9c 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Parameter.kt @@ -16,7 +16,7 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class Parameter(val identifier: Identifier, val `type`: Type, @@ -29,10 +29,10 @@ class Parameter(val identifier: Identifier, Var } - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { val builder = StringBuilder() - builder.append(annotations.toKotlin(commentConverter)) + builder.append(annotations.toKotlin(commentsAndSpaces)) builder.append(modifiers.toKotlin()) if (`type` is VarArgType) { @@ -45,7 +45,7 @@ class Parameter(val identifier: Identifier, VarValModifier.Val -> builder.append("val ") } - builder.append(identifier.toKotlin(commentConverter)).append(": ").append(`type`.toKotlin(commentConverter)) + builder.append(identifier.toKotlin(commentsAndSpaces)).append(": ").append(`type`.toKotlin(commentsAndSpaces)) return builder.toString() } } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt index 8a3e770801c..096a58850b0 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ParameterList.kt @@ -16,10 +16,9 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces - -open class ParameterList(val parameters: List) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter) = parameters.map { it.toKotlin(commentConverter) }.makeString(", ") +class ParameterList(val parameters: List) : Element() { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = parameters.map { it.toKotlin(commentsAndSpaces) }.makeString(", ") } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt index 98b7eff616c..b9e5f1f4f5b 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ReferenceElement.kt @@ -16,8 +16,8 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class ReferenceElement(val reference: Identifier, val types: List) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter) = reference.toKotlin(commentConverter) + types.toKotlin(commentConverter, ", ", "<", ">") + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = reference.toKotlin(commentsAndSpaces) + types.toKotlin(commentsAndSpaces, ", ", "<", ">") } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt index a059e1bafea..e4bd15dbea4 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Statements.kt @@ -16,12 +16,12 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces abstract class Statement() : Element() { object Empty : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "" override val isEmpty: Boolean get() = true @@ -29,20 +29,20 @@ abstract class Statement() : Element() { } class DeclarationStatement(val elements: List) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter): String - = elements.filterIsInstance(javaClass()).map { it.toKotlin(commentConverter) }.makeString("\n") + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String + = elements.filterIsInstance(javaClass()).map { it.toKotlin(commentsAndSpaces) }.makeString("\n") } class ExpressionListStatement(val expressions: List) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = expressions.toKotlin(commentConverter, "\n") + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = expressions.toKotlin(commentsAndSpaces, "\n") } class LabelStatement(val name: Identifier, val statement: Element) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = "@" + name.toKotlin(commentConverter) + " " + statement.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "@" + name.toKotlin(commentsAndSpaces) + " " + statement.toKotlin(commentsAndSpaces) } class ReturnStatement(val expression: Expression) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "return " + expression.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "return " + expression.toKotlin(commentsAndSpaces) } class IfStatement( @@ -53,10 +53,10 @@ class IfStatement( ) : Expression() { private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentConverter: CommentConverter): String { - val result = "if (" + condition.toKotlin(commentConverter) + ")$br" + thenStatement.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + val result = "if (" + condition.toKotlin(commentsAndSpaces) + ")$br" + thenStatement.toKotlin(commentsAndSpaces) if (!elseStatement.isEmpty) { - return "$result${br}else$br${elseStatement.toKotlin(commentConverter)}" + return "$result${br}else$br${elseStatement.toKotlin(commentsAndSpaces)}" } return result } @@ -67,13 +67,13 @@ class IfStatement( class WhileStatement(val condition: Expression, val body: Element, singleLine: Boolean) : Statement() { private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentConverter: CommentConverter) = "while (" + condition.toKotlin(commentConverter) + ")$br" + body.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "while (" + condition.toKotlin(commentsAndSpaces) + ")$br" + body.toKotlin(commentsAndSpaces) } class DoWhileStatement(val condition: Expression, val body: Element, singleLine: Boolean) : Statement() { private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentConverter: CommentConverter) = "do$br" + body.toKotlin(commentConverter) + "${br}while (" + condition.toKotlin(commentConverter) + ")" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "do$br" + body.toKotlin(commentsAndSpaces) + "${br}while (" + condition.toKotlin(commentsAndSpaces) + ")" } class ForeachStatement( @@ -85,7 +85,7 @@ class ForeachStatement( private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentConverter: CommentConverter) = "for (" + variable.identifier.toKotlin(commentConverter) + " in " + expression.toKotlin(commentConverter) + ")$br" + body.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "for (" + variable.identifier.toKotlin(commentsAndSpaces) + " in " + expression.toKotlin(commentsAndSpaces) + ")$br" + body.toKotlin(commentsAndSpaces) } class ForeachWithRangeStatement(val identifier: Identifier, @@ -95,70 +95,64 @@ class ForeachWithRangeStatement(val identifier: Identifier, singleLine: Boolean) : Statement() { private val br = if (singleLine) " " else "\n" - override fun toKotlinImpl(commentConverter: CommentConverter) = "for (" + identifier.toKotlin(commentConverter) + " in " + start.toKotlin(commentConverter) + ".." + end.toKotlin(commentConverter) + ")$br" + body.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "for (" + identifier.toKotlin(commentsAndSpaces) + " in " + start.toKotlin(commentsAndSpaces) + ".." + end.toKotlin(commentsAndSpaces) + ")$br" + body.toKotlin(commentsAndSpaces) } class BreakStatement(val label: Identifier = Identifier.Empty) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "break" + label.withPrefix("@", commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "break" + label.withPrefix("@", commentsAndSpaces) } class ContinueStatement(val label: Identifier = Identifier.Empty) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "continue" + label.withPrefix("@", commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "continue" + label.withPrefix("@", commentsAndSpaces) } // Exceptions ---------------------------------------------------------------------------------------------- class TryStatement(val block: Block, val catches: List, val finallyBlock: Block) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { val builder = StringBuilder() .append("try\n") - .append(block.toKotlin(commentConverter)) + .append(block.toKotlin(commentsAndSpaces)) .append("\n") - .append(catches.toKotlin(commentConverter, "\n")) + .append(catches.toKotlin(commentsAndSpaces, "\n")) .append("\n") if (!finallyBlock.isEmpty) { - builder.append("finally\n").append(finallyBlock.toKotlin(commentConverter)) + builder.append("finally\n").append(finallyBlock.toKotlin(commentsAndSpaces)) } return builder.toString() } } class ThrowStatement(val expression: Expression) : Expression() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "throw " + expression.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "throw " + expression.toKotlin(commentsAndSpaces) } class CatchStatement(val variable: Parameter, val block: Block) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = "catch (" + variable.toKotlin(commentConverter) + ") " + block.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "catch (" + variable.toKotlin(commentsAndSpaces) + ") " + block.toKotlin(commentsAndSpaces) } // Switch -------------------------------------------------------------------------------------------------- class SwitchContainer(val expression: Expression, val caseContainers: List) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "when (" + expression.toKotlin(commentConverter) + ") {\n" + caseContainers.toKotlin(commentConverter, "\n") + "\n}" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "when (" + expression.toKotlin(commentsAndSpaces) + ") {\n" + caseContainers.toKotlin(commentsAndSpaces, "\n") + "\n}" } class CaseContainer(val caseStatement: List, statements: List) : Statement() { - private val block = Block(statements.filterNot { it is BreakStatement || it is ContinueStatement }, true) + private val block = Block(statements.filterNot { it is BreakStatement || it is ContinueStatement }, LBrace(), RBrace(), true) - override fun toKotlinImpl(commentConverter: CommentConverter) = caseStatement.toKotlin(commentConverter, ", ") + " -> " + block.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = caseStatement.toKotlin(commentsAndSpaces, ", ") + " -> " + block.toKotlin(commentsAndSpaces) } class SwitchLabelStatement(val expression: Expression) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = expression.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = expression.toKotlin(commentsAndSpaces) } class DefaultSwitchLabelStatement() : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "else" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "else" } // Other ------------------------------------------------------------------------------------------------------ class SynchronizedStatement(val expression: Expression, val block: Block) : Statement() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "synchronized (" + expression.toKotlin(commentConverter) + ") " + block.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "synchronized (" + expression.toKotlin(commentsAndSpaces) + ") " + block.toKotlin(commentsAndSpaces) } - -class StatementList(elements: List) - : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NewLine) { - val statements: List - get() = elements.filterIsInstance(javaClass()) -} \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt index 881c04e3e6e..462e9dc0477 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt @@ -17,10 +17,9 @@ package org.jetbrains.jet.j2k.ast import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class Trait(name: Identifier, - comments: MemberComments, annotations: Annotations, modifiers: Set, typeParameterList: TypeParameterList, @@ -28,12 +27,12 @@ class Trait(name: Identifier, baseClassParams: List, implementsTypes: List, body: ClassBody -) : Class(name, comments, annotations, modifiers, typeParameterList, extendsTypes, baseClassParams, implementsTypes, body) { +) : Class(name, annotations, modifiers, typeParameterList, extendsTypes, baseClassParams, implementsTypes, body) { override val keyword: String get() = "trait" - override fun primaryConstructorSignatureToKotlin(commentConverter: CommentConverter) = "" + override fun primaryConstructorSignatureToKotlin(commentsAndSpaces: CommentsAndSpaces) = "" override fun modifiersToKotlin(): String { val modifierList = ArrayList() diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt b/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt index 0a4a7961270..4259c1804cb 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/TypeElement.kt @@ -16,8 +16,8 @@ package org.jetbrains.jet.j2k.ast -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class TypeElement(val `type`: Type) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter) = `type`.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = `type`.toKotlin(commentsAndSpaces) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt b/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt index 7ecbb5ba7f0..b77cca56b31 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/TypeParameters.kt @@ -20,39 +20,39 @@ import com.intellij.psi.PsiTypeParameter import org.jetbrains.jet.j2k.Converter import com.intellij.psi.PsiTypeParameterList import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces class TypeParameter(val name: Identifier, val extendsTypes: List) : Element() { fun hasWhere(): Boolean = extendsTypes.size() > 1 - fun whereToKotlin(commentConverter: CommentConverter): String { + fun whereToKotlin(commentsAndSpaces: CommentsAndSpaces): String { if (hasWhere()) { - return name.toKotlin(commentConverter) + " : " + extendsTypes[1].toKotlin(commentConverter) + return name.toKotlin(commentsAndSpaces) + " : " + extendsTypes[1].toKotlin(commentsAndSpaces) } return "" } - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { if (extendsTypes.size() > 0) { - return name.toKotlin(commentConverter) + " : " + extendsTypes[0].toKotlin(commentConverter) + return name.toKotlin(commentsAndSpaces) + " : " + extendsTypes[0].toKotlin(commentsAndSpaces) } - return name.toKotlin(commentConverter) + return name.toKotlin(commentsAndSpaces) } } class TypeParameterList(val parameters: List) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { return if (parameters.isNotEmpty()) - parameters.map { it.toKotlin(commentConverter) }.makeString(", ", "<", ">") + parameters.map { it.toKotlin(commentsAndSpaces) }.makeString(", ", "<", ">") else "" } - fun whereToKotlin(commentConverter: CommentConverter): String { + fun whereToKotlin(commentsAndSpaces: CommentsAndSpaces): String { if (hasWhere()) { - val wheres = parameters.map { it.whereToKotlin(commentConverter) } + val wheres = parameters.map { it.whereToKotlin(commentsAndSpaces) } return "where " + wheres.makeString(", ") } return "" diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt index 2c81c825e2c..4894ee96bbd 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Types.kt @@ -17,7 +17,7 @@ package org.jetbrains.jet.j2k.ast import org.jetbrains.jet.j2k.ConverterSettings -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces fun Type.isUnit(): Boolean = this == Type.Unit @@ -59,26 +59,26 @@ abstract class Type() : Element() { } object Empty : NotNullType() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = "UNRESOLVED_TYPE" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "UNRESOLVED_TYPE" } object Unit: NotNullType() { - override fun toKotlinImpl(commentConverter: CommentConverter) = "Unit" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces) = "Unit" } - override fun equals(other: Any?): Boolean = other is Type && other.toKotlin(CommentConverter.Dummy) == this.toKotlin(CommentConverter.Dummy) + override fun equals(other: Any?): Boolean = other is Type && other.toKotlin(CommentsAndSpaces.None) == this.toKotlin(CommentsAndSpaces.None) - override fun hashCode(): Int = toKotlin(CommentConverter.Dummy).hashCode() + override fun hashCode(): Int = toKotlin(CommentsAndSpaces.None).hashCode() - override fun toString(): String = toKotlin(CommentConverter.Dummy) + override fun toString(): String = toKotlin(CommentsAndSpaces.None) } class ClassType(val `type`: Identifier, val typeArgs: List, nullability: Nullability, settings: ConverterSettings) : MayBeNullableType(nullability, settings) { - override fun toKotlinImpl(commentConverter: CommentConverter): String { - var params = if (typeArgs.isEmpty()) "" else typeArgs.map { it.toKotlin(commentConverter) }.makeString(", ", "<", ">") - return `type`.toKotlin(commentConverter) + params + isNullableStr + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { + var params = if (typeArgs.isEmpty()) "" else typeArgs.map { it.toKotlin(commentsAndSpaces) }.makeString(", ", "<", ">") + return `type`.toKotlin(commentsAndSpaces) + params + isNullableStr } @@ -89,12 +89,12 @@ class ClassType(val `type`: Identifier, val typeArgs: List, nullability class ArrayType(val elementType: Type, nullability: Nullability, settings: ConverterSettings) : MayBeNullableType(nullability, settings) { - override fun toKotlinImpl(commentConverter: CommentConverter): String { + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String { if (elementType is PrimitiveType) { - return elementType.toKotlin(commentConverter) + "Array" + isNullableStr + return elementType.toKotlin(commentsAndSpaces) + "Array" + isNullableStr } - return "Array<" + elementType.toKotlin(commentConverter) + ">" + isNullableStr + return "Array<" + elementType.toKotlin(commentsAndSpaces) + ">" + isNullableStr } override fun toNotNullType(): Type = ArrayType(elementType, Nullability.NotNull, settings) @@ -102,21 +102,21 @@ class ArrayType(val elementType: Type, nullability: Nullability, settings: Conve } class InProjectionType(val bound: Type) : NotNullType() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = "in " + bound.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "in " + bound.toKotlin(commentsAndSpaces) } class OutProjectionType(val bound: Type) : NotNullType() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = "out " + bound.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "out " + bound.toKotlin(commentsAndSpaces) } class StarProjectionType() : NotNullType() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = "*" + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = "*" } class PrimitiveType(val `type`: Identifier) : NotNullType() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = `type`.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = `type`.toKotlin(commentsAndSpaces) } class VarArgType(val `type`: Type) : NotNullType() { - override fun toKotlinImpl(commentConverter: CommentConverter): String = `type`.toKotlin(commentConverter) + override fun toKotlinImpl(commentsAndSpaces: CommentsAndSpaces): String = `type`.toKotlin(commentsAndSpaces) } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt index 39282ad01f4..4f719813a55 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt @@ -16,65 +16,20 @@ package org.jetbrains.jet.j2k.ast -import java.util.ArrayList -import org.jetbrains.jet.j2k.CommentConverter +import org.jetbrains.jet.j2k.CommentsAndSpaces -fun List.toKotlin(commentConverter: CommentConverter, separator: String, prefix: String = "", postfix: String = ""): String - = if (isNotEmpty()) map { it.toKotlin(commentConverter) }.makeString(separator, prefix, postfix) else "" +fun List.toKotlin(commentsAndSpaces: CommentsAndSpaces, separator: String, prefix: String = "", postfix: String = ""): String { + val texts = map { it.toKotlin(commentsAndSpaces) }.filter { it.isNotEmpty() } + return if (texts.isNotEmpty()) texts.makeString(separator, prefix, postfix) else "" +} fun String.withSuffix(suffix: String): String = if (isEmpty()) "" else this + suffix fun String.withPrefix(prefix: String): String = if (isEmpty()) "" else prefix + this -fun Expression.withPrefix(prefix: String, commentConverter: CommentConverter): String = if (isEmpty) "" else prefix + toKotlin(commentConverter) +fun Expression.withPrefix(prefix: String, commentsAndSpaces: CommentsAndSpaces): String = if (isEmpty) "" else prefix + toKotlin(commentsAndSpaces) -open class WhiteSpaceSeparatedElementList( - val elements: List, - val minimalWhiteSpace: WhiteSpace, - val ensureSurroundedByWhiteSpace: Boolean = true -) { - val nonEmptyElements = elements.filter { !it.isEmpty } - - fun isEmpty() = nonEmptyElements.all { it is WhiteSpace } - - fun toKotlin(commentConverter: CommentConverter): String { - if (isEmpty()) return "" - return nonEmptyElements.surroundWithWhiteSpaces().insertAndMergeWhiteSpaces().map { it.toKotlin(commentConverter) }.makeString("") - } - - private fun List.surroundWithWhiteSpaces(): List - = if (ensureSurroundedByWhiteSpace) listOf(minimalWhiteSpace) + this + listOf(minimalWhiteSpace) else this - - - // ensure that there is whitespace between non-whitespace elements - // choose maximum among subsequent whitespaces - // all resulting whitespaces are at least minimal whitespace - private fun List.insertAndMergeWhiteSpaces(): List { - var currentWhiteSpace: WhiteSpace? = null - val result = ArrayList() - for (i in 0..lastIndex) { - val element = get(i) - if (element is WhiteSpace) { - if (currentWhiteSpace == null || element > currentWhiteSpace!!) { - currentWhiteSpace = if (element > minimalWhiteSpace) element else minimalWhiteSpace - } - } - else { - if (i != 0) { //do not insert whitespace before first element - result.add(currentWhiteSpace ?: minimalWhiteSpace) - } - result.add(element) - currentWhiteSpace = null - } - } - if (currentWhiteSpace != null) { - result.add(currentWhiteSpace!!) - } - return result - } -} - -fun Expression.operandToKotlin(operand: Expression, commentConverter: CommentConverter, parenthesisForSamePrecedence: Boolean = false): String { +fun Expression.operandToKotlin(operand: Expression, commentsAndSpaces: CommentsAndSpaces, parenthesisForSamePrecedence: Boolean = false): String { val parentPrecedence = precedence() ?: throw IllegalArgumentException("Unknown precendence for $this") - val kotlinCode = operand.toKotlin(commentConverter) + val kotlinCode = operand.toKotlin(commentsAndSpaces) val operandPrecedence = operand.precedence() ?: return kotlinCode val needParenthesis = parentPrecedence < operandPrecedence || parentPrecedence == operandPrecedence && parenthesisForSamePrecedence return if (needParenthesis) "($kotlinCode)" else kotlinCode diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt b/j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt deleted file mode 100644 index 30e53f184fa..00000000000 --- a/j2k/src/org/jetbrains/jet/j2k/ast/WhiteSpace.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2010-2013 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.ast - -import org.jetbrains.jet.j2k.CommentConverter - - -class WhiteSpace(val text: String) : Element() { - override fun toKotlinImpl(commentConverter: CommentConverter) = text - - override val isEmpty: Boolean - get() = text.isEmpty() - - fun compareTo(other: WhiteSpace): Int { - - fun newLinesCount(w: WhiteSpace) = w.text.count { it == '\n' } - - val lineCountDiff = newLinesCount(this) - newLinesCount(other) - if (lineCountDiff != 0) return lineCountDiff - - fun spacesCount(w: WhiteSpace) = w.text.count { it == ' ' } - - return spacesCount(this) - spacesCount(other) - } - - class object { - val NewLine = WhiteSpace("\n") - val NoSpace = WhiteSpace("") - } -} - - diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt index 6a370792ceb..04ae75a7702 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/ElementVisitor.kt @@ -27,7 +27,7 @@ class ElementVisitor(private val converter: Converter) : JavaElementVisitor() { protected set override fun visitLocalVariable(variable: PsiLocalVariable) { - result = LocalVariable(Identifier(variable.getName()!!), + result = LocalVariable(variable.declarationIdentifier(), converter.convertAnnotations(variable), converter.convertModifiers(variable), { typeConverter.convertVariableType(variable) }, @@ -62,19 +62,11 @@ class ElementVisitor(private val converter: Converter) : JavaElementVisitor() { } override fun visitTypeParameter(classParameter: PsiTypeParameter) { - result = TypeParameter(Identifier(classParameter.getName()!!), - classParameter.getExtendsListTypes().map { typeConverter.convertType(it) }) + result = TypeParameter(classParameter.declarationIdentifier(), + classParameter.getExtendsListTypes().map { typeConverter.convertType(it) }) } override fun visitParameterList(list: PsiParameterList) { result = converter.convertParameterList(list) } - - override fun visitComment(comment: PsiComment) { - result = Comment(comment.getText()!!) - } - - override fun visitWhiteSpace(space: PsiWhiteSpace) { - result = WhiteSpace(space.getText()!!) - } } diff --git a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt index feb536f6856..783f711b72b 100644 --- a/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt +++ b/j2k/src/org/jetbrains/jet/j2k/visitors/StatementVisitor.kt @@ -45,7 +45,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito result = MethodCallExpression.buildNotNull(null, "assert", listOf(condition, description)) } else { - result = MethodCallExpression.build(null, "assert", listOf(condition), listOf(), false, LambdaExpression(null, StatementList(listOf(description)))) + result = MethodCallExpression.build(null, "assert", listOf(condition), listOf(), false, LambdaExpression(null, Block(listOf(description), LBrace(), RBrace()))) } } } @@ -117,11 +117,8 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito && loopVar.getNameIdentifier() != null && onceWritableIterator) { val end = converter.convertExpression((condition as PsiBinaryExpression).getROperand()) - val endExpression = if (operationTokenType == JavaTokenType.LT) - BinaryExpression(end, Identifier("1"), "-") - else - end - result = ForeachWithRangeStatement(Identifier(loopVar.getName()!!), + val endExpression = if (operationTokenType == JavaTokenType.LT) BinaryExpression(end, LiteralExpression("1"), "-") else end + result = ForeachWithRangeStatement(loopVar.declarationIdentifier(), converter.convertExpression(loopVar.getInitializer()), endExpression, converter.convertStatement(body), @@ -131,12 +128,12 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito var forStatements = ArrayList() forStatements.add(converter.convertStatement(initialization)) val bodyAndUpdate = listOf(converter.convertStatement(body), - Block(listOf(converter.convertStatement(update)))) + Block(listOf(converter.convertStatement(update)), LBrace(), RBrace())) forStatements.add(WhileStatement( if (condition == null) LiteralExpression("true") else converter.convertExpression(condition), - Block(bodyAndUpdate), + Block(bodyAndUpdate, LBrace(), RBrace()), statement.isInSingleLine())) - result = Block(forStatements) + result = Block(forStatements, LBrace(), RBrace()) } } @@ -269,13 +266,12 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito }} } - var bodyConverted = converterForBody.convertBlock(tryBlock) - var statementList = bodyConverted.statementList + var block = converterForBody.convertBlock(tryBlock) var expression: Expression = Expression.Empty for (variable in variables.reverse()) { - val lambda = LambdaExpression(Identifier.toKotlin(variable.getName()!!), statementList) + val lambda = LambdaExpression(Identifier.toKotlin(variable.getName()!!), block) expression = MethodCallExpression.build(converter.convertExpression(variable.getInitializer()), "use", listOf(), listOf(), false, lambda) - statementList = StatementList(listOf(expression)) + block = Block(listOf(expression), LBrace(), RBrace()) } if (catchesConverted.isEmpty() && finallyConverted.isEmpty) { @@ -283,8 +279,7 @@ open class StatementVisitor(public val converter: Converter) : JavaElementVisito return } - bodyConverted = Block(StatementList(listOf(wrapResultStatement(expression))), true) - result = TryStatement(bodyConverted, catchesConverted, finallyConverted) + result = TryStatement(Block(listOf(wrapResultStatement(expression)), LBrace(), RBrace(), true), catchesConverted, finallyConverted) return } } diff --git a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java index efe6226c743..b01a2402ac0 100644 --- a/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java +++ b/j2k/tests/test/org/jetbrains/jet/j2k/test/JavaToKotlinConverterTestGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.j2k.test.AbstractJavaToKotlinConverterTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("j2k/tests/testData/ast") -@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Equals.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinApiAccess.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.StaticMembers.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.ToKotlinClasses.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TryWithResource.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class}) +@InnerTestClasses({JavaToKotlinConverterTestGenerated.Annotations.class, JavaToKotlinConverterTestGenerated.AnonymousBlock.class, JavaToKotlinConverterTestGenerated.ArrayAccessExpression.class, JavaToKotlinConverterTestGenerated.ArrayInitializerExpression.class, JavaToKotlinConverterTestGenerated.ArrayType.class, JavaToKotlinConverterTestGenerated.AssertStatement.class, JavaToKotlinConverterTestGenerated.AssignmentExpression.class, JavaToKotlinConverterTestGenerated.BinaryExpression.class, JavaToKotlinConverterTestGenerated.BoxedType.class, JavaToKotlinConverterTestGenerated.BreakStatement.class, JavaToKotlinConverterTestGenerated.CallChainExpression.class, JavaToKotlinConverterTestGenerated.Class.class, JavaToKotlinConverterTestGenerated.ClassExpression.class, JavaToKotlinConverterTestGenerated.Comments.class, JavaToKotlinConverterTestGenerated.ConditionalExpression.class, JavaToKotlinConverterTestGenerated.Constructors.class, JavaToKotlinConverterTestGenerated.ContinueStatement.class, JavaToKotlinConverterTestGenerated.DeclarationStatement.class, JavaToKotlinConverterTestGenerated.DoWhileStatement.class, JavaToKotlinConverterTestGenerated.Enum.class, JavaToKotlinConverterTestGenerated.Equals.class, JavaToKotlinConverterTestGenerated.Field.class, JavaToKotlinConverterTestGenerated.For.class, JavaToKotlinConverterTestGenerated.ForeachStatement.class, JavaToKotlinConverterTestGenerated.Formatting.class, JavaToKotlinConverterTestGenerated.Function.class, JavaToKotlinConverterTestGenerated.Identifier.class, JavaToKotlinConverterTestGenerated.IfStatement.class, JavaToKotlinConverterTestGenerated.ImportStatement.class, JavaToKotlinConverterTestGenerated.InProjectionType.class, JavaToKotlinConverterTestGenerated.Inheritance.class, JavaToKotlinConverterTestGenerated.IsOperator.class, JavaToKotlinConverterTestGenerated.Issues.class, JavaToKotlinConverterTestGenerated.KotlinApiAccess.class, JavaToKotlinConverterTestGenerated.LabelStatement.class, JavaToKotlinConverterTestGenerated.List.class, JavaToKotlinConverterTestGenerated.LiteralExpression.class, JavaToKotlinConverterTestGenerated.LocalVariable.class, JavaToKotlinConverterTestGenerated.MethodCallExpression.class, JavaToKotlinConverterTestGenerated.Misc.class, JavaToKotlinConverterTestGenerated.NewClassExpression.class, JavaToKotlinConverterTestGenerated.Nullability.class, JavaToKotlinConverterTestGenerated.ObjectLiteral.class, JavaToKotlinConverterTestGenerated.OutProjectionType.class, JavaToKotlinConverterTestGenerated.PackageStatement.class, JavaToKotlinConverterTestGenerated.ParenthesizedExpression.class, JavaToKotlinConverterTestGenerated.PolyadicExpression.class, JavaToKotlinConverterTestGenerated.PostfixOperator.class, JavaToKotlinConverterTestGenerated.PrefixOperator.class, JavaToKotlinConverterTestGenerated.RawGenerics.class, JavaToKotlinConverterTestGenerated.ReturnStatement.class, JavaToKotlinConverterTestGenerated.Settings.class, JavaToKotlinConverterTestGenerated.StarProjectionType.class, JavaToKotlinConverterTestGenerated.StaticMembers.class, JavaToKotlinConverterTestGenerated.SuperExpression.class, JavaToKotlinConverterTestGenerated.Switch.class, JavaToKotlinConverterTestGenerated.SynchronizedStatement.class, JavaToKotlinConverterTestGenerated.ThisExpression.class, JavaToKotlinConverterTestGenerated.ThrowStatement.class, JavaToKotlinConverterTestGenerated.ToKotlinClasses.class, JavaToKotlinConverterTestGenerated.Trait.class, JavaToKotlinConverterTestGenerated.TryStatement.class, JavaToKotlinConverterTestGenerated.TryWithResource.class, JavaToKotlinConverterTestGenerated.TypeCastExpression.class, JavaToKotlinConverterTestGenerated.TypeParameters.class, JavaToKotlinConverterTestGenerated.VarArg.class, JavaToKotlinConverterTestGenerated.WhileStatement.class}) public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConverterTest { public void testAllFilesPresentInAst() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast"), Pattern.compile("^(.+)\\.java$"), true); @@ -731,6 +731,19 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv } + @TestMetadata("j2k/tests/testData/ast/comments") + public static class Comments extends AbstractJavaToKotlinConverterTest { + public void testAllFilesPresentInComments() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/comments"), Pattern.compile("^(.+)\\.java$"), true); + } + + @TestMetadata("Comments.java") + public void testComments() throws Exception { + doTest("j2k/tests/testData/ast/comments/Comments.java"); + } + + } + @TestMetadata("j2k/tests/testData/ast/conditionalExpression") public static class ConditionalExpression extends AbstractJavaToKotlinConverterTest { public void testAllFilesPresentInConditionalExpression() throws Exception { @@ -2786,6 +2799,7 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv suite.addTestSuite(CallChainExpression.class); suite.addTestSuite(Class.class); suite.addTestSuite(ClassExpression.class); + suite.addTestSuite(Comments.class); suite.addTestSuite(ConditionalExpression.class); suite.addTestSuite(Constructors.class); suite.addTestSuite(ContinueStatement.class); diff --git a/j2k/tests/testData/ast/comments/Comments.kt b/j2k/tests/testData/ast/comments/Comments.kt new file mode 100644 index 00000000000..8fbef48f875 --- /dev/null +++ b/j2k/tests/testData/ast/comments/Comments.kt @@ -0,0 +1,30 @@ +package foo + +// we use package 'foo' + +// imports: +import java.util.ArrayList + +// we need ArrayList + +// let's declare a class: +class A /* just a sample name*/() : Runnable /* let's implement Runnable */ { + fun foo/* again a sample name */(p: Int /* parameter p */, c: Char /* parameter c */) { + // let's print something: + System.out.println("1") // print 1 + System.out.println("2") // print 2 + + System.out.println("3") // print 3 + + // end of printing + + if (p > 0) { + // do this only when p > 0 + // we print 4 and return + System.out.println("3") + return // do not continue + } + + // some code to be added + } +} // end of class A \ No newline at end of file diff --git a/j2k/tests/testData/ast/comments/comments.java b/j2k/tests/testData/ast/comments/comments.java new file mode 100644 index 00000000000..61c1099cc74 --- /dev/null +++ b/j2k/tests/testData/ast/comments/comments.java @@ -0,0 +1,26 @@ +//file +package foo; // we use package 'foo' + +// imports: +import java.util.ArrayList; // we need ArrayList + +// let's declare a class: +class A /* just a sample name*/ implements Runnable /* let's implement Runnable */ { + void foo /* again a sample name */(int p /* parameter p */, char c /* parameter c */) { + // let's print something: + System.out.println("1"); // print 1 + System.out.println("2"); // print 2 + + System.out.println("3"); // print 3 + + // end of printing + + if (p > 0) { // do this only when p > 0 + // we print 4 and return + System.out.println("3"); + return; // do not continue + } + + // some code to be added + } +} // end of class A \ No newline at end of file diff --git a/j2k/tests/testData/ast/comments/comments.kt.todo b/j2k/tests/testData/ast/comments/comments.kt.todo new file mode 100644 index 00000000000..c2b1c4c52da --- /dev/null +++ b/j2k/tests/testData/ast/comments/comments.kt.todo @@ -0,0 +1,25 @@ +package foo // we use package 'foo' + +// imports: +import java.util.ArrayList // we need ArrayList + +// let's declare a class: +class A /* just a sample name*/() : Runnable /* let's implement Runnable */ { + fun foo /* again a sample name */( p: Int /* parameter p */, c: Char /* parameter c */) { + // let's print something: + System.out.println("1") // print 1 + System.out.println("2") // print 2 + + System.out.println("3") // print 3 + + // end of printing + + if (p > 0) { // do this only when p > 0 + // we print 4 and return + System.out.println("3") + return // do not continue + } + + // some code to be added + } +} // end of class A diff --git a/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt b/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt index 10a1911bad5..2e19d45aa08 100644 --- a/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt +++ b/j2k/tests/testData/ast/constructors/withManyDefaultParams.kt @@ -11,7 +11,6 @@ public class Test private(private val myName: String, private var a: Boolean, pr return __ } - fun foo(n: String): String { return "" } diff --git a/j2k/tests/testData/ast/formatting/nonStaticMembers.kt b/j2k/tests/testData/ast/formatting/nonStaticMembers.kt index 32ea2da202f..72079e2c1e7 100644 --- a/j2k/tests/testData/ast/formatting/nonStaticMembers.kt +++ b/j2k/tests/testData/ast/formatting/nonStaticMembers.kt @@ -3,7 +3,6 @@ class F() { fun f1() { } - fun f2() { } var i: Int = 0 diff --git a/j2k/tests/testData/ast/formatting/nonStaticMembersWithComments.kt b/j2k/tests/testData/ast/formatting/nonStaticMembersWithComments.kt index 163c5d65b5a..61be9023894 100644 --- a/j2k/tests/testData/ast/formatting/nonStaticMembersWithComments.kt +++ b/j2k/tests/testData/ast/formatting/nonStaticMembersWithComments.kt @@ -7,7 +7,6 @@ class F() { fun f1() { } - //c3 diff --git a/j2k/tests/testData/ast/formatting/staticAndNonStaticMembersWithComments.kt b/j2k/tests/testData/ast/formatting/staticAndNonStaticMembersWithComments.kt index 7840a9982f7..482f5783f08 100644 --- a/j2k/tests/testData/ast/formatting/staticAndNonStaticMembersWithComments.kt +++ b/j2k/tests/testData/ast/formatting/staticAndNonStaticMembersWithComments.kt @@ -1,6 +1,5 @@ class F() { - //c3 @@ -31,8 +30,8 @@ class F() { fun f5() { } - - //c6 - } + + //c6 + } \ No newline at end of file diff --git a/j2k/tests/testData/ast/formatting/staticMembersWithComments.kt b/j2k/tests/testData/ast/formatting/staticMembersWithComments.kt index c3197e5af63..51c1ee14d3c 100644 --- a/j2k/tests/testData/ast/formatting/staticMembersWithComments.kt +++ b/j2k/tests/testData/ast/formatting/staticMembersWithComments.kt @@ -8,7 +8,6 @@ class F() { fun f1() { } - //c3 @@ -22,7 +21,7 @@ class F() { fun f3() { } - - //c5 } + + //c5 } \ No newline at end of file diff --git a/j2k/tests/testData/ast/issues/kt-836.kt b/j2k/tests/testData/ast/issues/kt-836.kt index e1799b31b15..1737733743c 100644 --- a/j2k/tests/testData/ast/issues/kt-836.kt +++ b/j2k/tests/testData/ast/issues/kt-836.kt @@ -9,7 +9,6 @@ public class Language(protected var code: String) : Serializable { } } - class Base() { fun test() { } diff --git a/j2k/tests/testData/ast/issues/kt-837.kt b/j2k/tests/testData/ast/issues/kt-837.kt index 587bc252bcc..0a85e5bb9cc 100644 --- a/j2k/tests/testData/ast/issues/kt-837.kt +++ b/j2k/tests/testData/ast/issues/kt-837.kt @@ -11,7 +11,6 @@ public class Language(protected var code: String) : Serializable { class object { public var ENGLISH: Language = Language("en") public var SWEDISH: Language = Language("sv") - private val serialVersionUID: Long = -2442762969929206780 } } \ No newline at end of file