提交 bfa64897 编写于 作者: M Mikhail Zarechenskiy

Introduce call checker for `Unit`-conversions

上级 6b0a803d
...@@ -24476,6 +24476,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte ...@@ -24476,6 +24476,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionCompatibility.kt"); runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionCompatibility.kt");
} }
@TestMetadata("unitConversionDisabledForSimpleArguments.kt")
public void testUnitConversionDisabledForSimpleArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.kt");
}
@TestMetadata("unitConversionForAllKinds.kt") @TestMetadata("unitConversionForAllKinds.kt")
public void testUnitConversionForAllKinds() throws Exception { public void testUnitConversionForAllKinds() throws Exception {
runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionForAllKinds.kt"); runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionForAllKinds.kt");
...@@ -49,7 +49,8 @@ private val DEFAULT_CALL_CHECKERS = listOf( ...@@ -49,7 +49,8 @@ private val DEFAULT_CALL_CHECKERS = listOf(
PrimitiveNumericComparisonCallChecker, LambdaWithSuspendModifierCallChecker, PrimitiveNumericComparisonCallChecker, LambdaWithSuspendModifierCallChecker,
UselessElvisCallChecker(), ResultTypeWithNullableOperatorsChecker(), NullableVarargArgumentCallChecker, UselessElvisCallChecker(), ResultTypeWithNullableOperatorsChecker(), NullableVarargArgumentCallChecker,
NamedFunAsExpressionChecker, ContractNotAllowedCallChecker, ReifiedTypeParameterSubstitutionChecker(), NamedFunAsExpressionChecker, ContractNotAllowedCallChecker, ReifiedTypeParameterSubstitutionChecker(),
MissingDependencySupertypeChecker.ForCalls, AbstractClassInstantiationChecker, SuspendConversionCallChecker MissingDependencySupertypeChecker.ForCalls, AbstractClassInstantiationChecker, SuspendConversionCallChecker,
UnitConversionCallChecker
) )
private val DEFAULT_TYPE_CHECKERS = emptyList<AdditionalTypeChecker>() private val DEFAULT_TYPE_CHECKERS = emptyList<AdditionalTypeChecker>()
private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf( private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf(
......
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.calls.checkers
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl
import org.jetbrains.kotlin.resolve.calls.tower.psiCallArgument
object UnitConversionCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
if (resolvedCall !is NewResolvedCallImpl<*>) return
if (context.languageVersionSettings.supportsFeature(LanguageFeature.UnitConversion)) return
// lambdas are working since 1.0, callable references are handled as part of reference adaptation
// => here we're checking only simple argument
val argumentsWithUnitConversion = resolvedCall.resolvedCallAtom.argumentsWithUnitConversion
for (argumentWithUnitConversion in argumentsWithUnitConversion.keys) {
context.trace.report(
Errors.UNSUPPORTED_FEATURE.on(
argumentWithUnitConversion.psiCallArgument.valueArgument.asElement(),
LanguageFeature.UnitConversion to context.languageVersionSettings
)
)
}
}
}
\ No newline at end of file
...@@ -75,6 +75,8 @@ object UnitTypeConversions : ParameterTypeConversion { ...@@ -75,6 +75,8 @@ object UnitTypeConversions : ParameterTypeConversion {
suspendFunction = expectedParameterType.isSuspendFunctionType suspendFunction = expectedParameterType.isSuspendFunctionType
) )
candidate.resolvedCall.registerArgumentWithUnitConversion(argument, nonUnitReturnedParameterType)
candidate.addDiagnostic(LowerPriorityToPreserveCompatibility) candidate.addDiagnostic(LowerPriorityToPreserveCompatibility)
return nonUnitReturnedParameterType return nonUnitReturnedParameterType
......
...@@ -69,6 +69,7 @@ abstract class ResolvedCallAtom : ResolvedAtom() { ...@@ -69,6 +69,7 @@ abstract class ResolvedCallAtom : ResolvedAtom() {
abstract val knownParametersSubstitutor: TypeSubstitutor abstract val knownParametersSubstitutor: TypeSubstitutor
abstract val argumentsWithConversion: Map<KotlinCallArgument, SamConversionDescription> abstract val argumentsWithConversion: Map<KotlinCallArgument, SamConversionDescription>
abstract val argumentsWithSuspendConversion: Map<KotlinCallArgument, UnwrappedType> abstract val argumentsWithSuspendConversion: Map<KotlinCallArgument, UnwrappedType>
abstract val argumentsWithUnitConversion: Map<KotlinCallArgument, UnwrappedType>
abstract val argumentsWithConstantConversion: Map<KotlinCallArgument, IntegerValueTypeConstant> abstract val argumentsWithConstantConversion: Map<KotlinCallArgument, IntegerValueTypeConstant>
} }
......
...@@ -193,6 +193,7 @@ class MutableResolvedCallAtom( ...@@ -193,6 +193,7 @@ class MutableResolvedCallAtom(
lateinit var argumentToCandidateParameter: Map<KotlinCallArgument, ValueParameterDescriptor> lateinit var argumentToCandidateParameter: Map<KotlinCallArgument, ValueParameterDescriptor>
private var samAdapterMap: HashMap<KotlinCallArgument, SamConversionDescription>? = null private var samAdapterMap: HashMap<KotlinCallArgument, SamConversionDescription>? = null
private var suspendAdapterMap: HashMap<KotlinCallArgument, UnwrappedType>? = null private var suspendAdapterMap: HashMap<KotlinCallArgument, UnwrappedType>? = null
private var unitAdapterMap: HashMap<KotlinCallArgument, UnwrappedType>? = null
private var signedUnsignedConstantConversions: HashMap<KotlinCallArgument, IntegerValueTypeConstant>? = null private var signedUnsignedConstantConversions: HashMap<KotlinCallArgument, IntegerValueTypeConstant>? = null
val hasSamConversion: Boolean val hasSamConversion: Boolean
...@@ -207,6 +208,9 @@ class MutableResolvedCallAtom( ...@@ -207,6 +208,9 @@ class MutableResolvedCallAtom(
override val argumentsWithSuspendConversion: Map<KotlinCallArgument, UnwrappedType> override val argumentsWithSuspendConversion: Map<KotlinCallArgument, UnwrappedType>
get() = suspendAdapterMap ?: emptyMap() get() = suspendAdapterMap ?: emptyMap()
override val argumentsWithUnitConversion: Map<KotlinCallArgument, UnwrappedType>
get() = unitAdapterMap ?: emptyMap()
override val argumentsWithConstantConversion: Map<KotlinCallArgument, IntegerValueTypeConstant> override val argumentsWithConstantConversion: Map<KotlinCallArgument, IntegerValueTypeConstant>
get() = signedUnsignedConstantConversions ?: emptyMap() get() = signedUnsignedConstantConversions ?: emptyMap()
...@@ -224,6 +228,13 @@ class MutableResolvedCallAtom( ...@@ -224,6 +228,13 @@ class MutableResolvedCallAtom(
suspendAdapterMap!![argument] = convertedType suspendAdapterMap!![argument] = convertedType
} }
fun registerArgumentWithUnitConversion(argument: KotlinCallArgument, convertedType: UnwrappedType) {
if (unitAdapterMap == null)
unitAdapterMap = hashMapOf()
unitAdapterMap!![argument] = convertedType
}
fun registerArgumentWithConstantConversion(argument: KotlinCallArgument, convertedConstant: IntegerValueTypeConstant) { fun registerArgumentWithConstantConversion(argument: KotlinCallArgument, convertedConstant: IntegerValueTypeConstant) {
if (signedUnsignedConstantConversions == null) if (signedUnsignedConstantConversions == null)
signedUnsignedConstantConversions = hashMapOf() signedUnsignedConstantConversions = hashMapOf()
......
// !DIAGNOSTICS: -UNUSED_PARAMETER
object Test1 {
fun foo(f: () -> Int) {}
object Scope {
fun foo(f: () -> Unit) {}
fun test(f: () -> Int) {
<!DEBUG_INFO_CALL("fqName: Test1.foo; typeCall: function")!>foo(f)<!>
}
}
}
object Test2 {
fun interface KRunnable {
fun run()
}
fun foo(f: () -> Unit) {}
object Scope1 {
fun foo(f: KRunnable) {}
fun test(f: () -> Int) {
<!DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!><!INAPPLICABLE_CANDIDATE!>foo<!>(f)<!>
}
}
}
// !DIAGNOSTICS: -UNUSED_PARAMETER
object Test1 {
fun foo(f: () -> Int) {}
object Scope {
fun foo(f: () -> Unit) {}
fun test(f: () -> Int) {
<!DEBUG_INFO_CALL("fqName: Test1.foo; typeCall: function")!><!COMPATIBILITY_WARNING!>foo<!>(f)<!>
}
}
}
object Test2 {
fun interface KRunnable {
fun run()
}
fun foo(f: () -> Unit) {}
object Scope1 {
fun foo(f: KRunnable) {}
fun test(f: () -> Int) {
<!DEBUG_INFO_CALL("fqName: Test2.Scope1.foo; typeCall: function")!>foo(<!UNSUPPORTED_FEATURE!>f<!>)<!>
}
}
}
package
public object Test1 {
private constructor Test1()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(/*0*/ f: () -> kotlin.Int): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public object Scope {
private constructor Scope()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(/*0*/ f: () -> kotlin.Unit): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun test(/*0*/ f: () -> kotlin.Int): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
public object Test2 {
private constructor Test2()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(/*0*/ f: () -> kotlin.Unit): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public fun interface KRunnable {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract fun run(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public object Scope1 {
private constructor Scope1()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(/*0*/ f: Test2.KRunnable): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun test(/*0*/ f: () -> kotlin.Int): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
// !LANGUAGE: -SuspendConversion
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION
fun foo(f: () -> Unit) {}
fun bar(): Int = 0
abstract class SubInt : () -> Int
fun test(f: () -> String, s: SubInt) {
foo { "lambda" }
foo(::bar)
<!INAPPLICABLE_CANDIDATE!>foo<!>(f)
<!INAPPLICABLE_CANDIDATE!>foo<!>(s)
}
\ No newline at end of file
// !LANGUAGE: -SuspendConversion
// !DIAGNOSTICS: -UNUSED_PARAMETER -UNUSED_EXPRESSION
fun foo(f: () -> Unit) {}
fun bar(): Int = 0
abstract class SubInt : () -> Int
fun test(f: () -> String, s: SubInt) {
foo { "lambda" }
foo(::bar)
foo(<!UNSUPPORTED_FEATURE!>f<!>)
foo(<!UNSUPPORTED_FEATURE!>s<!>)
}
\ No newline at end of file
package
public fun bar(): kotlin.Int
public fun foo(/*0*/ f: () -> kotlin.Unit): kotlin.Unit
public fun test(/*0*/ f: () -> kotlin.String, /*1*/ s: SubInt): kotlin.Unit
public abstract class SubInt : () -> kotlin.Int {
public constructor SubInt()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract override /*1*/ /*fake_override*/ fun invoke(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
...@@ -24558,6 +24558,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali ...@@ -24558,6 +24558,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionCompatibility.kt"); runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionCompatibility.kt");
} }
@TestMetadata("unitConversionDisabledForSimpleArguments.kt")
public void testUnitConversionDisabledForSimpleArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.kt");
}
@TestMetadata("unitConversionForAllKinds.kt") @TestMetadata("unitConversionForAllKinds.kt")
public void testUnitConversionForAllKinds() throws Exception { public void testUnitConversionForAllKinds() throws Exception {
runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionForAllKinds.kt"); runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionForAllKinds.kt");
...@@ -24478,6 +24478,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing ...@@ -24478,6 +24478,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionCompatibility.kt"); runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionCompatibility.kt");
} }
@TestMetadata("unitConversionDisabledForSimpleArguments.kt")
public void testUnitConversionDisabledForSimpleArguments() throws Exception {
runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionDisabledForSimpleArguments.kt");
}
@TestMetadata("unitConversionForAllKinds.kt") @TestMetadata("unitConversionForAllKinds.kt")
public void testUnitConversionForAllKinds() throws Exception { public void testUnitConversionForAllKinds() throws Exception {
runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionForAllKinds.kt"); runTest("compiler/testData/diagnostics/tests/unitConversion/unitConversionForAllKinds.kt");
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册