Join declaration & assignment is no more suggested in case of potential smart cast available #KT-15412 Fixed
This commit is contained in:
+20
-3
@@ -21,6 +21,7 @@ import com.intellij.openapi.editor.ScrollType
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiReferenceService
|
import com.intellij.psi.PsiReferenceService
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
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.canOmitDeclaredType
|
||||||
import org.jetbrains.kotlin.idea.core.moveCaret
|
import org.jetbrains.kotlin.idea.core.moveCaret
|
||||||
import org.jetbrains.kotlin.idea.core.unblockDocument
|
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.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
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>(
|
class JoinDeclarationAndAssignmentInspection : IntentionBasedInspection<KtProperty>(
|
||||||
JoinDeclarationAndAssignmentIntention::class,
|
JoinDeclarationAndAssignmentIntention::class,
|
||||||
@@ -39,6 +44,12 @@ class JoinDeclarationAndAssignmentIntention : SelfTargetingOffsetIndependentInte
|
|||||||
"Join declaration and assignment"
|
"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 {
|
override fun isApplicableTo(element: KtProperty): Boolean {
|
||||||
if (element.hasDelegate()
|
if (element.hasDelegate()
|
||||||
|| element.hasInitializer()
|
|| element.hasInitializer()
|
||||||
@@ -50,7 +61,13 @@ class JoinDeclarationAndAssignmentIntention : SelfTargetingOffsetIndependentInte
|
|||||||
}
|
}
|
||||||
|
|
||||||
val assignment = findAssignment(element) ?: return false
|
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?) {
|
override fun applyTo(element: KtProperty, editor: Editor?) {
|
||||||
@@ -60,7 +77,7 @@ class JoinDeclarationAndAssignmentIntention : SelfTargetingOffsetIndependentInte
|
|||||||
val initializer = assignment.right ?: return
|
val initializer = assignment.right ?: return
|
||||||
val newInitializer = element.setInitializer(initializer)!!
|
val newInitializer = element.setInitializer(initializer)!!
|
||||||
|
|
||||||
val initializerBlock = assignment.parent?.parent as? KtAnonymousInitializer
|
val initializerBlock = assignment.parent.parent as? KtAnonymousInitializer
|
||||||
assignment.delete()
|
assignment.delete()
|
||||||
if (initializerBlock != null && (initializerBlock.body as? KtBlockExpression)?.isEmpty() == true) {
|
if (initializerBlock != null && (initializerBlock.body as? KtBlockExpression)?.isEmpty() == true) {
|
||||||
initializerBlock.delete()
|
initializerBlock.delete()
|
||||||
@@ -108,7 +125,7 @@ class JoinDeclarationAndAssignmentIntention : SelfTargetingOffsetIndependentInte
|
|||||||
if (assignments.any { it.parent.invalidParent() }) return null
|
if (assignments.any { it.parent.invalidParent() }) return null
|
||||||
|
|
||||||
val first = assignments.firstOrNull() ?: 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
|
return first
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// IS_APPLICABLE: true
|
||||||
|
// WITH_RUNTIME
|
||||||
|
fun foo() {
|
||||||
|
val x: String<caret>
|
||||||
|
x = System.getProperty("")
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// IS_APPLICABLE: true
|
||||||
|
// WITH_RUNTIME
|
||||||
|
fun foo() {
|
||||||
|
val x: String = System.getProperty("")
|
||||||
|
}
|
||||||
+6
@@ -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);
|
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")
|
@TestMetadata("assignmentInIf.kt")
|
||||||
public void testAssignmentInIf() throws Exception {
|
public void testAssignmentInIf() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinDeclarationAndAssignment/assignmentInIf.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/joinDeclarationAndAssignment/assignmentInIf.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user