KT-6118 Redundant type cast can be not redundant?

#KT-6118 Fixed
This commit is contained in:
Andrey Breslav
2015-02-16 14:38:34 +03:00
parent 47f772e75a
commit 54483dbb95
14 changed files with 178 additions and 2 deletions
@@ -78,6 +78,12 @@ public class DataFlowValueFactory {
}
}
@NotNull
public static DataFlowValue createDataFlowValue(@NotNull VariableDescriptor variableDescriptor) {
JetType type = variableDescriptor.getType();
return new DataFlowValue(variableDescriptor, type, isStableVariable(variableDescriptor), getImmanentNullability(type));
}
@NotNull
private static Nullability getImmanentNullability(@NotNull JetType type) {
return TypeUtils.isNullableType(type) ? Nullability.UNKNOWN : Nullability.NOT_NULL;
@@ -22,6 +22,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.TypeUtils;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
@@ -130,7 +131,39 @@ import static org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability.NOT_NULL
boolean changed = false;
changed |= putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB));
changed |= putNullability(builder, b, nullabilityOfB.refine(nullabilityOfA));
return changed ? new DelegatingDataFlowInfo(this, ImmutableMap.copyOf(builder), EMPTY_TYPE_INFO) : this;
SetMultimap<DataFlowValue, JetType> newTypeInfo = newTypeInfo();
newTypeInfo.putAll(a, collectTypesFromMeAndParents(b));
newTypeInfo.putAll(b, collectTypesFromMeAndParents(a));
changed |= !newTypeInfo.isEmpty();
return !changed
? this
: new DelegatingDataFlowInfo(
this,
ImmutableMap.copyOf(builder),
newTypeInfo.isEmpty() ? EMPTY_TYPE_INFO : newTypeInfo
);
}
@NotNull
private Set<JetType> collectTypesFromMeAndParents(@NotNull DataFlowValue value) {
Set<JetType> types = new LinkedHashSet<JetType>();
DataFlowInfo current = this;
while (current != null) {
if (current instanceof DelegatingDataFlowInfo) {
DelegatingDataFlowInfo delegatingInfo = (DelegatingDataFlowInfo) current;
types.addAll(delegatingInfo.typeInfo.get(value));
current = delegatingInfo.parent;
}
else {
types.addAll(current.getPossibleTypes(value));
break;
}
}
return types;
}
@Override
@@ -38,6 +38,8 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil;
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.JetScope;
import org.jetbrains.kotlin.resolve.scopes.WritableScope;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
@@ -135,6 +137,12 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
JetType outType = propertyDescriptor.getType();
JetTypeInfo typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType));
dataFlowInfo = typeInfo.getDataFlowInfo();
JetType type = typeInfo.getType();
if (property.getTypeReference() == null && type != null) {
DataFlowValue variableDataFlowValue = DataFlowValueFactory.createDataFlowValue(propertyDescriptor);
DataFlowValue initializerDataFlowValue = DataFlowValueFactory.createDataFlowValue(initializer, type, context.trace.getBindingContext());
dataFlowInfo = dataFlowInfo.equate(variableDataFlowValue, initializerDataFlowValue);
}
}
{
@@ -335,6 +343,12 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
if (right != null) {
JetTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType));
dataFlowInfo = rightInfo.getDataFlowInfo();
JetType rightType = rightInfo.getType();
if (left != null && leftType != null && rightType != null) {
DataFlowValue leftValue = DataFlowValueFactory.createDataFlowValue(left, leftType, context.trace.getBindingContext());
DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rightType, context.trace.getBindingContext());
dataFlowInfo = dataFlowInfo.equate(leftValue, rightValue);
}
}
if (leftType != null && leftOperand != null) { //if leftType == null, some other error has been generated
BasicExpressionTypingVisitor.checkLValue(context.trace, leftOperand);
@@ -0,0 +1,10 @@
fun test(a: Any?) {
if (a == null) return
<!DEBUG_INFO_SMARTCAST!>a<!>.hashCode()
val b = a
<!DEBUG_INFO_SMARTCAST!>b<!>.hashCode()
val c: Any? = a
c<!UNSAFE_CALL!>.<!>hashCode()
}
@@ -0,0 +1,3 @@
package
internal fun test(/*0*/ a: kotlin.Any?): kotlin.Unit
@@ -0,0 +1,16 @@
// KT-6118 Redundant type cast can be not redundant?
fun foo(o: Any) {
if (o is String) {
val s = o <!USELESS_CAST_STATIC_ASSERT_IS_FINE!>as String<!>
s.length()
}
}
fun foo1(o: Any) {
if (o is String) {
<!DEBUG_INFO_SMARTCAST!>o<!>.length()
val s = o
<!DEBUG_INFO_SMARTCAST!>s<!>.length()
}
}
@@ -0,0 +1,4 @@
package
internal fun foo(/*0*/ o: kotlin.Any): kotlin.Unit
internal fun foo1(/*0*/ o: kotlin.Any): kotlin.Unit
@@ -0,0 +1,15 @@
fun test(a: Any?, flag: Boolean, x: Any?) {
if (a !is String) return
<!DEBUG_INFO_SMARTCAST!>a<!>.length()
val b: Any?
if (flag) {
b = a
<!DEBUG_INFO_SMARTCAST!>b<!>.length()
}
else {
b = x
b.<!UNRESOLVED_REFERENCE!>length<!>()
}
}
@@ -0,0 +1,3 @@
package
internal fun test(/*0*/ a: kotlin.Any?, /*1*/ flag: kotlin.Boolean, /*2*/ x: kotlin.Any?): kotlin.Unit
@@ -0,0 +1,15 @@
fun test(a: Any?, flag: Boolean, x: Any?) {
if (a == null) return
<!DEBUG_INFO_SMARTCAST!>a<!>.hashCode()
val b: Any?
if (flag) {
b = a
<!DEBUG_INFO_SMARTCAST!>b<!>.hashCode()
}
else {
b = x
b<!UNSAFE_CALL!>.<!>hashCode()
}
}
@@ -0,0 +1,3 @@
package
internal fun test(/*0*/ a: kotlin.Any?, /*1*/ flag: kotlin.Boolean, /*2*/ x: kotlin.Any?): kotlin.Unit
@@ -0,0 +1,12 @@
fun test(a: Any?) {
when (a) {
is String -> {
val s = a
<!DEBUG_INFO_SMARTCAST!>s<!>.length()
}
"" -> {
val s = a
<!DEBUG_INFO_SMARTCAST!>s<!>.hashCode()
}
}
}
@@ -0,0 +1,3 @@
package
internal fun test(/*0*/ a: kotlin.Any?): kotlin.Unit
@@ -2277,7 +2277,7 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
@TestMetadata("compiler/testData/diagnostics/tests/dataFlow")
@TestDataPath("$PROJECT_ROOT")
@InnerTestClasses({DataFlow.Local.class})
@InnerTestClasses({DataFlow.Assignment.class, DataFlow.Local.class})
@RunWith(JUnit3RunnerWithInners.class)
public static class DataFlow extends AbstractJetDiagnosticsTest {
public void testAllFilesPresentInDataFlow() throws Exception {
@@ -2308,6 +2308,45 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("compiler/testData/diagnostics/tests/dataFlow/assignment")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Assignment extends AbstractJetDiagnosticsTest {
public void testAllFilesPresentInAssignment() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/dataFlow/assignment"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("assignToNewVal.kt")
public void testAssignToNewVal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataFlow/assignment/assignToNewVal.kt");
doTest(fileName);
}
@TestMetadata("kt6118.kt")
public void testKt6118() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataFlow/assignment/kt6118.kt");
doTest(fileName);
}
@TestMetadata("uninitializedValIsCheck.kt")
public void testUninitializedValIsCheck() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataFlow/assignment/uninitializedValIsCheck.kt");
doTest(fileName);
}
@TestMetadata("uninitializedValNullability.kt")
public void testUninitializedValNullability() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataFlow/assignment/uninitializedValNullability.kt");
doTest(fileName);
}
@TestMetadata("when.kt")
public void testWhen() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/dataFlow/assignment/when.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/diagnostics/tests/dataFlow/local")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)