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 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)
}
+3 -3
View File
@@ -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)
}
+5 -5
View File
@@ -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()) {
+3 -2
View File
@@ -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("")
+1 -1
View File
@@ -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()}"
}
}
}
+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()
}
@@ -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) {
+10 -12
View File
@@ -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");
+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()