Add IDEA data-flow analysis to guess nullability

Add "if return..." folding to "return if"
This commit is contained in:
Simon Ogorodnik
2017-05-25 15:54:10 +03:00
parent 1f26353de4
commit e41c027c9a
24 changed files with 261 additions and 40 deletions
@@ -63,6 +63,11 @@ fun KtExpression.unwrapBlockOrParenthesis(): KtExpression {
return innerExpression
}
fun KtExpression?.isTrivialStatementBody(): Boolean = when (this?.unwrapBlockOrParenthesis()) {
is KtIfExpression, is KtBlockExpression -> false
else -> true
}
fun KtExpression?.isNullExpression(): Boolean = this?.unwrapBlockOrParenthesis()?.node?.elementType == KtNodeTypes.NULL
fun KtExpression?.isNullExpressionOrEmptyBlock(): Boolean = this.isNullExpression() || this is KtBlockExpression && this.statements.isEmpty()
@@ -16,8 +16,13 @@
package org.jetbrains.kotlin.idea.j2k
import com.intellij.codeInspection.dataFlow.DfaUtil
import com.intellij.codeInspection.dataFlow.Nullness
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiVariable
import org.jetbrains.kotlin.j2k.*
import org.jetbrains.kotlin.j2k.ast.Nullability
object IdeaJavaToKotlinServices : JavaToKotlinConverterServices {
override val referenceSearcher: ReferenceSearcher
@@ -31,8 +36,25 @@ object IdeaJavaToKotlinServices : JavaToKotlinConverterServices {
override val docCommentConverter: DocCommentConverter
get() = IdeaDocCommentConverter
override val javaDataFlowAnalyzerFacade: JavaDataFlowAnalyzerFacade
get() = IdeaJavaDataFlowAnalyzerFacade
}
object IdeaSuperMethodSearcher : SuperMethodsSearcher {
override fun findDeepestSuperMethods(method: PsiMethod) = method.findDeepestSuperMethods().asList()
}
private object IdeaJavaDataFlowAnalyzerFacade : JavaDataFlowAnalyzerFacade {
override fun variableNullability(variable: PsiVariable, context: PsiElement): Nullability =
DfaUtil.checkNullness(variable, context).toNullability()
override fun methodNullability(method: PsiMethod): Nullability =
DfaUtil.inferMethodNullity(method).toNullability()
private fun Nullness.toNullability() = when (this) {
Nullness.UNKNOWN -> Nullability.Default
Nullness.NOT_NULL -> Nullability.NotNull
Nullness.NULLABLE -> Nullability.Nullable
}
}
@@ -27,8 +27,11 @@ import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.core.setVisibility
import org.jetbrains.kotlin.idea.inspections.RedundantSamConstructorInspection
import org.jetbrains.kotlin.idea.intentions.*
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FoldIfToReturnAsymmetricallyIntention
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.FoldIfToReturnIntention
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfThenToElvisIntention
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions.IfThenToSafeAccessIntention
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isTrivialStatementBody
import org.jetbrains.kotlin.idea.intentions.conventionNameCalls.ReplaceGetOrSetInspection
import org.jetbrains.kotlin.idea.intentions.conventionNameCalls.ReplaceGetOrSetIntention
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
@@ -76,9 +79,14 @@ object J2KPostProcessingRegistrar {
_processings.add(RemoveRedundantCastToNullableProcessing())
registerIntentionBasedProcessing(ConvertToExpressionBodyIntention(convertEmptyToUnit = false)) { it is KtPropertyAccessor }
registerIntentionBasedProcessing(FoldInitializerAndIfToElvisIntention())
registerIntentionBasedProcessing(FoldIfToReturnIntention()) { it.then.isTrivialStatementBody() && it.`else`.isTrivialStatementBody() }
registerIntentionBasedProcessing(FoldIfToReturnAsymmetricallyIntention()) { it.then.isTrivialStatementBody() && (KtPsiUtil.skipTrailingWhitespacesAndComments(it) as KtReturnExpression).returnedExpression.isTrivialStatementBody() }
registerIntentionBasedProcessing(IfThenToSafeAccessIntention())
registerIntentionBasedProcessing(IfThenToElvisIntention())
registerIntentionBasedProcessing(FoldInitializerAndIfToElvisIntention())
registerIntentionBasedProcessing(SimplifyNegatedBinaryExpressionIntention())
registerIntentionBasedProcessing(ReplaceGetOrSetIntention(), additionalChecker = ReplaceGetOrSetInspection.additionalChecker)
registerIntentionBasedProcessing(AddOperatorModifierIntention())