Report warnings on overrides with wrong types nullability
^KT-48899 Fixed
This commit is contained in:
committed by
TeamCityServer
parent
ec97dab6cd
commit
f7ef551f99
+15
-11
@@ -189,17 +189,6 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio
|
||||
return metWrongNullabilityInsideArguments
|
||||
}
|
||||
|
||||
private fun isNullableTypeAgainstNotNullTypeParameter(
|
||||
subType: KotlinType,
|
||||
superType: KotlinType
|
||||
): Boolean {
|
||||
if (superType !is NotNullTypeVariable) return false
|
||||
return !AbstractNullabilityChecker.isSubtypeOfAny(
|
||||
createClassicTypeCheckerState(isErrorTypeEqualsToAnything = true),
|
||||
subType
|
||||
)
|
||||
}
|
||||
|
||||
override fun checkReceiver(
|
||||
receiverParameter: ReceiverParameterDescriptor,
|
||||
receiverArgument: ReceiverValue,
|
||||
@@ -279,6 +268,10 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio
|
||||
}
|
||||
|
||||
companion object {
|
||||
val typePreparatorUnwrappingEnhancement: KotlinTypePreparator = object : KotlinTypePreparator() {
|
||||
override fun prepareType(type: KotlinTypeMarker): UnwrappedType =
|
||||
super.prepareType(type).let { it.getEnhancementDeeply() ?: it }.unwrap()
|
||||
}
|
||||
val typeCheckerForEnhancedTypes = NewKotlinTypeCheckerImpl(
|
||||
kotlinTypeRefiner = KotlinTypeRefiner.Default,
|
||||
kotlinTypePreparator = object : KotlinTypePreparator() {
|
||||
@@ -287,6 +280,17 @@ class JavaNullabilityChecker(val upperBoundChecker: UpperBoundChecker) : Additio
|
||||
}
|
||||
)
|
||||
val typeCheckerForBaseTypes = NewKotlinTypeCheckerImpl(KotlinTypeRefiner.Default)
|
||||
|
||||
fun isNullableTypeAgainstNotNullTypeParameter(
|
||||
subType: KotlinType,
|
||||
superType: KotlinType
|
||||
): Boolean {
|
||||
if (superType !is NotNullTypeVariable || subType is NotNullTypeVariable) return false
|
||||
return !AbstractNullabilityChecker.isSubtypeOfAny(
|
||||
createClassicTypeCheckerState(isErrorTypeEqualsToAnything = true),
|
||||
subType
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.jvm.checkers
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
import org.jetbrains.kotlin.types.*
|
||||
|
||||
object JavaOverrideWithWrongNullabilityOverrideChecker : DeclarationChecker {
|
||||
private val overridingUtilWithEnhancementUnwrapped =
|
||||
OverridingUtil
|
||||
.createWithTypePreparatorAndCustomSubtype(JavaNullabilityChecker.typePreparatorUnwrappingEnhancement) { subtype, supertype ->
|
||||
!JavaNullabilityChecker.isNullableTypeAgainstNotNullTypeParameter(subtype, supertype)
|
||||
}
|
||||
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
if (descriptor !is CallableMemberDescriptor) return
|
||||
if (descriptor.overriddenDescriptors.isEmpty()) return
|
||||
|
||||
val containingClass = descriptor.containingDeclaration as? ClassDescriptor ?: return
|
||||
|
||||
for (overriddenDescriptor in descriptor.overriddenDescriptors) {
|
||||
if (overriddenDescriptor !is JavaMethodDescriptor) continue
|
||||
// Skip, if even with enhancement unwrapped, it's still a valid override
|
||||
if (overridingUtilWithEnhancementUnwrapped
|
||||
.isOverridableBy(
|
||||
overriddenDescriptor, descriptor, containingClass, true
|
||||
).result == OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE) continue
|
||||
|
||||
// Skip if it wasn't an override already before enhancement unwrappement, since errors already have been reported
|
||||
if (OverridingUtil.DEFAULT
|
||||
.isOverridableBy(
|
||||
overriddenDescriptor, descriptor, containingClass, true
|
||||
).result != OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE) continue
|
||||
|
||||
|
||||
val unwrappedOverridden = overriddenDescriptor.substitute(TypeSubstitutor.create(object : TypeSubstitution() {
|
||||
override fun get(key: KotlinType): TypeProjection? = null
|
||||
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance) =
|
||||
topLevelType.getEnhancementDeeply() ?: topLevelType
|
||||
})) ?: overriddenDescriptor
|
||||
|
||||
context.trace.report(ErrorsJvm.WRONG_NULLABILITY_FOR_JAVA_OVERRIDE.on(declaration, descriptor, unwrappedOverridden))
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+4
@@ -109,6 +109,10 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
|
||||
MAP.put(RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS,
|
||||
"Unsafe use of a nullable receiver of type {0}", RENDER_TYPE);
|
||||
|
||||
MAP.put(WRONG_NULLABILITY_FOR_JAVA_OVERRIDE,
|
||||
"Override ''{0}'' has incorrect nullability in its signature comparing with overridden ''{1}''", COMPACT, COMPACT);
|
||||
|
||||
|
||||
MAP.put(ANNOTATION_TARGETS_NON_EXISTENT_ACCESSOR,
|
||||
"An accessor will not be generated for ''{0}'', so the annotation will not be written to the class file", STRING);
|
||||
|
||||
|
||||
+3
-4
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.resolve.jvm.diagnostics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.Named;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.diagnostics.*;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
@@ -163,6 +160,8 @@ public interface ErrorsJvm {
|
||||
DiagnosticFactory1<KtElement, KotlinType> RECEIVER_NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS
|
||||
= DiagnosticFactory1.create(WARNING);
|
||||
|
||||
DiagnosticFactory2<KtModifierListOwner, CallableMemberDescriptor, CallableMemberDescriptor> WRONG_NULLABILITY_FOR_JAVA_OVERRIDE =
|
||||
DiagnosticFactory2.create(WARNING, OVERRIDE_MODIFIER);
|
||||
DiagnosticFactory1<KtAnnotationEntry, String> ANNOTATION_TARGETS_NON_EXISTENT_ACCESSOR = DiagnosticFactory1.create(WARNING);
|
||||
|
||||
DiagnosticFactory1<PsiElement, String> SUSPENSION_POINT_INSIDE_MONITOR = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
+2
-1
@@ -41,7 +41,8 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase(
|
||||
JvmMultifileClassStateChecker,
|
||||
DefaultCheckerInTailrec,
|
||||
FunctionDelegateMemberNameClashChecker,
|
||||
ClassInheritsJavaSealedClassChecker
|
||||
ClassInheritsJavaSealedClassChecker,
|
||||
JavaOverrideWithWrongNullabilityOverrideChecker,
|
||||
),
|
||||
|
||||
additionalCallCheckers = listOf(
|
||||
|
||||
Reference in New Issue
Block a user