Join declaration & assignment is no more suggested in case of potential smart cast available #KT-15412 Fixed

This commit is contained in:
Mikhail Glukhikh
2017-01-09 17:52:20 +03:00
parent 31a8689999
commit 7c6d5c825c
5 changed files with 49 additions and 3 deletions
@@ -21,6 +21,7 @@ import com.intellij.openapi.editor.ScrollType
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReferenceService
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.canOmitDeclaredType
import org.jetbrains.kotlin.idea.core.moveCaret
import org.jetbrains.kotlin.idea.core.unblockDocument
@@ -28,6 +29,10 @@ import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
class JoinDeclarationAndAssignmentInspection : IntentionBasedInspection<KtProperty>(
JoinDeclarationAndAssignmentIntention::class,
@@ -39,6 +44,12 @@ class JoinDeclarationAndAssignmentIntention : SelfTargetingOffsetIndependentInte
"Join declaration and assignment"
) {
private fun equalNullableTypes(type1: KotlinType?, type2: KotlinType?): Boolean {
if (type1 == null) return type2 == null
if (type2 == null) return false
return TypeUtils.equalTypes(type1, type2)
}
override fun isApplicableTo(element: KtProperty): Boolean {
if (element.hasDelegate()
|| element.hasInitializer()
@@ -50,7 +61,13 @@ class JoinDeclarationAndAssignmentIntention : SelfTargetingOffsetIndependentInte
}
val assignment = findAssignment(element) ?: return false
return assignment.right?.let { hasNoLocalDependencies(it, element.parent) } ?: false
return assignment.right?.let {
hasNoLocalDependencies(it, element.parent) &&
assignment.analyze().let { context ->
(element.isVar && !element.isLocal) ||
equalNullableTypes(it.getType(context), context[BindingContext.TYPE, element.typeReference])
}
} ?: false
}
override fun applyTo(element: KtProperty, editor: Editor?) {
@@ -60,7 +77,7 @@ class JoinDeclarationAndAssignmentIntention : SelfTargetingOffsetIndependentInte
val initializer = assignment.right ?: return
val newInitializer = element.setInitializer(initializer)!!
val initializerBlock = assignment.parent?.parent as? KtAnonymousInitializer
val initializerBlock = assignment.parent.parent as? KtAnonymousInitializer
assignment.delete()
if (initializerBlock != null && (initializerBlock.body as? KtBlockExpression)?.isEmpty() == true) {
initializerBlock.delete()
@@ -108,7 +125,7 @@ class JoinDeclarationAndAssignmentIntention : SelfTargetingOffsetIndependentInte
if (assignments.any { it.parent.invalidParent() }) return null
val first = assignments.firstOrNull() ?: return null
if (assignments.any { it !== first && it.parent?.parent is KtSecondaryConstructor}) return null
if (assignments.any { it !== first && it.parent.parent is KtSecondaryConstructor}) return null
return first
}
@@ -0,0 +1,6 @@
// IS_APPLICABLE: true
// WITH_RUNTIME
fun foo() {
val x: String<caret>
x = System.getProperty("")
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: true
// WITH_RUNTIME
fun foo() {
val x: String = System.getProperty("")
}
@@ -0,0 +1,6 @@
// IS_APPLICABLE: false
fun foo() {
val x: Any<caret>
x = "123"
x.length // Smart cast before join, error after join
}
@@ -8754,6 +8754,18 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/joinDeclarationAndAssignment"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("assignmentForFlexible.kt")
public void testAssignmentForFlexible() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinDeclarationAndAssignment/assignmentForFlexible.kt");
doTest(fileName);
}
@TestMetadata("assignmentForSmartCast.kt")
public void testAssignmentForSmartCast() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinDeclarationAndAssignment/assignmentForSmartCast.kt");
doTest(fileName);
}
@TestMetadata("assignmentInIf.kt")
public void testAssignmentInIf() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinDeclarationAndAssignment/assignmentInIf.kt");