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.editor.Editor
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
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.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
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) {
|
class ChangeToStarProjectionFix(element: KtTypeElement) : KotlinQuickFixAction<KtTypeElement>(element) {
|
||||||
override fun getFamilyName() = "Change to star projection"
|
override fun getFamilyName() = "Change to star projection"
|
||||||
@@ -36,14 +42,38 @@ class ChangeToStarProjectionFix(element: KtTypeElement) : KotlinQuickFixAction<K
|
|||||||
|
|
||||||
companion object : KotlinSingleIntentionActionFactory() {
|
companion object : KotlinSingleIntentionActionFactory() {
|
||||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||||
val typeReference = diagnostic.psiElement.getNonStrictParentOfType<KtBinaryExpressionWithTypeRHS>()?.right
|
val binaryExpr = diagnostic.psiElement.getNonStrictParentOfType<KtBinaryExpressionWithTypeRHS>()
|
||||||
?: diagnostic.psiElement.getNonStrictParentOfType<KtTypeReference>()
|
val typeReference = binaryExpr?.right ?: diagnostic.psiElement.getNonStrictParentOfType<KtTypeReference>()
|
||||||
val typeElement = typeReference?.typeElement ?: return null
|
val typeElement = typeReference?.typeElement ?: return null
|
||||||
if (typeElement is KtFunctionType) 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()) {
|
if (typeElement.typeArgumentsAsTypes.isNotEmpty()) {
|
||||||
return ChangeToStarProjectionFix(typeElement)
|
return ChangeToStarProjectionFix(typeElement)
|
||||||
}
|
}
|
||||||
return null
|
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");
|
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")
|
@TestMetadata("uncheckedCastOnTypeParameter.kt")
|
||||||
public void testUncheckedCastOnTypeParameter() throws Exception {
|
public void testUncheckedCastOnTypeParameter() throws Exception {
|
||||||
runTest("idea/testData/quickfix/addStarProjections/cast/uncheckedCastOnTypeParameter.kt");
|
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")
|
@TestMetadata("idea/testData/quickfix/addStarProjections/checkType")
|
||||||
|
|||||||
Reference in New Issue
Block a user