Better texts of change variable type quickfixes
This commit is contained in:
@@ -16,10 +16,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix
|
||||
|
||||
import com.intellij.codeInsight.intention.HighPriorityAction
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
@@ -34,16 +36,45 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||
import java.util.*
|
||||
|
||||
class ChangeVariableTypeFix(element: KtVariableDeclaration, type: KotlinType) : KotlinQuickFixAction<KtVariableDeclaration>(element) {
|
||||
open class ChangeVariableTypeFix(element: KtVariableDeclaration, type: KotlinType) : KotlinQuickFixAction<KtVariableDeclaration>(element) {
|
||||
private val typeContainsError = ErrorUtils.containsErrorType(type)
|
||||
private val typePresentation = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type)
|
||||
private val typeSourceCode = IdeDescriptorRenderers.SOURCE_CODE.renderType(type)
|
||||
|
||||
open fun variablePresentation(): String? {
|
||||
val name = element.name
|
||||
if (name != null) {
|
||||
val container = element.resolveToDescriptor().containingDeclaration as? ClassDescriptor
|
||||
val containerName = container?.name?.check { !it.isSpecial }?.asString()
|
||||
return if (containerName != null) "'$containerName.$name'" else "'$name'"
|
||||
}
|
||||
else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
override fun getText(): String {
|
||||
val propertyName = element.fqName?.asString() ?: element.name
|
||||
return "Change '$propertyName' type to '$typePresentation'"
|
||||
val variablePresentation = variablePresentation()
|
||||
if (variablePresentation != null) {
|
||||
return "Change type of $variablePresentation to '$typePresentation'"
|
||||
}
|
||||
else {
|
||||
return "Change type to '$typePresentation'"
|
||||
}
|
||||
}
|
||||
|
||||
class OnType(element: KtVariableDeclaration, type: KotlinType) : ChangeVariableTypeFix(element, type), HighPriorityAction {
|
||||
override fun variablePresentation() = null
|
||||
}
|
||||
|
||||
class ForOverridden(element: KtVariableDeclaration, type: KotlinType) : ChangeVariableTypeFix(element, type) {
|
||||
override fun variablePresentation(): String? {
|
||||
val presentation = super.variablePresentation() ?: return null
|
||||
return "overridden property $presentation"
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFamilyName()
|
||||
@@ -118,13 +149,13 @@ class ChangeVariableTypeFix(element: KtVariableDeclaration, type: KotlinType) :
|
||||
}
|
||||
|
||||
if (lowerBoundOfOverriddenPropertiesTypes != null) {
|
||||
actions.add(ChangeVariableTypeFix(property, lowerBoundOfOverriddenPropertiesTypes))
|
||||
actions.add(ChangeVariableTypeFix.OnType(property, lowerBoundOfOverriddenPropertiesTypes))
|
||||
}
|
||||
|
||||
if (overriddenMismatchingProperties.size == 1 && canChangeOverriddenPropertyType) {
|
||||
val overriddenProperty = DescriptorToSourceUtils.descriptorToDeclaration(overriddenMismatchingProperties.single())
|
||||
if (overriddenProperty is KtProperty) {
|
||||
actions.add(ChangeVariableTypeFix(overriddenProperty, propertyType))
|
||||
actions.add(ChangeVariableTypeFix.ForOverridden(overriddenProperty, propertyType))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// "Create secondary constructor" "false"
|
||||
// ACTION: Add parameter to constructor 'A'
|
||||
// ACTION: Change 'b' type to 'A'
|
||||
// ACTION: Change type of 'b' to 'A'
|
||||
// ACTION: Create function 'A'
|
||||
// ERROR: Type mismatch: inferred type is A but B was expected
|
||||
// ERROR: Too many arguments for public constructor A() defined in A
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
// "Change 'A.x' type to '(Int) -> Int'" "false"
|
||||
// ACTION: Change 'C.x' type to '(String) -> Int'
|
||||
// "Change type of overriden property 'A.x' to '(Int) -> Int'" "false"
|
||||
// ACTION: Change type to '(String) -> Int'
|
||||
// ERROR: Type of 'x' is not a subtype of the overridden property 'public abstract val x: (String) -> Int defined in A'
|
||||
interface A {
|
||||
val x: (String) -> Int
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'B.x' type to '(Int) -> Int'" "true"
|
||||
// "Change type of overridden property 'B.x' to '(Int) -> Int'" "true"
|
||||
interface A {
|
||||
val x: (Int) -> Int
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'B.x' type to '(Int) -> Int'" "true"
|
||||
// "Change type of overridden property 'B.x' to '(Int) -> Int'" "true"
|
||||
interface A {
|
||||
val x: (Int) -> Int
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'A.x' type to 'String'" "true"
|
||||
// "Change type of overridden property 'A.x' to 'String'" "true"
|
||||
interface A {
|
||||
var x: Int
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'A.x' type to 'String'" "true"
|
||||
// "Change type of overridden property 'A.x' to 'String'" "true"
|
||||
interface A {
|
||||
var x: String
|
||||
}
|
||||
|
||||
idea/testData/quickfix/override/typeMismatchOnOverride/changeOverridingPropertyTypeToFunctionType.kt
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'B.x' type to '(String) -> Int'" "true"
|
||||
// "Change type to '(String) -> Int'" "true"
|
||||
interface A {
|
||||
var x: (String) -> Int
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'B.x' type to '(String) -> Int'" "true"
|
||||
// "Change type to '(String) -> Int'" "true"
|
||||
interface A {
|
||||
var x: (String) -> Int
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Change 'prop' type to 'Int'" "true"
|
||||
// "Change type to 'Int'" "true"
|
||||
// ERROR: Null can not be a value of a non-null type Int
|
||||
interface Test<T> {
|
||||
val prop : T
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'prop' type to 'Int'" "true"
|
||||
// "Change type to 'Int'" "true"
|
||||
// ERROR: Null can not be a value of a non-null type Int
|
||||
interface Test<T> {
|
||||
val prop : T
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'A.x' type to 'Int'" "true"
|
||||
// "Change type to 'Int'" "true"
|
||||
interface X {
|
||||
val x: Int
|
||||
}
|
||||
|
||||
idea/testData/quickfix/override/typeMismatchOnOverride/propertyReturnTypeMismatchOnOverride.kt.after
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'A.x' type to 'Int'" "true"
|
||||
// "Change type to 'Int'" "true"
|
||||
interface X {
|
||||
val x: Int
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'B.x' type to 'Int'" "true"
|
||||
// "Change type to 'Int'" "true"
|
||||
abstract class A {
|
||||
abstract var x : Int
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'B.x' type to 'Int'" "true"
|
||||
// "Change type to 'Int'" "true"
|
||||
abstract class A {
|
||||
abstract var x : Int
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'B.x' type to 'Int'" "true"
|
||||
// "Change type to 'Int'" "true"
|
||||
abstract class A {
|
||||
abstract var x : Int
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'B.x' type to 'Int'" "true"
|
||||
// "Change type to 'Int'" "true"
|
||||
abstract class A {
|
||||
abstract var x : Int
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Change 't' type to 'T'" "true"
|
||||
// "Change type of 't' to 'T'" "true"
|
||||
interface T
|
||||
|
||||
fun foo() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Change 't' type to 'T'" "true"
|
||||
// "Change type of 't' to 'T'" "true"
|
||||
interface T
|
||||
|
||||
fun foo() {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'y' type to 'Int'" "true"
|
||||
// "Change type of 'y' to 'Int'" "true"
|
||||
class A {
|
||||
operator fun component1() = 42
|
||||
operator fun component2() = 42
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'y' type to 'Int'" "true"
|
||||
// "Change type of 'y' to 'Int'" "true"
|
||||
class A {
|
||||
operator fun component1() = 42
|
||||
operator fun component2() = 42
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
// "Change 'B.x' type to '(String) -> [ERROR : Ay]'" "false"
|
||||
// ACTION: Change 'A.x' type to '(Int) -> Int'
|
||||
// "Change type to '(String) -> [ERROR : Ay]'" "false"
|
||||
// ACTION: Change type of overridden property 'A.x' to '(Int) -> Int'
|
||||
// ERROR: Type of 'x' is not a subtype of the overridden property 'public abstract val x: (String) -> [ERROR : Ay] defined in A'
|
||||
// ERROR: Unresolved reference: Ay
|
||||
interface A {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Change 'x' type to 'Int'" "true"
|
||||
// "Change type of 'x' to 'Int'" "true"
|
||||
|
||||
fun foo() {
|
||||
val x: Short = <caret>100000
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Change 'x' type to 'Int'" "true"
|
||||
// "Change type of 'x' to 'Int'" "true"
|
||||
|
||||
fun foo() {
|
||||
val x: Int = 100000
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Change 'x' type to 'Long'" "true"
|
||||
// "Change type of 'x' to 'Long'" "true"
|
||||
|
||||
fun foo() {
|
||||
val x: Double = <caret>0L
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Change 'x' type to 'Long'" "true"
|
||||
// "Change type of 'x' to 'Long'" "true"
|
||||
|
||||
fun foo() {
|
||||
val x: Long = 0L
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Change 'x' type to 'Long'" "true"
|
||||
// "Change type of 'x' to 'Long'" "true"
|
||||
|
||||
fun foo() {
|
||||
val x: Int = <caret>0L
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Change 'x' type to 'Long'" "true"
|
||||
// "Change type of 'x' to 'Long'" "true"
|
||||
|
||||
fun foo() {
|
||||
val x: Long = 0L
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Change 'f' type to '(Long) -> Unit'" "true"
|
||||
// "Change type of 'f' to '(Long) -> Unit'" "true"
|
||||
fun foo() {
|
||||
var f: Int = if (true) { x: Long -> }<caret> else { x: Long -> }
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Change 'f' type to '(Long) -> Unit'" "true"
|
||||
// "Change type of 'f' to '(Long) -> Unit'" "true"
|
||||
fun foo() {
|
||||
var f: (Long) -> Unit = if (true) { x: Long -> }<caret> else { x: Long -> }
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Change 'f' type to '(Delegates) -> Unit'" "true"
|
||||
// "Change type of 'f' to '(Delegates) -> Unit'" "true"
|
||||
|
||||
fun foo() {
|
||||
var f: Int = { x: kotlin.properties.Delegates -> }<caret>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
// "Change 'f' type to '(Delegates) -> Unit'" "true"
|
||||
// "Change type of 'f' to '(Delegates) -> Unit'" "true"
|
||||
|
||||
fun foo() {
|
||||
var f: (Delegates) -> Unit = { x: kotlin.properties.Delegates -> }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Change 'x' type to 'Int'" "true"
|
||||
// "Change type of 'x' to 'Int'" "true"
|
||||
|
||||
fun foo() {
|
||||
val x: Byte = <caret>1000
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Change 'x' type to 'Int'" "true"
|
||||
// "Change type of 'x' to 'Int'" "true"
|
||||
|
||||
fun foo() {
|
||||
val x: Int = 1000
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'f' type to '() -> Unit'" "true"
|
||||
// "Change type of 'f' to '() -> Unit'" "true"
|
||||
fun foo() {
|
||||
val f: () -> Int = {
|
||||
var x = 1
|
||||
|
||||
idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/assignmentTypeMismatch.kt.after
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'f' type to '() -> Unit'" "true"
|
||||
// "Change type of 'f' to '() -> Unit'" "true"
|
||||
fun foo() {
|
||||
val f: () -> Unit = {
|
||||
var x = 1
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'complex' type to '(Int) -> Long'" "true"
|
||||
// "Change type of 'complex' to '(Int) -> Long'" "true"
|
||||
|
||||
val complex: (Int) -> String
|
||||
get() = { it.toLong()<caret> }
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'complex' type to '(Int) -> Long'" "true"
|
||||
// "Change type of 'complex' to '(Int) -> Long'" "true"
|
||||
|
||||
val complex: (Int) -> Long
|
||||
get() = { it.toLong() }
|
||||
Vendored
+2
-2
@@ -1,5 +1,5 @@
|
||||
// "Change 'A' function return type to 'B'" "false"
|
||||
// ACTION: Change 'b' type to 'A'
|
||||
// "class org.jetbrains.kotlin.idea.quickfix.ChangeFunctionReturnTypeFix" "false"
|
||||
// ACTION: Change type of 'b' to 'A'
|
||||
// ACTION: Convert property initializer to getter
|
||||
// ACTION: Let 'A' implement interface 'B'
|
||||
// ERROR: Type mismatch: inferred type is A but B was expected
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'A.x' type to '() -> Int'" "true"
|
||||
// "Change type of 'A.x' to '() -> Int'" "true"
|
||||
class A {
|
||||
var x: Int
|
||||
get(): Int = if (true) { {42}<caret> } else { {24} }
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'A.x' type to '() -> Int'" "true"
|
||||
// "Change type of 'A.x' to '() -> Int'" "true"
|
||||
class A {
|
||||
var x: () -> Int
|
||||
get(): () -> Int = if (true) { {42}<caret> } else { {24} }
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'f' type to '(Int, Int) -> (String) -> Int'" "true"
|
||||
// "Change type of 'f' to '(Int, Int) -> (String) -> Int'" "true"
|
||||
fun foo() {
|
||||
val f: () -> Long = {
|
||||
a: Int, b: Int ->
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// "Change 'f' type to '(Int, Int) -> (String) -> Int'" "true"
|
||||
// "Change type of 'f' to '(Int, Int) -> (String) -> Int'" "true"
|
||||
fun foo() {
|
||||
val f: (Int, Int) -> (String) -> Int = {
|
||||
a: Int, b: Int ->
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// "Change to '1'" "false"
|
||||
// ACTION: Add 'const' modifier
|
||||
// ACTION: Change 'a' type to 'Double'
|
||||
// ACTION: Change type of 'a' to 'Double'
|
||||
// ACTION: Convert expression to 'Int'
|
||||
// ACTION: Convert property initializer to getter
|
||||
// ERROR: The floating-point literal does not conform to the expected type Int
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// "Change to '10000000000000000000L'" "false"
|
||||
// ACTION: Add 'const' modifier
|
||||
// ACTION: Change 'a' type to 'Double'
|
||||
// ACTION: Change type of 'a' to 'Double'
|
||||
// ACTION: Convert expression to 'Long'
|
||||
// ACTION: Convert property initializer to getter
|
||||
// ERROR: The floating-point literal does not conform to the expected type Long
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// "Change to '65000'" "false"
|
||||
// ACTION: Add 'const' modifier
|
||||
// ACTION: Change 'a' type to 'Double'
|
||||
// ACTION: Change type of 'a' to 'Double'
|
||||
// ACTION: Convert expression to 'Short'
|
||||
// ACTION: Convert property initializer to getter
|
||||
// ERROR: The floating-point literal does not conform to the expected type Short
|
||||
|
||||
Reference in New Issue
Block a user