From 7de0cfde16507d74ec7a4a478bd47b3132eb7a5c Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 6 Dec 2016 19:03:31 +0300 Subject: [PATCH] Report error on pre-release top level members --- .../checkers/MissingDependencyClassChecker.kt | 22 +++++++++++++----- .../library/a.kt | 4 ++++ .../output.txt | 23 ++++++++++++++++++- .../source.kt | 5 ++++ .../kotlin/DeserializedDescriptorResolver.kt | 5 +++- .../load/kotlin/JvmPackagePartSource.kt | 16 +++++++++---- .../kotlin/KotlinJvmBinarySourceElement.kt | 5 +++- .../DeserializedMemberDescriptor.kt | 4 ++++ 8 files changed, 70 insertions(+), 14 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/MissingDependencyClassChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/MissingDependencyClassChecker.kt index 06f73945071..ba889ca9fbe 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/MissingDependencyClassChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/MissingDependencyClassChecker.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor +import org.jetbrains.kotlin.descriptors.SourceElement import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Errors.MISSING_DEPENDENCY_CLASS import org.jetbrains.kotlin.diagnostics.Errors.PRE_RELEASE_CLASS @@ -32,14 +33,19 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.utils.newLinkedHashSetWithExpectedSize object MissingDependencyClassChecker : CallChecker { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { - for (diagnostic in collectDiagnostics(reportOn, resolvedCall.resultingDescriptor)) { + val resultingDescriptor = resolvedCall.resultingDescriptor + for (diagnostic in collectDiagnostics(reportOn, resultingDescriptor)) { context.trace.report(diagnostic) } + + val containerSource = (resultingDescriptor as? DeserializedMemberDescriptor)?.containerSource + incompatibilityDiagnosticFor(containerSource, reportOn)?.let(context.trace::report) } private fun diagnosticFor(descriptor: ClassifierDescriptor, reportOn: PsiElement): Diagnostic? { @@ -47,10 +53,13 @@ object MissingDependencyClassChecker : CallChecker { return MISSING_DEPENDENCY_CLASS.on(reportOn, descriptor.fqNameSafe) } - val source = descriptor.source + return incompatibilityDiagnosticFor(descriptor.source, reportOn) + } + + private fun incompatibilityDiagnosticFor(source: SourceElement?, reportOn: PsiElement): Diagnostic? { if (source is DeserializedContainerSource && source.isPreReleaseInvisible) { // TODO: if at least one PRE_RELEASE_CLASS is reported, display a hint to disable the diagnostic - return PRE_RELEASE_CLASS.on(reportOn, descriptor.fqNameSafe) + return PRE_RELEASE_CLASS.on(reportOn, source.presentableFqName) } return null @@ -88,9 +97,10 @@ object MissingDependencyClassChecker : CallChecker { element: PsiElement, languageVersionSettings: LanguageVersionSettings ) { - diagnosticFor(targetDescriptor, element)?.let { diagnostic -> - trace.report(diagnostic) - } + diagnosticFor(targetDescriptor, element)?.let(trace::report) + + val containerSource = (targetDescriptor as? DeserializedMemberDescriptor)?.containerSource + incompatibilityDiagnosticFor(containerSource, element)?.let(trace::report) } } } diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/library/a.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/library/a.kt index 11e5dc8eda8..79d858eaf54 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/library/a.kt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/library/a.kt @@ -3,3 +3,7 @@ package a open class A { class Nested } + +fun foo() = "" +var bar = 42 +typealias TA = String diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/output.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/output.txt index 4fd92ed66f3..1af8e443240 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/output.txt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/output.txt @@ -1,9 +1,18 @@ compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt:5:16: error: class 'a.A' is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler -fun baz(param: A) { +fun baz(param: A, nested: A.Nested) { ^ +compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt:5:27: error: class 'a.A' is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler +fun baz(param: A, nested: A.Nested) { + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt:5:29: error: class 'a.A.Nested' is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler +fun baz(param: A, nested: A.Nested) { + ^ compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt:6:23: error: class 'a.A' is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler val constructor = A() ^ +compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt:7:18: error: class 'a.A' is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler + val nested = A.Nested() + ^ compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt:7:20: error: class 'a.A.Nested' is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler val nested = A.Nested() ^ @@ -16,4 +25,16 @@ compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreRe compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt:9:30: error: class 'a.A' is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler val supertype = object : A() {} ^ +compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt:11:13: error: class 'a.AKt' is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler + val x = foo() + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt:12:13: error: class 'a.AKt' is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler + val y = bar + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt:13:5: error: class 'a.AKt' is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler + bar = 239 + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt:14:12: error: class 'a.AKt' is compiled by a pre-release version of Kotlin and cannot be loaded by this version of the compiler + val z: TA = "" + ^ COMPILATION_ERROR \ No newline at end of file diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt index 6ecf1012539..f15b2e0bd70 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/source.kt @@ -7,4 +7,9 @@ fun baz(param: A, nested: A.Nested) { val nested = A.Nested() val methodCall = param.method() val supertype = object : A() {} + + val x = foo() + val y = bar + bar = 239 + val z: TA = "" } diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.kt index a578a875f24..f0034d0e348 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.kt @@ -60,7 +60,10 @@ class DeserializedDescriptorResolver(private val errorReporter: ErrorReporter) { val (nameResolver, packageProto) = parseProto(kotlinClass) { JvmProtoBufUtil.readPackageDataFrom(data, strings) } - val source = JvmPackagePartSource(kotlinClass) + val source = JvmPackagePartSource( + kotlinClass, + isPreReleaseInvisible = !IS_PRE_RELEASE && kotlinClass.classHeader.isPreRelease + ) return DeserializedPackageMemberScope(descriptor, packageProto, nameResolver, source, components) { // All classes are included into Java scope emptyList() diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartSource.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartSource.kt index 0c95aeb192e..19dee966ddc 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartSource.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartSource.kt @@ -18,20 +18,26 @@ package org.jetbrains.kotlin.load.kotlin import org.jetbrains.kotlin.descriptors.SourceFile import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource -class JvmPackagePartSource(val className: JvmClassName, val facadeClassName: JvmClassName?) : DeserializedContainerSource { - constructor(kotlinClass: KotlinJvmBinaryClass) : this( +class JvmPackagePartSource( + val className: JvmClassName, + val facadeClassName: JvmClassName?, + override val isPreReleaseInvisible: Boolean = false +) : DeserializedContainerSource { + constructor(kotlinClass: KotlinJvmBinaryClass, isPreReleaseInvisible: Boolean = false) : this( JvmClassName.byClassId(kotlinClass.classId), kotlinClass.classHeader.multifileClassName?.let { if (it.isNotEmpty()) JvmClassName.byInternalName(it) else null - } + }, + isPreReleaseInvisible ) - // TODO - override val isPreReleaseInvisible: Boolean get() = false + override val presentableFqName: FqName + get() = classId.asSingleFqName() val simpleName: Name get() = Name.identifier(className.internalName.substringAfterLast('/')) diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmBinarySourceElement.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmBinarySourceElement.kt index 95aeeea4d49..419971c82d3 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmBinarySourceElement.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmBinarySourceElement.kt @@ -16,14 +16,17 @@ package org.jetbrains.kotlin.load.kotlin -import org.jetbrains.kotlin.descriptors.SourceElement import org.jetbrains.kotlin.descriptors.SourceFile +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource class KotlinJvmBinarySourceElement( val binaryClass: KotlinJvmBinaryClass, override val isPreReleaseInvisible: Boolean = false ) : DeserializedContainerSource { + override val presentableFqName: FqName + get() = binaryClass.classId.asSingleFqName() + override fun getContainingFile(): SourceFile = SourceFile.NO_SOURCE_FILE override fun toString() = "${javaClass.simpleName}: $binaryClass" diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberDescriptor.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberDescriptor.kt index 51a3b810f86..cf44096cfb6 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberDescriptor.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedMemberDescriptor.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.serialization.deserialization.descriptors import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.* +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.protobuf.MessageLite import org.jetbrains.kotlin.serialization.Flags @@ -44,6 +45,9 @@ interface DeserializedMemberDescriptor : MemberDescriptor { interface DeserializedContainerSource : SourceElement { // True iff this is container is "invisible" because it's loaded from a pre-release class and this compiler is a release val isPreReleaseInvisible: Boolean + + // This FQ name should only be used for error messages + val presentableFqName: FqName } interface DeserializedCallableMemberDescriptor : DeserializedMemberDescriptor, CallableMemberDescriptor