Better texts of change variable type quickfixes

This commit is contained in:
Valentin Kipyatkov
2016-09-20 22:42:19 +03:00
parent 80d82d2dee
commit e4f80e277f
46 changed files with 84 additions and 53 deletions
@@ -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,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
@@ -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,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,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,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
}
@@ -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
}
@@ -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 '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,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,4 +1,4 @@
// "Change 'A.x' type to 'Int'" "true"
// "Change type to 'Int'" "true"
interface X {
val x: Int
}
@@ -1,4 +1,4 @@
// "Change 'A.x' type to 'Int'" "true"
// "Change type to 'Int'" "true"
interface X {
val x: Int
}
@@ -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 'B.x' type to 'Int'" "true"
// "Change type to 'Int'" "true"
abstract class A {
abstract var x : Int
}
@@ -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 '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,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,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,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,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
@@ -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
@@ -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
@@ -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,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() }
@@ -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,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,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,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,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,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,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,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