FIR IDE: AddToString quickfix
This commit is contained in:
committed by
Ilya Kirillov
parent
1b8b5b9a79
commit
f6078b24df
+1
@@ -1183,6 +1183,7 @@ fun main(args: Array<String>) {
|
||||
model("quickfix/wrapWithSafeLetCall", pattern = pattern, filenameStartsLowerCase = true)
|
||||
model("quickfix/typeMismatch/componentFunctionReturnTypeMismatch", pattern = pattern, filenameStartsLowerCase = true)
|
||||
model("quickfix/typeMismatch/typeMismatchOnReturnedExpression", pattern = pattern, filenameStartsLowerCase = true)
|
||||
model("quickfix/toString", pattern = pattern, filenameStartsLowerCase = true)
|
||||
}
|
||||
|
||||
testClass<AbstractHighLevelQuickFixMultiFileTest> {
|
||||
|
||||
@@ -137,11 +137,18 @@ class MainKtQuickFixRegistrar : KtQuickFixRegistrar() {
|
||||
registerPsiQuickFixes(KtFirDiagnostic.InapplicableLateinitModifier::class, RemoveNullableFix.removeForLateInitProperty)
|
||||
}
|
||||
|
||||
private val returnTypes = KtQuickFixesListBuilder.registerPsiQuickFix {
|
||||
private val typeMismatch = KtQuickFixesListBuilder.registerPsiQuickFix {
|
||||
registerApplicator(ChangeTypeQuickFixFactories.componentFunctionReturnTypeMismatch)
|
||||
registerApplicator(ChangeTypeQuickFixFactories.returnTypeMismatch)
|
||||
|
||||
registerApplicator(AddToStringFixFactories.typeMismatch)
|
||||
registerApplicator(AddToStringFixFactories.argumentTypeMismatch)
|
||||
registerApplicator(AddToStringFixFactories.assignmentTypeMismatch)
|
||||
registerApplicator(AddToStringFixFactories.returnTypeMismatch)
|
||||
registerApplicator(AddToStringFixFactories.initializerTypeMismatch)
|
||||
}
|
||||
|
||||
|
||||
override val list: KtQuickFixesList = KtQuickFixesList.createCombined(
|
||||
keywords,
|
||||
propertyInitialization,
|
||||
@@ -149,6 +156,6 @@ class MainKtQuickFixRegistrar : KtQuickFixRegistrar() {
|
||||
imports,
|
||||
mutability,
|
||||
expressions,
|
||||
returnTypes
|
||||
typeMismatch
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.fixes
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.fir.api.fixes.diagnosticFixFactory
|
||||
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
||||
import org.jetbrains.kotlin.idea.frontend.api.fir.diagnostics.KtFirDiagnostic
|
||||
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
|
||||
import org.jetbrains.kotlin.idea.quickfix.AddToStringFix
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
object AddToStringFixFactories {
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private fun KtAnalysisSession.getFixes(element: PsiElement?, expectedType: KtType, actualType: KtType): List<AddToStringFix> {
|
||||
if (element !is KtExpression) return emptyList()
|
||||
return buildList {
|
||||
if (expectedType.isString || expectedType.isCharSequence) {
|
||||
add(AddToStringFix(element, false))
|
||||
if (expectedType.isMarkedNullable && actualType.isMarkedNullable) {
|
||||
add(AddToStringFix(element, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val typeMismatch = diagnosticFixFactory(KtFirDiagnostic.TypeMismatch::class) { diagnostic ->
|
||||
getFixes(diagnostic.psi, diagnostic.expectedType, diagnostic.actualType)
|
||||
}
|
||||
|
||||
val argumentTypeMismatch = diagnosticFixFactory(KtFirDiagnostic.ArgumentTypeMismatch::class) { diagnostic ->
|
||||
getFixes(diagnostic.psi, diagnostic.expectedType, diagnostic.actualType)
|
||||
}
|
||||
|
||||
val assignmentTypeMismatch = diagnosticFixFactory(KtFirDiagnostic.AssignmentTypeMismatch::class) { diagnostic ->
|
||||
getFixes(diagnostic.psi, diagnostic.expectedType, diagnostic.actualType)
|
||||
}
|
||||
|
||||
val returnTypeMismatch = diagnosticFixFactory(KtFirDiagnostic.ReturnTypeMismatch::class) { diagnostic ->
|
||||
getFixes(diagnostic.psi, diagnostic.expectedType, diagnostic.actualType)
|
||||
}
|
||||
|
||||
val initializerTypeMismatch = diagnosticFixFactory(KtFirDiagnostic.InitializerTypeMismatch::class) { diagnostic ->
|
||||
getFixes(diagnostic.psi.initializer, diagnostic.expectedType, diagnostic.actualType)
|
||||
}
|
||||
}
|
||||
Generated
+48
@@ -2334,4 +2334,52 @@ public class HighLevelQuickFixTestGenerated extends AbstractHighLevelQuickFixTes
|
||||
runTest("idea/testData/quickfix/typeMismatch/typeMismatchOnReturnedExpression/typeMismatchInReturnStatement.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/toString")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ToString extends AbstractHighLevelQuickFixTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInToString() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/toString"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("callArgument.kt")
|
||||
public void testCallArgument() throws Exception {
|
||||
runTest("idea/testData/quickfix/toString/callArgument.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notNullableExpectedNullable.kt")
|
||||
public void testNotNullableExpectedNullable() throws Exception {
|
||||
runTest("idea/testData/quickfix/toString/notNullableExpectedNullable.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullableExpectedNotNullable.kt")
|
||||
public void testNullableExpectedNotNullable() throws Exception {
|
||||
runTest("idea/testData/quickfix/toString/nullableExpectedNotNullable.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullableExpectedNullable.kt")
|
||||
public void testNullableExpectedNullable() throws Exception {
|
||||
runTest("idea/testData/quickfix/toString/nullableExpectedNullable.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyInitializer.kt")
|
||||
public void testPropertyInitializer() throws Exception {
|
||||
runTest("idea/testData/quickfix/toString/propertyInitializer.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("returnStatement.kt")
|
||||
public void testReturnStatement() throws Exception {
|
||||
runTest("idea/testData/quickfix/toString/returnStatement.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("variableAssignment.kt")
|
||||
public void testVariableAssignment() throws Exception {
|
||||
runTest("idea/testData/quickfix/toString/variableAssignment.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -38,6 +38,7 @@ interface KtTypeInfoProviderMixIn : KtAnalysisSessionMixIn {
|
||||
val KtType.isChar: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.CHAR)
|
||||
val KtType.isBoolean: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.BOOLEAN)
|
||||
val KtType.isString: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.STRING)
|
||||
val KtType.isCharSequence: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.CHAR_SEQUENCE)
|
||||
val KtType.isAny: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.ANY)
|
||||
|
||||
val KtType.isUInt: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uInt)
|
||||
@@ -85,6 +86,7 @@ object DefaultTypeClassIds {
|
||||
val CHAR = ClassId.topLevel(StandardNames.FqNames._char.toSafe())
|
||||
val BOOLEAN = ClassId.topLevel(StandardNames.FqNames._boolean.toSafe())
|
||||
val STRING = ClassId.topLevel(StandardNames.FqNames.string.toSafe())
|
||||
val CHAR_SEQUENCE = ClassId.topLevel(StandardNames.FqNames.charSequence.toSafe())
|
||||
val ANY = ClassId.topLevel(StandardNames.FqNames.any.toSafe())
|
||||
val PRIMITIVES = setOf(INT, LONG, SHORT, BYTE, FLOAT, DOUBLE, CHAR, BOOLEAN)
|
||||
}
|
||||
|
||||
+3
-3
@@ -17,12 +17,12 @@ 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) :
|
||||
class AddToStringFix(element: KtExpression, private val useSafeCallOperator: Boolean) :
|
||||
KotlinPsiOnlyQuickFixAction<KtExpression>(element), KotlinUniversalQuickFix, LowPriorityAction {
|
||||
override fun getFamilyName() = KotlinBundle.message("fix.add.tostring.call.family")
|
||||
|
||||
override fun getText(): String {
|
||||
return when (nullable) {
|
||||
return when (useSafeCallOperator) {
|
||||
true -> KotlinBundle.message("fix.add.tostring.call.text.safe")
|
||||
false -> KotlinBundle.message("fix.add.tostring.call.text")
|
||||
}
|
||||
@@ -30,7 +30,7 @@ class AddToStringFix(element: KtExpression, private val nullable: Boolean) :
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
val element = element ?: return
|
||||
val pattern = if (nullable) "$0?.toString()" else "$0.toString()"
|
||||
val pattern = if (useSafeCallOperator) "$0?.toString()" else "$0.toString()"
|
||||
val expressionToInsert = KtPsiFactory(file).createExpressionByPattern(pattern, element)
|
||||
val newExpression = element.replaced(expressionToInsert)
|
||||
editor?.caretModel?.moveToOffset(newExpression.endOffset)
|
||||
|
||||
Vendored
@@ -0,0 +1,3 @@
|
||||
// "Add 'toString()' call" "true"
|
||||
|
||||
val s: String = 1 <caret>+ 2 * 3
|
||||
@@ -0,0 +1,3 @@
|
||||
// "Add 'toString()' call" "true"
|
||||
|
||||
val s: String = (1 + 2 * 3).toString()<caret>
|
||||
@@ -0,0 +1,5 @@
|
||||
// "Add 'toString()' call" "true"
|
||||
|
||||
fun test(): String {
|
||||
return 1 <caret>+ 2 * 3
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// "Add 'toString()' call" "true"
|
||||
|
||||
fun test(): String {
|
||||
return (1 + 2 * 3).toString()<caret>
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Add 'toString()' call" "true"
|
||||
|
||||
fun test() {
|
||||
var s: String = ""
|
||||
s = 1 <caret>+ 2 * 3
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Add 'toString()' call" "true"
|
||||
|
||||
fun test() {
|
||||
var s: String = ""
|
||||
s = (1 + 2 * 3).toString()<caret>
|
||||
}
|
||||
@@ -13668,6 +13668,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/toString"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("callArgument.kt")
|
||||
public void testCallArgument() throws Exception {
|
||||
runTest("idea/testData/quickfix/toString/callArgument.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notNullableExpectedNullable.kt")
|
||||
public void testNotNullableExpectedNullable() throws Exception {
|
||||
runTest("idea/testData/quickfix/toString/notNullableExpectedNullable.kt");
|
||||
@@ -13683,9 +13688,19 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
runTest("idea/testData/quickfix/toString/nullableExpectedNullable.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("idea/testData/quickfix/toString/simple.kt");
|
||||
@TestMetadata("propertyInitializer.kt")
|
||||
public void testPropertyInitializer() throws Exception {
|
||||
runTest("idea/testData/quickfix/toString/propertyInitializer.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("returnStatement.kt")
|
||||
public void testReturnStatement() throws Exception {
|
||||
runTest("idea/testData/quickfix/toString/returnStatement.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("variableAssignment.kt")
|
||||
public void testVariableAssignment() throws Exception {
|
||||
runTest("idea/testData/quickfix/toString/variableAssignment.kt");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user