mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin-dfa] Better approach to ignore smart-casts while computing DFA hints in debugging
Fixes IDEA-360842 Kotlin Debugger: no DFA hints in if condition with return statement and smartcast GitOrigin-RevId: c7700f782d6298490d9604d60915014748b77f7a
This commit is contained in:
committed by
intellij-monorepo-bot
parent
44ac817eb2
commit
0914c4dc26
+6
-6
@@ -316,7 +316,7 @@ class KotlinConstantConditionsInspection : AbstractKotlinInspection() {
|
||||
if (condition.textLength == 0) return true
|
||||
return isCompilationWarning(condition)
|
||||
}
|
||||
|
||||
|
||||
private fun isFailingBranchInExhaustiveWhen(condition: KtWhenCondition): Boolean {
|
||||
val entry = condition.parent as? KtWhenEntry ?: return false
|
||||
val whenExpr = entry.parent as? KtWhenExpression ?: return false
|
||||
@@ -538,11 +538,11 @@ class KotlinConstantConditionsInspection : AbstractKotlinInspection() {
|
||||
DfTypes.intValue(0), DfTypes.longValue(0) -> ConstantValue.ZERO
|
||||
else -> ConstantValue.UNKNOWN
|
||||
}
|
||||
return analyze(expression) { shouldSuppress(constant, expression) }
|
||||
return analyze(expression) { shouldSuppress(constant, expression, true) }
|
||||
}
|
||||
|
||||
context(KaSession)
|
||||
private fun shouldSuppress(value: ConstantValue, expression: KtExpression): Boolean {
|
||||
private fun shouldSuppress(value: ConstantValue, expression: KtExpression, ignoreSmartCasts: Boolean = false): Boolean {
|
||||
var parent = expression.parent
|
||||
if (parent is KtDotQualifiedExpression && parent.selectorExpression == expression) {
|
||||
// Will be reported for parent qualified expression
|
||||
@@ -577,7 +577,7 @@ class KotlinConstantConditionsInspection : AbstractKotlinInspection() {
|
||||
ConstantValue.TRUE -> {
|
||||
//if (isUselessIsCheck(expression)) return true
|
||||
if (isAndOrConditionWithNothingOperand(expression, KtTokens.OROR)) return true
|
||||
if (isSmartCastNecessary(expression, true)) return true
|
||||
if (!ignoreSmartCasts && isSmartCastNecessary(expression, true)) return true
|
||||
if (isPairingConditionInWhen(expression)) return true
|
||||
if (isAssertion(parent, true)) return true
|
||||
}
|
||||
@@ -585,7 +585,7 @@ class KotlinConstantConditionsInspection : AbstractKotlinInspection() {
|
||||
ConstantValue.FALSE -> {
|
||||
//if (isUselessIsCheck(expression)) return true
|
||||
if (isAndOrConditionWithNothingOperand(expression, KtTokens.ANDAND)) return true
|
||||
if (isSmartCastNecessary(expression, false)) return true
|
||||
if (!ignoreSmartCasts && isSmartCastNecessary(expression, false)) return true
|
||||
if (isAssertion(parent, false)) return true
|
||||
}
|
||||
|
||||
@@ -638,7 +638,7 @@ class KotlinConstantConditionsInspection : AbstractKotlinInspection() {
|
||||
}
|
||||
if (typeParameterType != null && expression.expectedType == typeParameterType) {
|
||||
// Do not report always-null when an expected expression type is the same type parameter
|
||||
// as it's not possible to replace it with a null literal without an unchecked cast
|
||||
// as it's not possible to replace it with a null literal without an unchecked cast
|
||||
return true
|
||||
}
|
||||
if (expression is KtBinaryExpressionWithTypeRHS && expression.left.isNull()) {
|
||||
|
||||
+1
-6
@@ -241,12 +241,7 @@ class K2DfaAssistProvider : DfaAssistProvider {
|
||||
var psi = when (anchor) {
|
||||
is KotlinAnchor.KotlinExpressionAnchor -> {
|
||||
if (!shouldTrackExpressionValue(anchor.expression)) return
|
||||
if (KotlinConstantConditionsInspection.shouldSuppress(dfType, anchor.expression) &&
|
||||
dfType.tryNegate()
|
||||
?.let { negated -> KotlinConstantConditionsInspection.shouldSuppress(negated, anchor.expression) } != false
|
||||
) {
|
||||
return
|
||||
}
|
||||
if (KotlinConstantConditionsInspection.shouldSuppress(dfType, anchor.expression)) return
|
||||
anchor.expression
|
||||
}
|
||||
|
||||
|
||||
+38
@@ -579,6 +579,44 @@ class K2DfaAssistTest : DfaAssistTest(), ExpectedPluginModeProvider {
|
||||
doTest(text) { _, _ -> }
|
||||
}
|
||||
|
||||
fun testSmartCastDoesNotAffectDebugging() {
|
||||
val text = """
|
||||
fun useNullable(clazz: Any?) {
|
||||
<caret>if (clazz == null/*TRUE*/) return
|
||||
/*unreachable_start*/with(clazz) {
|
||||
if (/*unreachable_start*/this !is String/*unreachable_end*/) /*unreachable_start*/return/*unreachable_end*/
|
||||
println(length)
|
||||
}/*unreachable_end*/
|
||||
}
|
||||
|
||||
fun main() {
|
||||
useNullable(null)
|
||||
}
|
||||
""".trimIndent()
|
||||
doTest(text) { vm, frame ->
|
||||
frame.addVariable(MockLocalVariable(vm, "clazz", vm.createReferenceType(Object::class.java), null))
|
||||
}
|
||||
}
|
||||
|
||||
fun testSmartCastDoesNotAffectDebugging2() {
|
||||
val text = """
|
||||
fun useNullable(clazz: Any?) {
|
||||
<caret>if (clazz == null/*FALSE*/) /*unreachable_start*/return/*unreachable_end*/
|
||||
with(clazz) {
|
||||
if (this !is String) return
|
||||
println(length)
|
||||
}
|
||||
}
|
||||
|
||||
fun main() {
|
||||
useNullable("foo")
|
||||
}
|
||||
""".trimIndent()
|
||||
doTest(text) { vm, frame ->
|
||||
frame.addVariable("clazz", MockValue.createValue("foo", String::class.java, vm))
|
||||
}
|
||||
}
|
||||
|
||||
private fun doTest(text: String, mockValues: BiConsumer<MockVirtualMachine, MockStackFrame>) {
|
||||
doTest(text, mockValues, "Test.kt")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user