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:
@@ -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>
|
||||
)
|
||||
@@ -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>
|
||||
)
|
||||
@@ -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>
|
||||
)
|
||||
@@ -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>
|
||||
)
|
||||
@@ -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>
|
||||
)
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user