[NI] Fix reporting UNSAFE_IMPLICIT_INVOKE_CALL diagnostic
This commit is contained in:
committed by
Mikhail Zarechenskiy
parent
251a02f71d
commit
e6deaf3315
+5
@@ -524,6 +524,11 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok
|
||||
runTest("compiler/testData/diagnostics/tests/ReturnInFunctionWithoutBody.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCall.kt")
|
||||
public void testSafeCall() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/safeCall.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("SafeCallInvoke.kt")
|
||||
public void testSafeCallInvoke() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/SafeCallInvoke.kt");
|
||||
|
||||
+3
-1
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
||||
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.BadNamedArgumentsTarget.INVOKE_ON_FUNCTION_TYPE
|
||||
@@ -86,7 +87,8 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
override fun onCallReceiver(callReceiver: SimpleKotlinCallArgument, diagnostic: KotlinCallDiagnostic) {
|
||||
when (diagnostic.javaClass) {
|
||||
UnsafeCallError::class.java -> {
|
||||
val implicitInvokeCheck = (callReceiver as? ReceiverExpressionKotlinCallArgument)?.isForImplicitInvoke ?: false
|
||||
val implicitInvokeCheck = (callReceiver as? ReceiverExpressionKotlinCallArgument)?.isForImplicitInvoke
|
||||
?: callReceiver.receiver.receiverValue.type.isExtensionFunctionType
|
||||
tracingStrategy.unsafeCall(trace, callReceiver.receiver.receiverValue.type, implicitInvokeCheck)
|
||||
}
|
||||
|
||||
|
||||
@@ -540,10 +540,12 @@ class PSICallResolver(
|
||||
resolvedArgumentsInParenthesis.forEach { it.setResultDataFlowInfoIfRelevant(resultDataFlowInfo) }
|
||||
astExternalArgument?.setResultDataFlowInfoIfRelevant(resultDataFlowInfo)
|
||||
|
||||
val isForImplicitInvoke = oldCall is CallTransformer.CallForImplicitInvoke
|
||||
|
||||
return PSIKotlinCallImpl(
|
||||
kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, dispatchReceiverForInvoke, name,
|
||||
resolvedTypeArguments, resolvedArgumentsInParenthesis, astExternalArgument, context.dataFlowInfo, resultDataFlowInfo,
|
||||
context.dataFlowInfoForArguments
|
||||
context.dataFlowInfoForArguments, isForImplicitInvoke
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,8 @@ class PSIKotlinCallImpl(
|
||||
override val externalArgument: KotlinCallArgument?,
|
||||
override val startingDataFlowInfo: DataFlowInfo,
|
||||
override val resultDataFlowInfo: DataFlowInfo,
|
||||
override val dataFlowInfoForArguments: DataFlowInfoForArguments
|
||||
override val dataFlowInfoForArguments: DataFlowInfoForArguments,
|
||||
override val isForImplicitInvoke: Boolean
|
||||
) : PSIKotlinCall()
|
||||
|
||||
class PSIKotlinCallForVariable(
|
||||
@@ -86,6 +87,8 @@ class PSIKotlinCallForVariable(
|
||||
override val psiCall: Call = CallTransformer.stripCallArguments(baseCall.psiCall).let {
|
||||
if (explicitReceiver == null) CallTransformer.stripReceiver(it) else it
|
||||
}
|
||||
|
||||
override val isForImplicitInvoke: Boolean get() = false
|
||||
}
|
||||
|
||||
class PSIKotlinCallForInvoke(
|
||||
@@ -105,6 +108,7 @@ class PSIKotlinCallForInvoke(
|
||||
override val dataFlowInfoForArguments: DataFlowInfoForArguments get() = baseCall.dataFlowInfoForArguments
|
||||
override val psiCall: Call
|
||||
override val tracingStrategy: TracingStrategy
|
||||
override val isForImplicitInvoke: Boolean = true
|
||||
|
||||
init {
|
||||
val variableReceiver = dispatchReceiverForInvokeExtension ?: explicitReceiver
|
||||
|
||||
@@ -24,6 +24,8 @@ interface KotlinCall : ResolutionAtom {
|
||||
val argumentsInParenthesis: List<KotlinCallArgument>
|
||||
|
||||
val externalArgument: KotlinCallArgument?
|
||||
|
||||
val isForImplicitInvoke: Boolean
|
||||
}
|
||||
|
||||
private fun SimpleKotlinCallArgument.checkReceiverInvariants() {
|
||||
|
||||
+6
-2
@@ -76,7 +76,9 @@ class SimpleCandidateFactory(
|
||||
fromResolution: ReceiverValueWithSmartCastInfo?
|
||||
): SimpleKotlinCallArgument? =
|
||||
explicitReceiver as? SimpleKotlinCallArgument ?: // qualifier receiver cannot be safe
|
||||
fromResolution?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall = false) } // todo smartcast implicit this
|
||||
fromResolution?.let {
|
||||
ReceiverExpressionKotlinCallArgument(it, isSafeCall = false, isForImplicitInvoke = kotlinCall.isForImplicitInvoke)
|
||||
} // todo smartcast implicit this
|
||||
|
||||
private fun KotlinCall.getExplicitDispatchReceiver(explicitReceiverKind: ExplicitReceiverKind) = when (explicitReceiverKind) {
|
||||
ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver
|
||||
@@ -94,7 +96,9 @@ class SimpleCandidateFactory(
|
||||
|
||||
val explicitReceiverKind =
|
||||
if (givenCandidate.dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER
|
||||
val dispatchArgumentReceiver = givenCandidate.dispatchReceiver?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall) }
|
||||
val dispatchArgumentReceiver = givenCandidate.dispatchReceiver?.let {
|
||||
ReceiverExpressionKotlinCallArgument(it, isSafeCall)
|
||||
}
|
||||
return createCandidate(
|
||||
givenCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver, null,
|
||||
listOf(), givenCandidate.knownTypeParametersResultingSubstitutor
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
|
||||
fun f(s: String, action: (String.() -> Unit)?) {
|
||||
s.foo().bar().<!UNSAFE_IMPLICIT_INVOKE_CALL!>action<!>()
|
||||
}
|
||||
|
||||
fun String.foo() = ""
|
||||
|
||||
fun String.bar() = ""
|
||||
|
||||
// --------------------------------------------------------
|
||||
|
||||
val functions: Map<String, () -> Any> = TODO()
|
||||
|
||||
fun run(name: String) = <!UNSAFE_IMPLICIT_INVOKE_CALL!>functions[name]<!>()
|
||||
@@ -0,0 +1,7 @@
|
||||
package
|
||||
|
||||
public val functions: kotlin.collections.Map<kotlin.String, () -> kotlin.Any>
|
||||
public fun f(/*0*/ s: kotlin.String, /*1*/ action: (kotlin.String.() -> kotlin.Unit)?): kotlin.Unit
|
||||
public fun run(/*0*/ name: kotlin.String): kotlin.Any
|
||||
public fun kotlin.String.bar(): kotlin.String
|
||||
public fun kotlin.String.foo(): kotlin.String
|
||||
@@ -526,6 +526,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
runTest("compiler/testData/diagnostics/tests/ReturnInFunctionWithoutBody.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCall.kt")
|
||||
public void testSafeCall() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/safeCall.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("SafeCallInvoke.kt")
|
||||
public void testSafeCallInvoke() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/SafeCallInvoke.kt");
|
||||
|
||||
Generated
+5
@@ -526,6 +526,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
runTest("compiler/testData/diagnostics/tests/ReturnInFunctionWithoutBody.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("safeCall.kt")
|
||||
public void testSafeCall() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/safeCall.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("SafeCallInvoke.kt")
|
||||
public void testSafeCallInvoke() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/SafeCallInvoke.kt");
|
||||
|
||||
Reference in New Issue
Block a user