From 5501cdf049a0c366890c27524bac9932d38ed0d6 Mon Sep 17 00:00:00 2001 From: e5l Date: Fri, 11 Aug 2017 14:21:23 +0300 Subject: [PATCH] Add warnings for jsr305 nullable annotations #KT-19115 Fixed --- .../arguments/K2JVMCompilerArguments.kt | 10 +- .../kotlin/frontend/java/di/injection.kt | 7 +- .../jvm/checkers/JavaNullabilityChecker.kt | 175 ++++++++++++++++++ .../jvm/checkers/WhenByPlatformEnumChecker.kt | 57 ------ .../diagnostics/DefaultErrorMessagesJvm.java | 2 + .../resolve/jvm/diagnostics/ErrorsJvm.java | 22 +++ .../jvm/platform/JvmPlatformConfigurator.kt | 2 +- .../kotlin/resolve/calls/CandidateResolver.kt | 4 + .../calls/checkers/AdditionalTypeChecker.kt | 18 +- compiler/testData/cli/jvm/extraHelp.out | 4 +- .../checkers/KotlinMultiFileTestWithJava.java | 2 +- ...nAnnotationsNoAnnotationInClasspathTest.kt | 21 ++- .../AbstractForeignAnnotationsTest.kt | 30 ++- .../LoadJavaPackageAnnotationsTest.kt | 2 +- .../TypeQualifierAnnotationResolverTest.kt | 2 +- .../jetbrains/kotlin/config/AnalysisFlag.kt | 4 +- .../java/AnnotationTypeQualifierResolver.kt | 29 ++- .../kotlin/load/java/lazy/context.kt | 12 +- .../descriptors/LazyJavaPackageFragment.kt | 3 +- .../typeEnhancement/signatureEnhancement.kt | 139 ++++++++------ .../java/typeEnhancement/typeEnhancement.kt | 31 ++-- .../java/typeEnhancement/typeQualifiers.kt | 3 +- .../kotlin/UnsafeVarianceTypeSubstitution.kt | 3 +- .../load/kotlin/reflect/RuntimeModuleData.kt | 3 +- .../kotlin/resolve/DescriptorUtils.kt | 2 + .../kotlin/types/CapturedTypeApproximation.kt | 10 +- .../kotlin/types/TypeSubstitutor.java | 15 ++ .../org/jetbrains/kotlin/types/TypeUtils.kt | 2 +- .../kotlin/types/TypeWithEnhancement.kt | 80 ++++++++ .../types/checker/NewKotlinTypeChecker.kt | 2 +- .../jetbrains/kotlin/types/flexibleTypes.kt | 2 +- .../compiler/IDELanguageSettingsProvider.kt | 4 +- .../highlighter/Jsr305HighlightingTest.kt | 2 +- 33 files changed, 506 insertions(+), 198 deletions(-) create mode 100644 compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityChecker.kt delete mode 100644 compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/WhenByPlatformEnumChecker.kt create mode 100644 core/descriptors/src/org/jetbrains/kotlin/types/TypeWithEnhancement.kt diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt index f94944d4723..084e5b4b5f2 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.kt @@ -156,18 +156,18 @@ class K2JVMCompilerArguments : CommonCompilerArguments() { @Argument( value = "-Xjsr305-annotations", - valueDescription = "{ignore|enable}", - description = "Specify global behavior for JSR-305 nullability annotations: ignore, or treat as other supported nullability annotations" + valueDescription = "{ignore|enable|warn}", + description = "Specify global behavior for JSR-305 nullability annotations: ignore, treat as other supported nullability annotations, or report a warning" ) - var jsr305GlobalReportLevel: String? by FreezableVar(Jsr305State.DEFAULT.description) + var jsr305GlobalState: String? by FreezableVar(Jsr305State.DEFAULT.description) // Paths to output directories for friend modules. var friendPaths: Array? by FreezableVar(null) override fun configureAnalysisFlags(): MutableMap, Any> { val result = super.configureAnalysisFlags() - Jsr305State.findByDescription(jsr305GlobalReportLevel)?.let { - result.put(AnalysisFlag.loadJsr305Annotations, it) + Jsr305State.findByDescription(jsr305GlobalState)?.let { + result.put(AnalysisFlag.jsr305GlobalState, it) } return result } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt index 21ba46214ca..4b6e5328001 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt @@ -103,12 +103,7 @@ fun createContainerForLazyResolveWithJava( useInstance(languageVersionSettings) - if (languageVersionSettings.getFlag(AnalysisFlag.loadJsr305Annotations).shouldReportError) { - useImpl() - } - else { - useInstance(AnnotationTypeQualifierResolver.Empty) - } + useInstance(languageVersionSettings.getFlag(AnalysisFlag.jsr305GlobalState)) if (useBuiltInsProvider) { useInstance((moduleContext.module.builtIns as JvmBuiltIns).settings) diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityChecker.kt new file mode 100644 index 00000000000..d5fd3f5c23d --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JavaNullabilityChecker.kt @@ -0,0 +1,175 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +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.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.BindingContext +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.* +import org.jetbrains.kotlin.types.expressions.SenselessComparisonChecker + +class JavaNullabilityChecker : AdditionalTypeChecker { + + 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)) + } + + when (expression) { + is KtWhenExpression -> + if (expression.elseExpression == null) { + // Check for conditionally-exhaustive when on platform enums, see KT-6399 + val subjectExpression = expression.subjectExpression ?: return + val type = c.trace.getType(subjectExpression) ?: return + if (type.isFlexible() && TypeUtils.isNullableType(type.asFlexibleType().upperBound)) { + val dataFlowValue = DataFlowValueFactory.createDataFlowValue(subjectExpression, type, c) + val dataFlowInfo = c.trace[BindingContext.EXPRESSION_TYPE_INFO, subjectExpression]?.dataFlowInfo + if (dataFlowInfo != null && !dataFlowInfo.getStableNullability(dataFlowValue).canBeNull()) { + return + } + + 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.operationReference, baseExpressionType)) + } + } + is KtBinaryExpression -> + when (expression.operationToken) { + 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 + } + ) + } + } + } + } + } + + override fun checkReceiver(receiverParameter: ReceiverParameterDescriptor, receiverArgument: ReceiverValue, safeAccess: Boolean, c: CallResolutionContext<*>) { + val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverArgument, c) + if (safeAccess) { + doIfNotNull(dataFlowValue, c) { + c.trace.report(Errors.UNNECESSARY_SAFE_CALL.on(c.call.callOperationNode!!.psi, receiverArgument.type)) + } + + return + } + + doCheckType( + receiverArgument.type, + receiverParameter.type, + dataFlowValue, + c.dataFlowInfo + ) { expectedMustNotBeNull, + actualMayBeNull -> + val reportOn = (receiverArgument as? ExpressionReceiver)?.expression ?: (c.call.calleeExpression ?: c.call.callElement) + c.trace.report(ErrorsJvm.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS.on( + reportOn, expectedMustNotBeNull, actualMayBeNull + )) + } + } + + 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.getStableNullability(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) + } + } + + private fun doIfNotNull(dataFlowValue: DataFlowValue, c: ResolutionContext<*>, body: () -> T): T? = + if (c.dataFlowInfo.getStableNullability(dataFlowValue).canBeNull() && + dataFlowValue.type.mustNotBeNull() == ErrorsJvm.NullabilityInformationSource.JAVA) + body() + else null + + private fun KotlinType.mustNotBeNull(): ErrorsJvm.NullabilityInformationSource? = when { + !isError && !isFlexible() && !TypeUtils.acceptsNullable(this) -> ErrorsJvm.NullabilityInformationSource.KOTLIN + isFlexible() && !TypeUtils.acceptsNullable(asFlexibleType().upperBound) -> ErrorsJvm.NullabilityInformationSource.KOTLIN + this is TypeWithEnhancement && enhancement.mustNotBeNull() != null -> ErrorsJvm.NullabilityInformationSource.JAVA + else -> null + } + + private fun KotlinType.mayBeNull(): ErrorsJvm.NullabilityInformationSource? = when { + !isError && !isFlexible() && TypeUtils.acceptsNullable(this) -> ErrorsJvm.NullabilityInformationSource.KOTLIN + isFlexible() && TypeUtils.acceptsNullable(asFlexibleType().lowerBound) -> ErrorsJvm.NullabilityInformationSource.KOTLIN + this is TypeWithEnhancement && enhancement.mayBeNull() != null -> ErrorsJvm.NullabilityInformationSource.JAVA + else -> null + } +} diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/WhenByPlatformEnumChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/WhenByPlatformEnumChecker.kt deleted file mode 100644 index 99187136385..00000000000 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/WhenByPlatformEnumChecker.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.resolve.jvm.checkers - -import org.jetbrains.kotlin.cfg.WhenChecker -import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtWhenExpression -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker -import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory -import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.asFlexibleType -import org.jetbrains.kotlin.types.isFlexible - -class WhenByPlatformEnumChecker : AdditionalTypeChecker { - - override fun checkType(expression: KtExpression, expressionType: KotlinType, expressionTypeWithSmartCast: KotlinType, c: ResolutionContext<*>) { - if (expression is KtWhenExpression && expression.elseExpression == null) { - // Check for conditionally-exhaustive when on platform enums, see KT-6399 - val subjectExpression = expression.subjectExpression ?: return - val type = c.trace.getType(subjectExpression) ?: return - if (type.isFlexible() && TypeUtils.isNullableType(type.asFlexibleType().upperBound)) { - val dataFlowValue = DataFlowValueFactory.createDataFlowValue(subjectExpression, type, c) - val dataFlowInfo = c.trace[BindingContext.EXPRESSION_TYPE_INFO, subjectExpression]?.dataFlowInfo - if (dataFlowInfo != null && !dataFlowInfo.getStableNullability(dataFlowValue).canBeNull()) { - return - } - - 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!!)) - } - } - } - } - -} 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 f0b67ec5ee7..0e9e612cc3b 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 @@ -79,6 +79,8 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension { MAP.put(INTERFACE_CANT_CALL_DEFAULT_METHOD_VIA_SUPER, "Interfaces can't call Java default methods via super"); MAP.put(SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC, "Using non-JVM static members protected in the superclass companion is unsupported yet"); + 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(WHEN_ENUM_CAN_BE_NULL_IN_JAVA, "Enum argument can be null in Java, but exhaustive when contains no null branch"); MAP.put(JAVA_CLASS_ON_COMPANION, 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 334d108a254..283bc7a1c05 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 @@ -17,11 +17,13 @@ package org.jetbrains.kotlin.resolve.jvm.diagnostics; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.diagnostics.*; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.KtAnnotationEntry; import org.jetbrains.kotlin.psi.KtDeclaration; +import org.jetbrains.kotlin.psi.KtElement; import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.types.KotlinType; @@ -98,6 +100,26 @@ public interface ErrorsJvm { DiagnosticFactory0 JAVA_MODULE_DOES_NOT_READ_UNNAMED_MODULE = DiagnosticFactory0.create(ERROR); DiagnosticFactory2 JAVA_MODULE_DOES_NOT_EXPORT_PACKAGE = DiagnosticFactory2.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); + @SuppressWarnings("UnusedDeclaration") Object _initializer = new Object() { { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt index 1aff0040597..e679950ddb2 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt @@ -56,7 +56,7 @@ object JvmPlatformConfigurator : PlatformConfigurator( ), additionalTypeCheckers = listOf( - WhenByPlatformEnumChecker(), + JavaNullabilityChecker(), RuntimeAssertionsTypeChecker, JavaGenericVarianceViolationTypeChecker, JavaTypeAccessibilityChecker() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt index 807f10bec6d..b50cef9583a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getErasedReceiverType import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isInvokeCallOnExpressionWithBothReceivers import org.jetbrains.kotlin.resolve.calls.callUtil.isExplicitSafeCall import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall +import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker import org.jetbrains.kotlin.resolve.calls.context.* import org.jetbrains.kotlin.resolve.calls.inference.SubstitutionFilteringInternalResolveAnnotations import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatchStatus @@ -60,6 +61,7 @@ class CandidateResolver( private val argumentTypeResolver: ArgumentTypeResolver, private val genericCandidateResolver: GenericCandidateResolver, private val reflectionTypes: ReflectionTypes, + private val additionalTypeCheckers: Iterable, private val smartCastManager: SmartCastManager ) { fun performResolutionForCandidateCall( @@ -581,6 +583,8 @@ class CandidateResolver( return UNSAFE_CALL_ERROR } + additionalTypeCheckers.forEach { it.checkReceiver(receiverParameter, receiverArgument, safeAccess, this) } + return SUCCESS } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AdditionalTypeChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AdditionalTypeChecker.kt index 85ff9fd1c7a..b1cf59aa2aa 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AdditionalTypeChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/AdditionalTypeChecker.kt @@ -16,10 +16,26 @@ package org.jetbrains.kotlin.resolve.calls.checkers +import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.types.KotlinType interface AdditionalTypeChecker { - fun checkType(expression: KtExpression, expressionType: KotlinType, expressionTypeWithSmartCast: KotlinType, c: ResolutionContext<*>) + fun checkType( + expression: KtExpression, + expressionType: KotlinType, + expressionTypeWithSmartCast: KotlinType, + c: ResolutionContext<*> + ) + + fun checkReceiver( + receiverParameter: ReceiverParameterDescriptor, + receiverArgument: ReceiverValue, + safeAccess: Boolean, + c: CallResolutionContext<*> + ) { } + } \ No newline at end of file diff --git a/compiler/testData/cli/jvm/extraHelp.out b/compiler/testData/cli/jvm/extraHelp.out index fe05cf5efa2..78b95b49014 100644 --- a/compiler/testData/cli/jvm/extraHelp.out +++ b/compiler/testData/cli/jvm/extraHelp.out @@ -8,8 +8,8 @@ where advanced options include: -Xmultifile-parts-inherit Compile multifile classes as a hierarchy of parts and facade -Xmodule-path= Paths where to find Java 9+ modules -Xjavac-arguments= Java compiler arguments - -Xjsr305-annotations={ignore|enable} - Specify global behavior for JSR-305 nullability annotations: ignore, or treat as other supported nullability annotations + -Xjsr305-annotations={ignore|enable|warn} + Specify global behavior for JSR-305 nullability annotations: ignore, treat as other supported nullability annotations, or report a warning -Xload-builtins-from-dependencies Load definitions of built-in declarations from module dependencies, instead of from the compiler -Xno-call-assertions Don't generate not-null assertion after each invocation of method returning not-null diff --git a/compiler/tests-common/org/jetbrains/kotlin/checkers/KotlinMultiFileTestWithJava.java b/compiler/tests-common/org/jetbrains/kotlin/checkers/KotlinMultiFileTestWithJava.java index 36d9877a424..47bea6619d6 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/checkers/KotlinMultiFileTestWithJava.java +++ b/compiler/tests-common/org/jetbrains/kotlin/checkers/KotlinMultiFileTestWithJava.java @@ -80,7 +80,7 @@ public abstract class KotlinMultiFileTestWithJava extends KtUsefulTestCase CollectionsKt.plus(Collections.singletonList(KotlinTestUtils.getAnnotationsJar()), getExtraClasspath()), isJavaSourceRootNeeded() ? Collections.singletonList(javaFilesDir) : Collections.emptyList() ); - configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition.INSTANCE); + configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition.INSTANCE); if (isKotlinSourceRootNeeded()) { ContentRootsKt.addKotlinSourceRoot(configuration, kotlinSourceRoot.getPath()); } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/AbstractForeignAnnotationsNoAnnotationInClasspathTest.kt b/compiler/tests/org/jetbrains/kotlin/checkers/AbstractForeignAnnotationsNoAnnotationInClasspathTest.kt index 3ae04fec489..0328196f3e4 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/AbstractForeignAnnotationsNoAnnotationInClasspathTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/checkers/AbstractForeignAnnotationsNoAnnotationInClasspathTest.kt @@ -25,8 +25,17 @@ import java.io.File abstract class AbstractForeignAnnotationsNoAnnotationInClasspathTest : AbstractForeignAnnotationsTest() { private val compiledJavaPath = KotlinTestUtils.tmpDir("java-compiled-files") override fun getExtraClasspath(): List { - compileJavaFiles() - return listOf(compiledJavaPath) + val foreignAnnotations = createJarWithForeignAnnotations() + val testAnnotations = compileTestAnnotations(foreignAnnotations) + + val additionalClasspath = (foreignAnnotations + testAnnotations).map { it.path } + CodegenTestUtil.compileJava( + CodegenTestUtil.findJavaSourcesInDirectory(javaFilesDir), + additionalClasspath, emptyList(), + compiledJavaPath + ) + + return listOf(compiledJavaPath) + testAnnotations } override fun analyzeAndCheck(testDataFile: File, files: List) { @@ -39,12 +48,4 @@ abstract class AbstractForeignAnnotationsNoAnnotationInClasspathTest : AbstractF private fun createJarWithForeignAnnotations(): List = listOf(MockLibraryUtil.compileJvmLibraryToJar(annotationsPath, "foreign-annotations")) - - private fun compileJavaFiles() { - CodegenTestUtil.compileJava( - CodegenTestUtil.findJavaSourcesInDirectory(javaFilesDir), - createJarWithForeignAnnotations().map { it.path }, emptyList(), - compiledJavaPath - ) - } } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/AbstractForeignAnnotationsTest.kt b/compiler/tests/org/jetbrains/kotlin/checkers/AbstractForeignAnnotationsTest.kt index d0021cf0ec3..8c43b016537 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/AbstractForeignAnnotationsTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/checkers/AbstractForeignAnnotationsTest.kt @@ -17,20 +17,40 @@ package org.jetbrains.kotlin.checkers import org.jetbrains.kotlin.config.* +import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.MockLibraryUtil import org.jetbrains.kotlin.utils.Jsr305State import java.io.File val FOREIGN_ANNOTATIONS_SOURCES_PATH = "compiler/testData/foreignAnnotations/annotations" +val TEST_ANNOTATIONS_SOURCE_PATH = "compiler/testData/foreignAnnotations/testAnnotations" abstract class AbstractForeignAnnotationsTest : AbstractDiagnosticsWithFullJdkTest() { - override fun getExtraClasspath(): List = - listOf(MockLibraryUtil.compileJvmLibraryToJar(annotationsPath, "foreign-annotations")) + private val WARNING_FOR_JSR305_ANNOTATIONS_DIRECTIVE = "WARNING_FOR_JSR305_ANNOTATIONS" + + override fun getExtraClasspath(): List { + val foreignAnnotations = listOf(MockLibraryUtil.compileJvmLibraryToJar(annotationsPath, "foreign-annotations")) + return foreignAnnotations + compileTestAnnotations(foreignAnnotations) + } + + protected fun compileTestAnnotations(extraClassPath: List): List = + listOf(MockLibraryUtil.compileJvmLibraryToJar( + TEST_ANNOTATIONS_SOURCE_PATH, + "test-foreign-annotations", + extraClasspath = extraClassPath.map { it.path } + )) open protected val annotationsPath: String get() = FOREIGN_ANNOTATIONS_SOURCES_PATH - override fun loadLanguageVersionSettings(module: List): LanguageVersionSettings = - LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, - mapOf(AnalysisFlag.loadJsr305Annotations to Jsr305State.ENABLE)) + override fun loadLanguageVersionSettings(module: List): LanguageVersionSettings { + val hasWarningDirective = module.any { + InTextDirectivesUtils.isDirectiveDefined(it.expectedText, WARNING_FOR_JSR305_ANNOTATIONS_DIRECTIVE) + } + + val jsr305State = if (hasWarningDirective) Jsr305State.WARN else Jsr305State.ENABLE + return LanguageVersionSettingsImpl(LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, + mapOf(AnalysisFlag.jsr305GlobalState to jsr305State) + ) + } } diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaPackageAnnotationsTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaPackageAnnotationsTest.kt index a87f072d01d..a2cfcd0d082 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaPackageAnnotationsTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/LoadJavaPackageAnnotationsTest.kt @@ -47,7 +47,7 @@ class LoadJavaPackageAnnotationsTest : KtUsefulTestCase() { put(JVMConfigurationKeys.USE_JAVAC, true) } languageVersionSettings = LanguageVersionSettingsImpl( - LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlag.loadJsr305Annotations to Jsr305State.ENABLE) + LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlag.jsr305GlobalState to Jsr305State.ENABLE) ) configurator(this) } diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/TypeQualifierAnnotationResolverTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/TypeQualifierAnnotationResolverTest.kt index 40e857f19e0..88f0730ea5e 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/TypeQualifierAnnotationResolverTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/TypeQualifierAnnotationResolverTest.kt @@ -96,7 +96,7 @@ class TypeQualifierAnnotationResolverTest : KtUsefulTestCase() { listOf(File(TEST_DATA_PATH)) ).apply { languageVersionSettings = LanguageVersionSettingsImpl( - LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlag.loadJsr305Annotations to Jsr305State.ENABLE) + LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE, mapOf(AnalysisFlag.jsr305GlobalState to Jsr305State.ENABLE) ) } diff --git a/compiler/util/src/org/jetbrains/kotlin/config/AnalysisFlag.kt b/compiler/util/src/org/jetbrains/kotlin/config/AnalysisFlag.kt index fe8eb63f0d5..1593d20b9b0 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/AnalysisFlag.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/AnalysisFlag.kt @@ -52,6 +52,6 @@ class AnalysisFlag internal constructor( val multiPlatformDoNotCheckImpl by Flag.Boolean @JvmStatic - val loadJsr305Annotations by Flag.Jsr305StateIgnoreByDefault + val jsr305GlobalState by Flag.Jsr305StateIgnoreByDefault } -} +} \ No newline at end of file diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt index 23d133ccb68..2bc0f256b7d 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt @@ -19,8 +19,6 @@ package org.jetbrains.kotlin.load.java import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor -import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver.QualifierApplicabilityType -import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver.TypeQualifierWithApplicability import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.constants.ArrayValue import org.jetbrains.kotlin.resolve.constants.ConstantValue @@ -28,17 +26,14 @@ import org.jetbrains.kotlin.resolve.constants.EnumValue import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.utils.Jsr305State import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult private val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname") private val TYPE_QUALIFIER_FQNAME = FqName("javax.annotation.meta.TypeQualifier") private val TYPE_QUALIFIER_DEFAULT_FQNAME = FqName("javax.annotation.meta.TypeQualifierDefault") -interface AnnotationTypeQualifierResolver { - fun resolveTypeQualifierAnnotation(annotationDescriptor: AnnotationDescriptor): AnnotationDescriptor? - - fun resolveTypeQualifierDefaultAnnotation(annotationDescriptor: AnnotationDescriptor): TypeQualifierWithApplicability? - +class AnnotationTypeQualifierResolver(storageManager: StorageManager, val jsr305State: Jsr305State) { enum class QualifierApplicabilityType { METHOD_RETURN_TYPE, VALUE_PARAMETER, FIELD, TYPE_USE } @@ -53,14 +48,6 @@ interface AnnotationTypeQualifierResolver { operator fun component2() = QualifierApplicabilityType.values().filter(this::isApplicableTo) } - object Empty : AnnotationTypeQualifierResolver { - override fun resolveTypeQualifierAnnotation(annotationDescriptor: AnnotationDescriptor): AnnotationDescriptor? = null - - override fun resolveTypeQualifierDefaultAnnotation(annotationDescriptor: AnnotationDescriptor): TypeQualifierWithApplicability? = null - } -} - -class AnnotationTypeQualifierResolverImpl(storageManager: StorageManager) : AnnotationTypeQualifierResolver { private val resolvedNicknames = storageManager.createMemoizedFunctionWithNullableValues(this::computeTypeQualifierNickname) @@ -76,14 +63,22 @@ class AnnotationTypeQualifierResolverImpl(storageManager: StorageManager) : Anno return resolvedNicknames(classDescriptor) } - override fun resolveTypeQualifierAnnotation(annotationDescriptor: AnnotationDescriptor): AnnotationDescriptor? { + fun resolveTypeQualifierAnnotation(annotationDescriptor: AnnotationDescriptor): AnnotationDescriptor? { + if (jsr305State.isIgnored()) { + return null + } + val annotationClass = annotationDescriptor.annotationClass ?: return null if (annotationClass.isAnnotatedWithTypeQualifier) return annotationDescriptor return resolveTypeQualifierNickname(annotationClass) } - override fun resolveTypeQualifierDefaultAnnotation(annotationDescriptor: AnnotationDescriptor): TypeQualifierWithApplicability? { + fun resolveTypeQualifierDefaultAnnotation(annotationDescriptor: AnnotationDescriptor): TypeQualifierWithApplicability? { + if (jsr305State.isIgnored()) { + return null + } + val typeQualifierDefaultAnnotatedClass = annotationDescriptor.annotationClass?.takeIf { it.annotations.hasAnnotation(TYPE_QUALIFIER_DEFAULT_FQNAME) } ?: return null diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/context.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/context.kt index d1303f3f875..a0e72954191 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/context.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/context.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.load.java.sources.JavaSourceElementFactory import org.jetbrains.kotlin.load.java.structure.JavaTypeParameterListOwner import org.jetbrains.kotlin.load.java.typeEnhancement.JavaTypeQualifiers import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifier +import org.jetbrains.kotlin.load.java.typeEnhancement.NullabilityQualifierWithMigrationStatus import org.jetbrains.kotlin.load.java.typeEnhancement.SignatureEnhancement import org.jetbrains.kotlin.load.kotlin.DeserializedDescriptorResolver import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder @@ -69,7 +70,7 @@ class JavaResolverComponents( ) } -private typealias QualifierByApplicabilityType = EnumMap +private typealias QualifierByApplicabilityType = EnumMap class JavaTypeQualifiersByElementType( internal val nullabilityQualifiers: QualifierByApplicabilityType @@ -80,7 +81,7 @@ class JavaTypeQualifiersByElementType( ( nullabilityQualifiers[applicabilityType] ?: nullabilityQualifiers[AnnotationTypeQualifierResolver.QualifierApplicabilityType.TYPE_USE] - )?.let { JavaTypeQualifiers(it, null, isNotNullTypeParameter = false) } + )?.let { JavaTypeQualifiers(it.qualifier, null, isNotNullTypeParameter = false, isNullabilityQualifierForWarning = it.isForWarningOnly) } } class LazyJavaResolverContext internal constructor( @@ -121,9 +122,10 @@ fun LazyJavaResolverContext.computeNewDefaultTypeQualifiers( ?: QualifierByApplicabilityType(AnnotationTypeQualifierResolver.QualifierApplicabilityType::class.java) var wasUpdate = false + val isForWarning = components.annotationTypeQualifierResolver.jsr305State.isWarning() for ((nullability, applicableTo) in nullabilityQualifiersWithApplicability) { for (applicabilityType in applicableTo) { - nullabilityQualifiersByType[applicabilityType] = nullability + nullabilityQualifiersByType[applicabilityType] = NullabilityQualifierWithMigrationStatus(nullability, isForWarning) wasUpdate = true } } @@ -140,9 +142,9 @@ private fun LazyJavaResolverContext.extractDefaultNullabilityQualifier( components.annotationTypeQualifierResolver.resolveTypeQualifierDefaultAnnotation(annotationDescriptor) ?: return null - val nullability = components.signatureEnhancement.extractNullability(typeQualifier) ?: return null + val nullabilityQualifier = components.signatureEnhancement.extractNullability(typeQualifier)?.qualifier ?: return null - return NullabilityQualifierWithApplicability(nullability, applicability) + return NullabilityQualifierWithApplicability(nullabilityQualifier, applicability) } data class NullabilityQualifierWithApplicability( diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageFragment.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageFragment.kt index cd5d5ba0681..9c6b95fd709 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageFragment.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaPackageFragment.kt @@ -20,7 +20,6 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.SourceElement import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl -import org.jetbrains.kotlin.load.java.AnnotationTypeQualifierResolver import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext import org.jetbrains.kotlin.load.java.lazy.childForClassOrPackage import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations @@ -56,7 +55,7 @@ class LazyJavaPackageFragment( override val annotations = // Do not resolve package annotations if JSR-305 is disabled - if (c.components.annotationTypeQualifierResolver == AnnotationTypeQualifierResolver.Empty) Annotations.EMPTY + if (c.components.annotationTypeQualifierResolver.jsr305State.isIgnored()) Annotations.EMPTY else c.resolveAnnotations(jPackage) internal fun getSubPackageFqNames(): List = subPackages() diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt index a5b47634ed7..a8b9b4b33ca 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt @@ -35,45 +35,56 @@ import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.platform.JavaToKotlinClassMap +import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgumentValue +import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.asFlexibleType import org.jetbrains.kotlin.types.checker.KotlinTypeChecker -import org.jetbrains.kotlin.types.isFlexible import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.util.* +data class NullabilityQualifierWithMigrationStatus( + val qualifier: NullabilityQualifier, + val isForWarningOnly: Boolean = false +) + class SignatureEnhancement(private val annotationTypeQualifierResolver: AnnotationTypeQualifierResolver) { - fun extractNullability(annotationDescriptor: AnnotationDescriptor): NullabilityQualifier? { - val annotationFqName = annotationDescriptor.fqName ?: return null - when (annotationFqName) { - in NULLABLE_ANNOTATIONS -> return NullabilityQualifier.NULLABLE - in NOT_NULL_ANNOTATIONS -> return NullabilityQualifier.NOT_NULL - } - - val typeQualifier = - when { - annotationFqName == JAVAX_NONNULL_ANNOTATION -> annotationDescriptor - else -> annotationTypeQualifierResolver.resolveTypeQualifierAnnotation(annotationDescriptor) - ?.takeIf { it.fqName == JAVAX_NONNULL_ANNOTATION } - } ?: return null - - val enumEntryDescriptor = - typeQualifier.allValueArguments.values.singleOrNull()?.value - // if no argument is specified, use default value: NOT_NULL - ?: return NullabilityQualifier.NOT_NULL + private fun AnnotationDescriptor.extractNullabilityTypeFromArgument(): NullabilityQualifierWithMigrationStatus? { + val enumEntryDescriptor = firstArgumentValue() + // if no argument is specified, use default value: NOT_NULL + ?: return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) if (enumEntryDescriptor !is ClassDescriptor) return null return when (enumEntryDescriptor.name.asString()) { - "ALWAYS" -> NullabilityQualifier.NOT_NULL - "MAYBE" -> NullabilityQualifier.NULLABLE + "ALWAYS" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) + "MAYBE" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE) else -> null } } + fun extractNullability(annotationDescriptor: AnnotationDescriptor): NullabilityQualifierWithMigrationStatus? { + val annotationFqName = annotationDescriptor.fqName ?: return null + + return when (annotationFqName) { + in NULLABLE_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE) + in NOT_NULL_ANNOTATIONS -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) + JAVAX_NONNULL_ANNOTATION -> annotationDescriptor.extractNullabilityTypeFromArgument() + else -> { + val forWarning = annotationTypeQualifierResolver.jsr305State.isWarning() + + annotationTypeQualifierResolver + .resolveTypeQualifierAnnotation(annotationDescriptor) + ?.takeIf { it.fqName == JAVAX_NONNULL_ANNOTATION } + ?.extractNullabilityTypeFromArgument() + ?.copy(isForWarningOnly = forWarning) + } + } + } + fun enhanceSignatures(c: LazyJavaResolverContext, platformSignatures: Collection): Collection { return platformSignatures.map { @@ -217,12 +228,17 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati fun uniqueNotNull(x: T?, y: T?) = if (x == null || y == null || x == y) x ?: y else null val defaultTypeQualifier = defaultTopLevelQualifiers?.takeIf { isHeadTypeConstructor } - val nullability = + val nullabilityInfo = composedAnnotation.extractNullability() - ?: defaultTypeQualifier?.nullability + ?: defaultTypeQualifier?.nullability?.let { + NullabilityQualifierWithMigrationStatus( + defaultTypeQualifier.nullability, + defaultTypeQualifier.isNullabilityQualifierForWarning + ) + } return JavaTypeQualifiers( - nullability, + nullabilityInfo?.qualifier, uniqueNotNull( READ_ONLY_ANNOTATIONS.ifPresent( MutabilityQualifier.READ_ONLY @@ -231,11 +247,12 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati MutabilityQualifier.MUTABLE ) ), - isNotNullTypeParameter = nullability == NullabilityQualifier.NOT_NULL && isTypeParameter() + isNotNullTypeParameter = nullabilityInfo?.qualifier == NullabilityQualifier.NOT_NULL && isTypeParameter(), + isNullabilityQualifierForWarning = nullabilityInfo?.isForWarningOnly == true ) } - private fun Annotations.extractNullability(): NullabilityQualifier? = + private fun Annotations.extractNullability(): NullabilityQualifierWithMigrationStatus? = this.firstNotNullResult(this@SignatureEnhancement::extractNullability) private fun computeIndexedQualifiersForOverride(): (Int) -> JavaTypeQualifiers { @@ -288,49 +305,57 @@ class SignatureEnhancement(private val annotationTypeQualifierResolver: Annotati fromSupertypes: Collection, isCovariant: Boolean, isHeadTypeConstructor: Boolean ): JavaTypeQualifiers { - val nullabilityFromSupertypes = fromSupertypes.mapNotNull { it.extractQualifiers().nullability }.toSet() - val mutabilityFromSupertypes = fromSupertypes.mapNotNull { it.extractQualifiers().mutability }.toSet() + val superQualifiers = fromSupertypes.map { it.extractQualifiers() } + val mutabilityFromSupertypes = superQualifiers.mapNotNull { it.mutability }.toSet() + val nullabilityFromSupertypes = superQualifiers.mapNotNull { it.nullability }.toSet() + val nullabilityFromSupertypesWithWarning = fromSupertypes + .mapNotNull { it.unwrapEnhancement().extractQualifiers().nullability } + .toSet() + .takeIf { it != nullabilityFromSupertypes } val own = extractQualifiersFromAnnotations(isHeadTypeConstructor) + val isAnyNonNullTypeParameter = own.isNotNullTypeParameter || superQualifiers.any { it.isNotNullTypeParameter } - val isAnyNonNullTypeParameter = own.isNotNullTypeParameter || fromSupertypes.any { it.extractQualifiers().isNotNullTypeParameter } - - fun createJavaTypeQualifiers(nullability: NullabilityQualifier?, mutability: MutabilityQualifier?): JavaTypeQualifiers { + fun createJavaTypeQualifiers( + nullability: NullabilityQualifier?, + mutability: MutabilityQualifier?, + forWarning: Boolean + ): JavaTypeQualifiers { if (!isAnyNonNullTypeParameter || nullability != NullabilityQualifier.NOT_NULL) { - return JavaTypeQualifiers(nullability, mutability, false) + return JavaTypeQualifiers(nullability, mutability, false, forWarning) } - return JavaTypeQualifiers( - nullability, mutability, - isNotNullTypeParameter = true) + return JavaTypeQualifiers(nullability, mutability, true, forWarning) } - if (isCovariant) { - fun Set.selectCovariantly(low: T, high: T, own: T?): T? { + fun Set.select(low: T, high: T, own: T?): T? { + if (isCovariant) { val supertypeQualifier = if (low in this) low else if (high in this) high else null return if (supertypeQualifier == low && own == high) null else own ?: supertypeQualifier } - return createJavaTypeQualifiers( - nullabilityFromSupertypes.selectCovariantly( - NullabilityQualifier.NOT_NULL, NullabilityQualifier.NULLABLE, own.nullability - ), - mutabilityFromSupertypes.selectCovariantly( - MutabilityQualifier.MUTABLE, MutabilityQualifier.READ_ONLY, own.mutability - ) - ) + + // isInvariant + val effectiveSet = own?.let { (this + own).toSet() } ?: this + // if this set contains exactly one element, it is the qualifier everybody agrees upon, + // otherwise (no qualifiers, or multiple qualifiers), there's no single such qualifier + // and all qualifiers are discarded + return effectiveSet.singleOrNull() } - else { - fun Set.selectInvariantly(own: T?): T? { - val effectiveSet = own?.let { (this + own).toSet() } ?: this - // if this set contains exactly one element, it is the qualifier everybody agrees upon, - // otherwise (no qualifiers, or multiple qualifiers), there's no single such qualifier - // and all qualifiers are discarded - return effectiveSet.singleOrNull() - } - return createJavaTypeQualifiers( - nullabilityFromSupertypes.selectInvariantly(own.nullability), - mutabilityFromSupertypes.selectInvariantly(own.mutability) - ) + + val ownNullability = own.takeIf { !it.isNullabilityQualifierForWarning }?.nullability + val ownNullabilityForWarning = own.nullability + + val nullability = nullabilityFromSupertypes.select(NullabilityQualifier.NOT_NULL, NullabilityQualifier.NULLABLE, ownNullability) + val mutability = mutabilityFromSupertypes.select(MutabilityQualifier.MUTABLE, MutabilityQualifier.READ_ONLY, own.mutability) + + val canChange = ownNullabilityForWarning != ownNullability || nullabilityFromSupertypesWithWarning != null + if (nullability == null && canChange) { + val nullabilityWithWarning = (nullabilityFromSupertypesWithWarning ?: nullabilityFromSupertypes) + .select(NullabilityQualifier.NOT_NULL, NullabilityQualifier.NULLABLE, ownNullabilityForWarning) + + return createJavaTypeQualifiers(nullabilityWithWarning, mutability, true) } + + return createJavaTypeQualifiers(nullability, mutability,nullability == null) } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt index b123b90f116..2e8283eeac3 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeEnhancement.kt @@ -71,17 +71,15 @@ private fun UnwrappedType.enhancePossiblyFlexible(qualifiers: (Int) -> JavaTypeQ } val wereChanges = lowerResult.wereChanges || upperResult.wereChanges + val enhancement = lowerResult.type.getEnhancement() ?: upperResult.type.getEnhancement() + val type = if (!wereChanges) this@enhancePossiblyFlexible + else when { + this is RawTypeImpl -> RawTypeImpl(lowerResult.type, upperResult.type) + else -> KotlinTypeFactory.flexibleType(lowerResult.type, upperResult.type) + }.wrapEnhancement(enhancement) + Result( - if (wereChanges) { - if (this is RawTypeImpl) { - RawTypeImpl(lowerResult.type, upperResult.type) - } - else { - KotlinTypeFactory.flexibleType(lowerResult.type, upperResult.type) - } - } - else - this@enhancePossiblyFlexible, + type, lowerResult.subtreeSize, wereChanges ) @@ -137,8 +135,11 @@ private fun SimpleType.enhanceInflexible(qualifiers: (Int) -> JavaTypeQualifiers enhancedNullability ) - val result = if (effectiveQualifiers.isNotNullTypeParameter) NotNullTypeParameter(enhancedType) else enhancedType - return SimpleResult(result, subtreeSize, wereChanges = true) + val enhancement = if (effectiveQualifiers.isNotNullTypeParameter) NotNullTypeParameter(enhancedType) else enhancedType + val nullabilityForWarning = enhancedNullabilityAnnotations != null && effectiveQualifiers.isNullabilityQualifierForWarning + val result = if (nullabilityForWarning) wrapEnhancement(enhancement) else enhancement + + return SimpleResult(result as SimpleType, subtreeSize, wereChanges = true) } private fun List.compositeAnnotationsOrSingle() = when (size) { @@ -225,8 +226,10 @@ internal class NotNullTypeParameter(override val delegate: SimpleType) : CustomT return when (unwrappedType) { is SimpleType -> unwrappedType.prepareReplacement() - is FlexibleType -> KotlinTypeFactory.flexibleType(unwrappedType.lowerBound.prepareReplacement(), - unwrappedType.upperBound.prepareReplacement()) + is FlexibleType -> KotlinTypeFactory.flexibleType( + unwrappedType.lowerBound.prepareReplacement(), + unwrappedType.upperBound.prepareReplacement() + ).wrapEnhancement(unwrappedType.getEnhancement()) else -> error("Incorrect type: $unwrappedType") } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeQualifiers.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeQualifiers.kt index ca48496da56..f7bc60bddc1 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeQualifiers.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/java/typeEnhancement/typeQualifiers.kt @@ -29,7 +29,8 @@ enum class MutabilityQualifier { class JavaTypeQualifiers internal constructor( val nullability: NullabilityQualifier?, val mutability: MutabilityQualifier?, - internal val isNotNullTypeParameter: Boolean + internal val isNotNullTypeParameter: Boolean, + internal val isNullabilityQualifierForWarning: Boolean = false ) { companion object { val NONE = JavaTypeQualifiers(null, null, false) diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/UnsafeVarianceTypeSubstitution.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/UnsafeVarianceTypeSubstitution.kt index 6b1d3e45783..5ba5ba97947 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/UnsafeVarianceTypeSubstitution.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/UnsafeVarianceTypeSubstitution.kt @@ -47,7 +47,8 @@ internal class UnsafeVarianceTypeSubstitution(builtIns: KotlinBuiltIns) : TypeSu is FlexibleType -> KotlinTypeFactory.flexibleType( lowerBound.annotatePartsWithUnsafeVariance(subPathsWithIndex(unsafeVariancePaths, 0)), - upperBound.annotatePartsWithUnsafeVariance(subPathsWithIndex(unsafeVariancePaths, 1))) + upperBound.annotatePartsWithUnsafeVariance(subPathsWithIndex(unsafeVariancePaths, 1)) + ).inheritEnhancement(this) is SimpleType -> annotatePartsWithUnsafeVariance(unsafeVariancePaths) } } diff --git a/core/descriptors.runtime/src/org/jetbrains/kotlin/load/kotlin/reflect/RuntimeModuleData.kt b/core/descriptors.runtime/src/org/jetbrains/kotlin/load/kotlin/reflect/RuntimeModuleData.kt index 6e64c16efd8..d7cdc51d00d 100644 --- a/core/descriptors.runtime/src/org/jetbrains/kotlin/load/kotlin/reflect/RuntimeModuleData.kt +++ b/core/descriptors.runtime/src/org/jetbrains/kotlin/load/kotlin/reflect/RuntimeModuleData.kt @@ -39,6 +39,7 @@ import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration import org.jetbrains.kotlin.storage.LockBasedStorageManager +import org.jetbrains.kotlin.utils.Jsr305State class RuntimeModuleData private constructor( val deserialization: DeserializationComponents, @@ -58,7 +59,7 @@ class RuntimeModuleData private constructor( val runtimePackagePartProvider = RuntimePackagePartProvider(classLoader) val javaResolverCache = JavaResolverCache.EMPTY val notFoundClasses = NotFoundClasses(storageManager, module) - val annotationTypeQualifierResolver = AnnotationTypeQualifierResolver.Empty + val annotationTypeQualifierResolver = AnnotationTypeQualifierResolver(storageManager, Jsr305State.IGNORE) val globalJavaResolverContext = JavaResolverComponents( storageManager, ReflectJavaClassFinder(classLoader), reflectKotlinClassFinder, deserializedDescriptorResolver, ExternalAnnotationResolver.EMPTY, SignaturePropagator.DO_NOTHING, RuntimeErrorReporter, javaResolverCache, diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt index f0895e05798..0d28dd951d8 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt @@ -415,6 +415,8 @@ fun ClassDescriptor.isSubclassOf(superclass: ClassDescriptor): Boolean = Descrip val AnnotationDescriptor.annotationClass: ClassDescriptor? get() = type.constructor.declarationDescriptor as? ClassDescriptor +fun AnnotationDescriptor.firstArgumentValue() = allValueArguments.values.firstOrNull()?.value + fun MemberDescriptor.isEffectivelyExternal(): Boolean { if (isExternal) return true diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/CapturedTypeApproximation.kt b/core/descriptors/src/org/jetbrains/kotlin/types/CapturedTypeApproximation.kt index 6a5d9effce7..facfa252fd6 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/CapturedTypeApproximation.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/CapturedTypeApproximation.kt @@ -112,8 +112,14 @@ fun approximateCapturedTypes(type: KotlinType): ApproximationBounds val boundsForFlexibleUpper = approximateCapturedTypes(type.upperIfFlexible()) return ApproximationBounds( - KotlinTypeFactory.flexibleType(boundsForFlexibleLower.lower.lowerIfFlexible(), boundsForFlexibleUpper.lower.upperIfFlexible()), - KotlinTypeFactory.flexibleType(boundsForFlexibleLower.upper.lowerIfFlexible(), boundsForFlexibleUpper.upper.upperIfFlexible())) + KotlinTypeFactory.flexibleType( + boundsForFlexibleLower.lower.lowerIfFlexible(), + boundsForFlexibleUpper.lower.upperIfFlexible() + ).inheritEnhancement(type), + KotlinTypeFactory.flexibleType( + boundsForFlexibleLower.upper.lowerIfFlexible(), + boundsForFlexibleUpper.upper.upperIfFlexible() + ).inheritEnhancement(type)) } val typeConstructor = type.constructor diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java index 481223bb495..893a87c20cf 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSubstitutor.java @@ -134,6 +134,21 @@ public class TypeSubstitutor { // The type is within the substitution range, i.e. T or T? KotlinType type = originalProjection.getType(); + if (type instanceof TypeWithEnhancement) { + KotlinType origin = ((TypeWithEnhancement) type).getOrigin(); + KotlinType enhancement = ((TypeWithEnhancement) type).getEnhancement(); + + TypeProjection substitution = unsafeSubstitute( + new TypeProjectionImpl(originalProjection.getProjectionKind(), origin), + recursionDepth + 1 + ); + + KotlinType substitutedEnhancement = substitute(enhancement, originalProjection.getProjectionKind()); + KotlinType resultingType = TypeWithEnhancementKt.wrapEnhancement(substitution.getType().unwrap(), substitutedEnhancement); + + return new TypeProjectionImpl(substitution.getProjectionKind(), resultingType); + } + if (DynamicTypesKt.isDynamic(type) || type.unwrap() instanceof RawType) { return originalProjection; // todo investigate } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt index 1fd42cb646e..32b1ee9bf80 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeUtils.kt @@ -165,7 +165,7 @@ fun KotlinType.replaceArgumentsWithStarProjections(): KotlinType { unwrapped.upperBound.replaceArgumentsWithStarProjections() ) is SimpleType -> unwrapped.replaceArgumentsWithStarProjections() - } + }.inheritEnhancement(unwrapped) } private fun SimpleType.replaceArgumentsWithStarProjections(): SimpleType { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeWithEnhancement.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeWithEnhancement.kt new file mode 100644 index 00000000000..83aae9a7713 --- /dev/null +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeWithEnhancement.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2010-2017 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.types + +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.renderer.DescriptorRendererOptions +import org.jetbrains.kotlin.resolve.scopes.MemberScope + +interface TypeWithEnhancement { + val origin: UnwrappedType + val enhancement: KotlinType +} + +class SimpleTypeWithEnhancement( + override val delegate: SimpleType, + override val enhancement: KotlinType +) : DelegatingSimpleType(), + TypeWithEnhancement { + + override val origin: UnwrappedType get() = delegate + + override fun replaceAnnotations(newAnnotations: Annotations): SimpleType + = origin.replaceAnnotations(newAnnotations).wrapEnhancement(enhancement) as SimpleType + + override fun makeNullableAsSpecified(newNullability: Boolean): SimpleType + = origin.makeNullableAsSpecified(newNullability).wrapEnhancement(enhancement) as SimpleType +} + +class FlexibleTypeWithEnhancement( + override val origin: FlexibleType, + override val enhancement: KotlinType +) : FlexibleType(origin.lowerBound, origin.upperBound), + TypeWithEnhancement { + + override fun replaceAnnotations(newAnnotations: Annotations): UnwrappedType + = origin.replaceAnnotations(newAnnotations).wrapEnhancement(enhancement) + + override fun makeNullableAsSpecified(newNullability: Boolean): UnwrappedType + = origin.makeNullableAsSpecified(newNullability).wrapEnhancement(enhancement) + + override fun render(renderer: DescriptorRenderer, options: DescriptorRendererOptions): String + = origin.render(renderer, options) + + override val delegate: SimpleType get() = origin.delegate +} + +fun KotlinType.getEnhancement(): KotlinType? = when (this) { + is TypeWithEnhancement -> enhancement + else -> null +} + +fun KotlinType.unwrapEnhancement(): KotlinType = getEnhancement() ?: this + +fun UnwrappedType.inheritEnhancement(origin: KotlinType): UnwrappedType = wrapEnhancement(origin.getEnhancement()) + +fun UnwrappedType.wrapEnhancement(enhancement: KotlinType?): UnwrappedType { + if (enhancement == null) { + return this + } + + return when (this) { + is SimpleType -> SimpleTypeWithEnhancement(this, enhancement) + is FlexibleType -> FlexibleTypeWithEnhancement(this, enhancement) + } +} diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt index ef9ad3c67af..91309cf06e8 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt @@ -149,7 +149,7 @@ object NewKotlinTypeChecker : KotlinTypeChecker { type } } - } + }.inheritEnhancement(type) private fun TypeCheckerContext.checkSubtypeForSpecialCases(subType: SimpleType, superType: SimpleType): Boolean? { if (subType.isError || superType.isError) { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/flexibleTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/types/flexibleTypes.kt index 9ef7d82e2d2..fc4b57f70aa 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/flexibleTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/flexibleTypes.kt @@ -119,7 +119,7 @@ class FlexibleTypeImpl(lowerBound: SimpleType, upperBound: SimpleType) : Flexibl return when(unwrapped) { is FlexibleType -> unwrapped is SimpleType -> KotlinTypeFactory.flexibleType(unwrapped, unwrapped.makeNullableAsSpecified(true)) - } + }.inheritEnhancement(unwrapped) } override fun replaceAnnotations(newAnnotations: Annotations): UnwrappedType diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt index 3c2aca7b52b..e372952b3f4 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt @@ -43,9 +43,9 @@ object IDELanguageSettingsProvider : LanguageSettingsProvider { val settings = KotlinFacetSettingsProvider.getInstance(project).getSettings(module) ?: continue val compilerArguments = settings.compilerArguments as? K2JVMCompilerArguments ?: continue - val jsr305state = Jsr305State.findByDescription(compilerArguments.jsr305GlobalReportLevel) + val jsr305state = Jsr305State.findByDescription(compilerArguments.jsr305GlobalState) if (jsr305state != null && jsr305state != Jsr305State.IGNORE) { - map.put(AnalysisFlag.loadJsr305Annotations, jsr305state) + map.put(AnalysisFlag.jsr305GlobalState, jsr305state) break } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/highlighter/Jsr305HighlightingTest.kt b/idea/tests/org/jetbrains/kotlin/idea/highlighter/Jsr305HighlightingTest.kt index e747cf19c71..3155d63e77d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/highlighter/Jsr305HighlightingTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/highlighter/Jsr305HighlightingTest.kt @@ -46,7 +46,7 @@ class Jsr305HighlightingTest : KotlinLightCodeInsightFixtureTestCase() { super.configureModule(module, model) module.createFacet(TargetPlatformKind.Jvm(JvmTarget.JVM_1_8)) val facetSettings = KotlinFacetSettingsProvider.getInstance(project).getInitializedSettings(module) - (facetSettings.compilerArguments as K2JVMCompilerArguments).jsr305GlobalReportLevel = Jsr305State.ENABLE.description + (facetSettings.compilerArguments as K2JVMCompilerArguments).jsr305GlobalState = Jsr305State.ENABLE.description } } }