Data flow information: stable complex expressions introduced back for brackets / elvis / if / when #KT-13468 Fixed

This reverts commit e515d7f773 and
also commit 1c9f08e986

(cherry picked from commit 9fa155b)
This commit is contained in:
Mikhail Glukhikh
2017-01-18 14:08:00 +03:00
committed by Mikhail Glukhikh
parent 86bc49558d
commit b6443eed9e
7 changed files with 75 additions and 12 deletions
@@ -39,6 +39,8 @@ class DataFlowValue(val identifierInfo: IdentifierInfo,
// or protected / public member value from the same module without open / custom getter
// Smart casts are completely safe
STABLE_VALUE("stable val"),
// Block, or if / else, or when
STABLE_COMPLEX_EXPRESSION("complex expression", ""),
// Member value with open / custom getter
// Smart casts are not safe
PROPERTY_WITH_GETTER("custom getter", "property that has open or custom getter"),
@@ -65,7 +67,7 @@ class DataFlowValue(val identifierInfo: IdentifierInfo,
* Stable means here we do not expect some sudden change of their values,
* like accessing mutable properties in another thread, so smart casts can be used safely.
*/
val isStable = (kind == Kind.STABLE_VALUE || kind == Kind.STABLE_VARIABLE)
val isStable = (kind == Kind.STABLE_VALUE || kind == Kind.STABLE_VARIABLE || kind == Kind.STABLE_COMPLEX_EXPRESSION)
override fun equals(other: Any?): Boolean {
if (this === other) return true
@@ -57,6 +57,16 @@ object DataFlowValueFactory {
resolutionContext: ResolutionContext<*>
) = createDataFlowValue(expression, type, resolutionContext.trace.bindingContext, resolutionContext.scope.ownerDescriptor)
private fun isComplexExpression(expression: KtExpression): Boolean = when(expression) {
is KtBlockExpression, is KtIfExpression, is KtWhenExpression -> true
is KtBinaryExpression -> expression.operationToken === KtTokens.ELVIS
is KtParenthesizedExpression -> {
val deparenthesized = KtPsiUtil.deparenthesize(expression)
deparenthesized != null && isComplexExpression(deparenthesized)
}
else -> false
}
@JvmStatic
fun createDataFlowValue(
expression: KtExpression,
@@ -85,6 +95,10 @@ object DataFlowValueFactory {
Nullability.NOT_NULL)
}
if (isComplexExpression(expression)) {
return createDataFlowValueForComplexExpression(expression, type)
}
val result = getIdForStableIdentifier(expression, bindingContext, containingDeclarationOrModule)
return DataFlowValue(if (result === IdentifierInfo.NO) ExpressionIdentifierInfo(expression) else result, type)
}
@@ -124,6 +138,11 @@ object DataFlowValueFactory {
bindingContext[BOUND_INITIALIZER_VALUE, variableDescriptor]),
variableDescriptor.type)
private fun createDataFlowValueForComplexExpression(
expression: KtExpression,
type: KotlinType
) = DataFlowValue(ExpressionIdentifierInfo(expression, stableComplex = true), type)
// For only ++ and -- postfix operations
private data class PostfixIdentifierInfo(val argumentInfo: IdentifierInfo, val op: KtToken) : IdentifierInfo {
override val kind: DataFlowValue.Kind get() = argumentInfo.kind
@@ -131,8 +150,13 @@ object DataFlowValueFactory {
override fun toString() = "$argumentInfo($op)"
}
data class ExpressionIdentifierInfo(val expression: KtExpression) : IdentifierInfo {
override val kind = OTHER
class ExpressionIdentifierInfo(val expression: KtExpression, stableComplex: Boolean = false) : IdentifierInfo {
override val kind = if (stableComplex) STABLE_COMPLEX_EXPRESSION else OTHER
override fun equals(other: Any?) = other is ExpressionIdentifierInfo && expression == other.expression
override fun hashCode() = expression.hashCode()
override fun toString() = expression.text ?: "(empty expression)"
}
@@ -177,7 +177,14 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (innerExpression == null) {
return TypeInfoFactoryKt.noTypeInfo(context);
}
return facade.getTypeInfo(innerExpression, context.replaceScope(context.scope));
KotlinTypeInfo result = facade.getTypeInfo(innerExpression, context.replaceScope(context.scope));
KotlinType resultType = result.getType();
if (resultType != null) {
DataFlowValue innerValue = DataFlowValueFactory.createDataFlowValue(innerExpression, resultType, context);
DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(expression, resultType, context);
result = result.replaceDataFlowInfo(result.getDataFlowInfo().assign(resultValue, innerValue));
}
return result;
}
@Override
@@ -1319,8 +1326,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
}
DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(expression, type, context);
dataFlowInfo = dataFlowInfo.disequate(resultValue, nullValue);
dataFlowInfo = dataFlowInfo.assign(resultValue, leftValue).disequate(resultValue, nullValue);
if (!jumpInRight) {
DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rightType, context);
rightDataFlowInfo = rightDataFlowInfo.assign(resultValue, rightValue);
dataFlowInfo = dataFlowInfo.or(rightDataFlowInfo);
}
}
@@ -31,6 +31,8 @@ import org.jetbrains.kotlin.resolve.ModifiersChecker;
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
@@ -150,6 +152,13 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
KotlinType elseType = elseTypeInfo.getType();
DataFlowInfo thenDataFlowInfo = thenTypeInfo.getDataFlowInfo();
DataFlowInfo elseDataFlowInfo = elseTypeInfo.getDataFlowInfo();
if (resultType != null && thenType != null && elseType != null) {
DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(ifExpression, resultType, context);
DataFlowValue thenValue = DataFlowValueFactory.createDataFlowValue(thenBranch, thenType, context);
thenDataFlowInfo = thenDataFlowInfo.assign(resultValue, thenValue);
DataFlowValue elseValue = DataFlowValueFactory.createDataFlowValue(elseBranch, elseType, context);
elseDataFlowInfo = elseDataFlowInfo.assign(resultValue, elseValue);
}
loopBreakContinuePossible |= thenTypeInfo.getJumpOutPossible() || elseTypeInfo.getJumpOutPossible();
@@ -30,6 +30,8 @@ import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency;
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
@@ -267,6 +269,13 @@ public class ExpressionTypingServices {
result = getTypeOfLastExpressionInBlock(
statementExpression, newContext.replaceExpectedType(context.expectedType), coercionStrategyForLastExpression,
blockLevelVisitor);
if (result.getType() != null && statementExpression.getParent() instanceof KtBlockExpression) {
DataFlowValue lastExpressionValue = DataFlowValueFactory.createDataFlowValue(
statementExpression, result.getType(), context);
DataFlowValue blockExpressionValue = DataFlowValueFactory.createDataFlowValue(
(KtBlockExpression) statementExpression.getParent(), result.getType(), context);
result = result.replaceDataFlowInfo(result.getDataFlowInfo().assign(blockExpressionValue, lastExpressionValue));
}
}
else {
result = blockLevelVisitor
@@ -105,8 +105,10 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
val dataFlowInfoForEntries = analyzeConditionsInWhenEntries(expression, contextAfterSubject, subjectDataFlowValue, subjectType)
val whenReturnType = inferTypeForWhenExpression(expression, contextWithExpectedType, contextAfterSubject, dataFlowInfoForEntries)
val whenResultValue = whenReturnType?.let { DataFlowValueFactory.createDataFlowValue(expression, it, contextAfterSubject) }
val branchesTypeInfo = joinWhenExpressionBranches(expression, contextAfterSubject, whenReturnType, jumpOutPossibleInSubject)
val branchesTypeInfo =
joinWhenExpressionBranches(expression, contextAfterSubject, whenReturnType, jumpOutPossibleInSubject, whenResultValue)
val isExhaustive = WhenChecker.isWhenExhaustive(expression, trace)
@@ -191,7 +193,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
expression: KtWhenExpression,
contextAfterSubject: ExpressionTypingContext,
resultType: KotlinType?,
jumpOutPossibleInSubject: Boolean
jumpOutPossibleInSubject: Boolean,
whenResultValue: DataFlowValue?
): KotlinTypeInfo {
val bindingContext = contextAfterSubject.trace.bindingContext
@@ -208,7 +211,14 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
errorTypeExistInBranch = true
}
val entryDataFlowInfo = entryTypeInfo.dataFlowInfo
val entryDataFlowInfo =
if (whenResultValue != null && entryType != null) {
val entryValue = DataFlowValueFactory.createDataFlowValue(entryExpression, entryType, contextAfterSubject)
entryTypeInfo.dataFlowInfo.assign(whenResultValue, entryValue)
}
else {
entryTypeInfo.dataFlowInfo
}
currentDataFlowInfo =
if (entryType != null && KotlinBuiltIns.isNothing(entryType))
@@ -3,7 +3,7 @@
fun basic(): String {
var current: String? = null
current = if (current == null) "bar" else current
return <!TYPE_MISMATCH!>current<!>
return <!DEBUG_INFO_SMARTCAST!>current<!>
}
fun foo(flag: Boolean) {
@@ -13,7 +13,7 @@ fun foo(flag: Boolean) {
x = if (flag) "34" else "12"
}
x<!UNSAFE_CALL!>.<!>hashCode()
<!DEBUG_INFO_SMARTCAST!>x<!>.hashCode()
}
fun bar(flag: Boolean) {
@@ -26,7 +26,7 @@ fun bar(flag: Boolean) {
}
}
x<!UNSAFE_CALL!>.<!>hashCode()
<!DEBUG_INFO_SMARTCAST!>x<!>.hashCode()
}
fun baz(flag: Boolean) {
@@ -40,7 +40,7 @@ fun baz(flag: Boolean) {
}
}
x<!UNSAFE_CALL!>.<!>hashCode()
<!DEBUG_INFO_SMARTCAST!>x<!>.hashCode()
}
fun gav(flag: Boolean, arg: String?) {