Skip to content

Commit 6157ebe

Browse files
committed
Separate UNSAFE_IMPLICIT_INVOKE_CALL diagnostics introduced (see KT-8252)
1 parent fe11b5a commit 6157ebe

File tree

11 files changed

+33
-14
lines changed

11 files changed

+33
-14
lines changed

compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,7 @@ enum BadNamedArgumentsTarget {
646646
// Nullability
647647

648648
DiagnosticFactory1<PsiElement, KotlinType> UNSAFE_CALL = DiagnosticFactory1.create(ERROR);
649+
DiagnosticFactory1<PsiElement, KotlinType> UNSAFE_IMPLICIT_INVOKE_CALL = DiagnosticFactory1.create(ERROR);
649650
DiagnosticFactory3<KtExpression, String, String, String> UNSAFE_INFIX_CALL = DiagnosticFactory3.create(ERROR);
650651
DiagnosticFactory1<PsiElement, KotlinType> UNNECESSARY_SAFE_CALL = DiagnosticFactory1.create(WARNING);
651652
DiagnosticFactory0<PsiElement> UNEXPECTED_SAFE_CALL = DiagnosticFactory0.create(ERROR);

compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,7 @@ public String render(@NotNull KtExpression expression) {
469469
MAP.put(DYNAMIC_SUPERTYPE, "A supertype cannot be dynamic");
470470
MAP.put(REDUNDANT_NULLABLE, "Redundant '?'");
471471
MAP.put(UNSAFE_CALL, "Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type {0}", RENDER_TYPE);
472+
MAP.put(UNSAFE_IMPLICIT_INVOKE_CALL, "Reference has a nullable type {0}, use explicit '?.invoke()' to make function-like call instead", RENDER_TYPE);
472473
MAP.put(AMBIGUOUS_LABEL, "Ambiguous label");
473474
MAP.put(UNSUPPORTED, "Unsupported [{0}]", STRING);
474475
MAP.put(EXCEPTION_FROM_ANALYZER, "Internal Error occurred while analyzing this expression:\n{0}", THROWABLE);

compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -464,13 +464,15 @@ class CandidateResolver(
464464
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverArgument, this)
465465
val nullability = dataFlowInfo.getPredictableNullability(dataFlowValue)
466466
var nullableImplicitInvokeReceiver = false
467+
var receiverArgumentType = receiverArgument.type
467468
if (implicitInvokeCheck && call is CallForImplicitInvoke && call.isSafeCall()) {
468469
val outerCallReceiver = call.outerCall.explicitReceiver
469470
if (outerCallReceiver != call.explicitReceiver && outerCallReceiver is ReceiverValue) {
470471
val outerReceiverDataFlowValue = DataFlowValueFactory.createDataFlowValue(outerCallReceiver, this)
471472
val outerReceiverNullability = dataFlowInfo.getPredictableNullability(outerReceiverDataFlowValue)
472473
if (outerReceiverNullability.canBeNull() && !TypeUtils.isNullableType(expectedReceiverParameterType)) {
473474
nullableImplicitInvokeReceiver = true
475+
receiverArgumentType = TypeUtils.makeNullable(receiverArgumentType)
474476
}
475477
}
476478
}
@@ -499,8 +501,6 @@ class CandidateResolver(
499501
}
500502
}
501503

502-
val receiverArgumentType = receiverArgument.type
503-
504504
if (reportUnsafeCall || nullableImplicitInvokeReceiver) {
505505
tracing.unsafeCall(trace, receiverArgumentType, implicitInvokeCheck)
506506
return UNSAFE_CALL_ERROR

compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tasks/AbstractTracingStrategy.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ public void unsafeCall(@NotNull BindingTrace trace, @NotNull KotlinType type, bo
180180
trace.report(UNSAFE_INFIX_CALL.on(reference, left.getText(), operationString.asString(), right.getText()));
181181
}
182182
}
183+
else if (isCallForImplicitInvoke) {
184+
trace.report(UNSAFE_IMPLICIT_INVOKE_CALL.on(reference, type));
185+
}
183186
else {
184187
trace.report(UNSAFE_CALL.on(reference, type));
185188
}

compiler/testData/diagnostics/tests/SafeCallInvoke.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fun foo() {
1313
rule?.apply?.invoke()
1414

1515
// this should be an error
16-
rule?.<!UNSAFE_CALL!>apply<!>()
16+
rule?.<!UNSAFE_IMPLICIT_INVOKE_CALL!>apply<!>()
1717

1818
// these both also ok (with smart cast / unnecessary safe call)
1919
if (rule != null) {

compiler/testData/diagnostics/tests/extensions/kt1875.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ interface T {
99
}
1010

1111
fun test(t: T) {
12-
t.<!UNSAFE_CALL!>f<!>(1) //unsafe call error
12+
t.<!UNSAFE_IMPLICIT_INVOKE_CALL!>f<!>(1) //unsafe call error
1313
t.f?.invoke(1)
1414
}
1515

1616
fun test1(t: T?) {
1717
t<!UNSAFE_CALL!>.<!><!FUNCTION_EXPECTED!>f<!>(1) // todo resolve f as value and report UNSAFE_CALL
18-
t?.<!UNSAFE_CALL!>f<!>(1)
18+
t?.<!UNSAFE_IMPLICIT_INVOKE_CALL!>f<!>(1)
1919
t<!UNSAFE_CALL!>.<!>f?.invoke(1)
2020
t?.f?.invoke(1)
2121
}

compiler/testData/diagnostics/tests/generics/nullability/functionalBound.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
fun <E : String?, T : ((CharSequence) -> Unit)?> foo(x: E, y: T) {
22
if (x != null) {
3-
<!UNSAFE_CALL!>y<!>(<!DEBUG_INFO_SMARTCAST!>x<!>)
3+
<!UNSAFE_IMPLICIT_INVOKE_CALL!>y<!>(<!DEBUG_INFO_SMARTCAST!>x<!>)
44
}
55

66
if (y != null) {

compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/invoke.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ public class J {
1818

1919
fun test() {
2020
J.staticNN()
21-
J.<!UNSAFE_CALL!>staticN<!>()
21+
J.<!UNSAFE_IMPLICIT_INVOKE_CALL!>staticN<!>()
2222
J.staticJ()
2323
}

compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@ class A(val x: (String.() -> Unit)?)
33
fun test(a: A) {
44
if (a.x != null) {
55
"".<!DEBUG_INFO_SMARTCAST!>(a.x)<!>()
6-
a.<!UNSAFE_CALL!>x<!>("") // todo
6+
a.<!UNSAFE_IMPLICIT_INVOKE_CALL!>x<!>("") // todo
77
<!DEBUG_INFO_SMARTCAST!>(a.x)<!>("")
88
}
9-
"".<!UNSAFE_CALL!>(a.x)<!>()
10-
a.<!UNSAFE_CALL!>x<!>("")
11-
<!UNSAFE_CALL!>(a.x)<!>("")
9+
"".<!UNSAFE_IMPLICIT_INVOKE_CALL!>(a.x)<!>()
10+
a.<!UNSAFE_IMPLICIT_INVOKE_CALL!>x<!>("")
11+
<!UNSAFE_IMPLICIT_INVOKE_CALL!>(a.x)<!>("")
1212

1313
with("") {
14-
a.<!UNSAFE_CALL!>x<!>(<!NO_VALUE_FOR_PARAMETER!>)<!>
15-
<!UNSAFE_CALL!>(a.x)<!>()
14+
a.<!UNSAFE_IMPLICIT_INVOKE_CALL!>x<!>(<!NO_VALUE_FOR_PARAMETER!>)<!>
15+
<!UNSAFE_IMPLICIT_INVOKE_CALL!>(a.x)<!>()
1616
if (a.x != null) {
17-
a.<!UNSAFE_CALL!>x<!>(<!NO_VALUE_FOR_PARAMETER!>)<!> // todo
17+
a.<!UNSAFE_IMPLICIT_INVOKE_CALL!>x<!>(<!NO_VALUE_FOR_PARAMETER!>)<!> // todo
1818
<!DEBUG_INFO_SMARTCAST!>(a.x)<!>()
1919
}
2020
}

idea/testData/checker/SafeInvoke.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class Rule(val apply: () -> Unit)
2+
3+
fun foo() {
4+
val rule: Rule? = Rule { }
5+
rule?.<error descr="[UNSAFE_IMPLICIT_INVOKE_CALL] Reference has a nullable type (() -> kotlin.Unit)?, use explicit ?.invoke() to make function-like call instead">apply</error>()
6+
val apply = rule?.apply
7+
<error descr="[UNSAFE_IMPLICIT_INVOKE_CALL] Reference has a nullable type (() -> kotlin.Unit)?, use explicit ?.invoke() to make function-like call instead">apply</error>()
8+
}

idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,12 @@ public void testReturnTypeMismatchOnOverride() throws Exception {
295295
doTest(fileName);
296296
}
297297

298+
@TestMetadata("SafeInvoke.kt")
299+
public void testSafeInvoke() throws Exception {
300+
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/SafeInvoke.kt");
301+
doTest(fileName);
302+
}
303+
298304
@TestMetadata("Shadowing.kt")
299305
public void testShadowing() throws Exception {
300306
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/Shadowing.kt");

0 commit comments

Comments
 (0)