FIR IDE: refactor hasRedundantTypeSpecification

No logic change.

GitOrigin-RevId: f578f7977765daa940307aa94e4ad175446ff9f6
This commit is contained in:
Tianyu Geng
2022-02-08 08:49:36 +00:00
committed by intellij-monorepo-bot
parent 8fea63479f
commit 759acce996
3 changed files with 28 additions and 22 deletions
@@ -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>(PsiElement::class, PsiElementSuitabilityCheckers.ALWAYS_SUITABLE) {
public override fun doCreateQuickFix(psiElement: PsiElement): List<IntentionAction> {
if (psiElement is KtDestructuringDeclarationEntry) return emptyList()
val expression = psiElement.getNonStrictParentOfType<KtProperty>() ?: return emptyList()
if (!hasRedundantTypeSpecification(expression.typeReference, expression.initializer)) return emptyList()
val ktProperty = psiElement.getNonStrictParentOfType<KtProperty>() ?: 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()
}
}
}
@@ -180,26 +180,32 @@ fun generateWhenBranches(element: KtWhenExpression, missingCases: List<WhenMissi
}
}
tailrec fun hasRedundantTypeSpecification(typeReference: KtTypeReference?, initializer: KtExpression?): Boolean {
if (initializer == null || typeReference == null) return true
if (initializer !is KtLambdaExpression && initializer !is KtNamedFunction) return true
val typeElement = typeReference.typeElement ?: return true
if (typeReference.hasModifier(KtTokens.SUSPEND_KEYWORD)) return false
/**
* Consider a property initialization `val f: (Int) -> 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
}
}
@@ -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<KtCallableDeclar
element.resolveToDescriptorIfAny()
)
) return null
if (!hasRedundantTypeSpecification(element.typeReference, initializer)) return null
if (element.isExplicitTypeReferenceNeededForTypeInference()) return null
return when {
initializer != null -> TextRange(element.startOffset, initializer.startOffset - 1)