Change to star projection: do not suggest in arguments or receiver

#KT-23259 Fixed
This commit is contained in:
Toshiaki Kameyama
2019-02-13 16:54:00 +09:00
committed by Dmitry Gridin
parent 73396b5018
commit 4e3d13fcee
19 changed files with 196 additions and 2 deletions
@@ -20,8 +20,14 @@ import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypes
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
class ChangeToStarProjectionFix(element: KtTypeElement) : KotlinQuickFixAction<KtTypeElement>(element) {
override fun getFamilyName() = "Change to star projection"
@@ -36,14 +42,38 @@ class ChangeToStarProjectionFix(element: KtTypeElement) : KotlinQuickFixAction<K
companion object : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val typeReference = diagnostic.psiElement.getNonStrictParentOfType<KtBinaryExpressionWithTypeRHS>()?.right
?: diagnostic.psiElement.getNonStrictParentOfType<KtTypeReference>()
val binaryExpr = diagnostic.psiElement.getNonStrictParentOfType<KtBinaryExpressionWithTypeRHS>()
val typeReference = binaryExpr?.right ?: diagnostic.psiElement.getNonStrictParentOfType<KtTypeReference>()
val typeElement = typeReference?.typeElement ?: return null
if (typeElement is KtFunctionType) return null
if (binaryExpr?.operationReference?.isAsKeyword() == true) {
val parent = binaryExpr.getParentOfTypes(true, KtValueArgument::class.java, KtQualifiedExpression::class.java)
val type = when (parent) {
is KtValueArgument -> {
val callExpr = parent.getStrictParentOfType<KtCallExpression>()
(callExpr?.resolveToCall()?.getArgumentMapping(parent) as? ArgumentMatch)?.valueParameter?.original?.type
}
is KtQualifiedExpression ->
if (KtPsiUtil.safeDeparenthesize(parent.receiverExpression) == binaryExpr)
parent.resolveToCall()?.resultingDescriptor?.extensionReceiverParameter?.value?.original?.type
else
null
else ->
null
}
if (type?.arguments?.any { !it.isStarProjection && !it.type.isTypeParameter() } == true) return null
}
if (typeElement.typeArgumentsAsTypes.isNotEmpty()) {
return ChangeToStarProjectionFix(typeElement)
}
return null
}
private fun KtSimpleNameExpression.isAsKeyword(): Boolean {
val elementType = getReferencedNameElementType()
return elementType == KtTokens.AS_KEYWORD || elementType == KtTokens.AS_SAFE
}
}
}
@@ -0,0 +1,8 @@
// "Change type arguments to <*>" "false"
// ACTION: Convert to run
// ACTION: Convert to with
fun test(a: Any) {
(a as List<Boolean><caret>).bar()
}
fun List<Boolean>.bar() {}
@@ -0,0 +1,8 @@
// "Change type arguments to <*, *>" "false"
// ACTION: Convert to run
// ACTION: Convert to with
fun test(a: Any) {
(a as Map<Int, Boolean><caret>).bar()
}
fun Map<Int, Boolean>.bar() {}
@@ -0,0 +1,6 @@
// "Change type arguments to <*>" "true"
fun test(a: Any) {
(a as List<Boolean><caret>).bar()
}
fun List<*>.bar() {}
@@ -0,0 +1,6 @@
// "Change type arguments to <*>" "true"
fun test(a: Any) {
(a as List<*>).bar()
}
fun List<*>.bar() {}
@@ -0,0 +1,6 @@
// "Change type arguments to <*>" "true"
fun test(a: Any) {
(a as List<Boolean><caret>).bar()
}
fun <T> List<T>.bar() {}
@@ -0,0 +1,6 @@
// "Change type arguments to <*>" "true"
fun test(a: Any) {
(a as List<*>).bar()
}
fun <T> List<T>.bar() {}
@@ -0,0 +1,6 @@
// "Change type arguments to <*, *>" "true"
fun test(a: Any) {
(a as Map<Int, Boolean><caret>).bar()
}
fun <T> Map<T, *>.bar() {}
@@ -0,0 +1,6 @@
// "Change type arguments to <*, *>" "true"
fun test(a: Any) {
(a as Map<*, *>).bar()
}
fun <T> Map<T, *>.bar() {}
@@ -0,0 +1,7 @@
// "Change type arguments to <*>" "false"
// ACTION: Add 'list =' to argument
fun test(a: Any) {
foo(a as List<Boolean><caret>)
}
fun foo(list: List<Boolean>) {}
@@ -0,0 +1,7 @@
// "Change type arguments to <*, *>" "false"
// ACTION: Add 'map =' to argument
fun test(a: Any) {
foo(a as Map<Int, Boolean><caret>)
}
fun foo(map: Map<Int, Boolean>) {}
@@ -0,0 +1,6 @@
// "Change type arguments to <*>" "true"
fun test(a: Any) {
foo(a as List<Boolean><caret>)
}
fun foo(list: List<*>) {}
@@ -0,0 +1,6 @@
// "Change type arguments to <*>" "true"
fun test(a: Any) {
foo(a as List<*>)
}
fun foo(list: List<*>) {}
@@ -0,0 +1,6 @@
// "Change type arguments to <*>" "true"
fun test(a: Any) {
foo(a as List<Boolean><caret>)
}
fun <T> foo(list: List<T>) {}
@@ -0,0 +1,6 @@
// "Change type arguments to <*>" "true"
fun test(a: Any) {
foo(a as List<*>)
}
fun <T> foo(list: List<T>) {}
@@ -0,0 +1,6 @@
// "Change type arguments to <*, *>" "true"
fun test(a: Any) {
foo(a as Map<Int, Boolean><caret>)
}
fun <T> foo(map: Map<T, *>) {}
@@ -0,0 +1,6 @@
// "Change type arguments to <*, *>" "true"
fun test(a: Any) {
foo(a as Map<*, *>)
}
fun <T> foo(map: Map<T, *>) {}
@@ -0,0 +1,7 @@
// "Change type arguments to <*>" "false"
// ACTION: Add 'list =' to argument
fun test(a: Any) {
foo(a as? List<Boolean><caret>)
}
fun foo(list: List<Boolean>?) {}
@@ -1075,10 +1075,65 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
runTest("idea/testData/quickfix/addStarProjections/cast/changeToStarProjectionNullable.kt");
}
@TestMetadata("extensionReceiver.kt")
public void testExtensionReceiver() throws Exception {
runTest("idea/testData/quickfix/addStarProjections/cast/extensionReceiver.kt");
}
@TestMetadata("extensionReceiver2.kt")
public void testExtensionReceiver2() throws Exception {
runTest("idea/testData/quickfix/addStarProjections/cast/extensionReceiver2.kt");
}
@TestMetadata("extensionReceiver3.kt")
public void testExtensionReceiver3() throws Exception {
runTest("idea/testData/quickfix/addStarProjections/cast/extensionReceiver3.kt");
}
@TestMetadata("extensionReceiver4.kt")
public void testExtensionReceiver4() throws Exception {
runTest("idea/testData/quickfix/addStarProjections/cast/extensionReceiver4.kt");
}
@TestMetadata("extensionReceiver5.kt")
public void testExtensionReceiver5() throws Exception {
runTest("idea/testData/quickfix/addStarProjections/cast/extensionReceiver5.kt");
}
@TestMetadata("uncheckedCastOnTypeParameter.kt")
public void testUncheckedCastOnTypeParameter() throws Exception {
runTest("idea/testData/quickfix/addStarProjections/cast/uncheckedCastOnTypeParameter.kt");
}
@TestMetadata("valueArgument.kt")
public void testValueArgument() throws Exception {
runTest("idea/testData/quickfix/addStarProjections/cast/valueArgument.kt");
}
@TestMetadata("valueArgument2.kt")
public void testValueArgument2() throws Exception {
runTest("idea/testData/quickfix/addStarProjections/cast/valueArgument2.kt");
}
@TestMetadata("valueArgument3.kt")
public void testValueArgument3() throws Exception {
runTest("idea/testData/quickfix/addStarProjections/cast/valueArgument3.kt");
}
@TestMetadata("valueArgument4.kt")
public void testValueArgument4() throws Exception {
runTest("idea/testData/quickfix/addStarProjections/cast/valueArgument4.kt");
}
@TestMetadata("valueArgument5.kt")
public void testValueArgument5() throws Exception {
runTest("idea/testData/quickfix/addStarProjections/cast/valueArgument5.kt");
}
@TestMetadata("valueArgument6.kt")
public void testValueArgument6() throws Exception {
runTest("idea/testData/quickfix/addStarProjections/cast/valueArgument6.kt");
}
}
@TestMetadata("idea/testData/quickfix/addStarProjections/checkType")