From 4da7d11364e2c0054a32179d6dd776cbb1dad0f3 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Tue, 8 Oct 2019 22:21:27 +0900 Subject: [PATCH] KT-30643 J2K: wrong position of TYPE_USE annotation (#2543) New J2K: fix wrong position of TYPE_USE annotation #KT-30643 Fixed --- j2k/testData/JavaApi.java | 16 +++++++- .../kotlin/nj2k/JavaToJKTreeBuilder.kt | 22 +++++++---- .../kotlin/nj2k/printing/JKCodeBuilder.kt | 1 + .../jetbrains/kotlin/nj2k/tree/elements.kt | 3 +- .../jetbrains/kotlin/nj2k/types/typesUtils.kt | 4 +- .../newJ2k/annotations/typeUseAnnotation.java | 28 ++++++++++++++ .../newJ2k/annotations/typeUseAnnotation.kt | 37 +++++++++++++++++++ ...otlinConverterSingleFileTestGenerated.java | 5 +++ 8 files changed, 104 insertions(+), 12 deletions(-) create mode 100644 nj2k/testData/newJ2k/annotations/typeUseAnnotation.java create mode 100644 nj2k/testData/newJ2k/annotations/typeUseAnnotation.kt diff --git a/j2k/testData/JavaApi.java b/j2k/testData/JavaApi.java index e598fc87476..d2c7a03d5cd 100644 --- a/j2k/testData/JavaApi.java +++ b/j2k/testData/JavaApi.java @@ -4,6 +4,8 @@ import org.jetbrains.annotations.Nullable; import java.util.Set; import kotlinApi.KotlinClassWithProperties; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; public @interface Anon1 { String[] value(); @@ -127,4 +129,16 @@ public class JavaClass { public @interface SpecialExternal { String[] names(); //array is used -} \ No newline at end of file +} + +@Target(ElementType.TYPE_USE) +public @interface TypeUseAnon1 { +} + +@Target({ElementType.TYPE_USE}) +public @interface TypeUseAnon2 { +} + +@Target({ElementType.TYPE_USE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +public @interface TypeUseAnon3 { +} diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/JavaToJKTreeBuilder.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/JavaToJKTreeBuilder.kt index cc787f68969..4201d6d5a7c 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/JavaToJKTreeBuilder.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/JavaToJKTreeBuilder.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.nj2k +import com.intellij.codeInsight.AnnotationTargetUtil import com.intellij.lang.jvm.JvmModifier import com.intellij.psi.* import com.intellij.psi.JavaTokenType.SUPER_KEYWORD @@ -44,7 +45,6 @@ import org.jetbrains.kotlin.nj2k.symbols.* import org.jetbrains.kotlin.nj2k.tree.* import org.jetbrains.kotlin.nj2k.tree.JKLiteralExpression.LiteralType.* import org.jetbrains.kotlin.nj2k.types.* - import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType @@ -720,7 +720,7 @@ class JavaToJKTreeBuilder constructor( fun PsiField.toJK(): JKField { return JKField( - JKTypeElement(type.toJK()).withFormattingFrom(typeElement), + JKTypeElement(type.toJK(), typeElement.annotationList()).withFormattingFrom(typeElement), nameIdentifier.toJK(), with(expressionTreeMapper) { initializer.toJK() }, annotationList(this), @@ -741,12 +741,16 @@ class JavaToJKTreeBuilder constructor( when { annotation !is PsiAnnotation -> null annotation.qualifiedName == DEPRECATED_ANNOTAION_FQ_NAME && deprecatedAnnotation != null -> null + AnnotationTargetUtil.isTypeAnnotation(annotation) -> null else -> annotation.toJK() } } return JKAnnotationList(plainAnnotations + listOfNotNull(deprecatedAnnotation)) } + fun PsiTypeElement?.annotationList(): JKAnnotationList { + return JKAnnotationList(this?.applicableAnnotations?.map { it.toJK() }.orEmpty()) + } fun PsiAnnotation.toJK(): JKAnnotation = JKAnnotation( @@ -814,7 +818,8 @@ class JavaToJKTreeBuilder constructor( JKTypeElement( returnType?.toJK() ?: JKJavaVoidType.takeIf { isConstructor } - ?: JKNoType), + ?: JKNoType, + returnTypeElement.annotationList()), nameIdentifier.toJK(), parameterList.parameters.map { it.toJK().withLineBreaksFrom(it) }, body?.toJK() ?: JKBodyStub, @@ -839,8 +844,8 @@ class JavaToJKTreeBuilder constructor( fun PsiParameter.toJK(): JKParameter { val rawType = type.toJK() val type = - if (isVarArgs && rawType is JKJavaArrayType) JKTypeElement(rawType.type) - else rawType.asTypeElement() + if (isVarArgs && rawType is JKJavaArrayType) JKTypeElement(rawType.type, typeElement.annotationList()) + else rawType.asTypeElement(typeElement.annotationList()) return JKParameter( type, nameIdentifier.toJK(), @@ -862,9 +867,9 @@ class JavaToJKTreeBuilder constructor( } - fun PsiLocalVariable.toJK(): JKLocalVariable = - JKLocalVariable( - JKTypeElement(type.toJK()).withFormattingFrom(typeElement), + fun PsiLocalVariable.toJK(): JKLocalVariable { + return JKLocalVariable( + JKTypeElement(type.toJK(), typeElement.annotationList()).withFormattingFrom(typeElement), nameIdentifier.toJK(), with(expressionTreeMapper) { initializer.toJK() }, JKMutabilityModifierElement( @@ -878,6 +883,7 @@ class JavaToJKTreeBuilder constructor( }.also { it.withFormattingFrom(this) } + } fun PsiStatement?.toJK(): JKStatement { return when (this) { diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/printing/JKCodeBuilder.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/printing/JKCodeBuilder.kt index 7026fe3ed8d..c4ea17291f3 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/printing/JKCodeBuilder.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/printing/JKCodeBuilder.kt @@ -599,6 +599,7 @@ internal class JKCodeBuilder(context: NewJ2kConverterContext) { } override fun visitTypeElementRaw(typeElement: JKTypeElement) { + typeElement.annotationList.accept(this) printer.renderType(typeElement.type, typeElement) } diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/elements.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/elements.kt index 55da8a3ce3a..5ec765c0686 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/tree/elements.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/tree/elements.kt @@ -27,8 +27,9 @@ class JKFile( var declarationList by children(declarationList) } -class JKTypeElement(var type: JKType) : JKTreeElement() { +class JKTypeElement(var type: JKType, annotationList: JKAnnotationList = JKAnnotationList()) : JKTreeElement(), JKAnnotationListOwner { override fun accept(visitor: JKVisitor) = visitor.visitTypeElement(this) + override var annotationList: JKAnnotationList by child(annotationList) } abstract class JKBlock : JKTreeElement() { diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/types/typesUtils.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/types/typesUtils.kt index 9cbea5edb2c..f71d2156c2f 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/types/typesUtils.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/types/typesUtils.kt @@ -24,8 +24,8 @@ import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.utils.addToStdlib.safeAs -fun JKType.asTypeElement() = - JKTypeElement(this) +fun JKType.asTypeElement(annotationList: JKAnnotationList = JKAnnotationList()) = + JKTypeElement(this, annotationList) fun JKClassSymbol.asType(nullability: Nullability = Nullability.Default): JKClassType = JKClassType(this, emptyList(), nullability) diff --git a/nj2k/testData/newJ2k/annotations/typeUseAnnotation.java b/nj2k/testData/newJ2k/annotations/typeUseAnnotation.java new file mode 100644 index 00000000000..3125f025405 --- /dev/null +++ b/nj2k/testData/newJ2k/annotations/typeUseAnnotation.java @@ -0,0 +1,28 @@ +import javaApi.Anon5 +import javaApi.TypeUseAnon1 +import javaApi.TypeUseAnon2 +import javaApi.TypeUseAnon3 + +public class TEST1 { + public @Anon5(1) @TypeUseAnon1 String foo(@Anon5(2) @TypeUseAnon1 Object o) { + @Anon5(3) @TypeUseAnon1 String baz = ""; + return ""; + } + @Anon5(4) @TypeUseAnon1 String bar; +} + +public class TEST2 { + public @Anon5(1) @TypeUseAnon2 String foo(@Anon5(2) @TypeUseAnon2 Object o) { + @Anon5(3) @TypeUseAnon2 String baz = ""; + return ""; + } + @Anon5(4) @TypeUseAnon2 String bar; +} + +public class TEST3 { + public @Anon5(1) @TypeUseAnon3 String foo(@Anon5(2) @TypeUseAnon3 Object o) { + @Anon5(3) @TypeUseAnon3 String baz = ""; + return ""; + } + @Anon5(4) @TypeUseAnon3 String bar; +} \ No newline at end of file diff --git a/nj2k/testData/newJ2k/annotations/typeUseAnnotation.kt b/nj2k/testData/newJ2k/annotations/typeUseAnnotation.kt new file mode 100644 index 00000000000..2114e820886 --- /dev/null +++ b/nj2k/testData/newJ2k/annotations/typeUseAnnotation.kt @@ -0,0 +1,37 @@ +import javaApi.Anon5 +import javaApi.TypeUseAnon1 +import javaApi.TypeUseAnon2 +import javaApi.TypeUseAnon3 + +class TEST1 { + @Anon5(1) + fun foo(@Anon5(2) o: @TypeUseAnon1 Any?): @TypeUseAnon1 String? { + @Anon5(3) val baz = "" + return "" + } + + @Anon5(4) + internal var bar: @TypeUseAnon1 String? = null +} + +class TEST2 { + @Anon5(1) + fun foo(@Anon5(2) o: @TypeUseAnon2 Any?): @TypeUseAnon2 String? { + @Anon5(3) val baz = "" + return "" + } + + @Anon5(4) + internal var bar: @TypeUseAnon2 String? = null +} + +class TEST3 { + @Anon5(1) + fun foo(@Anon5(2) o: @TypeUseAnon3 Any?): @TypeUseAnon3 String? { + @Anon5(3) val baz = "" + return "" + } + + @Anon5(4) + internal var bar: @TypeUseAnon3 String? = null +} \ No newline at end of file diff --git a/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java b/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java index 730e46185ba..b36770b4e5f 100644 --- a/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java +++ b/nj2k/tests/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverterSingleFileTestGenerated.java @@ -135,6 +135,11 @@ public class NewJavaToKotlinConverterSingleFileTestGenerated extends AbstractNew public void testSuppressWarnings() throws Exception { runTest("nj2k/testData/newJ2k/annotations/suppressWarnings.java"); } + + @TestMetadata("typeUseAnnotation.java") + public void testTypeUseAnnotation() throws Exception { + runTest("nj2k/testData/newJ2k/annotations/typeUseAnnotation.java"); + } } @TestMetadata("nj2k/testData/newJ2k/anonymousBlock")