All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.resolve.jvm.checkers.JavaOverrideWithWrongNullabilityOverrideChecker.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-RC
Show newest version
/*
 * 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.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.lexer.KtTokens
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.*
import org.jetbrains.kotlin.types.checker.KotlinTypePreparator
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
import org.jetbrains.kotlin.utils.addIfNotNull

object JavaOverrideWithWrongNullabilityOverrideChecker : DeclarationChecker {
    private val typePreparatorUnwrappingEnhancement: KotlinTypePreparator = object : KotlinTypePreparator() {
        override fun prepareType(type: KotlinTypeMarker): UnwrappedType =
            super.prepareType(type).let { it.getEnhancementDeeply() ?: it }.unwrap()
    }

    override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
        if (descriptor !is CallableMemberDescriptor) return
        if (descriptor.overriddenDescriptors.isEmpty()) return

        val modifierList = declaration.modifierList
        val hasOverrideNode = modifierList != null && modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD)
        if (!hasOverrideNode) return

        val containingClass = descriptor.containingDeclaration as? ClassDescriptor ?: return

        for (overriddenDescriptor in descriptor.overriddenDescriptors) {
            if (overriddenDescriptor !is JavaMethodDescriptor) continue

            val relatedTypeParameters = mutableSetOf()
            val overridingUtilWithEnhancementUnwrapped =
                OverridingUtil
                    .createWithTypePreparatorAndCustomSubtype(typePreparatorUnwrappingEnhancement) { subtype, supertype ->
                        !JavaNullabilityChecker.isNullableTypeAgainstNotNullTypeParameter(subtype, supertype).also {
                            if (it) {
                                relatedTypeParameters.addIfNotNull(subtype.constructor.declarationDescriptor as? TypeParameterDescriptor)
                            }
                        }
                    }

            // 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

            if (relatedTypeParameters.isNotEmpty()) {
                context.trace.report(
                    ErrorsJvm.WRONG_TYPE_PARAMETER_NULLABILITY_FOR_JAVA_OVERRIDE.on(declaration, relatedTypeParameters.first())
                )
            } else {
                context.trace.report(ErrorsJvm.WRONG_NULLABILITY_FOR_JAVA_OVERRIDE.on(declaration, descriptor, unwrappedOverridden))
            }

            break
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy