Implement quick fix for "Invalid type of annotation member"

Quickfix changes array of boxed type to array of primitive type

#KT-8568 Fixed
This commit is contained in:
Vyacheslav Gerasimov
2017-03-14 16:56:37 +03:00
parent b8563f7fcf
commit 087551ad61
19 changed files with 231 additions and 0 deletions
@@ -483,5 +483,6 @@ class QuickFixRegistrar : QuickFixContributor {
UNRESOLVED_REFERENCE.registerFactory(CreateLabelFix)
YIELD_IS_RESERVED.registerFactory(UnsupportedYieldFix)
INVALID_TYPE_OF_ANNOTATION_MEMBER.registerFactory(TypeOfAnnotationMemberFix)
}
}
@@ -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<KtTypeReference>(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)
}
}
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "true"
annotation class SuperAnnotation(
val boo: <caret>Array<Boolean>,
val str: Array<String>
)
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "true"
annotation class SuperAnnotation(
val boo: BooleanArray,
val str: Array<String>
)
+5
View File
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "true"
annotation class SuperAnnotation(
val b: <caret>Array<Byte>,
val str: Array<String>
)
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "true"
annotation class SuperAnnotation(
val b: ByteArray,
val str: Array<String>
)
+5
View File
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "true"
annotation class SuperAnnotation(
val c: <caret>Array<Char>,
val str: Array<String>
)
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "true"
annotation class SuperAnnotation(
val c: CharArray,
val str: Array<String>
)
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "true"
annotation class SuperAnnotation(
val f: <caret>Array<Float>,
val str: Array<String>
)
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "true"
annotation class SuperAnnotation(
val f: FloatArray,
val str: Array<String>
)
+5
View File
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "true"
annotation class SuperAnnotation(
val i: <caret>Array<Int>,
val str: Array<String>
)
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "true"
annotation class SuperAnnotation(
val i: IntArray,
val str: Array<String>
)
+5
View File
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "true"
annotation class SuperAnnotation(
val l: <caret>Array<Long>,
val str: Array<String>
)
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "true"
annotation class SuperAnnotation(
val l: LongArray,
val str: Array<String>
)
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "true"
annotation class SuperAnnotation(
val s: <caret>Array<Short>,
val str: Array<String>
)
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "true"
annotation class SuperAnnotation(
val s: ShortArray,
val str: Array<String>
)
+7
View File
@@ -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: <caret>Array<*>,
val str: Array<String>
)
@@ -0,0 +1,5 @@
// "Replace array of boxed with array of primitive" "false"
// ACTION: Convert to secondary constructor
annotation class SuperAnnotation(
val str: <caret>Array<String>
)
@@ -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)