Report error if some deserialized classes are missing in dependencies
Technically we often can compile code which uses missing classes (as long as nothing is called on them) but it seems better to let the user know something's wrong in their setup before the error manifests itself at runtime. Also the Java compiler does the same #KT-4328 Fixed
This commit is contained in:
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.isComputingDeferredType
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.newLinkedHashSetWithExpectedSize
|
||||
|
||||
class MissingDependencyClassChecker : CallChecker {
|
||||
override fun check(resolvedCall: ResolvedCall<*>, context: BasicCallResolutionContext) {
|
||||
for (classId in collectNotFoundClasses(resolvedCall.resultingDescriptor)) {
|
||||
context.trace.report(ErrorsJvm.MISSING_DEPENDENCY_CLASS.on(resolvedCall.call.callElement, classId.asSingleFqName()))
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectNotFoundClasses(descriptor: CallableDescriptor): Set<ClassId> {
|
||||
val result: MutableSet<ClassId> = newLinkedHashSetWithExpectedSize(1)
|
||||
|
||||
fun consider(classDescriptor: ClassDescriptor) {
|
||||
if (classDescriptor is NotFoundClasses.MockClassDescriptor) {
|
||||
result.add(classDescriptor.classId)
|
||||
return
|
||||
}
|
||||
(classDescriptor.containingDeclaration as? ClassDescriptor)?.let(::consider)
|
||||
}
|
||||
|
||||
fun consider(type: KotlinType) {
|
||||
if (!isComputingDeferredType(type)) {
|
||||
(type.constructor.declarationDescriptor as? ClassDescriptor)?.let(::consider)
|
||||
}
|
||||
}
|
||||
|
||||
descriptor.returnType?.let(::consider)
|
||||
descriptor.extensionReceiverParameter?.value?.type?.let(::consider)
|
||||
descriptor.valueParameters.forEach { consider(it.type) }
|
||||
|
||||
return result.orEmpty()
|
||||
}
|
||||
}
|
||||
+3
@@ -54,6 +54,9 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
|
||||
MAP.put(ErrorsJvm.CONFLICTING_JVM_DECLARATIONS, "Platform declaration clash: {0}", CONFLICTING_JVM_DECLARATIONS_DATA);
|
||||
MAP.put(ErrorsJvm.ACCIDENTAL_OVERRIDE, "Accidental override: {0}", CONFLICTING_JVM_DECLARATIONS_DATA);
|
||||
MAP.put(ErrorsJvm.CONFLICTING_INHERITED_JVM_DECLARATIONS, "Inherited platform declarations clash: {0}", CONFLICTING_JVM_DECLARATIONS_DATA);
|
||||
|
||||
MAP.put(ErrorsJvm.MISSING_DEPENDENCY_CLASS, "Cannot access class ''{0}''. Check your module classpath for missing or conflicting dependencies", Renderers.TO_STRING);
|
||||
|
||||
MAP.put(ErrorsJvm.JVM_STATIC_NOT_IN_OBJECT, "Only functions in named objects and companion objects of classes can be annotated with ''@JvmStatic''");
|
||||
MAP.put(ErrorsJvm.JVM_STATIC_ON_CONST_OR_JVM_FIELD, "''@JvmStatic'' annotation is useless for const or ''@JvmField'' properties");
|
||||
MAP.put(ErrorsJvm.OVERRIDE_CANNOT_BE_STATIC, "Override member cannot be ''@JvmStatic'' in object");
|
||||
|
||||
@@ -41,6 +41,8 @@ public interface ErrorsJvm {
|
||||
DiagnosticFactory1<PsiElement, ConflictingJvmDeclarationsData> CONFLICTING_INHERITED_JVM_DECLARATIONS =
|
||||
DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||
|
||||
DiagnosticFactory1<PsiElement, FqName> MISSING_DEPENDENCY_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<KtDeclaration> OVERRIDE_CANNOT_BE_STATIC = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtDeclaration> JVM_STATIC_NOT_IN_OBJECT = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtDeclaration> JVM_STATIC_ON_CONST_OR_JVM_FIELD = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
|
||||
+2
-2
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.resolve.jvm.checkers.*
|
||||
import org.jetbrains.kotlin.synthetic.JavaSyntheticScopes
|
||||
import org.jetbrains.kotlin.types.DynamicTypesSettings
|
||||
|
||||
|
||||
object JvmPlatformConfigurator : PlatformConfigurator(
|
||||
DynamicTypesSettings(),
|
||||
additionalDeclarationCheckers = listOf(
|
||||
@@ -51,7 +50,8 @@ object JvmPlatformConfigurator : PlatformConfigurator(
|
||||
JavaClassOnCompanionChecker(),
|
||||
ProtectedInSuperClassCompanionCallChecker(),
|
||||
UnsupportedSyntheticCallableReferenceChecker(),
|
||||
SuperCallWithDefaultArgumentsChecker()
|
||||
SuperCallWithDefaultArgumentsChecker(),
|
||||
MissingDependencyClassChecker()
|
||||
),
|
||||
|
||||
additionalTypeCheckers = listOf(
|
||||
|
||||
Reference in New Issue
Block a user