Add intention to specify all types explicitly in destructuring assignment
#KT-16260 Fixed
This commit is contained in:
committed by
Dmitry Jemerov
parent
3529d61a7d
commit
6b2c22aff1
+3
@@ -0,0 +1,3 @@
|
||||
fun main(args: Array<String>) {
|
||||
val (i<spot>: Int</spot>, s<spot>: String</spot>) = Pair(1, "s")
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fun main(args: Array<String>) {
|
||||
val <spot>(i, s)</spot> = Pair(1, "s")
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Specifies all types explicitly in a destructuring declaration.
|
||||
</body>
|
||||
</html>
|
||||
@@ -799,6 +799,11 @@
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyInDestructuringAssignmentIntention</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeIntention</className>
|
||||
<category>Kotlin</category>
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. 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.intentions
|
||||
|
||||
import com.intellij.codeInsight.intention.LowPriorityAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import org.jetbrains.kotlin.idea.core.setType
|
||||
import org.jetbrains.kotlin.psi.KtCodeFragment
|
||||
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtParameterList
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.types.isError
|
||||
|
||||
class SpecifyTypeExplicitlyInDestructuringAssignmentIntention : SelfTargetingRangeIntention<KtDestructuringDeclaration>(
|
||||
KtDestructuringDeclaration::class.java, "Specify all types explicitly in destructuring declaration"
|
||||
), LowPriorityAction {
|
||||
|
||||
override fun applicabilityRange(element: KtDestructuringDeclaration): TextRange? {
|
||||
if (element.containingFile is KtCodeFragment) return null
|
||||
val entries = element.noTypeReferenceEntries()
|
||||
if (entries.isEmpty()) return null
|
||||
if (entries.any { SpecifyTypeExplicitlyIntention.getTypeForDeclaration(it).isError }) return null
|
||||
return TextRange(element.startOffset, element.initializer?.let { it.startOffset - 1 } ?: element.endOffset)
|
||||
}
|
||||
|
||||
override fun applyTo(element: KtDestructuringDeclaration, editor: Editor?) {
|
||||
val entries = element.noTypeReferenceEntries()
|
||||
if (editor != null && element.getParentOfType<KtParameterList>(false) == null)
|
||||
SpecifyTypeExplicitlyIntention.addTypeAnnotationWithTemplate(editor, entries.iterator())
|
||||
else
|
||||
entries.forEach {
|
||||
it.setType(SpecifyTypeExplicitlyIntention.getTypeForDeclaration(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtDestructuringDeclaration.noTypeReferenceEntries() = entries.filter { it.typeReference == null }
|
||||
@@ -166,18 +166,32 @@ class SpecifyTypeExplicitlyIntention :
|
||||
}
|
||||
}
|
||||
|
||||
fun createTypeReferencePostprocessor(declaration: KtCallableDeclaration): TemplateEditingAdapter {
|
||||
@JvmOverloads
|
||||
fun createTypeReferencePostprocessor(declaration: KtCallableDeclaration,
|
||||
iterator: Iterator<KtCallableDeclaration>? = null,
|
||||
editor: Editor? = null): TemplateEditingAdapter {
|
||||
return object : TemplateEditingAdapter() {
|
||||
override fun templateFinished(template: Template?, brokenOff: Boolean) {
|
||||
val typeRef = declaration.typeReference
|
||||
if (typeRef != null && typeRef.isValid) {
|
||||
runWriteAction { ShortenReferences.DEFAULT.process(typeRef) }
|
||||
runWriteAction {
|
||||
ShortenReferences.DEFAULT.process(typeRef)
|
||||
if (iterator != null && editor != null) addTypeAnnotationWithTemplate(editor, iterator)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addTypeAnnotationWithTemplate(editor: Editor, declaration: KtCallableDeclaration, exprType: KotlinType) {
|
||||
fun addTypeAnnotationWithTemplate(editor: Editor, iterator: Iterator<KtCallableDeclaration>?) {
|
||||
if (iterator == null || !iterator.hasNext()) return
|
||||
val declaration = iterator.next()
|
||||
val exprType = getTypeForDeclaration(declaration)
|
||||
addTypeAnnotationWithTemplate(editor, declaration, exprType, iterator)
|
||||
}
|
||||
|
||||
private fun addTypeAnnotationWithTemplate(editor: Editor, declaration: KtCallableDeclaration, exprType: KotlinType,
|
||||
iterator: Iterator<KtCallableDeclaration>? = null) {
|
||||
assert(!exprType.isError) { "Unexpected error type, should have been checked before: " + declaration.getElementTextWithContext() + ", type = " + exprType }
|
||||
|
||||
val project = declaration.project
|
||||
@@ -194,7 +208,10 @@ class SpecifyTypeExplicitlyIntention :
|
||||
|
||||
editor.caretModel.moveToOffset(newTypeRef.node.startOffset)
|
||||
|
||||
TemplateManager.getInstance(project).startTemplate(editor, builder.buildInlineTemplate(), createTypeReferencePostprocessor(declaration))
|
||||
TemplateManager.getInstance(project).startTemplate(
|
||||
editor,
|
||||
builder.buildInlineTemplate(),
|
||||
createTypeReferencePostprocessor(declaration, iterator, editor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyInDestructuringAssignmentIntention
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test() {
|
||||
val map = mapOf(1 to "two")
|
||||
for (<caret>(key, value) in map) {
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test() {
|
||||
val map = mapOf(1 to "two")
|
||||
for ((key: Int, value: String<caret>) in map) {
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test() {
|
||||
val list = emptyList<Pair<Int, String>>()
|
||||
list.forEach { (i, s)<caret> ->
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test() {
|
||||
val list = emptyList<Pair<Int, String>>()
|
||||
list.forEach { (i: Int, s: String)<caret> ->
|
||||
}
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test() {
|
||||
val list = emptyList<Pair<Int, String>>()
|
||||
list.forEach { (i, s)<caret>: Pair<Int, String> ->
|
||||
}
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
fun test() {
|
||||
val list = emptyList<Pair<Int, String>>()
|
||||
list.forEach { (i: Int, s: String)<caret>: Pair<Int, String> ->
|
||||
}
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
// IS_APPLICABLE: false
|
||||
// WITH_RUNTIME
|
||||
fun test() {
|
||||
val (i: Int, s: String)<caret> = Pair(1, "s")
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test() {
|
||||
val (i, s)<caret> = Pair(1, "s")
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test() {
|
||||
val (i: Int, s: String<caret>) = Pair(1, "s")
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test() {
|
||||
val (i: Int, s) <caret>= Pair(1, "s")
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test() {
|
||||
val (i: Int, s: String<caret>) = Pair(1, "s")
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test() {
|
||||
val (_, s) =<caret> Pair(1, "s")
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// WITH_RUNTIME
|
||||
fun test() {
|
||||
val (_: Int, s: String<caret>) = Pair(1, "s")
|
||||
}
|
||||
@@ -14724,6 +14724,57 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/specifyTypeExplicitlyInDestructuringAssignment")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class SpecifyTypeExplicitlyInDestructuringAssignment extends AbstractIntentionTest {
|
||||
public void testAllFilesPresentInSpecifyTypeExplicitlyInDestructuringAssignment() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/specifyTypeExplicitlyInDestructuringAssignment"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("in.kt")
|
||||
public void testIn() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyTypeExplicitlyInDestructuringAssignment/in.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lambda.kt")
|
||||
public void testLambda() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyTypeExplicitlyInDestructuringAssignment/lambda.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lambdaHasSignature.kt")
|
||||
public void testLambdaHasSignature() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyTypeExplicitlyInDestructuringAssignment/lambdaHasSignature.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("variableHasAllTypes.kt")
|
||||
public void testVariableHasAllTypes() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyTypeExplicitlyInDestructuringAssignment/variableHasAllTypes.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("variableHasNoTypes.kt")
|
||||
public void testVariableHasNoTypes() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyTypeExplicitlyInDestructuringAssignment/variableHasNoTypes.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("variableHasTypes.kt")
|
||||
public void testVariableHasTypes() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyTypeExplicitlyInDestructuringAssignment/variableHasTypes.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("variableHasUnderscore.kt")
|
||||
public void testVariableHasUnderscore() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/specifyTypeExplicitlyInDestructuringAssignment/variableHasUnderscore.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/splitIf")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user