mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] Quickfix update: change T to T & Any (CR fixes)
* Removed the check that prevented unsafe cast action for DNN types: this behavior is more consistent as unsafe casts are allowed for other types. * Removed unnecessary DNN feature check. * Added the action to change the type of a variable. * Refactored and cleaned up the code. * Updated tests. ^KTIJ-20425 Fixed (cherry picked from commit 6f685e1f4dda27282fd9ec37caef5785e3b27838) GitOrigin-RevId: 0f5811fae3442c3246ec91e1a52ebfc046f8e214
This commit is contained in:
committed by
intellij-monorepo-bot
parent
c2afb0763b
commit
5e91e7fb01
-10
@@ -2529,16 +2529,6 @@ public abstract class HighLevelQuickFixTestGenerated extends AbstractHighLevelQu
|
||||
runTest("../idea/tests/testData/quickfix/typeMismatch/casts/typeMismatch4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeMismatchDefNonNullable1.kt")
|
||||
public void testTypeMismatchDefNonNullable1() throws Exception {
|
||||
runTest("../idea/tests/testData/quickfix/typeMismatch/casts/typeMismatchDefNonNullable1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeMismatchDefNonNullable2.kt")
|
||||
public void testTypeMismatchDefNonNullable2() throws Exception {
|
||||
runTest("../idea/tests/testData/quickfix/typeMismatch/casts/typeMismatchDefNonNullable2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeMismatchLongNameRuntime.kt")
|
||||
public void testTypeMismatchLongNameRuntime() throws Exception {
|
||||
runTest("../idea/tests/testData/quickfix/typeMismatch/casts/typeMismatchLongNameRuntime.kt");
|
||||
|
||||
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.isDefinitelyNotNullType
|
||||
|
||||
class ChangeParameterTypeFix(element: KtParameter, type: KotlinType) : KotlinQuickFixAction<KtParameter>(element) {
|
||||
private val typePresentation = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderType(type)
|
||||
|
||||
+19
-25
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.jvm.ir.psiElement
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.isKFunctionType
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
@@ -22,7 +23,6 @@ import org.jetbrains.kotlin.idea.intentions.reflectToRegularFunctionType
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.util.approximateWithResolvableType
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.idea.util.module
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
|
||||
@@ -153,33 +153,10 @@ class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() {
|
||||
return qualifiedOrThis
|
||||
}
|
||||
|
||||
// Check if the type is a definitely non-nullable type (`T & Any`)
|
||||
// or contains a definitely non-nullable type as a type argument (e.g., `Collection<T & Any>`)
|
||||
fun KotlinType.containsDefinitelyNotNullComponent(): Boolean {
|
||||
if (isDefinitelyNotNullType) return true
|
||||
return arguments.any { it.type.containsDefinitelyNotNullComponent() }
|
||||
}
|
||||
|
||||
// Suggest replacing type argument `T` with its expected definitely non-nullable subtype `T & Any`.
|
||||
// Types that contain DNN types as arguments (like `(Mutable)Collection<T & Any>`) are currently not supported.
|
||||
if (diagnosticElement is KtReferenceExpression &&
|
||||
expectedType.isDefinitelyNotNullType &&
|
||||
diagnosticElement.module?.languageVersionSettings?.supportsFeature(LanguageFeature.DefinitelyNonNullableTypes) == true
|
||||
) {
|
||||
val descriptor = context[BindingContext.REFERENCE_TARGET, diagnosticElement]?.safeAs<DeclarationDescriptorWithSource>()
|
||||
val parameter = descriptor?.psiElement?.safeAs<KtParameter>()
|
||||
val parentParameterList = parameter?.parent as? KtParameterList
|
||||
if (parameter != null && parentParameterList != null) {
|
||||
actions.add(ChangeParameterTypeFix(parameter, expectedType))
|
||||
}
|
||||
}
|
||||
|
||||
// We don't want to cast a cast or type-asserted expression.
|
||||
// We also don't want to cast a potentially nullable type `T` to its definitely non-nullable subtype `T & Any` as it is unsafe.
|
||||
if (diagnostic.factory != Errors.SIGNED_CONSTANT_CONVERTED_TO_UNSIGNED &&
|
||||
diagnosticElement !is KtBinaryExpressionWithTypeRHS &&
|
||||
diagnosticElement.parent !is KtBinaryExpressionWithTypeRHS &&
|
||||
!expectedType.containsDefinitelyNotNullComponent()
|
||||
diagnosticElement.parent !is KtBinaryExpressionWithTypeRHS
|
||||
) {
|
||||
actions.add(CastExpressionFix(diagnosticElement.getTopMostQualifiedForSelectorIfAny(), expectedType))
|
||||
}
|
||||
@@ -208,6 +185,23 @@ class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() {
|
||||
actions.add(createFix(callable, typeToInsert))
|
||||
}
|
||||
|
||||
// Suggest replacing the parameter type `T` with its expected definitely non-nullable subtype `T & Any`.
|
||||
// Types that contain DNN types as arguments (like `(Mutable)Collection<T & Any>`) are currently not supported.
|
||||
if (diagnosticElement is KtReferenceExpression && expectedType.isDefinitelyNotNullType) {
|
||||
val descriptor = context[BindingContext.REFERENCE_TARGET, diagnosticElement]?.safeAs<CallableDescriptor>()
|
||||
when (val declaration = QuickFixUtil.safeGetDeclaration(descriptor)) {
|
||||
is KtParameter -> {
|
||||
// Check the parent parameter list to avoid creating actions for loop iterators
|
||||
if (declaration.parent is KtParameterList) {
|
||||
actions.add(ChangeParameterTypeFix(declaration, expectedType))
|
||||
}
|
||||
}
|
||||
is KtProperty -> {
|
||||
addChangeTypeFix(declaration, expectedType, ::ChangeVariableTypeFix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Property initializer type mismatch property type:
|
||||
val property = PsiTreeUtil.getParentOfType(diagnosticElement, KtProperty::class.java)
|
||||
if (property != null) {
|
||||
|
||||
+43
-20
@@ -13988,16 +13988,6 @@ public abstract class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
runTest("testData/quickfix/typeMismatch/casts/typeMismatch4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeMismatchDefNonNullable1.kt")
|
||||
public void testTypeMismatchDefNonNullable1() throws Exception {
|
||||
runTest("testData/quickfix/typeMismatch/casts/typeMismatchDefNonNullable1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeMismatchDefNonNullable2.kt")
|
||||
public void testTypeMismatchDefNonNullable2() throws Exception {
|
||||
runTest("testData/quickfix/typeMismatch/casts/typeMismatchDefNonNullable2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeMismatchLongNameRuntime.kt")
|
||||
public void testTypeMismatchLongNameRuntime() throws Exception {
|
||||
runTest("testData/quickfix/typeMismatch/casts/typeMismatchLongNameRuntime.kt");
|
||||
@@ -14110,6 +14100,49 @@ public abstract class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("testData/quickfix/typeMismatch/definitelyNonNullableTypes")
|
||||
public static class DefinitelyNonNullableTypes extends AbstractQuickFixTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("changeFunctionParameterType1.kt")
|
||||
public void testChangeFunctionParameterType1() throws Exception {
|
||||
runTest("testData/quickfix/typeMismatch/definitelyNonNullableTypes/changeFunctionParameterType1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("changeFunctionParameterType2.kt")
|
||||
public void testChangeFunctionParameterType2() throws Exception {
|
||||
runTest("testData/quickfix/typeMismatch/definitelyNonNullableTypes/changeFunctionParameterType2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("changePrimaryConstructorParameterType.kt")
|
||||
public void testChangePrimaryConstructorParameterType() throws Exception {
|
||||
runTest("testData/quickfix/typeMismatch/definitelyNonNullableTypes/changePrimaryConstructorParameterType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("changeVariableType1.kt")
|
||||
public void testChangeVariableType1() throws Exception {
|
||||
runTest("testData/quickfix/typeMismatch/definitelyNonNullableTypes/changeVariableType1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("changeVariableType2.kt")
|
||||
public void testChangeVariableType2() throws Exception {
|
||||
runTest("testData/quickfix/typeMismatch/definitelyNonNullableTypes/changeVariableType2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("explicitCast1.kt")
|
||||
public void testExplicitCast1() throws Exception {
|
||||
runTest("testData/quickfix/typeMismatch/definitelyNonNullableTypes/explicitCast1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("explicitCast2.kt")
|
||||
public void testExplicitCast2() throws Exception {
|
||||
runTest("testData/quickfix/typeMismatch/definitelyNonNullableTypes/explicitCast2.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("testData/quickfix/typeMismatch/fixOverloadedOperator")
|
||||
public static class FixOverloadedOperator extends AbstractQuickFixTest {
|
||||
@@ -14188,16 +14221,6 @@ public abstract class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
runTest("testData/quickfix/typeMismatch/parameterTypeMismatch/changeFunctionParameterType4.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("changeFunctionParameterTypeDefNonNullable1.kt")
|
||||
public void testChangeFunctionParameterTypeDefNonNullable1() throws Exception {
|
||||
runTest("testData/quickfix/typeMismatch/parameterTypeMismatch/changeFunctionParameterTypeDefNonNullable1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("changeFunctionParameterTypeDefNonNullable2.kt")
|
||||
public void testChangeFunctionParameterTypeDefNonNullable2() throws Exception {
|
||||
runTest("testData/quickfix/typeMismatch/parameterTypeMismatch/changeFunctionParameterTypeDefNonNullable2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("changeFunctionParameterTypeWithComment.kt")
|
||||
public void testChangeFunctionParameterTypeWithComment() throws Exception {
|
||||
runTest("testData/quickfix/typeMismatch/parameterTypeMismatch/changeFunctionParameterTypeWithComment.kt");
|
||||
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
// "class org.jetbrains.kotlin.idea.quickfix.CastExpressionFix" "false"
|
||||
// LANGUAGE_VERSION: 1.7
|
||||
// ERROR: Type mismatch: inferred type is Collection<T> but Collection<T & Any> was expected
|
||||
fun <T> foo(x: Collection<T & Any>) {}
|
||||
|
||||
fun <T> bar(x: Collection<T>) {
|
||||
foo(x<caret>)
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// "Change parameter 'x' type of function 'bar' to 'T & Any'" "true"
|
||||
// LANGUAGE_VERSION: 1.7
|
||||
// LANGUAGE_VERSION: 1.8
|
||||
package a
|
||||
|
||||
fun <T> foo(x: T & Any) {}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// "Change parameter 'x' type of function 'bar' to 'T & Any'" "true"
|
||||
// LANGUAGE_VERSION: 1.7
|
||||
// LANGUAGE_VERSION: 1.8
|
||||
package a
|
||||
|
||||
fun <T> foo(x: T & Any) {}
|
||||
+2
-1
@@ -2,9 +2,10 @@
|
||||
// ERROR: Type mismatch: inferred type is List<T> but List<T & Any> was expected
|
||||
// ACTION: Add 'Any' as upper bound for T to make it non-nullable
|
||||
// ACTION: Add 'x =' to argument
|
||||
// ACTION: Cast expression 'x' to 'List<T & Any>'
|
||||
// ACTION: Change parameter 'x' type of function 'foo' to 'List<T>'
|
||||
// ACTION: Create function 'foo'
|
||||
// LANGUAGE_VERSION: 1.7
|
||||
// LANGUAGE_VERSION: 1.8
|
||||
package a
|
||||
|
||||
fun <T> foo(x: List<T & Any>) {}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Change parameter 'x' type of primary constructor of class 'Foo' to 'T & Any'" "true"
|
||||
// LANGUAGE_VERSION: 1.8
|
||||
package a
|
||||
|
||||
class Foo<T>(val x: T) {
|
||||
fun foo(y: T & Any) {}
|
||||
}
|
||||
|
||||
fun <T> Foo<T>.bar(z: T) {
|
||||
foo(x<caret>)
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Change parameter 'x' type of primary constructor of class 'Foo' to 'T & Any'" "true"
|
||||
// LANGUAGE_VERSION: 1.8
|
||||
package a
|
||||
|
||||
class Foo<T>(val x: T & Any) {
|
||||
fun foo(y: T & Any) {}
|
||||
}
|
||||
|
||||
fun <T> Foo<T>.bar(z: T) {
|
||||
foo(x)
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Change type of 'z' to 'T & Any'" "true"
|
||||
// LANGUAGE_VERSION: 1.8
|
||||
package a
|
||||
|
||||
fun <T> foo(x: T & Any) {}
|
||||
|
||||
fun <T> bar(x: T & Any) {
|
||||
val z: T = x
|
||||
foo(z<caret>)
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Change type of 'z' to 'T & Any'" "true"
|
||||
// LANGUAGE_VERSION: 1.8
|
||||
package a
|
||||
|
||||
fun <T> foo(x: T & Any) {}
|
||||
|
||||
fun <T> bar(x: T & Any) {
|
||||
val z: T & Any = x
|
||||
foo(z)
|
||||
}
|
||||
+6
-3
@@ -1,8 +1,11 @@
|
||||
// "class org.jetbrains.kotlin.idea.quickfix.CastExpressionFix" "false"
|
||||
// LANGUAGE_VERSION: 1.7
|
||||
// "Change type of 'z' to 'T & Any'" "true"
|
||||
// ERROR: Type mismatch: inferred type is T but T & Any was expected
|
||||
// LANGUAGE_VERSION: 1.8
|
||||
package a
|
||||
|
||||
fun <T> foo(x: T & Any) {}
|
||||
|
||||
fun <T> bar(x: T) {
|
||||
foo(x<caret>)
|
||||
val z: T = x
|
||||
foo(z<caret>)
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Change type of 'z' to 'T & Any'" "true"
|
||||
// ERROR: Type mismatch: inferred type is T but T & Any was expected
|
||||
// LANGUAGE_VERSION: 1.8
|
||||
package a
|
||||
|
||||
fun <T> foo(x: T & Any) {}
|
||||
|
||||
fun <T> bar(x: T) {
|
||||
val z: T & Any = x
|
||||
foo(z)
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Cast expression 'x' to 'T & Any'" "true"
|
||||
// LANGUAGE_VERSION: 1.8
|
||||
fun <T> foo(x: T & Any) {}
|
||||
|
||||
fun <T> bar(x: T) {
|
||||
foo(x<caret>)
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Cast expression 'x' to 'T & Any'" "true"
|
||||
// LANGUAGE_VERSION: 1.8
|
||||
fun <T> foo(x: T & Any) {}
|
||||
|
||||
fun <T> bar(x: T) {
|
||||
foo(x as (T & Any))
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Cast expression 'x' to 'Collection<T & Any>'" "true"
|
||||
// LANGUAGE_VERSION: 1.8
|
||||
fun <T> foo(x: Collection<T & Any>) {}
|
||||
|
||||
fun <T> bar(x: Collection<T>) {
|
||||
foo(x<caret>)
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Cast expression 'x' to 'Collection<T & Any>'" "true"
|
||||
// LANGUAGE_VERSION: 1.8
|
||||
fun <T> foo(x: Collection<T & Any>) {}
|
||||
|
||||
fun <T> bar(x: Collection<T>) {
|
||||
foo(x as Collection<T & Any>)
|
||||
}
|
||||
Reference in New Issue
Block a user