Fix unsound smartcast from loop condition on assigned vars

^KT-22379 Fixed
This commit is contained in:
Dmitry Savvinov
2018-06-21 12:57:36 +03:00
committed by Dmitry Savvinov
parent a7d706f693
commit 447c127036
8 changed files with 85 additions and 2 deletions
@@ -286,9 +286,16 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo(),
components.languageVersionSettings));
}
DataFlowInfo conservativeInfoAfterLoop =
components.languageVersionSettings.supportsFeature(LanguageFeature.SoundSmartcastFromLoopConditionForLoopAssignedVariables)
? loopVisitor.clearDataFlowInfoForAssignedLocalVariables(dataFlowInfo, components.languageVersionSettings)
: dataFlowInfo;
return components.dataFlowAnalyzer
.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType)
.replaceDataFlowInfo(dataFlowInfo);
.replaceDataFlowInfo(conservativeInfoAfterLoop);
}
private boolean containsJumpOutOfLoop(@NotNull KtExpression expression, ExpressionTypingContext context) {
@@ -459,9 +466,14 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
bodyTypeInfo = loopRangeInfo;
}
DataFlowInfo conservativeInfoAfterLoop =
components.languageVersionSettings.supportsFeature(LanguageFeature.SoundSmartcastFromLoopConditionForLoopAssignedVariables)
? loopVisitor.clearDataFlowInfoForAssignedLocalVariables(loopRangeInfo.getDataFlowInfo(), components.languageVersionSettings)
: loopRangeInfo.getDataFlowInfo();
return components.dataFlowAnalyzer
.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType)
.replaceDataFlowInfo(loopRangeInfo.getDataFlowInfo());
.replaceDataFlowInfo(conservativeInfoAfterLoop);
}
private VariableDescriptor createLoopParameterDescriptor(
@@ -0,0 +1,21 @@
// !LANGUAGE: +SoundSmartcastFromLoopConditionForLoopAssignedVariables
fun foo() {
var x: String? = "123"
while (x!!.length < 42) {
x = null
break
}
x<!UNSAFE_CALL!>.<!>length // 'x' is unsoundly smartcasted here
}
fun bar() {
var x: List<Int>? = ArrayList<Int>(1)
for (i in x!!) {
x = null
break
}
x<!UNSAFE_CALL!>.<!>size // 'x' is unsoundly smartcasted here
}
@@ -0,0 +1,4 @@
package
public fun bar(): kotlin.Unit
public fun foo(): kotlin.Unit
@@ -0,0 +1,21 @@
// !LANGUAGE: -SoundSmartcastFromLoopConditionForLoopAssignedVariables
fun foo() {
var x: String? = "123"
while (x!!.length < 42) {
x = null
break
}
<!DEBUG_INFO_SMARTCAST!>x<!>.length // 'x' is unsoundly smartcasted here
}
fun bar() {
var x: List<Int>? = ArrayList<Int>(1)
for (i in x!!) {
x = null
break
}
<!DEBUG_INFO_SMARTCAST!>x<!>.size // 'x' is unsoundly smartcasted here
}
@@ -0,0 +1,4 @@
package
public fun bar(): kotlin.Unit
public fun foo(): kotlin.Unit
@@ -19822,6 +19822,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
public void testWhileTrueWithBreakInIfCondition() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/WhileTrueWithBreakInIfCondition.kt");
}
@TestMetadata("whileWithAssertInConditionAndBreakAfter.kt")
public void testWhileWithAssertInConditionAndBreakAfter() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/whileWithAssertInConditionAndBreakAfter.kt");
}
@TestMetadata("whileWithAssertInConditionAndBreakBefore.kt")
public void testWhileWithAssertInConditionAndBreakBefore() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/whileWithAssertInConditionAndBreakBefore.kt");
}
}
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts/objectLiterals")
@@ -19822,6 +19822,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
public void testWhileTrueWithBreakInIfCondition() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/WhileTrueWithBreakInIfCondition.kt");
}
@TestMetadata("whileWithAssertInConditionAndBreakAfter.kt")
public void testWhileWithAssertInConditionAndBreakAfter() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/whileWithAssertInConditionAndBreakAfter.kt");
}
@TestMetadata("whileWithAssertInConditionAndBreakBefore.kt")
public void testWhileWithAssertInConditionAndBreakBefore() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/whileWithAssertInConditionAndBreakBefore.kt");
}
}
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts/objectLiterals")
@@ -85,6 +85,7 @@ enum class LanguageFeature(
NormalizeConstructorCalls(KOTLIN_1_3),
StrictJavaNullabilityAssertions(KOTLIN_1_3, kind = BUG_FIX),
SoundSmartcastForEnumEntries(KOTLIN_1_3, kind = BUG_FIX),
SoundSmartcastFromLoopConditionForLoopAssignedVariables(KOTLIN_1_3, kind = BUG_FIX),
RestrictReturnStatementTarget(KOTLIN_1_4, kind = BUG_FIX),
ProperIeee754Comparisons(sinceVersion = null, defaultState = State.DISABLED, kind = BUG_FIX),