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
|
@NotNull
|
||||||
private static Nullability getImmanentNullability(@NotNull JetType type) {
|
private static Nullability getImmanentNullability(@NotNull JetType type) {
|
||||||
return TypeUtils.isNullableType(type) ? Nullability.UNKNOWN : Nullability.NOT_NULL;
|
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.JetType;
|
||||||
import org.jetbrains.kotlin.types.TypeUtils;
|
import org.jetbrains.kotlin.types.TypeUtils;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -130,7 +131,39 @@ import static org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability.NOT_NULL
|
|||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
changed |= putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB));
|
changed |= putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB));
|
||||||
changed |= putNullability(builder, b, nullabilityOfB.refine(nullabilityOfA));
|
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
|
@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.OverloadResolutionResults;
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil;
|
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil;
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
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.JetScope;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.WritableScope;
|
import org.jetbrains.kotlin.resolve.scopes.WritableScope;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||||
@@ -135,6 +137,12 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
|
|||||||
JetType outType = propertyDescriptor.getType();
|
JetType outType = propertyDescriptor.getType();
|
||||||
JetTypeInfo typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType));
|
JetTypeInfo typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType));
|
||||||
dataFlowInfo = typeInfo.getDataFlowInfo();
|
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) {
|
if (right != null) {
|
||||||
JetTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType));
|
JetTypeInfo rightInfo = facade.getTypeInfo(right, context.replaceDataFlowInfo(dataFlowInfo).replaceExpectedType(leftType));
|
||||||
dataFlowInfo = rightInfo.getDataFlowInfo();
|
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
|
if (leftType != null && leftOperand != null) { //if leftType == null, some other error has been generated
|
||||||
BasicExpressionTypingVisitor.checkLValue(context.trace, leftOperand);
|
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")
|
@TestMetadata("compiler/testData/diagnostics/tests/dataFlow")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@InnerTestClasses({DataFlow.Local.class})
|
@InnerTestClasses({DataFlow.Assignment.class, DataFlow.Local.class})
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public static class DataFlow extends AbstractJetDiagnosticsTest {
|
public static class DataFlow extends AbstractJetDiagnosticsTest {
|
||||||
public void testAllFilesPresentInDataFlow() throws Exception {
|
public void testAllFilesPresentInDataFlow() throws Exception {
|
||||||
@@ -2308,6 +2308,45 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("compiler/testData/diagnostics/tests/dataFlow/local")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user