Report error on pre-release top level members

This commit is contained in:
Alexander Udalov
2016-12-06 19:03:31 +03:00
parent 11f975fe89
commit 7de0cfde16
8 changed files with 70 additions and 14 deletions
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors.MISSING_DEPENDENCY_CLASS import org.jetbrains.kotlin.diagnostics.Errors.MISSING_DEPENDENCY_CLASS
import org.jetbrains.kotlin.diagnostics.Errors.PRE_RELEASE_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.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource 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.types.KotlinType
import org.jetbrains.kotlin.utils.newLinkedHashSetWithExpectedSize import org.jetbrains.kotlin.utils.newLinkedHashSetWithExpectedSize
object MissingDependencyClassChecker : CallChecker { object MissingDependencyClassChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { 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) 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? { private fun diagnosticFor(descriptor: ClassifierDescriptor, reportOn: PsiElement): Diagnostic? {
@@ -47,10 +53,13 @@ object MissingDependencyClassChecker : CallChecker {
return MISSING_DEPENDENCY_CLASS.on(reportOn, descriptor.fqNameSafe) 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) { if (source is DeserializedContainerSource && source.isPreReleaseInvisible) {
// TODO: if at least one PRE_RELEASE_CLASS is reported, display a hint to disable the diagnostic // 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 return null
@@ -88,9 +97,10 @@ object MissingDependencyClassChecker : CallChecker {
element: PsiElement, element: PsiElement,
languageVersionSettings: LanguageVersionSettings languageVersionSettings: LanguageVersionSettings
) { ) {
diagnosticFor(targetDescriptor, element)?.let { diagnostic -> diagnosticFor(targetDescriptor, element)?.let(trace::report)
trace.report(diagnostic)
} val containerSource = (targetDescriptor as? DeserializedMemberDescriptor)?.containerSource
incompatibilityDiagnosticFor(containerSource, element)?.let(trace::report)
} }
} }
} }
@@ -3,3 +3,7 @@ package a
open class A { open class A {
class Nested class Nested
} }
fun foo() = ""
var bar = 42
typealias TA = String
@@ -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 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 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() 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 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() 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 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() {} 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 COMPILATION_ERROR
@@ -7,4 +7,9 @@ fun baz(param: A, nested: A.Nested) {
val nested = A.Nested() val nested = A.Nested()
val methodCall = param.method() val methodCall = param.method()
val supertype = object : A() {} val supertype = object : A() {}
val x = foo()
val y = bar
bar = 239
val z: TA = ""
} }
@@ -60,7 +60,10 @@ class DeserializedDescriptorResolver(private val errorReporter: ErrorReporter) {
val (nameResolver, packageProto) = parseProto(kotlinClass) { val (nameResolver, packageProto) = parseProto(kotlinClass) {
JvmProtoBufUtil.readPackageDataFrom(data, strings) 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) { return DeserializedPackageMemberScope(descriptor, packageProto, nameResolver, source, components) {
// All classes are included into Java scope // All classes are included into Java scope
emptyList() emptyList()
@@ -18,20 +18,26 @@ package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.descriptors.SourceFile import org.jetbrains.kotlin.descriptors.SourceFile
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
class JvmPackagePartSource(val className: JvmClassName, val facadeClassName: JvmClassName?) : DeserializedContainerSource { class JvmPackagePartSource(
constructor(kotlinClass: KotlinJvmBinaryClass) : this( val className: JvmClassName,
val facadeClassName: JvmClassName?,
override val isPreReleaseInvisible: Boolean = false
) : DeserializedContainerSource {
constructor(kotlinClass: KotlinJvmBinaryClass, isPreReleaseInvisible: Boolean = false) : this(
JvmClassName.byClassId(kotlinClass.classId), JvmClassName.byClassId(kotlinClass.classId),
kotlinClass.classHeader.multifileClassName?.let { kotlinClass.classHeader.multifileClassName?.let {
if (it.isNotEmpty()) JvmClassName.byInternalName(it) else null if (it.isNotEmpty()) JvmClassName.byInternalName(it) else null
} },
isPreReleaseInvisible
) )
// TODO override val presentableFqName: FqName
override val isPreReleaseInvisible: Boolean get() = false get() = classId.asSingleFqName()
val simpleName: Name get() = Name.identifier(className.internalName.substringAfterLast('/')) val simpleName: Name get() = Name.identifier(className.internalName.substringAfterLast('/'))
@@ -16,14 +16,17 @@
package org.jetbrains.kotlin.load.kotlin package org.jetbrains.kotlin.load.kotlin
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.SourceFile import org.jetbrains.kotlin.descriptors.SourceFile
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
class KotlinJvmBinarySourceElement( class KotlinJvmBinarySourceElement(
val binaryClass: KotlinJvmBinaryClass, val binaryClass: KotlinJvmBinaryClass,
override val isPreReleaseInvisible: Boolean = false override val isPreReleaseInvisible: Boolean = false
) : DeserializedContainerSource { ) : DeserializedContainerSource {
override val presentableFqName: FqName
get() = binaryClass.classId.asSingleFqName()
override fun getContainingFile(): SourceFile = SourceFile.NO_SOURCE_FILE override fun getContainingFile(): SourceFile = SourceFile.NO_SOURCE_FILE
override fun toString() = "${javaClass.simpleName}: $binaryClass" override fun toString() = "${javaClass.simpleName}: $binaryClass"
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.serialization.deserialization.descriptors
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.protobuf.MessageLite import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.serialization.Flags import org.jetbrains.kotlin.serialization.Flags
@@ -44,6 +45,9 @@ interface DeserializedMemberDescriptor : MemberDescriptor {
interface DeserializedContainerSource : SourceElement { 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 // 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 val isPreReleaseInvisible: Boolean
// This FQ name should only be used for error messages
val presentableFqName: FqName
} }
interface DeserializedCallableMemberDescriptor : DeserializedMemberDescriptor, CallableMemberDescriptor interface DeserializedCallableMemberDescriptor : DeserializedMemberDescriptor, CallableMemberDescriptor