From 665e13e4ecc2b4c77a4b79c2cae5eea3ea21e407 Mon Sep 17 00:00:00 2001 From: Stanislav Erokhin Date: Sat, 20 Feb 2016 18:32:11 +0300 Subject: [PATCH] Remove obsolete code about warnings for expressions which can be null in java(has @Nullable annotation in java) and in kotlin not marked nullable. After introducing flexible types and signature enhancement there is no more such expressions. --- .../JavaNullabilityWarningsChecker.kt | 165 ++---------------- .../diagnostics/DefaultErrorMessagesJvm.java | 5 +- .../resolve/jvm/diagnostics/ErrorsJvm.java | 22 +-- 3 files changed, 14 insertions(+), 178 deletions(-) diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityWarningsChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityWarningsChecker.kt index 4b2d6ea83b8..7029cee5fe8 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityWarningsChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityWarningsChecker.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,182 +18,41 @@ package org.jetbrains.kotlin.resolve.jvm.checkers import org.jetbrains.kotlin.cfg.WhenChecker import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor -import org.jetbrains.kotlin.diagnostics.Errors -import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.load.java.lazy.types.isMarkedNotNull -import org.jetbrains.kotlin.load.java.lazy.types.isMarkedNullable -import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtPostfixExpression import org.jetbrains.kotlin.psi.KtWhenExpression import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory -import org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm -import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.expressions.SenselessComparisonChecker import org.jetbrains.kotlin.types.flexibility import org.jetbrains.kotlin.types.isFlexible class JavaNullabilityWarningsChecker : AdditionalTypeChecker { - private fun KotlinType.mayBeNull(): ErrorsJvm.NullabilityInformationSource? { - if (!isError && !isFlexible() && TypeUtils.isNullableType(this)) return ErrorsJvm.NullabilityInformationSource.KOTLIN - - if (isFlexible() && TypeUtils.isNullableType(flexibility().lowerBound)) return ErrorsJvm.NullabilityInformationSource.KOTLIN - - if (annotations.isMarkedNullable()) return ErrorsJvm.NullabilityInformationSource.JAVA - return null - } - - private fun KotlinType.mustNotBeNull(): ErrorsJvm.NullabilityInformationSource? { - if (!isError && !isFlexible() && !TypeUtils.isNullableType(this)) return ErrorsJvm.NullabilityInformationSource.KOTLIN - - if (isFlexible() && !TypeUtils.isNullableType(flexibility().upperBound)) return ErrorsJvm.NullabilityInformationSource.KOTLIN - - if (!isMarkedNullable && annotations.isMarkedNotNull()) return ErrorsJvm.NullabilityInformationSource.JAVA - return null - } - - private fun doCheckType( - expressionType: KotlinType, - expectedType: KotlinType, - dataFlowValue: DataFlowValue, - dataFlowInfo: DataFlowInfo, - reportWarning: (expectedMustNotBeNull: ErrorsJvm.NullabilityInformationSource, actualMayBeNull: ErrorsJvm.NullabilityInformationSource) -> Unit - ) { - if (TypeUtils.noExpectedType(expectedType)) return - - val expectedMustNotBeNull = expectedType.mustNotBeNull() - if (dataFlowInfo.getPredictableNullability(dataFlowValue) == Nullability.NOT_NULL) return - - val actualMayBeNull = expressionType.mayBeNull() - - if (expectedMustNotBeNull == ErrorsJvm.NullabilityInformationSource.KOTLIN && actualMayBeNull == ErrorsJvm.NullabilityInformationSource.KOTLIN) { - // a type mismatch error will be reported elsewhere - return; - } - - if (expectedMustNotBeNull != null && actualMayBeNull != null) { - reportWarning(expectedMustNotBeNull, actualMayBeNull) - } - } override fun checkType(expression: KtExpression, expressionType: KotlinType, expressionTypeWithSmartCast: KotlinType, c: ResolutionContext<*>) { - doCheckType( - expressionType, - c.expectedType, - DataFlowValueFactory.createDataFlowValue(expression, expressionType, c), - c.dataFlowInfo - ) { - expectedMustNotBeNull, - actualMayBeNull -> - c.trace.report(ErrorsJvm.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS.on(expression, expectedMustNotBeNull, actualMayBeNull)) - } + if (expression is KtWhenExpression && expression.elseExpression == null) { + // Check for conditionally-exhaustive when on platform enums, see KT-6399 + val type = expression.subjectExpression?.let { c.trace.getType(it) } ?: return + if (type.isFlexible() && TypeUtils.isNullableType(type.flexibility().upperBound) && !type.annotations.isMarkedNotNull()) { + val enumClassDescriptor = WhenChecker.getClassDescriptorOfTypeIfEnum(type) ?: return + val context = c.trace.bindingContext + if (WhenChecker.getEnumMissingCases(expression, context, enumClassDescriptor).isEmpty() + && !WhenChecker.containsNullCase(expression, context)) { - when (expression) { - is KtWhenExpression -> - if (expression.elseExpression == null) { - // Check for conditionally-exhaustive when on platform enums, see KT-6399 - val type = expression.subjectExpression?.let { c.trace.getType(it) } ?: return - if (type.isFlexible() && TypeUtils.isNullableType(type.flexibility().upperBound) && !type.annotations.isMarkedNotNull()) { - val enumClassDescriptor = WhenChecker.getClassDescriptorOfTypeIfEnum(type) ?: return - val context = c.trace.bindingContext - if (WhenChecker.getEnumMissingCases(expression, context, enumClassDescriptor).isEmpty() - && !WhenChecker.containsNullCase(expression, context)) { - - c.trace.report(ErrorsJvm.WHEN_ENUM_CAN_BE_NULL_IN_JAVA.on(expression.subjectExpression!!)) - } - } - } - is KtPostfixExpression -> - if (expression.operationToken == KtTokens.EXCLEXCL) { - val baseExpression = expression.baseExpression ?: return - val baseExpressionType = c.trace.getType(baseExpression) ?: return - doIfNotNull( - DataFlowValueFactory.createDataFlowValue(baseExpression, baseExpressionType, c), - c - ) { - c.trace.report(Errors.UNNECESSARY_NOT_NULL_ASSERTION.on(expression.getOperationReference(), baseExpressionType)) - } - } - is KtBinaryExpression -> - when (expression.operationToken) { - KtTokens.ELVIS -> { - val baseExpression = expression.left - val baseExpressionType = baseExpression?.let{ c.trace.getType(it) } ?: return - doIfNotNull( - DataFlowValueFactory.createDataFlowValue(baseExpression!!, baseExpressionType, c), - c - ) { - c.trace.report(Errors.USELESS_ELVIS.on(expression, baseExpressionType)) - } - } - KtTokens.EQEQ, - KtTokens.EXCLEQ, - KtTokens.EQEQEQ, - KtTokens.EXCLEQEQEQ -> { - if (expression.left != null && expression.right != null) { - SenselessComparisonChecker.checkSenselessComparisonWithNull( - expression, expression.left!!, expression.right!!, c, - { c.trace.getType(it) }, - { - value -> - doIfNotNull(value, c) { Nullability.NOT_NULL } ?: Nullability.UNKNOWN - } - ) - } - } + c.trace.report(ErrorsJvm.WHEN_ENUM_CAN_BE_NULL_IN_JAVA.on(expression.subjectExpression!!)) } + } } } - private fun doIfNotNull(dataFlowValue: DataFlowValue, c: ResolutionContext<*>, body: () -> T): T? { - if (c.dataFlowInfo.getPredictableNullability(dataFlowValue).canBeNull() - && dataFlowValue.type.mustNotBeNull() == ErrorsJvm.NullabilityInformationSource.JAVA) { - return body() - } - return null - } - override fun checkReceiver( receiverParameter: ReceiverParameterDescriptor, receiverArgument: ReceiverValue, safeAccess: Boolean, c: CallResolutionContext<*> - ) { - val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverArgument, c) - if (!safeAccess) { - doCheckType( - receiverArgument.type, - receiverParameter.type, - dataFlowValue, - c.dataFlowInfo - ) { - expectedMustNotBeNull, - actualMayBeNull -> - val reportOn = - if (receiverArgument is ExpressionReceiver) - receiverArgument.expression - else - c.call.getCalleeExpression() ?: c.call.getCallElement() - - c.trace.report(ErrorsJvm.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS.on( - reportOn, expectedMustNotBeNull, actualMayBeNull - )) - - } - } - else { - doIfNotNull(dataFlowValue, c) { - c.trace.report(Errors.UNNECESSARY_SAFE_CALL.on(c.call.getCallOperationNode()!!.getPsi(), receiverArgument.getType())) - } - } - } + ) {} } \ No newline at end of file diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java index a57a1213785..76642a3e194 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -79,9 +79,6 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension { MAP.put(ErrorsJvm.NO_REFLECTION_IN_CLASS_PATH, "Call uses reflection API which is not found in compilation classpath. " + "Make sure you have kotlin-reflect.jar in the classpath"); - MAP.put(ErrorsJvm.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS, - "Expected type does not accept nulls in {0}, but the value may be null in {1}", Renderers.TO_STRING, Renderers.TO_STRING); - MAP.put(ErrorsJvm.INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER, "Interfaces can't call Java default methods via super"); MAP.put(ErrorsJvm.SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC, "Using non-JVM static members protected in the superclass companion is unsupported yet"); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java index 1d181a575a1..ce580f47872 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ package org.jetbrains.kotlin.resolve.jvm.diagnostics; import com.intellij.psi.PsiElement; -import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0; import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1; import org.jetbrains.kotlin.diagnostics.DiagnosticFactory2; @@ -85,25 +84,6 @@ public interface ErrorsJvm { DiagnosticFactory1 SUPER_CALL_WITH_DEFAULT_PARAMETERS = DiagnosticFactory1.create(ERROR); - enum NullabilityInformationSource { - KOTLIN { - @NotNull - @Override - public String toString() { - return "Kotlin"; - } - }, - JAVA { - @NotNull - @Override - public String toString() { - return "Java"; - } - } - } - - DiagnosticFactory2 NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS = DiagnosticFactory2.create(WARNING); - DiagnosticFactory0 WHEN_ENUM_CAN_BE_NULL_IN_JAVA = DiagnosticFactory0.create(WARNING); @SuppressWarnings("UnusedDeclaration")