Converter from Java: basic implementation of annotations conversion
This commit is contained in:
@@ -72,6 +72,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
|
||||
is PsiComment -> Comment(element.getText()!!)
|
||||
is PsiImportList -> convertImportList(element)
|
||||
is PsiImportStatementBase -> convertImport(element, false)
|
||||
is PsiAnnotation -> convertAnnotation(element)
|
||||
is PsiPackageStatement -> PackageStatement(quoteKeywords(element.getPackageName() ?: ""))
|
||||
is PsiWhiteSpace -> WhiteSpace(element.getText()!!)
|
||||
else -> null
|
||||
@@ -100,7 +101,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -201,6 +202,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
|
||||
}
|
||||
|
||||
private fun convertClass(psiClass: PsiClass): Class {
|
||||
val annotations = convertAnnotations(psiClass)
|
||||
val modifiers = convertModifiers(psiClass)
|
||||
val typeParameters = convertTypeParameterList(psiClass.getTypeParameterList())
|
||||
val implementsTypes = convertToNotNullableTypes(psiClass.getImplementsListTypes())
|
||||
@@ -209,9 +211,9 @@ public class Converter private(val project: Project, val settings: ConverterSett
|
||||
var classBody = convertClassBody(psiClass)
|
||||
|
||||
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 -> {
|
||||
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)
|
||||
}
|
||||
|
||||
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?
|
||||
val parameters = finalOrWithEmptyInitializerFields.map { field ->
|
||||
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) })
|
||||
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 {
|
||||
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()))
|
||||
@@ -309,6 +313,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
|
||||
|
||||
return Field(Identifier(field.getName()!!),
|
||||
getComments(field),
|
||||
annotations,
|
||||
modifiers,
|
||||
typeConverter.convertVariableType(field),
|
||||
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 {
|
||||
val returnType = typeConverter.convertMethodReturnType(method)
|
||||
|
||||
val annotations = convertAnnotations(method)
|
||||
val modifiers = convertModifiers(method)
|
||||
|
||||
val comments = getComments(method)
|
||||
|
||||
if (method.isConstructor()) {
|
||||
if (method.isPrimaryConstructor()) {
|
||||
return convertPrimaryConstructor(method, modifiers, comments, membersToRemove)
|
||||
return convertPrimaryConstructor(method, annotations, modifiers, comments, membersToRemove)
|
||||
}
|
||||
else {
|
||||
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 {
|
||||
@@ -364,6 +370,7 @@ public class Converter private(val project: Project, val settings: ConverterSett
|
||||
val correctedParameter = Parameter(Identifier("other"),
|
||||
ClassType(Identifier("Any"), listOf(), Nullability.Nullable, settings),
|
||||
Parameter.VarValModifier.None,
|
||||
params.parameters.single().annotations,
|
||||
listOf())
|
||||
params = ParameterList(listOf(correctedParameter))
|
||||
}
|
||||
@@ -371,7 +378,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, 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,
|
||||
annotations: List<Annotation>,
|
||||
modifiers: Set<Modifier>,
|
||||
comments: MemberComments,
|
||||
membersToRemove: MutableSet<PsiMember>): PrimaryConstructor {
|
||||
@@ -460,10 +468,11 @@ public class Converter private(val project: Project, val settings: ConverterSett
|
||||
Parameter(Identifier(field.getName()!!),
|
||||
`type`,
|
||||
if (field.hasModifierProperty(PsiModifier.FINAL)) Parameter.VarValModifier.Val else Parameter.VarValModifier.Var,
|
||||
convertAnnotations(it) + convertAnnotations(field),
|
||||
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>? {
|
||||
@@ -550,7 +559,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, modifiers)
|
||||
return Parameter(Identifier(parameter.getName()!!), `type`, varValModifier, convertAnnotations(parameter), modifiers)
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
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(
|
||||
JAVA_LANG_BYTE to "byte",
|
||||
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 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(
|
||||
"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 java.util.Collections
|
||||
|
||||
class AnonymousClassBody(converter: Converter, body: ClassBody, val extendsTrait: Boolean)
|
||||
: Class(converter,
|
||||
Identifier(""),
|
||||
MemberComments.Empty,
|
||||
setOf(),
|
||||
TypeParameterList.Empty,
|
||||
listOf(),
|
||||
listOf(),
|
||||
listOf(),
|
||||
body) {
|
||||
class AnonymousClassBody(body: ClassBody, val extendsTrait: Boolean)
|
||||
: Class(Identifier(""), MemberComments.Empty, listOf(), setOf(), TypeParameterList.Empty, listOf(), listOf(), listOf(), body) {
|
||||
override fun toKotlin() = body.toKotlin(null)
|
||||
}
|
||||
|
||||
@@ -16,23 +16,23 @@
|
||||
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.Converter
|
||||
import java.util.ArrayList
|
||||
|
||||
open class Class(
|
||||
val converter: Converter,
|
||||
val name: Identifier,
|
||||
comments: MemberComments,
|
||||
annotations: List<Annotation>,
|
||||
modifiers: Set<Modifier>,
|
||||
val typeParameterList: TypeParameterList,
|
||||
val extendsTypes: List<Type>,
|
||||
val baseClassParams: List<Expression>,
|
||||
val implementsTypes: List<Type>,
|
||||
val body: ClassBody
|
||||
) : Member(comments, modifiers) {
|
||||
) : Member(comments, annotations, modifiers) {
|
||||
|
||||
override fun toKotlin(): String =
|
||||
commentsToKotlin() +
|
||||
annotations.toKotlin() +
|
||||
modifiersToKotlin() +
|
||||
keyword + " " + name.toKotlin() +
|
||||
typeParameterList.toKotlin() +
|
||||
|
||||
@@ -23,17 +23,19 @@ import java.util.ArrayList
|
||||
abstract class Constructor(
|
||||
converter: Converter,
|
||||
comments: MemberComments,
|
||||
annotations: List<Annotation>,
|
||||
modifiers: Set<Modifier>,
|
||||
parameterList: ParameterList,
|
||||
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,
|
||||
comments: MemberComments,
|
||||
annotations: List<Annotation>,
|
||||
modifiers: Set<Modifier>,
|
||||
parameterList: ParameterList,
|
||||
block: Block)
|
||||
: Constructor(converter, comments, modifiers, parameterList, block) {
|
||||
: Constructor(converter, comments, annotations, modifiers, parameterList, block) {
|
||||
|
||||
public fun signatureToKotlin(): String {
|
||||
val accessModifier = modifiers.accessModifier()
|
||||
@@ -46,10 +48,11 @@ class PrimaryConstructor(converter: Converter,
|
||||
|
||||
class SecondaryConstructor(converter: Converter,
|
||||
comments: MemberComments,
|
||||
annotations: List<Annotation>,
|
||||
modifiers: Set<Modifier>,
|
||||
parameterList: ParameterList,
|
||||
block: Block)
|
||||
: Constructor(converter, comments, modifiers, parameterList, block) {
|
||||
: Constructor(converter, comments, annotations, modifiers, parameterList, block) {
|
||||
|
||||
public fun toInitFunction(containingClass: Class): Function {
|
||||
val modifiers = HashSet(modifiers)
|
||||
@@ -58,7 +61,7 @@ class SecondaryConstructor(converter: Converter,
|
||||
val block = Block(statements)
|
||||
val typeParameters = ArrayList<TypeParameter>()
|
||||
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),
|
||||
TypeParameterList(typeParameters), parameterList, block, false)
|
||||
}
|
||||
|
||||
@@ -16,26 +16,26 @@
|
||||
|
||||
package org.jetbrains.jet.j2k.ast
|
||||
|
||||
import org.jetbrains.jet.j2k.Converter
|
||||
|
||||
class Enum(
|
||||
converter: Converter,
|
||||
name: Identifier,
|
||||
comments: MemberComments,
|
||||
annotations: List<Annotation>,
|
||||
modifiers: Set<Modifier>,
|
||||
typeParameterList: TypeParameterList,
|
||||
extendsTypes: List<Type>,
|
||||
baseClassParams: List<Expression>,
|
||||
implementsTypes: List<Type>,
|
||||
body: ClassBody
|
||||
) : Class(converter, name, comments, modifiers, typeParameterList,
|
||||
) : Class(name, comments, annotations, modifiers, typeParameterList,
|
||||
extendsTypes, baseClassParams, implementsTypes, body) {
|
||||
|
||||
override fun primaryConstructorSignatureToKotlin(): String
|
||||
= body.primaryConstructor?.signatureToKotlin() ?: ""
|
||||
|
||||
override fun toKotlin(): String {
|
||||
return modifiersToKotlin() +
|
||||
return commentsToKotlin() +
|
||||
annotations.toKotlin() +
|
||||
modifiersToKotlin() +
|
||||
"enum class " + name.toKotlin() +
|
||||
primaryConstructorSignatureToKotlin() +
|
||||
typeParameterList.toKotlin() +
|
||||
|
||||
@@ -19,17 +19,18 @@ package org.jetbrains.jet.j2k.ast
|
||||
class EnumConstant(
|
||||
identifier: Identifier,
|
||||
members: MemberComments,
|
||||
annotations: List<Annotation>,
|
||||
modifiers: Set<Modifier>,
|
||||
`type`: Type,
|
||||
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 {
|
||||
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 {
|
||||
val elementType = arrayType.elementType
|
||||
val createArrayFunction = if (elementType.isPrimitive()) {
|
||||
|
||||
@@ -22,15 +22,16 @@ import java.util.ArrayList
|
||||
open class Field(
|
||||
val identifier: Identifier,
|
||||
comments: MemberComments,
|
||||
annotations: List<Annotation>,
|
||||
modifiers: Set<Modifier>,
|
||||
val `type`: Type,
|
||||
val initializer: Element,
|
||||
val isVal: Boolean,
|
||||
private val hasWriteAccesses: Boolean
|
||||
) : Member(comments, modifiers) {
|
||||
) : Member(comments, annotations, modifiers) {
|
||||
|
||||
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)
|
||||
declaration + (if (isVal && hasWriteAccesses) "" else " = " + getDefaultInitializer(this))
|
||||
else
|
||||
|
||||
@@ -23,13 +23,14 @@ open class Function(
|
||||
val converter: Converter,
|
||||
val name: Identifier,
|
||||
comments: MemberComments,
|
||||
annotations: List<Annotation>,
|
||||
modifiers: Set<Modifier>,
|
||||
val `type`: Type,
|
||||
val typeParameterList: TypeParameterList,
|
||||
val parameterList: ParameterList,
|
||||
var block: Block?,
|
||||
val isInTrait: Boolean
|
||||
) : Member(comments, modifiers) {
|
||||
) : Member(comments, annotations, modifiers) {
|
||||
|
||||
private fun modifiersToKotlin(): String {
|
||||
val resultingModifiers = ArrayList<Modifier>()
|
||||
@@ -58,11 +59,12 @@ open class Function(
|
||||
|
||||
override fun toKotlin(): String {
|
||||
return commentsToKotlin() +
|
||||
modifiersToKotlin() +
|
||||
"fun ${typeParameterList.toKotlin().withSuffix(" ")}${name.toKotlin()}" +
|
||||
"(${parameterList.toKotlin()})" +
|
||||
returnTypeToKotlin() +
|
||||
typeParameterList.whereToKotlin() +
|
||||
block?.toKotlin()
|
||||
annotations.toKotlin() +
|
||||
modifiersToKotlin() +
|
||||
"fun ${typeParameterList.toKotlin().withSuffix(" ")}${name.toKotlin()}" +
|
||||
"(${parameterList.toKotlin()})" +
|
||||
returnTypeToKotlin() +
|
||||
typeParameterList.whereToKotlin() +
|
||||
block?.toKotlin()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ class Identifier(
|
||||
|
||||
private fun quote(str: String): String = "`" + str + "`"
|
||||
|
||||
override fun toString() = if (isNullable) "$name?" else name
|
||||
|
||||
class object {
|
||||
val Empty = Identifier("")
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ public fun Converter.convertImport(anImport: PsiImportStatementBase, filter: Boo
|
||||
}
|
||||
|
||||
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 (!JavaToKotlinClassMap.getInstance().mapPlatformClass(FqName(name)).isEmpty()) return null
|
||||
|
||||
@@ -18,7 +18,7 @@ package org.jetbrains.jet.j2k.ast
|
||||
|
||||
|
||||
//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 {
|
||||
return block.toKotlin()
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.jet.j2k.ConverterSettings
|
||||
|
||||
class LocalVariable(
|
||||
private val identifier: Identifier,
|
||||
private val annotations: List<Annotation>,
|
||||
private val modifiers: Set<Modifier>,
|
||||
private val typeCalculator: () -> Type /* we use lazy type calculation for better performance */,
|
||||
private val initializer: Expression,
|
||||
@@ -28,16 +29,16 @@ class LocalVariable(
|
||||
) : Element {
|
||||
|
||||
override fun toKotlin(): String {
|
||||
val varVal = if (isVal) "val" else "var"
|
||||
val start = annotations.toKotlin() + if (isVal) "val" else "var"
|
||||
return if (initializer.isEmpty) {
|
||||
"$varVal ${identifier.toKotlin()} : ${typeCalculator().toKotlin()}"
|
||||
"$start ${identifier.toKotlin()} : ${typeCalculator().toKotlin()}"
|
||||
}
|
||||
else {
|
||||
val shouldSpecifyType = settings.specifyLocalVariableTypeByDefault
|
||||
if (shouldSpecifyType)
|
||||
"$varVal ${identifier.toKotlin()} : ${typeCalculator().toKotlin()} = ${initializer.toKotlin()}"
|
||||
"$start ${identifier.toKotlin()} : ${typeCalculator().toKotlin()} = ${initializer.toKotlin()}"
|
||||
else
|
||||
"$varVal ${identifier.toKotlin()} = ${initializer.toKotlin()}"
|
||||
"$start ${identifier.toKotlin()} = ${initializer.toKotlin()}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
|
||||
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 {
|
||||
None
|
||||
Val
|
||||
@@ -26,6 +30,7 @@ class Parameter(val identifier: Identifier, val `type`: Type, val varVal: Parame
|
||||
override fun toKotlin(): String {
|
||||
val builder = StringBuilder()
|
||||
|
||||
builder.append(annotations.toKotlin())
|
||||
builder.append(modifiers.toKotlin())
|
||||
|
||||
if (`type` is VarArgType) {
|
||||
|
||||
@@ -19,18 +19,16 @@ package org.jetbrains.jet.j2k.ast
|
||||
import org.jetbrains.jet.j2k.Converter
|
||||
import java.util.ArrayList
|
||||
|
||||
class Trait(
|
||||
converter: Converter,
|
||||
name: Identifier,
|
||||
comments: MemberComments,
|
||||
modifiers: Set<Modifier>,
|
||||
typeParameterList: TypeParameterList,
|
||||
extendsTypes: List<Type>,
|
||||
baseClassParams: List<Expression>,
|
||||
implementsTypes: List<Type>,
|
||||
body: ClassBody
|
||||
) : Class(converter, name, comments, modifiers, typeParameterList,
|
||||
extendsTypes, baseClassParams, implementsTypes, body) {
|
||||
class Trait(name: Identifier,
|
||||
comments: MemberComments,
|
||||
annotations: List<Annotation>,
|
||||
modifiers: Set<Modifier>,
|
||||
typeParameterList: TypeParameterList,
|
||||
extendsTypes: List<Type>,
|
||||
baseClassParams: List<Expression>,
|
||||
implementsTypes: List<Type>,
|
||||
body: ClassBody
|
||||
) : Class(name, comments, annotations, modifiers, typeParameterList, extendsTypes, baseClassParams, implementsTypes, body) {
|
||||
|
||||
override val keyword: String
|
||||
get() = "trait"
|
||||
|
||||
@@ -28,11 +28,12 @@ class ElementVisitor(private val converter: Converter) : JavaElementVisitor() {
|
||||
|
||||
override fun visitLocalVariable(variable: PsiLocalVariable) {
|
||||
result = LocalVariable(Identifier(variable.getName()!!),
|
||||
converter.convertModifiers(variable),
|
||||
{ typeConverter.convertVariableType(variable) },
|
||||
converter.convertExpression(variable.getInitializer(), variable.getType()),
|
||||
converter.settings.forceLocalVariableImmutability || variable.hasModifierProperty(PsiModifier.FINAL),
|
||||
converter.settings)
|
||||
converter.convertAnnotations(variable),
|
||||
converter.convertModifiers(variable),
|
||||
{ typeConverter.convertVariableType(variable) },
|
||||
converter.convertExpression(variable.getInitializer(), variable.getType()),
|
||||
converter.settings.forceLocalVariableImmutability || variable.hasModifierProperty(PsiModifier.FINAL),
|
||||
converter.settings)
|
||||
}
|
||||
|
||||
override fun visitExpressionList(list: PsiExpressionList) {
|
||||
|
||||
@@ -41,11 +41,17 @@ abstract class AbstractJavaToKotlinConverterTest() : LightIdeaTestCase() {
|
||||
override fun 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{
|
||||
val kotlinApiFileName = "KotlinApi.kt"
|
||||
val kotlinCode = FileUtil.loadFile(File("j2k/tests/testData/$kotlinApiFileName"), true)
|
||||
val kotlinFile = LightPlatformTestCase.getSourceRoot()!!.createChildData(null, kotlinApiFileName)!!
|
||||
kotlinFile.getOutputStream(null)!!.writer().use { it.write(kotlinCode) }
|
||||
addFile("KotlinApi.kt", "kotlinApi")
|
||||
addFile("JavaApi.java", "javaApi")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@TestMetadata("annotationUsages.java")
|
||||
public void testAnnotationUsages() throws Exception {
|
||||
doTest("j2k/tests/testData/ast/annotations/annotationUsages.java");
|
||||
}
|
||||
|
||||
@TestMetadata("jetbrainsNotNull.java")
|
||||
public void testJetbrainsNotNull() throws Exception {
|
||||
doTest("j2k/tests/testData/ast/annotations/jetbrainsNotNull.java");
|
||||
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user