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(), dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo(),
components.languageVersionSettings)); components.languageVersionSettings));
} }
DataFlowInfo conservativeInfoAfterLoop =
components.languageVersionSettings.supportsFeature(LanguageFeature.SoundSmartcastFromLoopConditionForLoopAssignedVariables)
? loopVisitor.clearDataFlowInfoForAssignedLocalVariables(dataFlowInfo, components.languageVersionSettings)
: dataFlowInfo;
return components.dataFlowAnalyzer return components.dataFlowAnalyzer
.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType) .checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType)
.replaceDataFlowInfo(dataFlowInfo); .replaceDataFlowInfo(conservativeInfoAfterLoop);
} }
private boolean containsJumpOutOfLoop(@NotNull KtExpression expression, ExpressionTypingContext context) { private boolean containsJumpOutOfLoop(@NotNull KtExpression expression, ExpressionTypingContext context) {
@@ -459,9 +466,14 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
bodyTypeInfo = loopRangeInfo; bodyTypeInfo = loopRangeInfo;
} }
DataFlowInfo conservativeInfoAfterLoop =
components.languageVersionSettings.supportsFeature(LanguageFeature.SoundSmartcastFromLoopConditionForLoopAssignedVariables)
? loopVisitor.clearDataFlowInfoForAssignedLocalVariables(loopRangeInfo.getDataFlowInfo(), components.languageVersionSettings)
: loopRangeInfo.getDataFlowInfo();
return components.dataFlowAnalyzer return components.dataFlowAnalyzer
.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType) .checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType)
.replaceDataFlowInfo(loopRangeInfo.getDataFlowInfo()); .replaceDataFlowInfo(conservativeInfoAfterLoop);
} }
private VariableDescriptor createLoopParameterDescriptor( 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 { public void testWhileTrueWithBreakInIfCondition() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/WhileTrueWithBreakInIfCondition.kt"); 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") @TestMetadata("compiler/testData/diagnostics/tests/smartCasts/objectLiterals")
@@ -19822,6 +19822,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
public void testWhileTrueWithBreakInIfCondition() throws Exception { public void testWhileTrueWithBreakInIfCondition() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/WhileTrueWithBreakInIfCondition.kt"); 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") @TestMetadata("compiler/testData/diagnostics/tests/smartCasts/objectLiterals")
@@ -85,6 +85,7 @@ enum class LanguageFeature(
NormalizeConstructorCalls(KOTLIN_1_3), NormalizeConstructorCalls(KOTLIN_1_3),
StrictJavaNullabilityAssertions(KOTLIN_1_3, kind = BUG_FIX), StrictJavaNullabilityAssertions(KOTLIN_1_3, kind = BUG_FIX),
SoundSmartcastForEnumEntries(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), RestrictReturnStatementTarget(KOTLIN_1_4, kind = BUG_FIX),
ProperIeee754Comparisons(sinceVersion = null, defaultState = State.DISABLED, kind = BUG_FIX), ProperIeee754Comparisons(sinceVersion = null, defaultState = State.DISABLED, kind = BUG_FIX),