KT-6118 Redundant type cast can be not redundant?
#KT-6118 Fixed
This commit is contained in:
+6
@@ -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;
|
||||
|
||||
+34
-1
@@ -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
|
||||
|
||||
+14
@@ -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
|
||||
+15
@@ -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()
|
||||
}
|
||||
}
|
||||
+3
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user