[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
|
package org.jetbrains.kotlin.resolve.calls
|
||||||
|
|
||||||
|
import com.intellij.psi.util.PsiUtil
|
||||||
import org.jetbrains.kotlin.builtins.UnsignedTypes
|
import org.jetbrains.kotlin.builtins.UnsignedTypes
|
||||||
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
||||||
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
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.Errors.BadNamedArgumentsTarget.NON_KOTLIN_FUNCTION
|
||||||
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnce
|
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnce
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isNull
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||||
@@ -128,6 +130,17 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
trace.report(UNRESOLVED_REFERENCE.on(it.callableReference, it.callableReference))
|
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.PsiSearchScopeUtil
|
||||||
import com.intellij.psi.search.SearchScope
|
import com.intellij.psi.search.SearchScope
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
|
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import java.util.*
|
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
|
// 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 ""
|
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}")
|
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.captureFromExpression
|
||||||
import org.jetbrains.kotlin.types.checker.hasSupertypeWithGivenTypeConstructor
|
import org.jetbrains.kotlin.types.checker.hasSupertypeWithGivenTypeConstructor
|
||||||
import org.jetbrains.kotlin.types.lowerIfFlexible
|
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.typeUtil.supertypes
|
||||||
import org.jetbrains.kotlin.types.upperIfFlexible
|
import org.jetbrains.kotlin.types.upperIfFlexible
|
||||||
|
|
||||||
@@ -66,6 +67,14 @@ private fun checkExpressionArgument(
|
|||||||
return UnstableSmartCast(expressionArgument, unstableType)
|
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)
|
csBuilder.addSubtypeConstraint(argumentType, actualExpectedType, position)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
+10
@@ -185,4 +185,14 @@ class NonApplicableCallForBuilderInferenceDiagnostic(val kotlinCall: KotlinCall)
|
|||||||
override fun report(reporter: DiagnosticReporter) {
|
override fun report(reporter: DiagnosticReporter) {
|
||||||
reporter.onCall(this)
|
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 <T> infer(<!UNUSED_PARAMETER!>a<!>: A<T>) : T {<!NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY!>}<!>
|
||||||
|
|
||||||
fun test(nothing: Nothing?) {
|
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 {
|
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)
|
elvis(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <S> test2(a: S?, b: S): S = <!TYPE_MISMATCH!>myRun {
|
fun <S> test2(a: S?, b: S): S = myRun {
|
||||||
<!TYPE_MISMATCH!>select(a, b)<!>
|
<!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?) {
|
fun test(j: J, nullStr: String?, nullByte: Byte?, nullDouble: Double?) {
|
||||||
j.foo(nullStr)
|
j.foo(nullStr)
|
||||||
j.<!NI;NONE_APPLICABLE!>foo<!>(<!OI;TYPE_MISMATCH!>nullDouble<!>)
|
j.foo(<!TYPE_MISMATCH!>nullDouble<!>)
|
||||||
j.foo(nullByte)
|
j.foo(nullByte)
|
||||||
}
|
}
|
||||||
Vendored
+1
-1
@@ -6,7 +6,7 @@ fun foo(x: Int) {}
|
|||||||
fun foo(x: Int, y: String) {}
|
fun foo(x: Int, y: String) {}
|
||||||
|
|
||||||
fun bar(nullX: Int?, nullY: String?, notNullY: 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<!>, notNullY)
|
||||||
foo(<!TYPE_MISMATCH!>nullX<!>, <!TYPE_MISMATCH!>nullY<!>)
|
foo(<!TYPE_MISMATCH!>nullX<!>, <!TYPE_MISMATCH!>nullY<!>)
|
||||||
<!NONE_APPLICABLE!>foo<!>()
|
<!NONE_APPLICABLE!>foo<!>()
|
||||||
|
|||||||
+2
-2
@@ -34,7 +34,7 @@ fun test() {
|
|||||||
platformJ++
|
platformJ++
|
||||||
|
|
||||||
1 + platformNN
|
1 + platformNN
|
||||||
1 <!NI;NONE_APPLICABLE!>+<!> <!OI;TYPE_MISMATCH!>platformN<!>
|
1 + <!TYPE_MISMATCH!>platformN<!>
|
||||||
1 + platformJ
|
1 + platformJ
|
||||||
|
|
||||||
platformNN + 1
|
platformNN + 1
|
||||||
@@ -42,7 +42,7 @@ fun test() {
|
|||||||
platformJ + 1
|
platformJ + 1
|
||||||
|
|
||||||
1 <!INFIX_MODIFIER_REQUIRED!>plus<!> platformNN
|
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
|
1 <!INFIX_MODIFIER_REQUIRED!>plus<!> platformJ
|
||||||
|
|
||||||
platformNN <!INFIX_MODIFIER_REQUIRED!>plus<!> 1
|
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
|
return i<!UNSAFE_CALL!>--<!> <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>+<!> i
|
||||||
}
|
}
|
||||||
if (i++ == 7L) {
|
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
|
return 0L
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ fun case_1(x: Double?, y: Double?) : Double {
|
|||||||
} else if (x == null && y != null) {
|
} else if (x == null && y != null) {
|
||||||
<!DEBUG_INFO_SMARTCAST!>y<!>
|
<!DEBUG_INFO_SMARTCAST!>y<!>
|
||||||
} else {
|
} else {
|
||||||
x <!NONE_APPLICABLE!>+<!> y
|
x <!UNSAFE_OPERATOR_CALL!>+<!> <!TYPE_MISMATCH!>y<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user