diff --git a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/RemovePsiElementSimpleFix.kt b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/RemovePsiElementSimpleFix.kt index f15f1bbba605..241613207d30 100644 --- a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/RemovePsiElementSimpleFix.kt +++ b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/quickfix/RemovePsiElementSimpleFix.kt @@ -12,7 +12,7 @@ import com.intellij.psi.PsiElement import org.jetbrains.annotations.Nls import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.util.CommentSaver -import org.jetbrains.kotlin.idea.util.hasRedundantTypeSpecification +import org.jetbrains.kotlin.idea.util.isExplicitTypeReferenceNeededForTypeInference import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType @@ -67,23 +67,23 @@ open class RemovePsiElementSimpleFix private constructor(element: PsiElement, @N object RemoveVariableFactory : QuickFixesPsiBasedFactory(PsiElement::class, PsiElementSuitabilityCheckers.ALWAYS_SUITABLE) { public override fun doCreateQuickFix(psiElement: PsiElement): List { if (psiElement is KtDestructuringDeclarationEntry) return emptyList() - val expression = psiElement.getNonStrictParentOfType() ?: return emptyList() - if (!hasRedundantTypeSpecification(expression.typeReference, expression.initializer)) return emptyList() + val ktProperty = psiElement.getNonStrictParentOfType() ?: return emptyList() + if (ktProperty.isExplicitTypeReferenceNeededForTypeInference()) return emptyList() return listOf(RemoveVariableFix(expression)) } } class RemoveVariableFix(expression: KtProperty) : - RemovePsiElementSimpleFix(expression, KotlinBundle.message("remove.variable.0", expression.name.toString())) { + RemovePsiElementSimpleFix(expression, KotlinBundle.message("remove.variable.0", ktProperty.name.toString())) { override fun invoke(project: Project, editor: Editor?, file: KtFile) { - val expression = element as? KtProperty ?: return - val initializer = expression.initializer + val ktProperty = element as? KtProperty ?: return + val initializer = ktProperty.initializer if (initializer != null && initializer !is KtConstantExpression) { - val commentSaver = CommentSaver(expression) - val replaced = expression.replace(initializer) + val commentSaver = CommentSaver(ktProperty) + val replaced = ktProperty.replace(initializer) commentSaver.restore(replaced) } else { - expression.delete() + ktProperty.delete() } } } diff --git a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/util/psiUtils.kt b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/util/psiUtils.kt index 4dc8cee2b080..1edc7f21d1e3 100644 --- a/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/util/psiUtils.kt +++ b/plugins/kotlin/frontend-independent/src/org/jetbrains/kotlin/idea/util/psiUtils.kt @@ -180,26 +180,32 @@ fun generateWhenBranches(element: KtWhenExpression, missingCases: List Unit = { println(it) }`. The type annotation `(Int) -> Unit` in this case is required + * in order for the code to type check because otherwise the compiler cannot infer the type of `it`. + */ +tailrec fun KtCallableDeclaration.isExplicitTypeReferenceNeededForTypeInference(typeRef: KtTypeReference? = typeReference): Boolean { + if (this !is KtDeclarationWithInitializer) return false + val initializer = initializer + if (initializer == null || typeRef == null) return false + if (initializer !is KtLambdaExpression && initializer !is KtNamedFunction) return false + val typeElement = typeRef.typeElement ?: return false + if (typeRef.hasModifier(KtTokens.SUSPEND_KEYWORD)) return true return when (typeElement) { is KtFunctionType -> { - if (typeElement.receiver != null) return false - if (typeElement.parameters.isEmpty()) return true + if (typeElement.receiver != null) return true + if (typeElement.parameters.isEmpty()) return false val valueParameters = when (initializer) { is KtLambdaExpression -> initializer.valueParameters is KtNamedFunction -> initializer.valueParameters else -> emptyList() } - valueParameters.isNotEmpty() && valueParameters.none { it.typeReference == null } + valueParameters.isEmpty() || valueParameters.any { it.typeReference == null } } is KtUserType -> { - val typeAlias = typeElement.referenceExpression?.mainReference?.resolve() as? KtTypeAlias ?: return true - return hasRedundantTypeSpecification(typeAlias.getTypeReference(), initializer) + val typeAlias = typeElement.referenceExpression?.mainReference?.resolve() as? KtTypeAlias ?: return false + return isExplicitTypeReferenceNeededForTypeInference(typeAlias.getTypeReference()) } - else -> true + else -> false } } diff --git a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveExplicitTypeIntention.kt b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveExplicitTypeIntention.kt index 61680550a9a5..586832428eb9 100644 --- a/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveExplicitTypeIntention.kt +++ b/plugins/kotlin/idea/src/org/jetbrains/kotlin/idea/intentions/RemoveExplicitTypeIntention.kt @@ -14,7 +14,7 @@ import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.refactoring.addTypeArgumentsIfNeeded import org.jetbrains.kotlin.idea.refactoring.getQualifiedTypeArgumentList import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor -import org.jetbrains.kotlin.idea.util.hasRedundantTypeSpecification +import org.jetbrains.kotlin.idea.util.isExplicitTypeReferenceNeededForTypeInference import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset @@ -68,7 +68,7 @@ class RemoveExplicitTypeIntention : SelfTargetingRangeIntention TextRange(element.startOffset, initializer.startOffset - 1)