Propagate control flow to bound double colon expressions
"Unused expression" should be reported on unused double colon expressions, this is postponed #KT-12551 Open
This commit is contained in:
@@ -53,6 +53,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
|||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
|
||||||
|
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -1349,7 +1350,16 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
|
|
||||||
override fun visitDoubleColonExpression(expression: KtDoubleColonExpression) {
|
override fun visitDoubleColonExpression(expression: KtDoubleColonExpression) {
|
||||||
mark(expression)
|
mark(expression)
|
||||||
createNonSyntheticValue(expression, MagicKind.CALLABLE_REFERENCE)
|
val receiverExpression = expression.receiverExpression
|
||||||
|
if (receiverExpression != null &&
|
||||||
|
trace.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, receiverExpression) is DoubleColonLHS.Expression) {
|
||||||
|
// TODO: UNUSED_EXPRESSION is not reported on the whole expression, see KT-12551
|
||||||
|
generateInstructions(receiverExpression)
|
||||||
|
createSyntheticValue(expression, MagicKind.BOUND_CALLABLE_REFERENCE, receiverExpression)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
createNonSyntheticValue(expression, MagicKind.UNBOUND_CALLABLE_REFERENCE)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitKtElement(element: KtElement) {
|
override fun visitKtElement(element: KtElement) {
|
||||||
|
|||||||
+2
-1
@@ -133,7 +133,8 @@ enum class MagicKind(val sideEffectFree: Boolean = false) {
|
|||||||
EQUALS_IN_WHEN_CONDITION(),
|
EQUALS_IN_WHEN_CONDITION(),
|
||||||
IS(),
|
IS(),
|
||||||
CAST(),
|
CAST(),
|
||||||
CALLABLE_REFERENCE(true),
|
UNBOUND_CALLABLE_REFERENCE(true),
|
||||||
|
BOUND_CALLABLE_REFERENCE(),
|
||||||
// implicit operations
|
// implicit operations
|
||||||
LOOP_RANGE_ITERATION(),
|
LOOP_RANGE_ITERATION(),
|
||||||
IMPLICIT_RECEIVER(),
|
IMPLICIT_RECEIVER(),
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ fun foo(): Any = ::bar
|
|||||||
L0:
|
L0:
|
||||||
1 <START>
|
1 <START>
|
||||||
mark(::bar)
|
mark(::bar)
|
||||||
magic[CALLABLE_REFERENCE](::bar) -> <v0>
|
magic[UNBOUND_CALLABLE_REFERENCE](::bar) -> <v0>
|
||||||
ret(*|<v0>) L1
|
ret(*|<v0>) L1
|
||||||
L1:
|
L1:
|
||||||
<END> NEXT:[<SINK>]
|
<END> NEXT:[<SINK>]
|
||||||
error:
|
error:
|
||||||
<ERROR> PREV:[]
|
<ERROR> PREV:[]
|
||||||
sink:
|
sink:
|
||||||
<SINK> PREV:[<ERROR>, <END>]
|
<SINK> PREV:[<ERROR>, <END>]
|
||||||
=====================
|
=====================
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ fun bar(): Int = 1
|
|||||||
== foo ==
|
== foo ==
|
||||||
fun foo(): Any = ::bar
|
fun foo(): Any = ::bar
|
||||||
---------------------
|
---------------------
|
||||||
::bar <v0>: {<: Any} NEW: magic[CALLABLE_REFERENCE](::bar) -> <v0>
|
::bar <v0>: {<: Any} NEW: magic[UNBOUND_CALLABLE_REFERENCE](::bar) -> <v0>
|
||||||
=====================
|
=====================
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
fun unusedExpression(s: String) {
|
||||||
|
// TODO: report UNUSED_EXPRESSION (KT-12551)
|
||||||
|
s::hashCode
|
||||||
|
s::class
|
||||||
|
}
|
||||||
|
|
||||||
|
fun noUnusedParameter(s: String): Int {
|
||||||
|
val f = s::hashCode
|
||||||
|
return f()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unreachableCode(): Int {
|
||||||
|
(if (true) return 1 else return 0)::toString
|
||||||
|
<!UNREACHABLE_CODE!>return 0<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unreachableCodeInLoop(): Int {
|
||||||
|
while (true) {
|
||||||
|
(break)::toString
|
||||||
|
<!UNREACHABLE_CODE!>return 1<!>
|
||||||
|
}
|
||||||
|
return 2
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun noUnusedParameter(/*0*/ s: kotlin.String): kotlin.Int
|
||||||
|
public fun unreachableCode(): kotlin.Int
|
||||||
|
public fun unreachableCodeInLoop(): kotlin.Int
|
||||||
|
public fun unusedExpression(/*0*/ s: kotlin.String): kotlin.Unit
|
||||||
+1
-1
@@ -15,6 +15,6 @@ data class User(val surname: String)
|
|||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
bar<String> {
|
bar<String> {
|
||||||
<!UNUSED_EXPRESSION!><!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>User<!>::<!OVERLOAD_RESOLUTION_AMBIGUITY!>surname<!><!>
|
<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>User<!>::<!OVERLOAD_RESOLUTION_AMBIGUITY!>surname<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1733,6 +1733,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("controlFlow.kt")
|
||||||
|
public void testControlFlow() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/bound/controlFlow.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("functionCallWithoutArguments.kt")
|
@TestMetadata("functionCallWithoutArguments.kt")
|
||||||
public void testFunctionCallWithoutArguments() throws Exception {
|
public void testFunctionCallWithoutArguments() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/bound/functionCallWithoutArguments.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/callableReference/bound/functionCallWithoutArguments.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user