Add quickfix to add 'toString' (#866)

Fixes #KT-12121
This commit is contained in:
Kirill Rakhman
2016-04-28 11:15:39 +02:00
committed by Dmitry Jemerov
parent a51fe9a9b0
commit 2629d23576
12 changed files with 159 additions and 0 deletions
@@ -879,6 +879,14 @@ public abstract class KotlinBuiltIns {
return type != null && isNotNullConstructedFromGivenClass(type, FQ_NAMES.string);
}
public static boolean isCharSequenceOrNullableCharSequence(@Nullable KotlinType type) {
return type != null && isConstructedFromGivenClass(type, FQ_NAMES.charSequence);
}
public static boolean isStringOrNullableString(@Nullable KotlinType type) {
return type != null && isConstructedFromGivenClass(type, FQ_NAMES.string);
}
public static boolean isCollectionOrNullableCollection(@NotNull KotlinType type) {
return isConstructedFromGivenClass(type, FQ_NAMES._collection);
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.createExpressionByPattern
import org.jetbrains.kotlin.psi.psiUtil.endOffset
class AddToStringFix(element: KtExpression, private val nullable: Boolean) : KotlinQuickFixAction<KtExpression>(element) {
override fun getFamilyName() = "Add 'toString()' call"
override fun getText() = if (nullable) "Add safe '?.toString()' call" else "Add 'toString()' call"
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
val pattern = if (nullable) "$0?.toString()" else "$0.toString()"
val expressionToInsert = KtPsiFactory(file).createExpressionByPattern(pattern, element)
val newExpression = element.replaced(expressionToInsert)
editor?.caretModel?.moveToOffset(newExpression.endOffset)
}
}
@@ -86,6 +86,14 @@ class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() {
actions.add(NumberConversionFix(diagnosticElement, expectedType))
}
if (KotlinBuiltIns.isCharSequenceOrNullableCharSequence(expectedType)
|| KotlinBuiltIns.isStringOrNullableString(expectedType)) {
actions.add(AddToStringFix(diagnosticElement, false))
if (expectedType.isMarkedNullable && expressionType.isMarkedNullable) {
actions.add(AddToStringFix(diagnosticElement, true))
}
}
if (expectedType.isInterface()) {
val expressionTypeDeclaration = expressionType.constructor.declarationDescriptor?.let {
DescriptorToSourceUtils.descriptorToDeclaration(it)
@@ -0,0 +1,9 @@
// "Add 'toString()' call" "true"
// ACTION: Add 'toString()' call
fun foo() {
bar(Any()<caret>)
}
fun bar(a: String?) {
}
@@ -0,0 +1,9 @@
// "Add 'toString()' call" "true"
// ACTION: Add 'toString()' call
fun foo() {
bar(Any().toString()<caret>)
}
fun bar(a: String?) {
}
@@ -0,0 +1,9 @@
// "Add 'toString()' call" "true"
// ACTION: Add 'toString()' call
fun foo() {
bar(null as Any?<caret>)
}
fun bar(a: String) {
}
@@ -0,0 +1,9 @@
// "Add 'toString()' call" "true"
// ACTION: Add 'toString()' call
fun foo() {
bar((null as Any?).toString()<caret>)
}
fun bar(a: String) {
}
@@ -0,0 +1,10 @@
// "Add safe '?.toString()' call" "true"
// ACTION: Add 'toString()' call
// ACTION: Add safe '?.toString()' call
fun foo() {
bar(null as Any?<caret>)
}
fun bar(a: String?) {
}
@@ -0,0 +1,10 @@
// "Add safe '?.toString()' call" "true"
// ACTION: Add 'toString()' call
// ACTION: Add safe '?.toString()' call
fun foo() {
bar((null as Any?)?.toString()<caret>)
}
fun bar(a: String?) {
}
+8
View File
@@ -0,0 +1,8 @@
// "Add 'toString()' call" "true"
fun foo() {
bar(Any()<caret>)
}
fun bar(a: String) {
}
+8
View File
@@ -0,0 +1,8 @@
// "Add 'toString()' call" "true"
fun foo() {
bar(Any().toString()<caret>)
}
fun bar(a: String) {
}
@@ -7265,6 +7265,39 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
}
}
@TestMetadata("idea/testData/quickfix/toString")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ToString extends AbstractQuickFixTest {
public void testAllFilesPresentInToString() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/toString"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
}
@TestMetadata("notNullableExpectedNullable.kt")
public void testNotNullableExpectedNullable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/toString/notNullableExpectedNullable.kt");
doTest(fileName);
}
@TestMetadata("nullableExpectedNotNullable.kt")
public void testNullableExpectedNotNullable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/toString/nullableExpectedNotNullable.kt");
doTest(fileName);
}
@TestMetadata("nullableExpectedNullable.kt")
public void testNullableExpectedNullable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/toString/nullableExpectedNullable.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/toString/simple.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/quickfix/typeAddition")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)