DFA: count null comparison as identity comparison #KT-16538 Fixed
+ minor parameter refactoring
This commit is contained in:
committed by
Mikhail Glukhikh
parent
b5aa529901
commit
4700936f66
@@ -73,9 +73,8 @@ interface DataFlowInfo {
|
||||
|
||||
/**
|
||||
* Call this function when it's known than a == b.
|
||||
* sameTypes should be true iff we have guarantee that a and b have the same type
|
||||
*/
|
||||
fun equate(a: DataFlowValue, b: DataFlowValue, sameTypes: Boolean, languageVersionSettings: LanguageVersionSettings): DataFlowInfo
|
||||
fun equate(a: DataFlowValue, b: DataFlowValue, identityEquals: Boolean, languageVersionSettings: LanguageVersionSettings): DataFlowInfo
|
||||
|
||||
/**
|
||||
* Call this function when it's known than a != b
|
||||
|
||||
+2
-2
@@ -169,7 +169,7 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
}
|
||||
|
||||
override fun equate(
|
||||
a: DataFlowValue, b: DataFlowValue, sameTypes: Boolean, languageVersionSettings: LanguageVersionSettings
|
||||
a: DataFlowValue, b: DataFlowValue, identityEquals: Boolean, languageVersionSettings: LanguageVersionSettings
|
||||
): DataFlowInfo {
|
||||
val builder = Maps.newHashMap<DataFlowValue, Nullability>()
|
||||
val nullabilityOfA = getStableNullability(a)
|
||||
@@ -180,7 +180,7 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
|
||||
// NB: == has no guarantees of type equality, see KT-11280 for the example
|
||||
val newTypeInfo = newTypeInfo()
|
||||
if (sameTypes) {
|
||||
if (identityEquals || !nullabilityOfA.canBeNonNull() || !nullabilityOfB.canBeNonNull()) {
|
||||
newTypeInfo.putAll(a, getStableTypes(b, false))
|
||||
newTypeInfo.putAll(b, getStableTypes(a, false))
|
||||
if (a.type != b.type) {
|
||||
|
||||
@@ -178,10 +178,11 @@ public class DataFlowAnalyzer {
|
||||
}
|
||||
if (equals != null) {
|
||||
if (equals == conditionValue) { // this means: equals && conditionValue || !equals && !conditionValue
|
||||
boolean byIdentity = operationToken == KtTokens.EQEQEQ || operationToken == KtTokens.EXCLEQEQEQ ||
|
||||
typeHasEqualsFromAny(lhsType, condition);
|
||||
boolean identityEquals = operationToken == KtTokens.EQEQEQ ||
|
||||
operationToken == KtTokens.EXCLEQEQEQ ||
|
||||
typeHasEqualsFromAny(lhsType, condition);
|
||||
result.set(context.dataFlowInfo
|
||||
.equate(leftValue, rightValue, byIdentity, languageVersionSettings)
|
||||
.equate(leftValue, rightValue, identityEquals, languageVersionSettings)
|
||||
.and(expressionFlowInfo));
|
||||
}
|
||||
else {
|
||||
|
||||
+2
-2
@@ -407,8 +407,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
||||
val result = noChange(newContext)
|
||||
return ConditionalDataFlowInfo(
|
||||
result.thenInfo.equate(subjectDataFlowValue, expressionDataFlowValue,
|
||||
DataFlowAnalyzer.typeHasEqualsFromAny(subjectType, expression),
|
||||
components.languageVersionSettings),
|
||||
identityEquals = DataFlowAnalyzer.typeHasEqualsFromAny(subjectType, expression),
|
||||
languageVersionSettings = components.languageVersionSettings),
|
||||
result.elseInfo.disequate(subjectDataFlowValue,
|
||||
expressionDataFlowValue,
|
||||
components.languageVersionSettings)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
fun foo(x: String?) = x
|
||||
|
||||
class Test
|
||||
|
||||
class TestWithEquals {
|
||||
override fun equals(other: Any?) = super.equals(other)
|
||||
}
|
||||
|
||||
fun bar(i: Test?) {
|
||||
if (i == null) foo(<!DEBUG_INFO_CONSTANT!>i<!>)
|
||||
}
|
||||
|
||||
fun bar(i: TestWithEquals?) {
|
||||
if (i == null) foo(<!DEBUG_INFO_CONSTANT!>i<!>)
|
||||
if (null == i) foo(<!DEBUG_INFO_CONSTANT!>i<!>)
|
||||
when (i) {
|
||||
null -> foo(<!DEBUG_INFO_CONSTANT!>i<!>)
|
||||
}
|
||||
}
|
||||
|
||||
fun gav(i: TestWithEquals?, j: TestWithEquals?) {
|
||||
if (j == null) {
|
||||
if (i == <!DEBUG_INFO_CONSTANT!>j<!>) foo(<!DEBUG_INFO_CONSTANT!>i<!>)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package
|
||||
|
||||
public fun bar(/*0*/ i: Test?): kotlin.Unit
|
||||
public fun bar(/*0*/ i: TestWithEquals?): kotlin.Unit
|
||||
public fun foo(/*0*/ x: kotlin.String?): kotlin.String?
|
||||
public fun gav(/*0*/ i: TestWithEquals?, /*1*/ j: TestWithEquals?): kotlin.Unit
|
||||
|
||||
public final class Test {
|
||||
public constructor Test()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class TestWithEquals {
|
||||
public constructor TestWithEquals()
|
||||
public open override /*1*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -19132,6 +19132,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("equals.kt")
|
||||
public void testEquals() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/equals.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("exclUnderAnd.kt")
|
||||
public void testExclUnderAnd() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/exclUnderAnd.kt");
|
||||
|
||||
Reference in New Issue
Block a user