Change to star projection: do not suggest in arguments or receiver
#KT-23259 Fixed
This commit is contained in:
committed by
Dmitry Gridin
parent
73396b5018
commit
4e3d13fcee
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user