diff --git a/j2k/src/org/jetbrains/kotlin/j2k/AnnotationConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/AnnotationConverter.kt index cbfb430dce1..0c655766d73 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/AnnotationConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/AnnotationConverter.kt @@ -20,13 +20,21 @@ import com.intellij.codeInsight.NullableNotNullManager import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.* import com.intellij.psi.javadoc.PsiDocTag +import org.jetbrains.kotlin.descriptors.annotations.AnnotationTarget import org.jetbrains.kotlin.j2k.ast.* import org.jetbrains.kotlin.j2k.ast.Annotation +import org.jetbrains.kotlin.load.java.components.JavaAnnotationTargetMapper +import java.lang.annotation.ElementType +import java.lang.annotation.Target class AnnotationConverter(private val converter: Converter) { - public val annotationsToRemove: Set = (NullableNotNullManager.getInstance(converter.project).getNotNulls() + private val annotationsToRemove: Set = (NullableNotNullManager.getInstance(converter.project).getNotNulls() + NullableNotNullManager.getInstance(converter.project).getNullables() - + listOf(CommonClassNames.JAVA_LANG_OVERRIDE)).toSet() + + listOf(CommonClassNames.JAVA_LANG_OVERRIDE, javaClass().name)).toSet() + + public fun isImportRequired(annotationName: String): Boolean { + return annotationName in annotationsToRemove || annotationName == javaClass().name + } public fun convertAnnotations(owner: PsiModifierListOwner): Annotations = convertAnnotationsOnly(owner) + convertModifiersToAnnotations(owner) @@ -88,12 +96,42 @@ class AnnotationConverter(private val converter: Converter) { PsiModifier.TRANSIENT to "transient" ) + private fun mapTargetByName(expr: PsiReferenceExpression): Set { + return expr.referenceName?.let { JavaAnnotationTargetMapper.mapJavaTargetArgumentByName(it) } ?: emptySet() + } + public fun convertAnnotation(annotation: PsiAnnotation, withAt: Boolean, newLineAfter: Boolean): Annotation? { val qualifiedName = annotation.getQualifiedName() if (qualifiedName == CommonClassNames.JAVA_LANG_DEPRECATED && annotation.getParameterList().getAttributes().isEmpty()) { val deferredExpression = converter.deferredElement { LiteralExpression("\"\"").assignNoPrototype() } return Annotation(Identifier("deprecated").assignNoPrototype(), listOf(null to deferredExpression), withAt, newLineAfter).assignPrototype(annotation) //TODO: insert comment } + if (qualifiedName == CommonClassNames.JAVA_LANG_ANNOTATION_TARGET) { + val attributes = annotation.parameterList.attributes + val arguments: Set + if (attributes.isEmpty()) { + arguments = setOf() + } + else { + val value = attributes[0].value + arguments = when (value) { + is PsiArrayInitializerMemberValue -> value.getInitializers().filterIsInstance() + .flatMap { mapTargetByName(it) } + .toSet() + is PsiReferenceExpression -> mapTargetByName(value) + else -> setOf() + } + } + val deferredExpressionList = arguments.map { + val name = it.name() + null to converter.deferredElement { + QualifiedExpression(Identifier("AnnotationTarget", false).assignNoPrototype(), + Identifier(name, false).assignNoPrototype()) + } + } + return Annotation(Identifier("target").assignNoPrototype(), + deferredExpressionList, withAt, newLineAfter).assignPrototype(annotation) + } val nameRef = annotation.getNameReferenceElement() val name = Identifier((nameRef ?: return null).getText()!!).assignPrototype(nameRef) diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ast/Imports.kt b/j2k/src/org/jetbrains/kotlin/j2k/ast/Imports.kt index 230753ce264..17859200a8e 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ast/Imports.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ast/Imports.kt @@ -65,7 +65,7 @@ public fun Converter.convertImport(anImport: PsiImportStatementBase, filter: Boo } private fun Converter.filterImport(name: String, ref: PsiJavaCodeReferenceElement): String? { - if (name in annotationConverter.annotationsToRemove) return null + if (annotationConverter.isImportRequired(name)) return null // If imported class has a kotlin analog, drop the import if (!JavaToKotlinClassMap.INSTANCE.mapPlatformClass(FqName(name)).isEmpty()) return null diff --git a/j2k/testData/fileOrElement/annotations/annotationInterface1.java b/j2k/testData/fileOrElement/annotations/annotationInterface1.java index 63da1005e3c..d160351edce 100644 --- a/j2k/testData/fileOrElement/annotations/annotationInterface1.java +++ b/j2k/testData/fileOrElement/annotations/annotationInterface1.java @@ -14,3 +14,11 @@ import java.lang.annotation.Target; @Target({ElementType.CONSTRUCTOR, ElementType.FIELD}) @interface I { } + +@Target(ElementType.METHOD) +@interface J { +} + +@Target({}) +@interface K { +} diff --git a/j2k/testData/fileOrElement/annotations/annotationInterface1.kt b/j2k/testData/fileOrElement/annotations/annotationInterface1.kt index 9d99a51f293..2c8c05d3f25 100644 --- a/j2k/testData/fileOrElement/annotations/annotationInterface1.kt +++ b/j2k/testData/fileOrElement/annotations/annotationInterface1.kt @@ -1,9 +1,12 @@ -import java.lang.annotation.ElementType -import java.lang.annotation.Target - annotation class Anon(public val stringArray: Array, public val intArray: IntArray, // string public val string: String) Anon(string = "a", stringArray = arrayOf("a", "b"), intArray = intArrayOf(1, 2)) -Target(ElementType.CONSTRUCTOR, ElementType.FIELD) +target(AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FIELD) annotation class I + +target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) +annotation class J + +target +annotation class K