From 11f975fe899ed51792787f024a919843f4a06f2b Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 6 Dec 2016 17:12:15 +0300 Subject: [PATCH] Add classifier usage checker for missing dependency classes This has no effect for the original use case of mock class descriptors (unresolved classes used in libraries), but is necessary for pre-release classes in case the compiler is a release, because such classes end up in scope and can be the result of the resolution --- .../jvm/platform/JvmPlatformConfigurator.kt | 4 +- .../checkers/MissingDependencyClassChecker.kt | 43 ++++++++++++++----- .../output.txt | 3 ++ 3 files changed, 39 insertions(+), 11 deletions(-) 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 afea86451d0..db4ef9c6d70 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 @@ -69,7 +69,9 @@ object JvmPlatformConfigurator : PlatformConfigurator( JavaTypeAccessibilityChecker() ), - additionalClassifierUsageCheckers = listOf(), + additionalClassifierUsageCheckers = listOf( + MissingDependencyClassChecker.ClassifierUsage + ), additionalAnnotationCheckers = listOf( RepeatableAnnotationChecker, 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 9d596565baf..06f73945071 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/MissingDependencyClassChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/MissingDependencyClassChecker.kt @@ -17,11 +17,14 @@ package org.jetbrains.kotlin.resolve.checkers import com.intellij.psi.PsiElement +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.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Errors.MISSING_DEPENDENCY_CLASS import org.jetbrains.kotlin.diagnostics.Errors.PRE_RELEASE_CLASS +import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext import org.jetbrains.kotlin.resolve.calls.checkers.isComputingDeferredType @@ -39,22 +42,29 @@ object MissingDependencyClassChecker : CallChecker { } } + private fun diagnosticFor(descriptor: ClassifierDescriptor, reportOn: PsiElement): Diagnostic? { + if (descriptor is NotFoundClasses.MockClassDescriptor) { + return MISSING_DEPENDENCY_CLASS.on(reportOn, descriptor.fqNameSafe) + } + + val source = descriptor.source + 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 null + } + private fun collectDiagnostics(reportOn: PsiElement, descriptor: CallableDescriptor): Set { val result: MutableSet = newLinkedHashSetWithExpectedSize(1) fun consider(classDescriptor: ClassDescriptor) { - if (classDescriptor is NotFoundClasses.MockClassDescriptor) { - result.add(MISSING_DEPENDENCY_CLASS.on(reportOn, classDescriptor.fqNameSafe)) + val diagnostic = diagnosticFor(classDescriptor, reportOn) + if (diagnostic != null) { + result.add(diagnostic) return } - - val source = classDescriptor.source - if (source is DeserializedContainerSource && source.isPreReleaseInvisible) { - // TODO: if at least one PRE_RELEASE_CLASS is reported, display a hint to disable the diagnostic - result.add(PRE_RELEASE_CLASS.on(reportOn, classDescriptor.fqNameSafe)) - return - } - (classDescriptor.containingDeclaration as? ClassDescriptor)?.let(::consider) } @@ -70,4 +80,17 @@ object MissingDependencyClassChecker : CallChecker { return result } + + object ClassifierUsage : ClassifierUsageChecker { + override fun check( + targetDescriptor: ClassifierDescriptor, + trace: BindingTrace, + element: PsiElement, + languageVersionSettings: LanguageVersionSettings + ) { + diagnosticFor(targetDescriptor, element)?.let { diagnostic -> + trace.report(diagnostic) + } + } + } } diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/output.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/output.txt index 5add492b744..4fd92ed66f3 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/output.txt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/releaseCompilerAgainstPreReleaseLibrary/output.txt @@ -1,3 +1,6 @@ +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) { + ^ 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() ^