RemoveExplicitTypeIntention: fix false positive for type aliases
#KT-33902 Fixed
This commit is contained in:
@@ -22,6 +22,7 @@ import com.intellij.openapi.util.TextRange
|
|||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.refactoring.addTypeArgumentsIfNeeded
|
import org.jetbrains.kotlin.idea.refactoring.addTypeArgumentsIfNeeded
|
||||||
import org.jetbrains.kotlin.idea.refactoring.getQualifiedTypeArgumentList
|
import org.jetbrains.kotlin.idea.refactoring.getQualifiedTypeArgumentList
|
||||||
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
@@ -68,7 +69,7 @@ class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclar
|
|||||||
|
|
||||||
val initializer = (element as? KtDeclarationWithInitializer)?.initializer
|
val initializer = (element as? KtDeclarationWithInitializer)?.initializer
|
||||||
|
|
||||||
if (!redundantTypeSpecification(element, initializer)) return null
|
if (!redundantTypeSpecification(element.typeReference, initializer)) return null
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
initializer != null -> TextRange(element.startOffset, initializer.startOffset - 1)
|
initializer != null -> TextRange(element.startOffset, initializer.startOffset - 1)
|
||||||
@@ -78,18 +79,27 @@ class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclar
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun redundantTypeSpecification(element: KtCallableDeclaration, initializer: KtExpression?): Boolean {
|
tailrec fun redundantTypeSpecification(typeReference: KtTypeReference?, initializer: KtExpression?): Boolean {
|
||||||
if (initializer == null) return true
|
if (initializer == null || typeReference == null) return true
|
||||||
if (initializer !is KtLambdaExpression && initializer !is KtNamedFunction) return true
|
if (initializer !is KtLambdaExpression && initializer !is KtNamedFunction) return true
|
||||||
val functionType = element.typeReference?.typeElement as? KtFunctionType ?: return true
|
val typeElement = typeReference.typeElement ?: return true
|
||||||
if (functionType.receiver != null) return false
|
return when (typeElement) {
|
||||||
if (functionType.parameters.isEmpty()) return true
|
is KtFunctionType -> {
|
||||||
val valueParameters = when (initializer) {
|
if (typeElement.receiver != null) return false
|
||||||
is KtLambdaExpression -> initializer.valueParameters
|
if (typeElement.parameters.isEmpty()) return true
|
||||||
is KtNamedFunction -> initializer.valueParameters
|
val valueParameters = when (initializer) {
|
||||||
else -> emptyList()
|
is KtLambdaExpression -> initializer.valueParameters
|
||||||
|
is KtNamedFunction -> initializer.valueParameters
|
||||||
|
else -> emptyList()
|
||||||
|
}
|
||||||
|
valueParameters.isNotEmpty() && valueParameters.none { it.typeReference == null }
|
||||||
|
}
|
||||||
|
is KtUserType -> {
|
||||||
|
val typeAlias = typeElement.referenceExpression?.mainReference?.resolve() as? KtTypeAlias ?: return true
|
||||||
|
return redundantTypeSpecification(typeAlias.getTypeReference(), initializer)
|
||||||
|
}
|
||||||
|
else -> true
|
||||||
}
|
}
|
||||||
return valueParameters.isNotEmpty() && valueParameters.none { it.typeReference == null }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ open class RemovePsiElementSimpleFix(element: PsiElement, private val text: Stri
|
|||||||
object RemoveVariableFactory : KotlinSingleIntentionActionFactory() {
|
object RemoveVariableFactory : KotlinSingleIntentionActionFactory() {
|
||||||
public override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<PsiElement>? {
|
public override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<PsiElement>? {
|
||||||
val expression = diagnostic.psiElement.getNonStrictParentOfType<KtProperty>() ?: return null
|
val expression = diagnostic.psiElement.getNonStrictParentOfType<KtProperty>() ?: return null
|
||||||
if (!RemoveExplicitTypeIntention.redundantTypeSpecification(expression, expression.initializer)) return null
|
if (!RemoveExplicitTypeIntention.redundantTypeSpecification(expression.typeReference, expression.initializer)) return null
|
||||||
return object : RemovePsiElementSimpleFix(expression, "Remove variable '${expression.name}'") {
|
return object : RemovePsiElementSimpleFix(expression, "Remove variable '${expression.name}'") {
|
||||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||||
val initializer = expression.initializer
|
val initializer = expression.initializer
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// IS_APPLICABLE: false
|
||||||
|
|
||||||
|
typealias ValidationRule2 = (String, String) -> String
|
||||||
|
typealias ValidationRule3 = ValidationRule2
|
||||||
|
typealias ValidationRule4 = ValidationRule3
|
||||||
|
|
||||||
|
fun getValidator(): ValidationRule4<caret> = { text, eventType ->
|
||||||
|
"abc"
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
typealias ValidationRule2 = String
|
||||||
|
typealias ValidationRule3 = ValidationRule2
|
||||||
|
typealias ValidationRule4 = ValidationRule3
|
||||||
|
|
||||||
|
fun getValidator(): ValidationRule4<caret> = "abc"
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
typealias ValidationRule2 = String
|
||||||
|
typealias ValidationRule3 = ValidationRule2
|
||||||
|
typealias ValidationRule4 = ValidationRule3
|
||||||
|
|
||||||
|
fun getValidator() = "abc"
|
||||||
@@ -13367,6 +13367,16 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
runTest("idea/testData/intentions/removeExplicitType/lambdaInitializer5.kt");
|
runTest("idea/testData/intentions/removeExplicitType/lambdaInitializer5.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("lambdaInitializerWithAlias.kt")
|
||||||
|
public void testLambdaInitializerWithAlias() throws Exception {
|
||||||
|
runTest("idea/testData/intentions/removeExplicitType/lambdaInitializerWithAlias.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("lambdaInitializerWithAlias2.kt")
|
||||||
|
public void testLambdaInitializerWithAlias2() throws Exception {
|
||||||
|
runTest("idea/testData/intentions/removeExplicitType/lambdaInitializerWithAlias2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("needTypeArgument.kt")
|
@TestMetadata("needTypeArgument.kt")
|
||||||
public void testNeedTypeArgument() throws Exception {
|
public void testNeedTypeArgument() throws Exception {
|
||||||
runTest("idea/testData/intentions/removeExplicitType/needTypeArgument.kt");
|
runTest("idea/testData/intentions/removeExplicitType/needTypeArgument.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user