[NI] Add check for non-null argument type in arguments check
#KT-31461 Fixed
This commit is contained in:
+13
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls
|
||||
|
||||
import com.intellij.psi.util.PsiUtil
|
||||
import org.jetbrains.kotlin.builtins.UnsignedTypes
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
||||
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||
@@ -14,6 +15,7 @@ import org.jetbrains.kotlin.diagnostics.Errors.BadNamedArgumentsTarget.INVOKE_ON
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.BadNamedArgumentsTarget.NON_KOTLIN_FUNCTION
|
||||
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnce
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isNull
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
@@ -128,6 +130,17 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
trace.report(UNRESOLVED_REFERENCE.on(it.callableReference, it.callableReference))
|
||||
}
|
||||
}
|
||||
|
||||
ArgumentTypeMismatchDiagnostic::class.java -> {
|
||||
require(diagnostic is ArgumentTypeMismatchDiagnostic)
|
||||
reportIfNonNull(callArgument.safeAs<PSIKotlinCallArgument>()?.valueArgument?.getArgumentExpression()) {
|
||||
if (it.isNull()) {
|
||||
trace.report(NULL_FOR_NONNULL_TYPE.on(it, diagnostic.expectedType))
|
||||
} else {
|
||||
trace.report(TYPE_MISMATCH.on(it, diagnostic.expectedType, diagnostic.actualType))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,10 +25,13 @@ import com.intellij.psi.impl.source.tree.TreeUtil
|
||||
import com.intellij.psi.search.PsiSearchScopeUtil
|
||||
import com.intellij.psi.search.SearchScope
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import java.util.*
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
// NOTE: in this file we collect only LANGUAGE INDEPENDENT methods working with PSI and not modifying it
|
||||
|
||||
@@ -477,3 +480,11 @@ fun LazyParseablePsiElement.getContainingKtFile(): KtFile {
|
||||
val fileString = if (file != null && file.isValid) file.text else ""
|
||||
throw IllegalStateException("KtElement not inside KtFile: $file with text \"$fileString\" for element $this of type ${this::class.java} node = ${this.node}")
|
||||
}
|
||||
|
||||
@UseExperimental(ExperimentalContracts::class)
|
||||
fun KtExpression.isNull(): Boolean {
|
||||
contract {
|
||||
returns(true) implies (this@isNull is KtConstantExpression)
|
||||
}
|
||||
return this is KtConstantExpression && this.node.elementType == KtNodeTypes.NULL
|
||||
}
|
||||
+9
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.checker.captureFromExpression
|
||||
import org.jetbrains.kotlin.types.checker.hasSupertypeWithGivenTypeConstructor
|
||||
import org.jetbrains.kotlin.types.lowerIfFlexible
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
import org.jetbrains.kotlin.types.upperIfFlexible
|
||||
|
||||
@@ -66,6 +67,14 @@ private fun checkExpressionArgument(
|
||||
return UnstableSmartCast(expressionArgument, unstableType)
|
||||
}
|
||||
}
|
||||
|
||||
if (argumentType.isMarkedNullable) {
|
||||
if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, actualExpectedType, position)) return null
|
||||
if (csBuilder.addSubtypeConstraintIfCompatible(argumentType.makeNotNullable(), actualExpectedType, position)) {
|
||||
return ArgumentTypeMismatchDiagnostic(actualExpectedType, argumentType, expressionArgument)
|
||||
}
|
||||
}
|
||||
|
||||
csBuilder.addSubtypeConstraint(argumentType, actualExpectedType, position)
|
||||
return null
|
||||
}
|
||||
|
||||
+10
@@ -185,4 +185,14 @@ class NonApplicableCallForBuilderInferenceDiagnostic(val kotlinCall: KotlinCall)
|
||||
override fun report(reporter: DiagnosticReporter) {
|
||||
reporter.onCall(this)
|
||||
}
|
||||
}
|
||||
|
||||
class ArgumentTypeMismatchDiagnostic(
|
||||
val expectedType: UnwrappedType,
|
||||
val actualType: UnwrappedType,
|
||||
val expressionArgument: ExpressionKotlinCallArgument
|
||||
) : KotlinCallDiagnostic(MAY_THROW_RUNTIME_ERROR) {
|
||||
override fun report(reporter: DiagnosticReporter) {
|
||||
reporter.onCallArgument(expressionArgument, this)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ interface A<T>
|
||||
fun <T> infer(<!UNUSED_PARAMETER!>a<!>: A<T>) : T {<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
|
||||
|
||||
fun test(nothing: Nothing?) {
|
||||
val <!UNUSED_VARIABLE!>i<!> = <!OI;TYPE_INFERENCE_INCORPORATION_ERROR!>infer<!>(<!DEBUG_INFO_CONSTANT, TYPE_MISMATCH!>nothing<!>)
|
||||
val <!UNUSED_VARIABLE!>i<!> = <!NI;NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER, OI;TYPE_INFERENCE_INCORPORATION_ERROR!>infer<!>(<!DEBUG_INFO_CONSTANT, TYPE_MISMATCH!>nothing<!>)
|
||||
}
|
||||
|
||||
fun sum(<!UNUSED_PARAMETER!>a<!> : IntArray) : Int {
|
||||
|
||||
+3
-3
@@ -15,6 +15,6 @@ fun <S> test1(a: ParameterizedChild<S>?, b: Child): Base<S> = myRun {
|
||||
elvis(a, b)
|
||||
}
|
||||
|
||||
fun <S> test2(a: S?, b: S): S = <!TYPE_MISMATCH!>myRun {
|
||||
<!TYPE_MISMATCH!>select(a, b)<!>
|
||||
}<!>
|
||||
fun <S> test2(a: S?, b: S): S = myRun {
|
||||
<!TYPE_MISMATCH, TYPE_MISMATCH!>select(a, b)<!>
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -13,6 +13,6 @@ public class J {
|
||||
|
||||
fun test(j: J, nullStr: String?, nullByte: Byte?, nullDouble: Double?) {
|
||||
j.foo(nullStr)
|
||||
j.<!NI;NONE_APPLICABLE!>foo<!>(<!OI;TYPE_MISMATCH!>nullDouble<!>)
|
||||
j.foo(<!TYPE_MISMATCH!>nullDouble<!>)
|
||||
j.foo(nullByte)
|
||||
}
|
||||
Vendored
+1
-1
@@ -6,7 +6,7 @@ fun foo(x: Int) {}
|
||||
fun foo(x: Int, y: String) {}
|
||||
|
||||
fun bar(nullX: Int?, nullY: String?, notNullY: String) {
|
||||
<!NI;NONE_APPLICABLE!>foo<!>(<!OI;TYPE_MISMATCH!>nullX<!>)
|
||||
foo(<!TYPE_MISMATCH!>nullX<!>)
|
||||
foo(<!TYPE_MISMATCH!>nullX<!>, notNullY)
|
||||
foo(<!TYPE_MISMATCH!>nullX<!>, <!TYPE_MISMATCH!>nullY<!>)
|
||||
<!NONE_APPLICABLE!>foo<!>()
|
||||
|
||||
+2
-2
@@ -34,7 +34,7 @@ fun test() {
|
||||
platformJ++
|
||||
|
||||
1 + platformNN
|
||||
1 <!NI;NONE_APPLICABLE!>+<!> <!OI;TYPE_MISMATCH!>platformN<!>
|
||||
1 + <!TYPE_MISMATCH!>platformN<!>
|
||||
1 + platformJ
|
||||
|
||||
platformNN + 1
|
||||
@@ -42,7 +42,7 @@ fun test() {
|
||||
platformJ + 1
|
||||
|
||||
1 <!INFIX_MODIFIER_REQUIRED!>plus<!> platformNN
|
||||
1 <!NI;NONE_APPLICABLE, OI;INFIX_MODIFIER_REQUIRED!>plus<!> <!OI;TYPE_MISMATCH!>platformN<!>
|
||||
1 <!INFIX_MODIFIER_REQUIRED!>plus<!> <!TYPE_MISMATCH!>platformN<!>
|
||||
1 <!INFIX_MODIFIER_REQUIRED!>plus<!> platformJ
|
||||
|
||||
platformNN <!INFIX_MODIFIER_REQUIRED!>plus<!> 1
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ fun bar(arg: Long?): Long {
|
||||
return i<!UNSAFE_CALL!>--<!> <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>+<!> i
|
||||
}
|
||||
if (i++ == 7L) {
|
||||
return i++ <!NI;NONE_APPLICABLE, OI;UNSAFE_OPERATOR_CALL!>+<!> <!OI;TYPE_MISMATCH!>i<!>
|
||||
return i++ <!UNSAFE_OPERATOR_CALL!>+<!> <!TYPE_MISMATCH!>i<!>
|
||||
}
|
||||
return 0L
|
||||
}
|
||||
@@ -23,7 +23,7 @@ fun case_1(x: Double?, y: Double?) : Double {
|
||||
} else if (x == null && y != null) {
|
||||
<!DEBUG_INFO_SMARTCAST!>y<!>
|
||||
} else {
|
||||
x <!NONE_APPLICABLE!>+<!> y
|
||||
x <!UNSAFE_OPERATOR_CALL!>+<!> <!TYPE_MISMATCH!>y<!>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user