Converter from Java: basic implementation of annotations conversion

This commit is contained in:
Valentin Kipyatkov
2014-06-11 21:54:20 +04:00
parent 93ba66b2a3
commit c0a5355928
23 changed files with 242 additions and 74 deletions
+67 -11
View File
@@ -72,6 +72,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
is PsiComment -> Comment(element.getText()!!) is PsiComment -> Comment(element.getText()!!)
is PsiImportList -> convertImportList(element) is PsiImportList -> convertImportList(element)
is PsiImportStatementBase -> convertImport(element, false) is PsiImportStatementBase -> convertImport(element, false)
is PsiAnnotation -> convertAnnotation(element)
is PsiPackageStatement -> PackageStatement(quoteKeywords(element.getPackageName() ?: "")) is PsiPackageStatement -> PackageStatement(quoteKeywords(element.getPackageName() ?: ""))
is PsiWhiteSpace -> WhiteSpace(element.getText()!!) is PsiWhiteSpace -> WhiteSpace(element.getText()!!)
else -> null else -> null
@@ -100,7 +101,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
} }
public fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody { public fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody {
return AnonymousClassBody(this, convertClassBody(anonymousClass), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false) return AnonymousClassBody(convertClassBody(anonymousClass), anonymousClass.getBaseClassType().resolve()?.isInterface() ?: false)
} }
private fun convertClassBody(psiClass: PsiClass): ClassBody { private fun convertClassBody(psiClass: PsiClass): ClassBody {
@@ -201,6 +202,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
} }
private fun convertClass(psiClass: PsiClass): Class { private fun convertClass(psiClass: PsiClass): Class {
val annotations = convertAnnotations(psiClass)
val modifiers = convertModifiers(psiClass) val modifiers = convertModifiers(psiClass)
val typeParameters = convertTypeParameterList(psiClass.getTypeParameterList()) val typeParameters = convertTypeParameterList(psiClass.getTypeParameterList())
val implementsTypes = convertToNotNullableTypes(psiClass.getImplementsListTypes()) val implementsTypes = convertToNotNullableTypes(psiClass.getImplementsListTypes())
@@ -209,9 +211,9 @@ public class Converter private(val project: Project, val settings: ConverterSett
var classBody = convertClassBody(psiClass) var classBody = convertClassBody(psiClass)
when { when {
psiClass.isInterface() -> return Trait(this, name, getComments(psiClass), modifiers, typeParameters, extendsTypes, listOf(), implementsTypes, classBody) psiClass.isInterface() -> return Trait(name, getComments(psiClass), annotations, modifiers, typeParameters, extendsTypes, listOf(), implementsTypes, classBody)
psiClass.isEnum() -> return Enum(this, name, getComments(psiClass), modifiers, typeParameters, listOf(), listOf(), implementsTypes, classBody) psiClass.isEnum() -> return Enum(name, getComments(psiClass), annotations, modifiers, typeParameters, listOf(), listOf(), implementsTypes, classBody)
else -> { else -> {
if (psiClass.getPrimaryConstructor() == null && psiClass.getConstructors().size > 1) { if (psiClass.getPrimaryConstructor() == null && psiClass.getConstructors().size > 1) {
@@ -238,7 +240,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
modifiers.add(Modifier.INNER) modifiers.add(Modifier.INNER)
} }
return Class(this, name, getComments(psiClass), modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, classBody) return Class(name, getComments(psiClass), annotations, modifiers, typeParameters, extendsTypes, baseClassParams, implementsTypes, classBody)
} }
} }
} }
@@ -285,10 +287,10 @@ public class Converter private(val project: Project, val settings: ConverterSett
//TODO: comments? //TODO: comments?
val parameters = finalOrWithEmptyInitializerFields.map { field -> val parameters = finalOrWithEmptyInitializerFields.map { field ->
val varValModifier = if (field.isVal) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var val varValModifier = if (field.isVal) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var
Parameter(field.identifier, field.`type`, varValModifier, field.modifiers.filter { ACCESS_MODIFIERS.contains(it) }) Parameter(field.identifier, field.`type`, varValModifier, field.annotations, field.modifiers.filter { ACCESS_MODIFIERS.contains(it) })
} }
val primaryConstructor = PrimaryConstructor(this, MemberComments.Empty, setOf(Modifier.PRIVATE), ParameterList(parameters), Block.Empty) val primaryConstructor = PrimaryConstructor(this, MemberComments.Empty, listOf(), setOf(Modifier.PRIVATE), ParameterList(parameters), Block.Empty)
val updatedMembers = MemberList(classBody.normalMembers.elements.filter { !finalOrWithEmptyInitializerFields.contains(it) }) val updatedMembers = MemberList(classBody.normalMembers.elements.filter { !finalOrWithEmptyInitializerFields.contains(it) })
return ClassBody(primaryConstructor, classBody.secondaryConstructors, updatedMembers, classBody.classObjectMembers) return ClassBody(primaryConstructor, classBody.secondaryConstructors, updatedMembers, classBody.classObjectMembers)
} }
@@ -298,10 +300,12 @@ public class Converter private(val project: Project, val settings: ConverterSett
} }
private fun convertField(field: PsiField): Field { private fun convertField(field: PsiField): Field {
val annotations = convertAnnotations(field)
val modifiers = convertModifiers(field) val modifiers = convertModifiers(field)
if (field is PsiEnumConstant) { if (field is PsiEnumConstant) {
return EnumConstant(Identifier(field.getName()!!), return EnumConstant(Identifier(field.getName()!!),
getComments(field), getComments(field),
annotations,
modifiers, modifiers,
typeConverter.convertType(field.getType(), Nullability.NotNull), typeConverter.convertType(field.getType(), Nullability.NotNull),
convertElement(field.getArgumentList())) convertElement(field.getArgumentList()))
@@ -309,6 +313,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
return Field(Identifier(field.getName()!!), return Field(Identifier(field.getName()!!),
getComments(field), getComments(field),
annotations,
modifiers, modifiers,
typeConverter.convertVariableType(field), typeConverter.convertVariableType(field),
convertExpression(field.getInitializer(), field.getType()), convertExpression(field.getInitializer(), field.getType()),
@@ -323,17 +328,18 @@ public class Converter private(val project: Project, val settings: ConverterSett
private fun doConvertMethod(method: PsiMethod, membersToRemove: MutableSet<PsiMember>): Function { private fun doConvertMethod(method: PsiMethod, membersToRemove: MutableSet<PsiMember>): Function {
val returnType = typeConverter.convertMethodReturnType(method) val returnType = typeConverter.convertMethodReturnType(method)
val annotations = convertAnnotations(method)
val modifiers = convertModifiers(method) val modifiers = convertModifiers(method)
val comments = getComments(method) val comments = getComments(method)
if (method.isConstructor()) { if (method.isConstructor()) {
if (method.isPrimaryConstructor()) { if (method.isPrimaryConstructor()) {
return convertPrimaryConstructor(method, modifiers, comments, membersToRemove) return convertPrimaryConstructor(method, annotations, modifiers, comments, membersToRemove)
} }
else { else {
val params = convertParameterList(method.getParameterList()) val params = convertParameterList(method.getParameterList())
return SecondaryConstructor(this, comments, modifiers, params, convertBlock(method.getBody())) return SecondaryConstructor(this, comments, annotations, modifiers, params, convertBlock(method.getBody()))
} }
} }
else { else {
@@ -364,6 +370,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
val correctedParameter = Parameter(Identifier("other"), val correctedParameter = Parameter(Identifier("other"),
ClassType(Identifier("Any"), listOf(), Nullability.Nullable, settings), ClassType(Identifier("Any"), listOf(), Nullability.Nullable, settings),
Parameter.VarValModifier.None, Parameter.VarValModifier.None,
params.parameters.single().annotations,
listOf()) listOf())
params = ParameterList(listOf(correctedParameter)) params = ParameterList(listOf(correctedParameter))
} }
@@ -371,7 +378,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
val typeParameterList = convertTypeParameterList(method.getTypeParameterList()) val typeParameterList = convertTypeParameterList(method.getTypeParameterList())
val block = convertBlock(method.getBody()) val block = convertBlock(method.getBody())
return Function(this, Identifier(method.getName()), comments, modifiers, returnType, typeParameterList, params, block, containingClass?.isInterface() ?: false) return Function(this, Identifier(method.getName()), comments, annotations, modifiers, returnType, typeParameterList, params, block, containingClass?.isInterface() ?: false)
} }
} }
@@ -411,6 +418,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
} }
private fun convertPrimaryConstructor(constructor: PsiMethod, private fun convertPrimaryConstructor(constructor: PsiMethod,
annotations: List<Annotation>,
modifiers: Set<Modifier>, modifiers: Set<Modifier>,
comments: MemberComments, comments: MemberComments,
membersToRemove: MutableSet<PsiMember>): PrimaryConstructor { membersToRemove: MutableSet<PsiMember>): PrimaryConstructor {
@@ -460,10 +468,11 @@ public class Converter private(val project: Project, val settings: ConverterSett
Parameter(Identifier(field.getName()!!), Parameter(Identifier(field.getName()!!),
`type`, `type`,
if (field.hasModifierProperty(PsiModifier.FINAL)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var, if (field.hasModifierProperty(PsiModifier.FINAL)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var,
convertAnnotations(it) + convertAnnotations(field),
convertModifiers(field).filter { ACCESS_MODIFIERS.contains(it) }) convertModifiers(field).filter { ACCESS_MODIFIERS.contains(it) })
} }
}) })
return PrimaryConstructor(this, comments, modifiers, parameterList, block) return PrimaryConstructor(this, comments, annotations, modifiers, parameterList, block)
} }
private fun findBackingFieldForConstructorParameter(parameter: PsiParameter, constructor: PsiMethod): Pair<PsiField, PsiStatement>? { private fun findBackingFieldForConstructorParameter(parameter: PsiParameter, constructor: PsiMethod): Pair<PsiField, PsiStatement>? {
@@ -550,7 +559,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
Nullability.NotNull -> `type` = `type`.toNotNullType() Nullability.NotNull -> `type` = `type`.toNotNullType()
Nullability.Nullable -> `type` = `type`.toNullableType() Nullability.Nullable -> `type` = `type`.toNullableType()
} }
return Parameter(Identifier(parameter.getName()!!), `type`, varValModifier, modifiers) return Parameter(Identifier(parameter.getName()!!), `type`, varValModifier, convertAnnotations(parameter), modifiers)
} }
public fun convertExpression(argument: PsiExpression?, expectedType: PsiType?): Expression { public fun convertExpression(argument: PsiExpression?, expectedType: PsiType?): Expression {
@@ -601,6 +610,52 @@ public class Converter private(val project: Project, val settings: ConverterSett
PsiModifier.PRIVATE to Modifier.PRIVATE PsiModifier.PRIVATE to Modifier.PRIVATE
) )
public fun convertAnnotations(owner: PsiModifierListOwner): List<Annotation> {
return owner.getModifierList()?.getAnnotations()
?.filter { it.getQualifiedName() !in ANNOTATIONS_TO_REMOVE }
?.map { convertAnnotation(it) }
?.filterNotNull() ?: listOf()
}
public fun convertAnnotation(annotation: PsiAnnotation): Annotation? {
val name = Identifier((annotation.getNameReferenceElement() ?: return null).getText()!!)
val annotationClass = annotation.getNameReferenceElement()?.resolve() as? PsiClass
val lastMethod = annotationClass?.getMethods()?.lastOrNull()
val arguments = annotation.getParameterList().getAttributes().flatMap {
val method = annotationClass?.findMethodsByName(it.getName() ?: "value", false)?.firstOrNull()
val expectedType = method?.getReturnType()
val attrName = it.getName()?.let { Identifier(it) }
val value = it.getValue()
val attrValues = when(value) {
is PsiExpression -> listOf(convertExpression(it.getValue() as? PsiExpression, expectedType))
is PsiArrayInitializerMemberValue -> {
val isVarArg = method == lastMethod /* converted to vararg in Kotlin */
if (isVarArg && it.getName() == null) {
value.getInitializers().map { DummyStringExpression(it.getText()!!)/*TODO*/ }
}
else {
val expectedTypeConverted = typeConverter.convertType(expectedType)
if (expectedTypeConverted is ArrayType) {
val array = createArrayInitializerExpression(expectedTypeConverted, value.getInitializers().map { DummyStringExpression(it.getText()!!)/*TODO*/ })
listOf(if (isVarArg) StarExpression(array) else array)
}
else {
listOf(DummyStringExpression(value.getText()!!))
}
}
}
else -> listOf(DummyStringExpression(value?.getText() ?: ""))
}
attrValues.map { attrName to it }
}
return Annotation(name, arguments)
}
private val TYPE_MAP: Map<String, String> = mapOf( private val TYPE_MAP: Map<String, String> = mapOf(
JAVA_LANG_BYTE to "byte", JAVA_LANG_BYTE to "byte",
JAVA_LANG_SHORT to "short", JAVA_LANG_SHORT to "short",
@@ -625,6 +680,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
val NOT_NULL_ANNOTATIONS: Set<String> = setOf("org.jetbrains.annotations.NotNull", "com.sun.istack.internal.NotNull", "javax.annotation.Nonnull") val NOT_NULL_ANNOTATIONS: Set<String> = setOf("org.jetbrains.annotations.NotNull", "com.sun.istack.internal.NotNull", "javax.annotation.Nonnull")
val NULLABLE_ANNOTATIONS: Set<String> = setOf("org.jetbrains.annotations.Nullable", "com.sun.istack.internal.Nullable", "javax.annotation.Nullable") val NULLABLE_ANNOTATIONS: Set<String> = setOf("org.jetbrains.annotations.Nullable", "com.sun.istack.internal.Nullable", "javax.annotation.Nullable")
val ANNOTATIONS_TO_REMOVE: Set<String> = HashSet(NOT_NULL_ANNOTATIONS + NULLABLE_ANNOTATIONS + listOf(CommonClassNames.JAVA_LANG_OVERRIDE))
val PRIMITIVE_TYPE_CONVERSIONS: Map<String, String> = mapOf( val PRIMITIVE_TYPE_CONVERSIONS: Map<String, String> = mapOf(
"byte" to BYTE.asString(), "byte" to BYTE.asString(),
@@ -0,0 +1,34 @@
/*
* 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.ast
import java.util.HashSet
class Annotation(val name: Identifier, val arguments: List<Pair<Identifier?, Expression>>) : Element {
override fun toKotlin(): String {
if (arguments.isEmpty()) return name.toKotlin()
return name.toKotlin() + "(" + arguments.map {
if (it.first != null)
it.first!!.toKotlin() + " = " + it.second.toKotlin()
else
it.second.toKotlin()
}.makeString(", ") + ")"
}
}
fun List<Annotation>.toKotlin(): String = if (isNotEmpty()) map { it.toKotlin() }.makeString("\n") + "\n" else ""
@@ -19,15 +19,7 @@ package org.jetbrains.jet.j2k.ast
import org.jetbrains.jet.j2k.Converter import org.jetbrains.jet.j2k.Converter
import java.util.Collections import java.util.Collections
class AnonymousClassBody(converter: Converter, body: ClassBody, val extendsTrait: Boolean) class AnonymousClassBody(body: ClassBody, val extendsTrait: Boolean)
: Class(converter, : Class(Identifier(""), MemberComments.Empty, listOf(), setOf(), TypeParameterList.Empty, listOf(), listOf(), listOf(), body) {
Identifier(""),
MemberComments.Empty,
setOf(),
TypeParameterList.Empty,
listOf(),
listOf(),
listOf(),
body) {
override fun toKotlin() = body.toKotlin(null) override fun toKotlin() = body.toKotlin(null)
} }
+3 -3
View File
@@ -16,23 +16,23 @@
package org.jetbrains.jet.j2k.ast package org.jetbrains.jet.j2k.ast
import org.jetbrains.jet.j2k.Converter
import java.util.ArrayList import java.util.ArrayList
open class Class( open class Class(
val converter: Converter,
val name: Identifier, val name: Identifier,
comments: MemberComments, comments: MemberComments,
annotations: List<Annotation>,
modifiers: Set<Modifier>, modifiers: Set<Modifier>,
val typeParameterList: TypeParameterList, val typeParameterList: TypeParameterList,
val extendsTypes: List<Type>, val extendsTypes: List<Type>,
val baseClassParams: List<Expression>, val baseClassParams: List<Expression>,
val implementsTypes: List<Type>, val implementsTypes: List<Type>,
val body: ClassBody val body: ClassBody
) : Member(comments, modifiers) { ) : Member(comments, annotations, modifiers) {
override fun toKotlin(): String = override fun toKotlin(): String =
commentsToKotlin() + commentsToKotlin() +
annotations.toKotlin() +
modifiersToKotlin() + modifiersToKotlin() +
keyword + " " + name.toKotlin() + keyword + " " + name.toKotlin() +
typeParameterList.toKotlin() + typeParameterList.toKotlin() +
@@ -23,17 +23,19 @@ import java.util.ArrayList
abstract class Constructor( abstract class Constructor(
converter: Converter, converter: Converter,
comments: MemberComments, comments: MemberComments,
annotations: List<Annotation>,
modifiers: Set<Modifier>, modifiers: Set<Modifier>,
parameterList: ParameterList, parameterList: ParameterList,
block: Block block: Block
) : Function(converter, Identifier.Empty, comments, modifiers, Type.Empty, TypeParameterList.Empty, parameterList, block, false) ) : Function(converter, Identifier.Empty, comments, annotations, modifiers, Type.Empty, TypeParameterList.Empty, parameterList, block, false)
class PrimaryConstructor(converter: Converter, class PrimaryConstructor(converter: Converter,
comments: MemberComments, comments: MemberComments,
annotations: List<Annotation>,
modifiers: Set<Modifier>, modifiers: Set<Modifier>,
parameterList: ParameterList, parameterList: ParameterList,
block: Block) block: Block)
: Constructor(converter, comments, modifiers, parameterList, block) { : Constructor(converter, comments, annotations, modifiers, parameterList, block) {
public fun signatureToKotlin(): String { public fun signatureToKotlin(): String {
val accessModifier = modifiers.accessModifier() val accessModifier = modifiers.accessModifier()
@@ -46,10 +48,11 @@ class PrimaryConstructor(converter: Converter,
class SecondaryConstructor(converter: Converter, class SecondaryConstructor(converter: Converter,
comments: MemberComments, comments: MemberComments,
annotations: List<Annotation>,
modifiers: Set<Modifier>, modifiers: Set<Modifier>,
parameterList: ParameterList, parameterList: ParameterList,
block: Block) block: Block)
: Constructor(converter, comments, modifiers, parameterList, block) { : Constructor(converter, comments, annotations, modifiers, parameterList, block) {
public fun toInitFunction(containingClass: Class): Function { public fun toInitFunction(containingClass: Class): Function {
val modifiers = HashSet(modifiers) val modifiers = HashSet(modifiers)
@@ -58,7 +61,7 @@ class SecondaryConstructor(converter: Converter,
val block = Block(statements) val block = Block(statements)
val typeParameters = ArrayList<TypeParameter>() val typeParameters = ArrayList<TypeParameter>()
typeParameters.addAll(containingClass.typeParameterList.parameters) typeParameters.addAll(containingClass.typeParameterList.parameters)
return Function(converter, Identifier("create"), MemberComments.Empty, modifiers, return Function(converter, Identifier("create"), comments, annotations, modifiers,
ClassType(containingClass.name, typeParameters, Nullability.NotNull, converter.settings), ClassType(containingClass.name, typeParameters, Nullability.NotNull, converter.settings),
TypeParameterList(typeParameters), parameterList, block, false) TypeParameterList(typeParameters), parameterList, block, false)
} }
+5 -5
View File
@@ -16,26 +16,26 @@
package org.jetbrains.jet.j2k.ast package org.jetbrains.jet.j2k.ast
import org.jetbrains.jet.j2k.Converter
class Enum( class Enum(
converter: Converter,
name: Identifier, name: Identifier,
comments: MemberComments, comments: MemberComments,
annotations: List<Annotation>,
modifiers: Set<Modifier>, modifiers: Set<Modifier>,
typeParameterList: TypeParameterList, typeParameterList: TypeParameterList,
extendsTypes: List<Type>, extendsTypes: List<Type>,
baseClassParams: List<Expression>, baseClassParams: List<Expression>,
implementsTypes: List<Type>, implementsTypes: List<Type>,
body: ClassBody body: ClassBody
) : Class(converter, name, comments, modifiers, typeParameterList, ) : Class(name, comments, annotations, modifiers, typeParameterList,
extendsTypes, baseClassParams, implementsTypes, body) { extendsTypes, baseClassParams, implementsTypes, body) {
override fun primaryConstructorSignatureToKotlin(): String override fun primaryConstructorSignatureToKotlin(): String
= body.primaryConstructor?.signatureToKotlin() ?: "" = body.primaryConstructor?.signatureToKotlin() ?: ""
override fun toKotlin(): String { override fun toKotlin(): String {
return modifiersToKotlin() + return commentsToKotlin() +
annotations.toKotlin() +
modifiersToKotlin() +
"enum class " + name.toKotlin() + "enum class " + name.toKotlin() +
primaryConstructorSignatureToKotlin() + primaryConstructorSignatureToKotlin() +
typeParameterList.toKotlin() + typeParameterList.toKotlin() +
@@ -19,17 +19,18 @@ package org.jetbrains.jet.j2k.ast
class EnumConstant( class EnumConstant(
identifier: Identifier, identifier: Identifier,
members: MemberComments, members: MemberComments,
annotations: List<Annotation>,
modifiers: Set<Modifier>, modifiers: Set<Modifier>,
`type`: Type, `type`: Type,
params: Element params: Element
) : Field(identifier, members, modifiers, `type`.toNotNullType(), params, true, false) { ) : Field(identifier, members, annotations, modifiers, `type`.toNotNullType(), params, true, false) {
override fun toKotlin(): String { override fun toKotlin(): String {
if (initializer.toKotlin().isEmpty()) { if (initializer.toKotlin().isEmpty()) {
return identifier.toKotlin() return annotations.toKotlin() + identifier.toKotlin()
} }
return identifier.toKotlin() + " : " + `type`.toKotlin() + "(" + initializer.toKotlin() + ")" return annotations.toKotlin() + identifier.toKotlin() + " : " + `type`.toKotlin() + "(" + initializer.toKotlin() + ")"
} }
@@ -104,6 +104,10 @@ class LambdaExpression(val arguments: String?, val statementList: StatementList)
} }
} }
class StarExpression(val methodCall: MethodCallExpression) : Expression() {
override fun toKotlin() = "*" + methodCall.toKotlin()
}
fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List<Expression>) : MethodCallExpression { fun createArrayInitializerExpression(arrayType: ArrayType, initializers: List<Expression>) : MethodCallExpression {
val elementType = arrayType.elementType val elementType = arrayType.elementType
val createArrayFunction = if (elementType.isPrimitive()) { val createArrayFunction = if (elementType.isPrimitive()) {
+3 -2
View File
@@ -22,15 +22,16 @@ import java.util.ArrayList
open class Field( open class Field(
val identifier: Identifier, val identifier: Identifier,
comments: MemberComments, comments: MemberComments,
annotations: List<Annotation>,
modifiers: Set<Modifier>, modifiers: Set<Modifier>,
val `type`: Type, val `type`: Type,
val initializer: Element, val initializer: Element,
val isVal: Boolean, val isVal: Boolean,
private val hasWriteAccesses: Boolean private val hasWriteAccesses: Boolean
) : Member(comments, modifiers) { ) : Member(comments, annotations, modifiers) {
override fun toKotlin(): String { override fun toKotlin(): String {
val declaration = commentsToKotlin() + modifiersToKotlin() + (if (isVal) "val " else "var ") + identifier.toKotlin() + " : " + `type`.toKotlin() val declaration = commentsToKotlin() + annotations.toKotlin() + modifiersToKotlin() + (if (isVal) "val " else "var ") + identifier.toKotlin() + " : " + `type`.toKotlin()
return if (initializer.isEmpty) return if (initializer.isEmpty)
declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this)) declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this))
else else
@@ -23,13 +23,14 @@ open class Function(
val converter: Converter, val converter: Converter,
val name: Identifier, val name: Identifier,
comments: MemberComments, comments: MemberComments,
annotations: List<Annotation>,
modifiers: Set<Modifier>, modifiers: Set<Modifier>,
val `type`: Type, val `type`: Type,
val typeParameterList: TypeParameterList, val typeParameterList: TypeParameterList,
val parameterList: ParameterList, val parameterList: ParameterList,
var block: Block?, var block: Block?,
val isInTrait: Boolean val isInTrait: Boolean
) : Member(comments, modifiers) { ) : Member(comments, annotations, modifiers) {
private fun modifiersToKotlin(): String { private fun modifiersToKotlin(): String {
val resultingModifiers = ArrayList<Modifier>() val resultingModifiers = ArrayList<Modifier>()
@@ -58,11 +59,12 @@ open class Function(
override fun toKotlin(): String { override fun toKotlin(): String {
return commentsToKotlin() + return commentsToKotlin() +
modifiersToKotlin() + annotations.toKotlin() +
"fun ${typeParameterList.toKotlin().withSuffix(" ")}${name.toKotlin()}" + modifiersToKotlin() +
"(${parameterList.toKotlin()})" + "fun ${typeParameterList.toKotlin().withSuffix(" ")}${name.toKotlin()}" +
returnTypeToKotlin() + "(${parameterList.toKotlin()})" +
typeParameterList.whereToKotlin() + returnTypeToKotlin() +
block?.toKotlin() typeParameterList.whereToKotlin() +
block?.toKotlin()
} }
} }
@@ -36,6 +36,8 @@ class Identifier(
private fun quote(str: String): String = "`" + str + "`" private fun quote(str: String): String = "`" + str + "`"
override fun toString() = if (isNullable) "$name?" else name
class object { class object {
val Empty = Identifier("") val Empty = Identifier("")
+1 -1
View File
@@ -57,7 +57,7 @@ public fun Converter.convertImport(anImport: PsiImportStatementBase, filter: Boo
} }
private fun filterImport(name: String, ref: PsiJavaCodeReferenceElement): String? { private fun filterImport(name: String, ref: PsiJavaCodeReferenceElement): String? {
if (name in NOT_NULL_ANNOTATIONS || name in NULLABLE_ANNOTATIONS) return null if (name in ANNOTATIONS_TO_REMOVE) return null
// If imported class has a kotlin analog, drop the import // If imported class has a kotlin analog, drop the import
if (!JavaToKotlinClassMap.getInstance().mapPlatformClass(FqName(name)).isEmpty()) return null if (!JavaToKotlinClassMap.getInstance().mapPlatformClass(FqName(name)).isEmpty()) return null
@@ -18,7 +18,7 @@ package org.jetbrains.jet.j2k.ast
//TODO: is a member? //TODO: is a member?
class Initializer(val block: Block, modifiers: Set<Modifier>) : Member(MemberComments.Empty, modifiers) { class Initializer(val block: Block, modifiers: Set<Modifier>) : Member(MemberComments.Empty, listOf(), modifiers) {
override fun toKotlin(): String { override fun toKotlin(): String {
return block.toKotlin() return block.toKotlin()
} }
@@ -20,6 +20,7 @@ import org.jetbrains.jet.j2k.ConverterSettings
class LocalVariable( class LocalVariable(
private val identifier: Identifier, private val identifier: Identifier,
private val annotations: List<Annotation>,
private val modifiers: Set<Modifier>, private val modifiers: Set<Modifier>,
private val typeCalculator: () -> Type /* we use lazy type calculation for better performance */, private val typeCalculator: () -> Type /* we use lazy type calculation for better performance */,
private val initializer: Expression, private val initializer: Expression,
@@ -28,16 +29,16 @@ class LocalVariable(
) : Element { ) : Element {
override fun toKotlin(): String { override fun toKotlin(): String {
val varVal = if (isVal) "val" else "var" val start = annotations.toKotlin() + if (isVal) "val" else "var"
return if (initializer.isEmpty) { return if (initializer.isEmpty) {
"$varVal ${identifier.toKotlin()} : ${typeCalculator().toKotlin()}" "$start ${identifier.toKotlin()} : ${typeCalculator().toKotlin()}"
} }
else { else {
val shouldSpecifyType = settings.specifyLocalVariableTypeByDefault val shouldSpecifyType = settings.specifyLocalVariableTypeByDefault
if (shouldSpecifyType) if (shouldSpecifyType)
"$varVal ${identifier.toKotlin()} : ${typeCalculator().toKotlin()} = ${initializer.toKotlin()}" "$start ${identifier.toKotlin()} : ${typeCalculator().toKotlin()} = ${initializer.toKotlin()}"
else else
"$varVal ${identifier.toKotlin()} = ${initializer.toKotlin()}" "$start ${identifier.toKotlin()} = ${initializer.toKotlin()}"
} }
} }
} }
+1 -1
View File
@@ -30,7 +30,7 @@ class MemberComments(elements: List<Element>) : WhiteSpaceSeparatedElementList(e
} }
} }
abstract class Member(val comments: MemberComments, val modifiers: Set<Modifier>) : Element { abstract class Member(val comments: MemberComments, val annotations: List<Annotation>, val modifiers: Set<Modifier>) : Element {
fun commentsToKotlin(): String = comments.toKotlin() fun commentsToKotlin(): String = comments.toKotlin()
} }
@@ -16,7 +16,11 @@
package org.jetbrains.jet.j2k.ast package org.jetbrains.jet.j2k.ast
class Parameter(val identifier: Identifier, val `type`: Type, val varVal: Parameter.VarValModifier, val modifiers: Collection<Modifier>) : Element { class Parameter(val identifier: Identifier,
val `type`: Type,
val varVal: Parameter.VarValModifier,
val annotations: List<Annotation>,
val modifiers: Collection<Modifier>) : Element {
public enum class VarValModifier { public enum class VarValModifier {
None None
Val Val
@@ -26,6 +30,7 @@ class Parameter(val identifier: Identifier, val `type`: Type, val varVal: Parame
override fun toKotlin(): String { override fun toKotlin(): String {
val builder = StringBuilder() val builder = StringBuilder()
builder.append(annotations.toKotlin())
builder.append(modifiers.toKotlin()) builder.append(modifiers.toKotlin())
if (`type` is VarArgType) { if (`type` is VarArgType) {
+10 -12
View File
@@ -19,18 +19,16 @@ package org.jetbrains.jet.j2k.ast
import org.jetbrains.jet.j2k.Converter import org.jetbrains.jet.j2k.Converter
import java.util.ArrayList import java.util.ArrayList
class Trait( class Trait(name: Identifier,
converter: Converter, comments: MemberComments,
name: Identifier, annotations: List<Annotation>,
comments: MemberComments, modifiers: Set<Modifier>,
modifiers: Set<Modifier>, typeParameterList: TypeParameterList,
typeParameterList: TypeParameterList, extendsTypes: List<Type>,
extendsTypes: List<Type>, baseClassParams: List<Expression>,
baseClassParams: List<Expression>, implementsTypes: List<Type>,
implementsTypes: List<Type>, body: ClassBody
body: ClassBody ) : Class(name, comments, annotations, modifiers, typeParameterList, extendsTypes, baseClassParams, implementsTypes, body) {
) : Class(converter, name, comments, modifiers, typeParameterList,
extendsTypes, baseClassParams, implementsTypes, body) {
override val keyword: String override val keyword: String
get() = "trait" get() = "trait"
@@ -28,11 +28,12 @@ class ElementVisitor(private val converter: Converter) : JavaElementVisitor() {
override fun visitLocalVariable(variable: PsiLocalVariable) { override fun visitLocalVariable(variable: PsiLocalVariable) {
result = LocalVariable(Identifier(variable.getName()!!), result = LocalVariable(Identifier(variable.getName()!!),
converter.convertModifiers(variable), converter.convertAnnotations(variable),
{ typeConverter.convertVariableType(variable) }, converter.convertModifiers(variable),
converter.convertExpression(variable.getInitializer(), variable.getType()), { typeConverter.convertVariableType(variable) },
converter.settings.forceLocalVariableImmutability || variable.hasModifierProperty(PsiModifier.FINAL), converter.convertExpression(variable.getInitializer(), variable.getType()),
converter.settings) converter.settings.forceLocalVariableImmutability || variable.hasModifierProperty(PsiModifier.FINAL),
converter.settings)
} }
override fun visitExpressionList(list: PsiExpressionList) { override fun visitExpressionList(list: PsiExpressionList) {
@@ -41,11 +41,17 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() {
override fun setUp() { override fun setUp() {
super.setUp() super.setUp()
fun addFile(fileName: String, packageName: String) {
val code = FileUtil.loadFile(File("j2k/tests/testData/$fileName"), true)
val root = LightPlatformTestCase.getSourceRoot()!!
val dir = root.findChild(packageName) ?: root.createChildDirectory(null, packageName)
val file = dir.createChildData(null, fileName)!!
file.getOutputStream(null)!!.writer().use { it.write(code) }
}
ApplicationManager.getApplication()!!.runWriteAction{ ApplicationManager.getApplication()!!.runWriteAction{
val kotlinApiFileName = "KotlinApi.kt" addFile("KotlinApi.kt", "kotlinApi")
val kotlinCode = FileUtil.loadFile(File("j2k/tests/testData/$kotlinApiFileName"), true) addFile("JavaApi.java", "javaApi")
val kotlinFile = LightPlatformTestCase.getSourceRoot()!!.createChildData(null, kotlinApiFileName)!!
kotlinFile.getOutputStream(null)!!.writer().use { it.write(kotlinCode) }
} }
} }
@@ -43,6 +43,11 @@ public class JavaToKotlinConverterTestGenerated extends AbstractJavaToKotlinConv
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/annotations"), Pattern.compile("^(.+)\\.java$"), true); JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("j2k/tests/testData/ast/annotations"), Pattern.compile("^(.+)\\.java$"), true);
} }
@TestMetadata("annotationUsages.java")
public void testAnnotationUsages() throws Exception {
doTest("j2k/tests/testData/ast/annotations/annotationUsages.java");
}
@TestMetadata("jetbrainsNotNull.java") @TestMetadata("jetbrainsNotNull.java")
public void testJetbrainsNotNull() throws Exception { public void testJetbrainsNotNull() throws Exception {
doTest("j2k/tests/testData/ast/annotations/jetbrainsNotNull.java"); doTest("j2k/tests/testData/ast/annotations/jetbrainsNotNull.java");
+37
View File
@@ -0,0 +1,37 @@
package javaApi;
public @interface Anon1 {
String[] value();
String[] stringArray();
int[] intArray();
String string();
}
public @interface Anon2 {
String value();
int intValue();
char charValue();
}
public @interface Anon3 {
E e();
String[] stringArray();
String[] value();
}
public @interface Anon4 {
String[] value();
}
public @interface Anon5 {
int value();
}
public @interface Anon6 {
String[] value();
int intValue() default 10;
}
public enum E {
A, B, C
}
@@ -0,0 +1,11 @@
//file
import javaApi.*;
@Anon1(value = {"a"}, stringArray = {"b"}, intArray = {1, 2}, string = "x")
@Anon2(value = "a", intValue = 1, charValue = 'a')
@Anon3(e = E.A, stringArray = {}, value = {"a", "b"})
@Anon4({"x", "y"})
@Anon5(1)
@Anon6({"x", "y"})
class C {
}
@@ -0,0 +1,9 @@
import javaApi.*
Anon1(value = array<String>("a"), stringArray = array<String>("b"), intArray = intArray(1, 2), string = "x")
Anon2(value = "a", intValue = 1, charValue = 'a')
Anon3(e = E.A, stringArray = array<String>(), value = *array<String>("a", "b"))
Anon4("x", "y")
Anon5(1)
Anon6(array<String>("x", "y"))
class C()