Separate UNSAFE_IMPLICIT_INVOKE_CALL diagnostics introduced (see KT-8252)
This commit is contained in:
@@ -646,6 +646,7 @@ public interface Errors {
|
||||
// Nullability
|
||||
|
||||
DiagnosticFactory1<PsiElement, KotlinType> UNSAFE_CALL = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, KotlinType> UNSAFE_IMPLICIT_INVOKE_CALL = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory3<KtExpression, String, String, String> UNSAFE_INFIX_CALL = DiagnosticFactory3.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, KotlinType> UNNECESSARY_SAFE_CALL = DiagnosticFactory1.create(WARNING);
|
||||
DiagnosticFactory0<PsiElement> UNEXPECTED_SAFE_CALL = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
+1
@@ -469,6 +469,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(DYNAMIC_SUPERTYPE, "A supertype cannot be dynamic");
|
||||
MAP.put(REDUNDANT_NULLABLE, "Redundant '?'");
|
||||
MAP.put(UNSAFE_CALL, "Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type {0}", RENDER_TYPE);
|
||||
MAP.put(UNSAFE_IMPLICIT_INVOKE_CALL, "Reference has a nullable type {0}, use explicit '?.invoke()' to make function-like call instead", RENDER_TYPE);
|
||||
MAP.put(AMBIGUOUS_LABEL, "Ambiguous label");
|
||||
MAP.put(UNSUPPORTED, "Unsupported [{0}]", STRING);
|
||||
MAP.put(EXCEPTION_FROM_ANALYZER, "Internal Error occurred while analyzing this expression:\n{0}", THROWABLE);
|
||||
|
||||
@@ -464,6 +464,7 @@ class CandidateResolver(
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverArgument, this)
|
||||
val nullability = dataFlowInfo.getPredictableNullability(dataFlowValue)
|
||||
var nullableImplicitInvokeReceiver = false
|
||||
var receiverArgumentType = receiverArgument.type
|
||||
if (implicitInvokeCheck && call is CallForImplicitInvoke && call.isSafeCall()) {
|
||||
val outerCallReceiver = call.outerCall.explicitReceiver
|
||||
if (outerCallReceiver != call.explicitReceiver && outerCallReceiver is ReceiverValue) {
|
||||
@@ -471,6 +472,7 @@ class CandidateResolver(
|
||||
val outerReceiverNullability = dataFlowInfo.getPredictableNullability(outerReceiverDataFlowValue)
|
||||
if (outerReceiverNullability.canBeNull() && !TypeUtils.isNullableType(expectedReceiverParameterType)) {
|
||||
nullableImplicitInvokeReceiver = true
|
||||
receiverArgumentType = TypeUtils.makeNullable(receiverArgumentType)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -499,8 +501,6 @@ class CandidateResolver(
|
||||
}
|
||||
}
|
||||
|
||||
val receiverArgumentType = receiverArgument.type
|
||||
|
||||
if (reportUnsafeCall || nullableImplicitInvokeReceiver) {
|
||||
tracing.unsafeCall(trace, receiverArgumentType, implicitInvokeCheck)
|
||||
return UNSAFE_CALL_ERROR
|
||||
|
||||
+3
@@ -180,6 +180,9 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
|
||||
trace.report(UNSAFE_INFIX_CALL.on(reference, left.getText(), operationString.asString(), right.getText()));
|
||||
}
|
||||
}
|
||||
else if (isCallForImplicitInvoke) {
|
||||
trace.report(UNSAFE_IMPLICIT_INVOKE_CALL.on(reference, type));
|
||||
}
|
||||
else {
|
||||
trace.report(UNSAFE_CALL.on(reference, type));
|
||||
}
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ fun foo() {
|
||||
rule?.apply?.invoke()
|
||||
|
||||
// this should be an error
|
||||
rule?.<!UNSAFE_CALL!>apply<!>()
|
||||
rule?.<!UNSAFE_IMPLICIT_INVOKE_CALL!>apply<!>()
|
||||
|
||||
// these both also ok (with smart cast / unnecessary safe call)
|
||||
if (rule != null) {
|
||||
|
||||
@@ -9,13 +9,13 @@ interface T {
|
||||
}
|
||||
|
||||
fun test(t: T) {
|
||||
t.<!UNSAFE_CALL!>f<!>(1) //unsafe call error
|
||||
t.<!UNSAFE_IMPLICIT_INVOKE_CALL!>f<!>(1) //unsafe call error
|
||||
t.f?.invoke(1)
|
||||
}
|
||||
|
||||
fun test1(t: T?) {
|
||||
t<!UNSAFE_CALL!>.<!><!FUNCTION_EXPECTED!>f<!>(1) // todo resolve f as value and report UNSAFE_CALL
|
||||
t?.<!UNSAFE_CALL!>f<!>(1)
|
||||
t?.<!UNSAFE_IMPLICIT_INVOKE_CALL!>f<!>(1)
|
||||
t<!UNSAFE_CALL!>.<!>f?.invoke(1)
|
||||
t?.f?.invoke(1)
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
fun <E : String?, T : ((CharSequence) -> Unit)?> foo(x: E, y: T) {
|
||||
if (x != null) {
|
||||
<!UNSAFE_CALL!>y<!>(<!DEBUG_INFO_SMARTCAST!>x<!>)
|
||||
<!UNSAFE_IMPLICIT_INVOKE_CALL!>y<!>(<!DEBUG_INFO_SMARTCAST!>x<!>)
|
||||
}
|
||||
|
||||
if (y != null) {
|
||||
|
||||
+1
-1
@@ -18,6 +18,6 @@ public class J {
|
||||
|
||||
fun test() {
|
||||
J.staticNN()
|
||||
J.<!UNSAFE_CALL!>staticN<!>()
|
||||
J.<!UNSAFE_IMPLICIT_INVOKE_CALL!>staticN<!>()
|
||||
J.staticJ()
|
||||
}
|
||||
@@ -3,18 +3,18 @@ class A(val x: (String.() -> Unit)?)
|
||||
fun test(a: A) {
|
||||
if (a.x != null) {
|
||||
"".<!DEBUG_INFO_SMARTCAST!>(a.x)<!>()
|
||||
a.<!UNSAFE_CALL!>x<!>("") // todo
|
||||
a.<!UNSAFE_IMPLICIT_INVOKE_CALL!>x<!>("") // todo
|
||||
<!DEBUG_INFO_SMARTCAST!>(a.x)<!>("")
|
||||
}
|
||||
"".<!UNSAFE_CALL!>(a.x)<!>()
|
||||
a.<!UNSAFE_CALL!>x<!>("")
|
||||
<!UNSAFE_CALL!>(a.x)<!>("")
|
||||
"".<!UNSAFE_IMPLICIT_INVOKE_CALL!>(a.x)<!>()
|
||||
a.<!UNSAFE_IMPLICIT_INVOKE_CALL!>x<!>("")
|
||||
<!UNSAFE_IMPLICIT_INVOKE_CALL!>(a.x)<!>("")
|
||||
|
||||
with("") {
|
||||
a.<!UNSAFE_CALL!>x<!>(<!NO_VALUE_FOR_PARAMETER!>)<!>
|
||||
<!UNSAFE_CALL!>(a.x)<!>()
|
||||
a.<!UNSAFE_IMPLICIT_INVOKE_CALL!>x<!>(<!NO_VALUE_FOR_PARAMETER!>)<!>
|
||||
<!UNSAFE_IMPLICIT_INVOKE_CALL!>(a.x)<!>()
|
||||
if (a.x != null) {
|
||||
a.<!UNSAFE_CALL!>x<!>(<!NO_VALUE_FOR_PARAMETER!>)<!> // todo
|
||||
a.<!UNSAFE_IMPLICIT_INVOKE_CALL!>x<!>(<!NO_VALUE_FOR_PARAMETER!>)<!> // todo
|
||||
<!DEBUG_INFO_SMARTCAST!>(a.x)<!>()
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
class Rule(val apply: () -> Unit)
|
||||
|
||||
fun foo() {
|
||||
val rule: Rule? = Rule { }
|
||||
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>()
|
||||
val apply = rule?.apply
|
||||
<error descr="[UNSAFE_IMPLICIT_INVOKE_CALL] Reference has a nullable type (() -> kotlin.Unit)?, use explicit ?.invoke() to make function-like call instead">apply</error>()
|
||||
}
|
||||
@@ -295,6 +295,12 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SafeInvoke.kt")
|
||||
public void testSafeInvoke() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/SafeInvoke.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Shadowing.kt")
|
||||
public void testShadowing() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/Shadowing.kt");
|
||||
|
||||
Reference in New Issue
Block a user