[NI] Fix reporting UNSAFE_IMPLICIT_INVOKE_CALL diagnostic

This commit is contained in:
Dmitriy Novozhilov
2019-04-25 17:59:20 +03:00
committed by Mikhail Zarechenskiy
parent 251a02f71d
commit e6deaf3315
10 changed files with 56 additions and 5 deletions
@@ -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");
@@ -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() {
@@ -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
View File
@@ -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]<!>()
+7
View File
@@ -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");
@@ -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");