Remove 'DataFlowValueKindUtils.isStable', use 'DataFlowValue.isStable' instead

This commit is contained in:
Dmitry Savvinov
2018-03-07 12:54:27 +03:00
parent 7b860eab36
commit 148573fcf6
25 changed files with 150 additions and 81 deletions
@@ -10,7 +10,7 @@ import com.intellij.codeInspection.*
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStable
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStableSimpleExpression
import org.jetbrains.kotlin.lexer.KtToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
@@ -94,8 +94,8 @@ class NullChecksToSafeCallInspection : AbstractKotlinInspection() {
}
private fun KtExpression.isChainStable(context: BindingContext): Boolean = when (this) {
is KtReferenceExpression -> isStable(context)
is KtQualifiedExpression -> selectorExpression?.isStable(context) == true && receiverExpression.isChainStable(context)
is KtReferenceExpression -> isStableSimpleExpression(context)
is KtQualifiedExpression -> selectorExpression?.isStableSimpleExpression(context) == true && receiverExpression.isChainStable(context)
else -> false
}
}
@@ -33,7 +33,7 @@ class IfThenToSafeAccessInspection : AbstractApplicabilityBasedInspection<KtIfEx
override fun isApplicable(element: KtIfExpression): Boolean {
val ifThenToSelectData = element.buildSelectTransformationData() ?: return false
if (!ifThenToSelectData.receiverExpression.isStable(ifThenToSelectData.context)) return false
if (!ifThenToSelectData.receiverExpression.isStableSimpleExpression(ifThenToSelectData.context)) return false
return ifThenToSelectData.clausesReplaceableBySafeCall()
}
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.evaluatesTo
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStable
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStableSimpleExpression
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
@@ -30,7 +30,7 @@ abstract class ReplaceSubstringIntention(text: String) : SelfTargetingRangeInten
protected abstract fun applicabilityRangeInner(element: KtDotQualifiedExpression): TextRange?
override fun applicabilityRange(element: KtDotQualifiedExpression): TextRange? {
if (element.receiverExpression.isStable() && element.isMethodCall("kotlin.text.substring")) {
if (element.receiverExpression.isStableSimpleExpression() && element.isMethodCall("kotlin.text.substring")) {
return applicabilityRangeInner(element)
}
return null
@@ -21,8 +21,9 @@ import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.intentions.getLeftMostReceiverExpression
@@ -31,15 +32,16 @@ import org.jetbrains.kotlin.idea.refactoring.inline.KotlinInlineValHandler
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler
import org.jetbrains.kotlin.idea.refactoring.isMultiLine
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getImplicitReceiverValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.isStableValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
@@ -158,11 +160,23 @@ fun KtPostfixExpression.inlineBaseExpressionIfApplicableWithPrompt(editor: Edito
(this.baseExpression as? KtNameReferenceExpression)?.inlineIfDeclaredLocallyAndOnlyUsedOnceWithPrompt(editor)
}
fun KtExpression.isStable(context: BindingContext = this.analyze()): Boolean {
if (this is KtConstantExpression || this is KtThisExpression) return true
val descriptor = BindingContextUtils.extractVariableDescriptorFromReference(context, this)
return descriptor is VariableDescriptor &&
isStableValue(descriptor, DescriptorUtils.getContainingModule(descriptor))
// I.e. stable val/var/receiver
// We exclude stable complex expressions here, because we don't do smartcasts on them (even though they are stable)
fun KtExpression.isStableSimpleExpression(context: BindingContext = this.analyze()): Boolean {
val dataFlowValue = this.toDataFlowValue(context)
return dataFlowValue?.isStable == true &&
dataFlowValue.kind != DataFlowValue.Kind.STABLE_COMPLEX_EXPRESSION
}
fun KtExpression.isStableVal(context: BindingContext = this.analyze()): Boolean {
return this.toDataFlowValue(context)?.kind == DataFlowValue.Kind.STABLE_VALUE
}
private fun KtExpression.toDataFlowValue(context: BindingContext): DataFlowValue? {
val expressionType = this.getType(context) ?: return null
val dataFlowValueFactory = this.getResolutionFacade().frontendService<DataFlowValueFactory>()
return dataFlowValueFactory.createDataFlowValue(this, expressionType, context, findModuleDescriptor())
}
data class IfThenToSelectData(
@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.convertToIfNotNullExpression
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.convertToIfNullExpression
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.introduceValueForCondition
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStable
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStableSimpleExpression
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtPostfixExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
@@ -56,7 +56,7 @@ class DoubleBangToIfThenIntention : SelfTargetingRangeIntention<KtPostfixExpress
val defaultException = KtPsiFactory(element).createExpression("throw NullPointerException()")
val isStatement = element.isUsedAsStatement(element.analyze())
val isStable = base.isStable()
val isStable = base.isStableSimpleExpression()
val ifStatement = if (isStatement)
element.convertToIfNullExpression(base, defaultException)
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.convertToIfNotNullExpression
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.convertToIfStatement
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.introduceValueForCondition
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStable
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStableSimpleExpression
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
@@ -82,14 +82,14 @@ class ElvisToIfThenIntention : SelfTargetingRangeIntention<KtBinaryExpression>(K
val newReceiver = leftSafeCastReceiver.left
val typeReference = leftSafeCastReceiver.right!!
val factory = KtPsiFactory(element)
newReceiver.isStable(context) to element.convertToIfStatement(
newReceiver.isStableSimpleExpression(context) to element.convertToIfStatement(
factory.createExpressionByPattern("$0 is $1", newReceiver, typeReference),
left.buildExpressionWithReplacedReceiver(factory, newReceiver),
right
)
}
else {
left.isStable(context) to element.convertToIfNotNullExpression(left, left, right)
left.isStableSimpleExpression(context) to element.convertToIfNotNullExpression(left, left, right)
}
if (!leftIsStable) {
@@ -38,7 +38,7 @@ class IfThenToDoubleBangIntention : SelfTargetingRangeIntention<KtIfExpression>(
val matchesAsStatement = element.isUsedAsStatement(context) && (baseClause?.isNullExpressionOrEmptyBlock() ?: true)
if (!matchesAsStatement &&
!(baseClause?.evaluatesTo(receiverExpression) ?: false && receiverExpression.isStable())) return null
!(baseClause?.evaluatesTo(receiverExpression) ?: false && receiverExpression.isStableSimpleExpression())) return null
var text = "Replace 'if' expression with '!!' expression"
if (!throwExpression.throwsNullPointerExceptionWithNoArguments()) {
@@ -57,7 +57,7 @@ class IfThenToElvisIntention : SelfTargetingOffsetIndependentIntention<KtIfExpre
override fun isApplicableTo(element: KtIfExpression): Boolean {
val ifThenToSelectData = element.buildSelectTransformationData() ?: return false
if (!ifThenToSelectData.receiverExpression.isStable(ifThenToSelectData.context)) return false
if (!ifThenToSelectData.receiverExpression.isStableSimpleExpression(ifThenToSelectData.context)) return false
val type = element.getType(ifThenToSelectData.context) ?: return false
if (KotlinBuiltIns.isUnit(type)) return false
@@ -23,7 +23,7 @@ import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.core.appendElement
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStable
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStableVal
import org.jetbrains.kotlin.idea.util.psi.patternMatching.matches
import org.jetbrains.kotlin.idea.util.psi.patternMatching.toRange
import org.jetbrains.kotlin.psi.*
@@ -36,7 +36,7 @@ class MergeWhenIntention : SelfTargetingRangeIntention<KtWhenExpression>(KtWhenE
val subject1 = element.subjectExpression
val subject2 = next.subjectExpression
if (!subject1.matches(subject2)) return null
if (subject1 != null && !subject1.isStable()) return null
if (subject1 != null && !subject1.isStableVal()) return null
val entries1 = element.entries
val entries2 = next.entries
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.convertToIfNotNullExpression
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.introduceValueForCondition
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStable
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStableSimpleExpression
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
@@ -40,7 +40,7 @@ class SafeAccessToIfThenIntention : SelfTargetingRangeIntention<KtSafeQualifiedE
val receiver = KtPsiUtil.safeDeparenthesize(element.receiverExpression)
val selector = element.selectorExpression!!
val receiverIsStable = receiver.isStable()
val receiverIsStable = receiver.isStableSimpleExpression()
val psiFactory = KtPsiFactory(element)
val dotQualified = psiFactory.createExpressionByPattern("$0.$1", receiver, selector)
@@ -23,7 +23,7 @@ import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStable
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStableSimpleExpression
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.psi.psiUtil.getLastParentOfTypeInRow
@@ -72,7 +72,7 @@ class SurroundWithNullCheckFix(
else -> return null
} as? KtReferenceExpression ?: return null
if (!nullableExpression.isStable(context)) return null
if (!nullableExpression.isStableSimpleExpression(context)) return null
val expressionTarget = expressionParent.getParentOfTypesAndPredicate(strict = false, parentClasses = KtExpression::class.java) {
!it.isUsedAsExpression(context) && it.hasAcceptableParent()
@@ -91,7 +91,7 @@ class SurroundWithNullCheckFix(
val forExpression = nullableExpression.parent.parent as? KtForExpression ?: return null
if (forExpression.parent !is KtBlockExpression) return null
if (!nullableExpression.isStable()) return null
if (!nullableExpression.isStableSimpleExpression()) return null
return SurroundWithNullCheckFix(forExpression, nullableExpression)
}
@@ -110,7 +110,7 @@ class SurroundWithNullCheckFix(
if (!isNullabilityMismatch(expected = typeMismatch.a, actual = typeMismatch.b)) return null
if (!nullableExpression.isStable()) return null
if (!nullableExpression.isStableSimpleExpression()) return null
return SurroundWithNullCheckFix(rootCall, nullableExpression)
}