diff --git a/compiler/testData/asJava/ultraLightClasses/annotations.kt b/compiler/testData/asJava/ultraLightClasses/annotations.kt index 99599161494..ea61612a6f0 100644 --- a/compiler/testData/asJava/ultraLightClasses/annotations.kt +++ b/compiler/testData/asJava/ultraLightClasses/annotations.kt @@ -1,9 +1,29 @@ import kotlin.reflect.KClass -/** should load cls */ -annotation class Anno(val p: String = "", val x: Array = arrayOf(Anno(p="a"), Anno(p="b"))) +@Target(*[AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION]) +annotation class Anno2() -/** should load cls */ +@Target(allowedTargets = [AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION]) +annotation class Anno3() + +@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION) +annotation class Anno4() + +@Target(*arrayOf(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION)) +annotation class Anno5() + +@Target(allowedTargets = arrayOf(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION)) +annotation class Anno6() + +annotation class AnnoWithCompanion() { + companion object { + fun foo() {} + @JvmField + val x: Int = 42 + } +} + +annotation class Anno(val p: String = "", val x: Array = arrayOf(Anno(p = "a"), Anno(p = "b"))) @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION) @Retention(AnnotationRetention.SOURCE) @@ -11,15 +31,14 @@ annotation class Anno(val p: String = "", val x: Array = arrayOf(Anno(p="a @Deprecated("This anno is deprecated, use === instead", ReplaceWith("this === other")) annotation class Fancy -/** should load cls */ annotation class ReplaceWith(val expression: String) -/** should load cls */ +annotation class AnnotatedAttribute(@get:Anno val x: String) + annotation class Deprecated( val message: String, val replaceWith: ReplaceWith = ReplaceWith("")) -/** should load cls */ annotation class Ann(val arg1: KClass<*>, val arg2: KClass) @@ -39,6 +58,6 @@ class Foo @Anno constructor(dependency: MyDependency) { @Ann(String::class, Int::class) class MyClass -class Example(@field:Ann val foo, // annotate Java field - @get:Ann val bar, // annotate Java getter - @param:Ann val quux) // annotate Java constructor parameter +class Example(@field:Ann val foo: String, // annotate Java field + @get:Ann val bar: String, // annotate Java getter + @param:Ann val quux: String) // annotate Java constructor parameter diff --git a/compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.java b/compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.java index f0c9811f56a..de2399934c7 100644 --- a/compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.java +++ b/compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.java @@ -1,11 +1,11 @@ -@java.lang.annotation.Retention(null=java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) public abstract @interface SimpleAnn /* SimpleAnn*/ { @null() public abstract java.lang.String value(); } -@java.lang.annotation.Retention(null=java.lang.annotation.RetentionPolicy.RUNTIME) +@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME) public abstract @interface Ann /* Ann*/ { @null() public abstract SimpleAnn[] t(); @@ -27,16 +27,16 @@ public abstract @interface Ann /* Ann*/ { } public abstract interface Base /* Base*/ { - @Ann(null=1, null="134", null=String::class, null=arrayOf(Int::class, Double::class), null=DeprecationLevel.WARNING, null=SimpleAnn("243"), null=SimpleAnn("4324")) - public abstract void foo(@Ann(null=2, null="324", null=Ann::class, null=arrayOf(Byte::class, Base::class), null=DeprecationLevel.WARNING, null=SimpleAnn("687"), null=SimpleAnn("78")) @org.jetbrains.annotations.NotNull() java.lang.String); + @Ann(x = 1, y = "134", z = String::class, e = {Int::class, Double::class}, depr = DeprecationLevel.WARNING, t = {@SimpleAnn(value = "243"), @SimpleAnn(value = "4324")}) + public abstract void foo(@Ann(x = 2, y = "324", z = Ann::class, e = {Byte::class, Base::class}, depr = DeprecationLevel.WARNING, t = {@SimpleAnn(value = "687"), @SimpleAnn(value = "78")}) @org.jetbrains.annotations.NotNull() java.lang.String); } public final class Derived /* Derived*/ implements Base { - @Ann(x=1, y="134", z=java.lang.String.class, e={int.class, double.class}, depr=kotlin.DeprecationLevel.WARNING, t={@SimpleAnn(value="243"), @SimpleAnn(value="4324")}) - public void foo(@Ann(x=2, y="324", z=Ann.class, e={byte.class, Base.class}, depr=kotlin.DeprecationLevel.WARNING, t={@SimpleAnn(value="687"), @SimpleAnn(value="78")}) @org.jetbrains.annotations.NotNull() java.lang.String); + @Ann(x = 1, y = "134", z = java.lang.String.class, e = {int.class, double.class}, depr = kotlin.DeprecationLevel.WARNING, t = {@SimpleAnn(value="243"), @SimpleAnn(value="4324")}) + public void foo(@Ann(x = 2, y = "324", z = Ann.class, e = {byte.class, Base.class}, depr = kotlin.DeprecationLevel.WARNING, t = {@SimpleAnn(value="687"), @SimpleAnn(value="78")}) @org.jetbrains.annotations.NotNull() java.lang.String); @null() public Derived(@org.jetbrains.annotations.NotNull() Base); -} +} \ No newline at end of file diff --git a/compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.kt b/compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.kt index d0b4393ecb9..de4234f85b6 100644 --- a/compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.kt +++ b/compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.kt @@ -1,15 +1,13 @@ import kotlin.reflect.KClass -/** should load cls */ annotation class SimpleAnn(val value: String) -/** should load cls */ annotation class Ann( val x: Int, val y: String, val z: KClass<*>, val e: Array>, - val depr: DeprecationLevel + val depr: DeprecationLevel, vararg val t: SimpleAnn ) diff --git a/idea/idea-completion/testData/injava/AnnotationParameter.java b/idea/idea-completion/testData/injava/AnnotationParameter.java index da8f1efbe56..1b2f50cac0b 100644 --- a/idea/idea-completion/testData/injava/AnnotationParameter.java +++ b/idea/idea-completion/testData/injava/AnnotationParameter.java @@ -5,5 +5,4 @@ public class Testing { } // EXIST: c -// EXIST: d -// LIGHT_CLASS: mockLib.foo.Anno \ No newline at end of file +// EXIST: d \ No newline at end of file diff --git a/idea/idea-completion/testData/injava/SingleFileFacadeMembers.java b/idea/idea-completion/testData/injava/SingleFileFacadeMembers.java index 70080176d59..47e04a8922e 100644 --- a/idea/idea-completion/testData/injava/SingleFileFacadeMembers.java +++ b/idea/idea-completion/testData/injava/SingleFileFacadeMembers.java @@ -8,4 +8,3 @@ public class Testing { // EXIST: topLevelExtFunction // EXIST: getTopLevelVar // EXIST: setTopLevelVar -// LIGHT_CLASS: mockLib.foo.MainKt diff --git a/idea/idea-completion/testData/injava/TopLevelMembers.java b/idea/idea-completion/testData/injava/TopLevelMembers.java index 9498d896910..a1aa345f8ae 100644 --- a/idea/idea-completion/testData/injava/TopLevelMembers.java +++ b/idea/idea-completion/testData/injava/TopLevelMembers.java @@ -6,5 +6,4 @@ public class Testing { // EXIST: topLevelFunction // EXIST: topLevelExtFunction -// EXIST: getTopLevelVar, setTopLevelVar -// LIGHT_CLASS: mockLib.foo.MainKt \ No newline at end of file +// EXIST: getTopLevelVar, setTopLevelVar \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/asJava/KtLightAnnotationTest.kt b/idea/tests/org/jetbrains/kotlin/asJava/KtLightAnnotationTest.kt index 3b51d460534..95981fd8ab2 100644 --- a/idea/tests/org/jetbrains/kotlin/asJava/KtLightAnnotationTest.kt +++ b/idea/tests/org/jetbrains/kotlin/asJava/KtLightAnnotationTest.kt @@ -467,6 +467,26 @@ class KtLightAnnotationTest : KotlinLightCodeInsightFixtureTestCase() { } + fun testKtVarargAnnotation() { + + myFixture.configureByText("Anno.kt", """ + annotation class Anno(vararg val vars: String) + """) + myFixture.configureByText("AnnotatedClass.kt", """ + @Anno("hello", "world") + class MyAnnotated + """.trimIndent()) + + val annotations = myFixture.findClass("MyAnnotated").expectAnnotations(1) + val annotationAttributeVal = annotations.first().findAttributeValue("vars") + annotationAttributeVal as PsiArrayInitializerMemberValue + assertTextAndRange("(\"hello\", \"world\")", annotationAttributeVal) + UsefulTestCase.assertInstanceOf(annotationAttributeVal.parent, PsiNameValuePair::class.java) + UsefulTestCase.assertEquals(annotationAttributeVal.initializers.size, 2) + assertTextAndRange("\"hello\"", annotationAttributeVal.initializers[0]) + assertTextAndRange("\"world\"", annotationAttributeVal.initializers[1]) + } + private fun doVarargTest(type: String, parameters: List) { val paramsJoined = parameters.joinToString(", ") @@ -574,7 +594,7 @@ class KtLightAnnotationTest : KotlinLightCodeInsightFixtureTestCase() { """.trimIndent()) myFixture.configureByText("AnnotatedClass.kt", """ - @Annotation(value = "a") + @Annotation("a") open class AnnotatedClass """.trimIndent()) myFixture.testHighlighting("Annotation.java", "AnnotatedClass.kt") diff --git a/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt b/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt index 20b186e27ba..921f4f44f94 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt @@ -16,10 +16,12 @@ import junit.framework.TestCase import org.jetbrains.kotlin.asJava.LightClassGenerationSupport import org.jetbrains.kotlin.asJava.classes.* import org.jetbrains.kotlin.asJava.elements.KtLightNullabilityAnnotation +import org.jetbrains.kotlin.asJava.elements.KtLightPsiArrayInitializerMemberValue import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.load.kotlin.NON_EXISTENT_CLASS_NAME import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtFile import org.junit.Assert @@ -94,23 +96,40 @@ object UltraLightChecker { } } - private fun PsiAnnotation.renderAnnotation() = - "@" + qualifiedName + "(" + parameterList.attributes.joinToString { it.name + "=" + (it.value?.text ?: "?") } + ")" + private fun PsiAnnotation.renderAnnotation(): String { + + val renderedAttributes = parameterList.attributes.map { + val attributeValue = it.value?.renderAnnotationMemberValue() ?: "?" + + val name = when { + it.name === null && qualifiedName?.startsWith("java.lang.annotation.") == true -> "value" + else -> it.name + } + + if (name !== null) "$name = $attributeValue" else attributeValue + } + return "@$qualifiedName(${renderedAttributes.joinToString()})" + } + private fun PsiModifierListOwner.renderModifiers(typeIfApplicable: PsiType? = null): String { - val buffer = StringBuilder() + val annotationsBuffer = mutableListOf() for (annotation in annotations) { if (annotation is KtLightNullabilityAnnotation<*> && skipRenderingNullability(typeIfApplicable)) { continue } - buffer.append(annotation.renderAnnotation()) - buffer.append(if (this is PsiParameter) " " else "\n") + annotationsBuffer.add( + annotation.renderAnnotation() + (if (this is PsiParameter) " " else "\n") + ) } + annotationsBuffer.sort() + + val resultBuffer = StringBuffer(annotationsBuffer.joinToString(separator = "")) for (modifier in PsiModifier.MODIFIERS.filter(::hasModifierProperty)) { - buffer.append(modifier).append(" ") + resultBuffer.append(modifier).append(" ") } - return buffer.toString() + return resultBuffer.toString() } private fun PsiModifierListOwner.skipRenderingNullability(typeIfApplicable: PsiType?) = @@ -127,9 +146,17 @@ object UltraLightChecker { private fun PsiType.renderType() = getCanonicalText(true) - private fun PsiReferenceList?.renderRefList(keyword: String): String { - if (this == null || this.referencedTypes.isEmpty()) return "" - return " " + keyword + " " + referencedTypes.joinToString { it.renderType() } + private fun PsiReferenceList?.renderRefList(keyword: String, sortReferences: Boolean = true): String { + if (this == null) return "" + + val references = referencedTypes + if (references.isEmpty()) return "" + + val referencesTypes = references.map { it.renderType() }.toTypedArray() + + if (sortReferences) referencesTypes.sort() + + return " " + keyword + " " + referencesTypes.joinToString() } private fun PsiVariable.renderVar(): String { @@ -151,6 +178,12 @@ object UltraLightChecker { it.name!! + bounds } + "> " + private fun PsiAnnotationMemberValue.renderAnnotationMemberValue(): String = when (this) { + is KtLightPsiArrayInitializerMemberValue -> "{${initializers.joinToString { it.renderAnnotationMemberValue() }}}" + is PsiAnnotation -> renderAnnotation() + else -> text + } + private fun PsiMethod.renderMethod() = renderModifiers(returnType) + (if (isVarArgs) "/* vararg */ " else "") + @@ -158,7 +191,7 @@ object UltraLightChecker { (returnType?.renderType() ?: "") + " " + name + "(" + parameterList.parameters.joinToString { it.renderModifiers(it.type) + it.type.renderType() } + ")" + - (this as? PsiAnnotationMethod)?.defaultValue?.let { " default " + it.text }.orEmpty() + + (this as? PsiAnnotationMethod)?.defaultValue?.let { " default " + it.renderAnnotationMemberValue() }.orEmpty() + throwsList.referencedTypes.let { thrownTypes -> if (thrownTypes.isEmpty()) "" else " throws " + thrownTypes.joinToString { it.renderType() } diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsTest.kt.182 b/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsTest.kt.182 index fbe58a796da..06ecd0ea6ba 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsTest.kt.182 +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsTest.kt.182 @@ -287,7 +287,7 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() { TestCase.assertEquals( "KtUltraLightMethodForSourceDeclaration -> org.jetbrains.annotations.NotNull," + - " KtUltraLightField -> pkg.myannotation.JavaAnnotation, org.jetbrains.annotations.NotNull", + " KtUltraLightFieldForSourceDeclaration -> pkg.myannotation.JavaAnnotation, org.jetbrains.annotations.NotNull", annotationsString(myFixture.findElementByText("bar", KtModifierListOwner::class.java)) ) } @@ -339,7 +339,7 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() { TestCase.assertEquals( "KtUltraLightMethodForSourceDeclaration -> org.jetbrains.annotations.NotNull," + - " KtUltraLightField -> pkg.myannotation.JavaAnnotation, org.jetbrains.annotations.NotNull", + " KtUltraLightFieldForSourceDeclaration -> pkg.myannotation.JavaAnnotation, org.jetbrains.annotations.NotNull", annotationsString(myFixture.findElementByText("bar", KtModifierListOwner::class.java)) ) }