From 5381c06936225aa0378d525c32e09383a05a591e Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 21 Sep 2016 16:31:04 +0300 Subject: [PATCH] Improve 1.0-compatibility mode for JDK dependent members Just reporting error by call checker may be too restrictive in case there are some extensions that can be used successfully Solution is to annotate additional members with @Deprecated(level=Error) + @kotlin.internal.LowPriorityInOverloadResolution --- .../kotlin/frontend/java/di/injection.kt | 4 +- .../AdditionalBuiltInsMembersChecker.kt | 12 ----- .../jvm/platform/JvmPlatformConfigurator.kt | 3 +- .../targetedBuiltIns/unsupportedFeature.kt | 21 ++++++--- .../MultiModuleJavaAnalysisCustomTest.kt | 9 +++- .../kotlin/load/kotlin/JvmBuiltInsSettings.kt | 47 +++++++++++++++++-- .../jetbrains/kotlin/platform/JvmBuiltIns.kt | 7 ++- .../load/kotlin/reflect/RuntimeModuleData.kt | 2 +- .../kotlin/resolve/annotationsForResolve.kt | 4 +- .../caches/resolve/KotlinCacheServiceImpl.kt | 10 +++- 10 files changed, 86 insertions(+), 33 deletions(-) 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 8ddf89cf473..e32794ef4bd 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 @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.frontend.java.di import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.container.* import org.jetbrains.kotlin.context.LazyResolveToken @@ -140,7 +141,8 @@ fun StorageComponentContainer.javaAnalysisInit() { // 'initBuiltIns' body cannot be merged with 'javaAnalysisInit' because the latter is used in IDE, // where built-ins instances are shared between modules and manual initialization is necessary (to avoid multiple initialization) fun StorageComponentContainer.initJvmBuiltInsForTopDownAnalysis() { - get().initialize(get()) + get().initialize(get(), + get().supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)) } class ContainerForTopDownAnalyzerForJvm(container: StorageComponentContainer) { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/AdditionalBuiltInsMembersChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/AdditionalBuiltInsMembersChecker.kt index 02e1069f70a..cfc338f7b06 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/AdditionalBuiltInsMembersChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/AdditionalBuiltInsMembersChecker.kt @@ -29,20 +29,8 @@ import org.jetbrains.kotlin.load.java.isFromBuiltins import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DeclarationChecker -import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker -import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeUniqueAsSequence -object AdditionalBuiltInsMembersCallChecker : CallChecker { - override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { - if (context.languageVersionSettings.supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)) return - val resultingDescriptor = resolvedCall.resultingDescriptor as? CallableMemberDescriptor ?: return - - reportErrorIfAdditionalBuiltinDescriptor(resultingDescriptor, context.trace, reportOn) - } -} - object AdditionalBuiltInsMemberOverrideDeclarationChecker : DeclarationChecker { override fun check( declaration: KtDeclaration, 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 7f92f196deb..67a64a93ec4 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 @@ -54,8 +54,7 @@ object JvmPlatformConfigurator : PlatformConfigurator( UnsupportedSyntheticCallableReferenceChecker(), SuperCallWithDefaultArgumentsChecker(), MissingDependencyClassChecker(), - ProtectedSyntheticExtensionCallChecker, - AdditionalBuiltInsMembersCallChecker + ProtectedSyntheticExtensionCallChecker ), additionalTypeCheckers = listOf( diff --git a/compiler/testData/diagnostics/testsWithJava8/targetedBuiltIns/unsupportedFeature.kt b/compiler/testData/diagnostics/testsWithJava8/targetedBuiltIns/unsupportedFeature.kt index b192bde94c5..ecd63c52388 100644 --- a/compiler/testData/diagnostics/testsWithJava8/targetedBuiltIns/unsupportedFeature.kt +++ b/compiler/testData/diagnostics/testsWithJava8/targetedBuiltIns/unsupportedFeature.kt @@ -1,18 +1,27 @@ +// !CHECK_TYPE // !LANGUAGE: -AdditionalBuiltInsMembers // SKIP_TXT class A : java.util.ArrayList() { - override fun stream(): java.util.stream.Stream = super.stream() + override fun stream(): java.util.stream.Stream = super.stream() } class A1 : java.util.ArrayList() { // TODO: should be allowed - fun stream(): java.util.stream.Stream = super.stream() + fun stream(): java.util.stream.Stream = super.stream() } -class B : Throwable("", null, false, false) +class B : Throwable("", null, false, false) -fun foo(x: List) { - x.stream() - java.util.ArrayList().stream() +fun Throwable.fillInStackTrace() = 1 + +fun foo(x: List, y: Throwable) { + x.stream() + java.util.ArrayList().stream() + + y.fillInStackTrace() checkType { _() } + + // TODO: Relevant extensions has been removed from stdlib + // We should consider reverting their removal + y.printStackTrace() } diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt index 44764c6325e..ed5674f4586 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt @@ -26,6 +26,9 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles import org.jetbrains.kotlin.cli.jvm.compiler.JvmPackagePartProvider import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.container.get import org.jetbrains.kotlin.context.ProjectContext import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.NoLookupLocation @@ -77,7 +80,11 @@ class MultiModuleJavaAnalysisCustomTest : KtUsefulTestCase() { packagePartProviderFactory = { a, b -> JvmPackagePartProvider(environment) } ) - builtIns.initialize(resolverForProject.descriptorForModule(resolverForProject.allModules.first())) + builtIns.initialize( + resolverForProject.descriptorForModule(resolverForProject.allModules.first()), + resolverForProject.resolverForModule(resolverForProject.allModules.first()) + .componentProvider.get() + .supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)) performChecks(resolverForProject, modules) } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmBuiltInsSettings.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmBuiltInsSettings.kt index aafed499506..0437e9c3fa4 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmBuiltInsSettings.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmBuiltInsSettings.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.load.kotlin import org.jetbrains.kotlin.builtins.BuiltInsInitializer import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl import org.jetbrains.kotlin.descriptors.annotations.createDeprecatedAnnotation import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl @@ -31,6 +32,7 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.JavaToKotlinClassMap import org.jetbrains.kotlin.platform.createMappedTypeParametersSubstitution import org.jetbrains.kotlin.resolve.OverridingUtil +import org.jetbrains.kotlin.resolve.descriptorUtil.LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_FQ_NAME import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType @@ -47,17 +49,20 @@ import org.jetbrains.kotlin.types.LazyWrappedType import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.SmartSet import org.jetbrains.kotlin.utils.addToStdlib.check +import org.jetbrains.kotlin.utils.addToStdlib.singletonList import java.io.Serializable import java.util.* open class JvmBuiltInsSettings( private val moduleDescriptor: ModuleDescriptor, storageManager: StorageManager, - deferredOwnerModuleDescriptor: () -> ModuleDescriptor + deferredOwnerModuleDescriptor: () -> ModuleDescriptor, + isAdditionalBuiltInsFeatureSupported: () -> Boolean ) : AdditionalClassPartsProvider, PlatformDependentDeclarationFilter { private val j2kClassMap = JavaToKotlinClassMap.INSTANCE private val ownerModuleDescriptor: ModuleDescriptor by lazy(deferredOwnerModuleDescriptor) + private val isAdditionalBuiltInsFeatureSupported: Boolean by lazy(isAdditionalBuiltInsFeatureSupported) private val mockSerializableType = storageManager.createMockJavaIoSerializableType() @@ -70,6 +75,28 @@ open class JvmBuiltInsSettings( ).let { AnnotationsImpl(listOf(it)) } } + private val notSupportedDeprecation by storageManager.createLazyValue { + // We use both LowPriorityInOverloadResolution to achieve the following goals: + // - If there is something to resolve to beside an additional built-in member, it's *almost* always will win + // - Otherwise error will be reported because of Deprecated annotation with Error level + val lowPriorityAnnotation = + ClassDescriptorImpl( + moduleDescriptor.getPackage(LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_FQ_NAME.parent()), + LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_FQ_NAME.shortName(), Modality.FINAL, ClassKind.ANNOTATION_CLASS, + moduleDescriptor.builtIns.anyType.singletonList(), SourceElement.NO_SOURCE + ).run { + initialize(MemberScope.Empty, emptySet(), null) + AnnotationDescriptorImpl(defaultType, emptyMap(), SourceElement.NO_SOURCE) + } + + val errorDeprecation = moduleDescriptor.builtIns.createDeprecatedAnnotation( + "This member is not supported by Kotlin compiler on this language level", + level = DeprecationLevel.ERROR.name + ) + + AnnotationsImpl(listOf(lowPriorityAnnotation, errorDeprecation)) + } + private fun StorageManager.createMockJavaIoSerializableType(): KotlinType { val mockJavaIoPackageFragment = object : PackageFragmentDescriptorImpl(moduleDescriptor, FqName("java.io")) { override fun getMemberScope() = MemberScope.Empty @@ -120,12 +147,21 @@ open class JvmBuiltInsSettings( } JDKMemberStatus.NOT_CONSIDERED -> { - setAdditionalAnnotations(notConsideredDeprecation) + if (!isAdditionalBuiltInsFeatureSupported) { + setAdditionalAnnotations(notSupportedDeprecation) + } + else { + setAdditionalAnnotations(notConsideredDeprecation) + } } JDKMemberStatus.DROP -> return@mapNotNull null - JDKMemberStatus.WHITE_LIST -> {} // Do nothing + JDKMemberStatus.WHITE_LIST -> { + if (!isAdditionalBuiltInsFeatureSupported) { + setAdditionalAnnotations(notSupportedDeprecation) + } + } } }.build()!! @@ -260,7 +296,10 @@ open class JvmBuiltInsSettings( setPreserveSourceElement() setSubstitution(substitutor.substitution) - if (SignatureBuildingComponents.signature(javaAnalogueDescriptor, javaConstructor.computeJvmDescriptor()) !in WHITE_LIST_CONSTRUCTOR_SIGNATURES) { + if (!isAdditionalBuiltInsFeatureSupported) { + setAdditionalAnnotations(notSupportedDeprecation) + } + else if (SignatureBuildingComponents.signature(javaAnalogueDescriptor, javaConstructor.computeJvmDescriptor()) !in WHITE_LIST_CONSTRUCTOR_SIGNATURES) { setAdditionalAnnotations(notConsideredDeprecation) } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JvmBuiltIns.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JvmBuiltIns.kt index cb9ec579dd4..b164eaf4987 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JvmBuiltIns.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/platform/JvmBuiltIns.kt @@ -26,10 +26,12 @@ import org.jetbrains.kotlin.utils.sure class JvmBuiltIns(storageManager: StorageManager) : KotlinBuiltIns(storageManager) { // Module containing JDK classes or having them among dependencies private var ownerModuleDescriptor: ModuleDescriptor? = null + private var isAdditionalBuiltInsFeatureSupported: Boolean = true - fun initialize(moduleDescriptor: ModuleDescriptor) { + fun initialize(moduleDescriptor: ModuleDescriptor, isAdditionalBuiltInsFeatureSupported: Boolean) { assert(ownerModuleDescriptor == null) { "JvmBuiltins repeated initialization" } this.ownerModuleDescriptor = moduleDescriptor + this.isAdditionalBuiltInsFeatureSupported = isAdditionalBuiltInsFeatureSupported } lateinit var settings: JvmBuiltInsSettings @@ -39,7 +41,8 @@ class JvmBuiltIns(storageManager: StorageManager) : KotlinBuiltIns(storageManage override fun getPlatformDependentDeclarationFilter(): PlatformDependentDeclarationFilter { settings = JvmBuiltInsSettings( builtInsModule, storageManager, - { ownerModuleDescriptor.sure { "JvmBuiltins has not been initialized properly" } } + { ownerModuleDescriptor.sure { "JvmBuiltins has not been initialized properly" } }, + { isAdditionalBuiltInsFeatureSupported } ) return settings 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 ef2664b350f..3bf82f56b32 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 @@ -63,7 +63,7 @@ class RuntimeModuleData private constructor(val deserialization: Deserialization val lazyJavaPackageFragmentProvider = LazyJavaPackageFragmentProvider(globalJavaResolverContext) - builtIns.initialize(module) + builtIns.initialize(module, isAdditionalBuiltInsFeatureSupported = true) val javaDescriptorResolver = JavaDescriptorResolver(lazyJavaPackageFragmentProvider, javaResolverCache) val javaClassDataFinder = JavaClassDataFinder(reflectKotlinClassFinder, deserializedDescriptorResolver) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/annotationsForResolve.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/annotationsForResolve.kt index f80f13295dd..9e3a6c09605 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/annotationsForResolve.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/annotationsForResolve.kt @@ -27,7 +27,7 @@ import org.jetbrains.kotlin.types.KotlinType private val NO_INFER_ANNOTATION_FQ_NAME = FqName("kotlin.internal.NoInfer") private val EXACT_ANNOTATION_FQ_NAME = FqName("kotlin.internal.Exact") -private val LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_FQ_NAME = FqName("kotlin.internal.LowPriorityInOverloadResolution") +val LOW_PRIORITY_IN_OVERLOAD_RESOLUTION_FQ_NAME = FqName("kotlin.internal.LowPriorityInOverloadResolution") private val HIDES_MEMBERS_ANNOTATION_FQ_NAME = FqName("kotlin.internal.HidesMembers") private val ONLY_INPUT_TYPES_FQ_NAME = FqName("kotlin.internal.OnlyInputTypes") @@ -65,4 +65,4 @@ private class AnnotationsWithOnly(val presentAnnotation: FqName): Annotations { override fun getUseSiteTargetedAnnotations(): List = emptyList() override fun getAllAnnotations(): List = emptyList() -} \ No newline at end of file +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt index b2eb4b6fb2a..9367dc6339c 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt @@ -32,6 +32,9 @@ import org.jetbrains.kotlin.analyzer.EmptyResolverForProject import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.caches.resolve.KotlinCacheService +import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.container.get import org.jetbrains.kotlin.container.getService import org.jetbrains.kotlin.context.GlobalContext import org.jetbrains.kotlin.context.GlobalContextImpl @@ -381,9 +384,12 @@ private fun globalResolveSessionProvider( if (newBuiltIns is JvmBuiltIns) { val sdkInfo = SdkInfo(project, sdk!!) - newBuiltIns.initialize(moduleResolverProvider.resolverForProject.descriptorForModule(sdkInfo)) + newBuiltIns.initialize( + moduleResolverProvider.resolverForProject.descriptorForModule(sdkInfo), + moduleResolverProvider.resolverForProject.resolverForModule(sdkInfo) + .componentProvider.get() + .supportsFeature(LanguageFeature.AdditionalBuiltInsMembers)) } moduleResolverProvider } -