[Jspecify] Report warnings on violated bounds of method type parameters
This commit is contained in:
+25
-3
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.UpperBoundChecker
|
import org.jetbrains.kotlin.resolve.UpperBoundChecker
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker
|
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext
|
import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
|
||||||
@@ -48,9 +49,7 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio
|
|||||||
expressionTypeWithSmartCast: KotlinType,
|
expressionTypeWithSmartCast: KotlinType,
|
||||||
c: ResolutionContext<*>
|
c: ResolutionContext<*>
|
||||||
) {
|
) {
|
||||||
if (expressionType is AbbreviatedType) {
|
checkTypeParameterBounds(expression, expressionType, c)
|
||||||
upperBoundChecker.checkBoundsOfExpandedTypeAlias(expressionType.expandedType, expression, c.trace)
|
|
||||||
}
|
|
||||||
|
|
||||||
val dataFlowValue by lazy(LazyThreadSafetyMode.NONE) {
|
val dataFlowValue by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
c.dataFlowValueFactory.createDataFlowValue(expression, expressionType, c)
|
c.dataFlowValueFactory.createDataFlowValue(expression, expressionType, c)
|
||||||
@@ -122,6 +121,29 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkTypeParameterBounds(
|
||||||
|
expression: KtExpression,
|
||||||
|
expressionType: KotlinType,
|
||||||
|
c: ResolutionContext<*>
|
||||||
|
) {
|
||||||
|
if (expressionType is AbbreviatedType) {
|
||||||
|
upperBoundChecker.checkBoundsOfExpandedTypeAlias(expressionType.expandedType, expression, c.trace)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c !is BasicCallResolutionContext || upperBoundChecker !is WarningAwareUpperBoundChecker) return
|
||||||
|
|
||||||
|
val resolvedCall = c.trace.bindingContext[BindingContext.RESOLVED_CALL, c.call] ?: return
|
||||||
|
|
||||||
|
for ((typeParameter, typeArgument) in resolvedCall.typeArguments) {
|
||||||
|
// continue if we don't have explicit type arguments
|
||||||
|
val typeReference = c.call.typeArguments.getOrNull(typeParameter.index)?.typeReference ?: continue
|
||||||
|
|
||||||
|
upperBoundChecker.checkBounds(
|
||||||
|
typeReference, typeArgument, typeParameter, TypeSubstitutor.create(typeArgument), c.trace, withOnlyCheckForWarning = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun isWrongTypeParameterNullabilityForSubtyping(
|
private fun isWrongTypeParameterNullabilityForSubtyping(
|
||||||
expressionType: KotlinType,
|
expressionType: KotlinType,
|
||||||
c: ResolutionContext<*>,
|
c: ResolutionContext<*>,
|
||||||
|
|||||||
+6
-2
@@ -49,7 +49,7 @@ class WarningAwareUpperBoundChecker : UpperBoundChecker() {
|
|||||||
typeParameterDescriptor: TypeParameterDescriptor,
|
typeParameterDescriptor: TypeParameterDescriptor,
|
||||||
substitutor: TypeSubstitutor,
|
substitutor: TypeSubstitutor,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
typeAliasUsageElement: KtElement?,
|
typeAliasUsageElement: KtElement? = null,
|
||||||
withOnlyCheckForWarning: Boolean = false
|
withOnlyCheckForWarning: Boolean = false
|
||||||
) {
|
) {
|
||||||
if (typeParameterDescriptor.upperBounds.isEmpty()) return
|
if (typeParameterDescriptor.upperBounds.isEmpty()) return
|
||||||
@@ -71,8 +71,12 @@ class WarningAwareUpperBoundChecker : UpperBoundChecker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val enhancedBound = bound.getEnhancementDeeply() ?: continue
|
val enhancedBound = bound.getEnhancementDeeply() ?: continue
|
||||||
|
val argumentTypeEnhancement = argumentType.getEnhancementDeeply() ?: argumentType
|
||||||
|
|
||||||
checkBound(enhancedBound, argumentType, argumentReference, substitutor, typeAliasUsageElement, diagnosticsReporterForWarnings)
|
checkBound(
|
||||||
|
enhancedBound, argumentTypeEnhancement, argumentReference,
|
||||||
|
substitutor, typeAliasUsageElement, diagnosticsReporterForWarnings
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-8
@@ -22,24 +22,24 @@ public class Test {}
|
|||||||
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
|
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
|
||||||
fun <T : Test> main(a1: A<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>Any?<!>>, a2: A<Test>, b1: B<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>Any?<!>>, b2: B<Test>, x: T): Unit {
|
fun <T : Test> main(a1: A<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>Any?<!>>, a2: A<Test>, b1: B<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>Any?<!>>, b2: B<Test>, x: T): Unit {
|
||||||
a1.foo(null)
|
a1.foo(null)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
a1.bar<T?>(null)
|
a1.bar<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>T?<!>>(null)
|
||||||
a1.bar<T>(x)
|
a1.bar<T>(x)
|
||||||
|
|
||||||
a2.foo(null)
|
a2.foo(null)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
a2.bar<T?>(null)
|
a2.bar<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>T?<!>>(null)
|
||||||
a2.bar<T>(x)
|
a2.bar<T>(x)
|
||||||
|
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch{mute}
|
||||||
b1.foo(null)
|
b1.foo(null)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
b1.bar<T?>(null)
|
b1.bar<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>T?<!>>(null)
|
||||||
b1.bar<T>(x)
|
b1.bar<T>(x)
|
||||||
|
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch{mute}
|
||||||
b2.foo(null)
|
b2.foo(null)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
b2.bar<T?>(null)
|
b2.bar<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>T?<!>>(null)
|
||||||
b2.bar<T>(x)
|
b2.bar<T>(x)
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-8
@@ -22,24 +22,24 @@ public class Test {}
|
|||||||
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
|
// jspecify_nullness_mismatch, jspecify_nullness_mismatch
|
||||||
fun <T : Test> main(a1: A<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>Any?<!>>, a2: A<Test>, b1: B<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>Any?<!>>, b2: B<Test>, x: T): Unit {
|
fun <T : Test> main(a1: A<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>Any?<!>>, a2: A<Test>, b1: B<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>Any?<!>>, b2: B<Test>, x: T): Unit {
|
||||||
a1.foo(null)
|
a1.foo(null)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
a1.bar<T?>(null)
|
a1.bar<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>T?<!>>(null)
|
||||||
a1.bar<T>(x)
|
a1.bar<T>(x)
|
||||||
|
|
||||||
a2.foo(null)
|
a2.foo(null)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
a2.bar<T?>(null)
|
a2.bar<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>T?<!>>(null)
|
||||||
a2.bar<T>(x)
|
a2.bar<T>(x)
|
||||||
|
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch{mute}
|
||||||
b1.foo(null)
|
b1.foo(null)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
b1.bar<T?>(null)
|
b1.bar<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>T?<!>>(null)
|
||||||
b1.bar<T>(x)
|
b1.bar<T>(x)
|
||||||
|
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch{mute}
|
||||||
b2.foo(null)
|
b2.foo(null)
|
||||||
// jspecify_nullness_mismatch{mute}
|
// jspecify_nullness_mismatch
|
||||||
b2.bar<T?>(null)
|
b2.bar<<!UPPER_BOUND_VIOLATED_BASED_ON_JAVA_ANNOTATIONS!>T?<!>>(null)
|
||||||
b2.bar<T>(x)
|
b2.bar<T>(x)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user