Fix bogus smartcast on enum entry members
Previously, enum entries were treated by the data-flow subsystem similar to other class/singletons. As a consequence, calls like 'Enum.ENTRY.property' had IdentifierInfo of 'property'. However, specially for enum entries, descriptor of 'property' is one and the same for all entries. It means that from the data-flow point of view, 'Enum.ONE.property' and 'Enum.TWO.property' are *one and the same data-flow values*. It could obviously lead to some bogus smartcasts, so this commit introduces separate IdentifierInfo.EnumEntry and uses it to build proper qualified values. ^KT-20772 Fixed
This commit is contained in:
committed by
Dmitry Savvinov
parent
ce6543b1cb
commit
952f67dafc
+13
-1
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.calls.smartcasts
|
package org.jetbrains.kotlin.resolve.calls.smartcasts
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.lexer.KtToken
|
import org.jetbrains.kotlin.lexer.KtToken
|
||||||
@@ -77,6 +78,10 @@ interface IdentifierInfo {
|
|||||||
override fun toString() = descriptor.toString()
|
override fun toString() = descriptor.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class EnumEntry(val descriptor: ClassDescriptor) : IdentifierInfo {
|
||||||
|
override val kind: DataFlowValue.Kind = STABLE_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
class Qualified(
|
class Qualified(
|
||||||
val receiverInfo: IdentifierInfo,
|
val receiverInfo: IdentifierInfo,
|
||||||
val selectorInfo: IdentifierInfo,
|
val selectorInfo: IdentifierInfo,
|
||||||
@@ -229,7 +234,14 @@ private fun getIdForSimpleNameExpression(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is PackageViewDescriptor, is ClassDescriptor -> IdentifierInfo.PackageOrClass(declarationDescriptor)
|
is ClassDescriptor -> {
|
||||||
|
if (declarationDescriptor.kind == ClassKind.ENUM_ENTRY && languageVersionSettings.supportsFeature(LanguageFeature.SoundSmartcastForEnumEntries))
|
||||||
|
IdentifierInfo.EnumEntry(declarationDescriptor)
|
||||||
|
else
|
||||||
|
IdentifierInfo.PackageOrClass(declarationDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
is PackageViewDescriptor -> IdentifierInfo.PackageOrClass(declarationDescriptor)
|
||||||
|
|
||||||
else -> IdentifierInfo.NO
|
else -> IdentifierInfo.NO
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// !LANGUAGE: +SoundSmartcastForEnumEntries
|
||||||
|
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||||
|
// SKIP_TXT
|
||||||
|
|
||||||
|
enum class Message(val text: String?) {
|
||||||
|
HELLO("hello"),
|
||||||
|
WORLD("world"),
|
||||||
|
NOTHING(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun printMessages() {
|
||||||
|
Message.HELLO.text!!
|
||||||
|
<!DEBUG_INFO_SMARTCAST!>Message.HELLO.text<!>.length
|
||||||
|
|
||||||
|
Message.NOTHING.text<!UNSAFE_CALL!>.<!>length
|
||||||
|
|
||||||
|
Message.NOTHING.text!!
|
||||||
|
<!DEBUG_INFO_SMARTCAST!>Message.NOTHING.text<!>.length
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// !LANGUAGE: -SoundSmartcastForEnumEntries
|
||||||
|
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||||
|
// SKIP_TXT
|
||||||
|
|
||||||
|
enum class Message(val text: String?) {
|
||||||
|
HELLO("hello"),
|
||||||
|
WORLD("world"),
|
||||||
|
NOTHING(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun printMessages() {
|
||||||
|
Message.HELLO.text!!
|
||||||
|
<!DEBUG_INFO_SMARTCAST!>Message.HELLO.text<!>.length
|
||||||
|
|
||||||
|
<!DEBUG_INFO_SMARTCAST!>Message.NOTHING.text<!>.length
|
||||||
|
|
||||||
|
Message.NOTHING.text<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
|
||||||
|
<!DEBUG_INFO_SMARTCAST!>Message.NOTHING.text<!>.length
|
||||||
|
}
|
||||||
@@ -18849,6 +18849,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/elvisRHS.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/elvisRHS.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("enumEntryMembers_after.kt")
|
||||||
|
public void testEnumEntryMembers_after() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/enumEntryMembers_after.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("enumEntryMembers_before.kt")
|
||||||
|
public void testEnumEntryMembers_before() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/enumEntryMembers_before.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("equals.kt")
|
@TestMetadata("equals.kt")
|
||||||
public void testEquals() throws Exception {
|
public void testEquals() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/equals.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/equals.kt");
|
||||||
|
|||||||
Generated
+10
@@ -18849,6 +18849,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/elvisRHS.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/elvisRHS.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("enumEntryMembers_after.kt")
|
||||||
|
public void testEnumEntryMembers_after() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/enumEntryMembers_after.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("enumEntryMembers_before.kt")
|
||||||
|
public void testEnumEntryMembers_before() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/enumEntryMembers_before.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("equals.kt")
|
@TestMetadata("equals.kt")
|
||||||
public void testEquals() throws Exception {
|
public void testEquals() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/equals.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/equals.kt");
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ enum class LanguageFeature(
|
|||||||
NoConstantValueAttributeForNonConstVals(KOTLIN_1_3, kind = BUG_FIX),
|
NoConstantValueAttributeForNonConstVals(KOTLIN_1_3, kind = BUG_FIX),
|
||||||
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),
|
||||||
|
|
||||||
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),
|
||||||
|
|||||||
Reference in New Issue
Block a user