From 182cde1e023cefae74ff2977293c980e563ce7de Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 30 Oct 2015 12:00:38 +0300 Subject: [PATCH] Standard data flow analysis results are taken into account during condition analysis #KT-7933 Fixed --- .../types/expressions/DataFlowAnalyzer.java | 23 ++++++-- .../smartCasts/complexConditionsWithExcl.kt | 55 +++++++++++++++++++ .../smartCasts/complexConditionsWithExcl.txt | 3 + .../tests/smartCasts/exclUnderAnd.kt | 13 +++++ .../tests/smartCasts/exclUnderAnd.txt | 12 ++++ .../checkers/JetDiagnosticsTestGenerated.java | 12 ++++ 6 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/smartCasts/complexConditionsWithExcl.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/complexConditionsWithExcl.txt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/exclUnderAnd.kt create mode 100644 compiler/testData/diagnostics/tests/smartCasts/exclUnderAnd.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java index b805fcc9ec2..21903c9d783 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java @@ -49,17 +49,20 @@ public class DataFlowAnalyzer { private final ConstantExpressionEvaluator constantExpressionEvaluator; private final KotlinBuiltIns builtIns; private final SmartCastManager smartCastManager; + private final ExpressionTypingFacade facade; public DataFlowAnalyzer( @NotNull Iterable additionalTypeCheckers, @NotNull ConstantExpressionEvaluator constantExpressionEvaluator, @NotNull KotlinBuiltIns builtIns, - @NotNull SmartCastManager smartCastManager + @NotNull SmartCastManager smartCastManager, + @NotNull ExpressionTypingFacade facade ) { this.additionalTypeCheckers = additionalTypeCheckers; this.constantExpressionEvaluator = constantExpressionEvaluator; this.builtIns = builtIns; this.smartCastManager = smartCastManager; + this.facade = facade; } @NotNull @@ -100,6 +103,7 @@ public class DataFlowAnalyzer { result.set(dataFlowInfo); } else { + DataFlowInfo expressionFlowInfo = facade.getTypeInfo(expression, context).getDataFlowInfo(); KtExpression left = expression.getLeft(); if (left == null) return; KtExpression right = expression.getRight(); @@ -122,12 +126,14 @@ public class DataFlowAnalyzer { } if (equals != null) { if (equals == conditionValue) { // this means: equals && conditionValue || !equals && !conditionValue - result.set(context.dataFlowInfo.equate(leftValue, rightValue)); + result.set(context.dataFlowInfo.equate(leftValue, rightValue).and(expressionFlowInfo)); } else { - result.set(context.dataFlowInfo.disequate(leftValue, rightValue)); + result.set(context.dataFlowInfo.disequate(leftValue, rightValue).and(expressionFlowInfo)); } - + } + else { + result.set(expressionFlowInfo); } } } @@ -141,6 +147,15 @@ public class DataFlowAnalyzer { result.set(extractDataFlowInfoFromCondition(baseExpression, !conditionValue, context)); } } + else { + visitExpression(expression); + } + } + + @Override + public void visitExpression(@NotNull KtExpression expression) { + // In fact, everything is taken from trace here + result.set(facade.getTypeInfo(expression, context).getDataFlowInfo()); } @Override diff --git a/compiler/testData/diagnostics/tests/smartCasts/complexConditionsWithExcl.kt b/compiler/testData/diagnostics/tests/smartCasts/complexConditionsWithExcl.kt new file mode 100644 index 00000000000..6bebc88fd02 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/complexConditionsWithExcl.kt @@ -0,0 +1,55 @@ +fun foo(x: String?, y: String?, z: String?) { + if ((x!!.hashCode() == 0 || y!!.hashCode() == 1) && z!!.hashCode() == 2) { + x.length + y.length + // condition is true => z!! after and is called + z.length + } + else { + x.length + y.length + z.length + } + // First element is always analyzed + x.length + var xx = y ?: z + if ((xx!!.hashCode() == 0 && y!!.hashCode() == 1) || z!!.hashCode() == 2) { + xx.length + y.length + z.length + } + else { + xx.length + y.length + // condition is false => z!! after or is called + z.length + } + // First element is always analyzed + x.length + xx = y ?: z + if (xx!!.hashCode() == 0 && y!!.hashCode() == 1 && z!!.hashCode() == 2) { + // all three are called + xx.length + y.length + z.length + } + else { + xx.length + y.length + z.length + } + // First element is always analyzed + x.length + xx = y ?: z + if (xx!!.hashCode() == 0 || y!!.hashCode() == 1 || z!!.hashCode() == 2) { + xx.length + y.length + z.length + } + else { + // all three are called + xx.length + y.length + z.length + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/complexConditionsWithExcl.txt b/compiler/testData/diagnostics/tests/smartCasts/complexConditionsWithExcl.txt new file mode 100644 index 00000000000..82abd2c8fa4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/complexConditionsWithExcl.txt @@ -0,0 +1,3 @@ +package + +public fun foo(/*0*/ x: kotlin.String?, /*1*/ y: kotlin.String?, /*2*/ z: kotlin.String?): kotlin.Unit diff --git a/compiler/testData/diagnostics/tests/smartCasts/exclUnderAnd.kt b/compiler/testData/diagnostics/tests/smartCasts/exclUnderAnd.kt new file mode 100644 index 00000000000..cecfa9fdede --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/exclUnderAnd.kt @@ -0,0 +1,13 @@ +class D(val a: String, val b: Boolean) + +fun foo(p: Boolean, v: D?): String { + if (p && v!!.b) v.a + else v.a + if (p && v!! == D("?", false)) v.a + else v.a + if (p || v!!.b) v.a + else v.a + if (p || v!! == D("?", false)) v.a + else v.a + return "" +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/exclUnderAnd.txt b/compiler/testData/diagnostics/tests/smartCasts/exclUnderAnd.txt new file mode 100644 index 00000000000..44c497b26c8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/exclUnderAnd.txt @@ -0,0 +1,12 @@ +package + +public fun foo(/*0*/ p: kotlin.Boolean, /*1*/ v: D?): kotlin.String + +public final class D { + public constructor D(/*0*/ a: kotlin.String, /*1*/ b: kotlin.Boolean) + public final val a: kotlin.String + public final val b: kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index e87ff1a0553..838d3e47ad4 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -14310,6 +14310,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("complexConditionsWithExcl.kt") + public void testComplexConditionsWithExcl() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/complexConditionsWithExcl.kt"); + doTest(fileName); + } + @TestMetadata("dataFlowInfoForArguments.kt") public void testDataFlowInfoForArguments() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/dataFlowInfoForArguments.kt"); @@ -14346,6 +14352,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("exclUnderAnd.kt") + public void testExclUnderAnd() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/exclUnderAnd.kt"); + doTest(fileName); + } + @TestMetadata("extensionSafeCall.kt") public void testExtensionSafeCall() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/extensionSafeCall.kt");