diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index ce673c3762f..8e369d0502b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -483,5 +483,6 @@ class QuickFixRegistrar : QuickFixContributor { UNRESOLVED_REFERENCE.registerFactory(CreateLabelFix) YIELD_IS_RESERVED.registerFactory(UnsupportedYieldFix) + INVALID_TYPE_OF_ANNOTATION_MEMBER.registerFactory(TypeOfAnnotationMemberFix) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/TypeOfAnnotationMemberFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/TypeOfAnnotationMemberFix.kt new file mode 100644 index 00000000000..bbb0edd7580 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/TypeOfAnnotationMemberFix.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2010-2017 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.kotlin.idea.quickfix + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.psi.KtTypeReference +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.types.KotlinType + +class TypeOfAnnotationMemberFix( + typeReference: KtTypeReference, + private val fixedType: String +): KotlinQuickFixAction(typeReference), CleanupFix { + override fun getText(): String = "Replace array of boxed with array of primitive" + + override fun getFamilyName(): String = text + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + val psiElement = element ?: return + psiElement.replace(KtPsiFactory(psiElement).createType(fixedType)) + } + + companion object : KotlinSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): IntentionAction? { + val typeReference = diagnostic.psiElement as? KtTypeReference ?: return null + val type = typeReference.analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, typeReference] ?: return null + + val itemType = type.getArrayItemType() ?: return null + val itemTypeName = itemType.constructor.declarationDescriptor?.name?.asString() ?: return null + val fixedArrayTypeText = if (itemType.isItemTypeToFix()) { + "${itemTypeName}Array" + } + else { + return null + } + + return TypeOfAnnotationMemberFix(typeReference, fixedArrayTypeText) + } + + private fun KotlinType.getArrayItemType(): KotlinType? { + if (!KotlinBuiltIns.isArray(this)) { + return null + } + + val boxedType = arguments.singleOrNull() ?: return null + if (boxedType.isStarProjection) { + return null + } + + return boxedType.type + } + + private fun KotlinType.isItemTypeToFix() = + KotlinBuiltIns.isByte(this) + || KotlinBuiltIns.isChar(this) + || KotlinBuiltIns.isShort(this) + || KotlinBuiltIns.isInt(this) + || KotlinBuiltIns.isLong(this) + || KotlinBuiltIns.isFloat(this) + || KotlinBuiltIns.isDouble(this) + || KotlinBuiltIns.isBoolean(this) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/boolean.kt b/idea/testData/quickfix/typeOfAnnotationMember/boolean.kt new file mode 100644 index 00000000000..003396f2634 --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/boolean.kt @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "true" +annotation class SuperAnnotation( + val boo: Array, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/boolean.kt.after b/idea/testData/quickfix/typeOfAnnotationMember/boolean.kt.after new file mode 100644 index 00000000000..def8ca8b6e1 --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/boolean.kt.after @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "true" +annotation class SuperAnnotation( + val boo: BooleanArray, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/byte.kt b/idea/testData/quickfix/typeOfAnnotationMember/byte.kt new file mode 100644 index 00000000000..8653266abda --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/byte.kt @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "true" +annotation class SuperAnnotation( + val b: Array, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/byte.kt.after b/idea/testData/quickfix/typeOfAnnotationMember/byte.kt.after new file mode 100644 index 00000000000..f6f2989aba6 --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/byte.kt.after @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "true" +annotation class SuperAnnotation( + val b: ByteArray, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/char.kt b/idea/testData/quickfix/typeOfAnnotationMember/char.kt new file mode 100644 index 00000000000..900bc801627 --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/char.kt @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "true" +annotation class SuperAnnotation( + val c: Array, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/char.kt.after b/idea/testData/quickfix/typeOfAnnotationMember/char.kt.after new file mode 100644 index 00000000000..3cbbb974006 --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/char.kt.after @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "true" +annotation class SuperAnnotation( + val c: CharArray, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/float.kt b/idea/testData/quickfix/typeOfAnnotationMember/float.kt new file mode 100644 index 00000000000..108870753a3 --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/float.kt @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "true" +annotation class SuperAnnotation( + val f: Array, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/float.kt.after b/idea/testData/quickfix/typeOfAnnotationMember/float.kt.after new file mode 100644 index 00000000000..41ca80a59fc --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/float.kt.after @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "true" +annotation class SuperAnnotation( + val f: FloatArray, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/int.kt b/idea/testData/quickfix/typeOfAnnotationMember/int.kt new file mode 100644 index 00000000000..3359500ab4f --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/int.kt @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "true" +annotation class SuperAnnotation( + val i: Array, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/int.kt.after b/idea/testData/quickfix/typeOfAnnotationMember/int.kt.after new file mode 100644 index 00000000000..791997c8441 --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/int.kt.after @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "true" +annotation class SuperAnnotation( + val i: IntArray, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/long.kt b/idea/testData/quickfix/typeOfAnnotationMember/long.kt new file mode 100644 index 00000000000..ee22890366d --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/long.kt @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "true" +annotation class SuperAnnotation( + val l: Array, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/long.kt.after b/idea/testData/quickfix/typeOfAnnotationMember/long.kt.after new file mode 100644 index 00000000000..ce62f6b99c7 --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/long.kt.after @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "true" +annotation class SuperAnnotation( + val l: LongArray, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/short.kt b/idea/testData/quickfix/typeOfAnnotationMember/short.kt new file mode 100644 index 00000000000..1805fcf7b11 --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/short.kt @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "true" +annotation class SuperAnnotation( + val s: Array, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/short.kt.after b/idea/testData/quickfix/typeOfAnnotationMember/short.kt.after new file mode 100644 index 00000000000..b169d5fa7f2 --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/short.kt.after @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "true" +annotation class SuperAnnotation( + val s: ShortArray, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/star.kt b/idea/testData/quickfix/typeOfAnnotationMember/star.kt new file mode 100644 index 00000000000..256be03280d --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/star.kt @@ -0,0 +1,7 @@ +// "Replace array of boxed with array of primitive" "false" +// ACTION: Convert to secondary constructor +// ERROR: Invalid type of annotation member +annotation class SuperAnnotation( + val foo: Array<*>, + val str: Array +) \ No newline at end of file diff --git a/idea/testData/quickfix/typeOfAnnotationMember/string.kt b/idea/testData/quickfix/typeOfAnnotationMember/string.kt new file mode 100644 index 00000000000..c0727380cc0 --- /dev/null +++ b/idea/testData/quickfix/typeOfAnnotationMember/string.kt @@ -0,0 +1,5 @@ +// "Replace array of boxed with array of primitive" "false" +// ACTION: Convert to secondary constructor +annotation class SuperAnnotation( + val str: Array +) \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 6926dd74f61..502e567568d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -10108,6 +10108,69 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/typeOfAnnotationMember") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class TypeOfAnnotationMember extends AbstractQuickFixTest { + public void testAllFilesPresentInTypeOfAnnotationMember() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/typeOfAnnotationMember"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("boolean.kt") + public void testBoolean() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeOfAnnotationMember/boolean.kt"); + doTest(fileName); + } + + @TestMetadata("byte.kt") + public void testByte() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeOfAnnotationMember/byte.kt"); + doTest(fileName); + } + + @TestMetadata("char.kt") + public void testChar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeOfAnnotationMember/char.kt"); + doTest(fileName); + } + + @TestMetadata("float.kt") + public void testFloat() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeOfAnnotationMember/float.kt"); + doTest(fileName); + } + + @TestMetadata("int.kt") + public void testInt() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeOfAnnotationMember/int.kt"); + doTest(fileName); + } + + @TestMetadata("long.kt") + public void testLong() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeOfAnnotationMember/long.kt"); + doTest(fileName); + } + + @TestMetadata("short.kt") + public void testShort() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeOfAnnotationMember/short.kt"); + doTest(fileName); + } + + @TestMetadata("star.kt") + public void testStar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeOfAnnotationMember/star.kt"); + doTest(fileName); + } + + @TestMetadata("string.kt") + public void testString() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/typeOfAnnotationMember/string.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/quickfix/typeParameters") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)