JS: prohibit overriding external functions with optional parameters by non-external fake functions

This commit is contained in:
Alexey Andreev
2016-12-13 14:45:03 +03:00
parent e2dab5ab5c
commit b08afb0e93
5 changed files with 89 additions and 4 deletions
@@ -69,6 +69,8 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
put(ErrorsJs.RUNTIME_ANNOTATION_NOT_SUPPORTED, "Reflection is not supported in JavaScript target, therefore you won't be able " +
"to read this annotation in run-time")
put(ErrorsJs.OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS, "Overriding `external` function with optional parameters")
put(ErrorsJs.OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS_WITH_FAKE,
"Overriding `external` function with optional parameters by declaration from superclass: {0}", Renderers.COMPACT)
this
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.js.resolve.diagnostics;
import com.intellij.psi.PsiElement;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.diagnostics.*;
import org.jetbrains.kotlin.psi.KtDeclaration;
import org.jetbrains.kotlin.psi.KtElement;
@@ -70,6 +71,8 @@ public interface ErrorsJs {
DiagnosticFactory0<PsiElement> RUNTIME_ANNOTATION_NOT_SUPPORTED = DiagnosticFactory0.create(WARNING, DECLARATION_SIGNATURE_OR_DEFAULT);
DiagnosticFactory0<KtElement> OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS =
DiagnosticFactory0.create(ERROR, PositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT);
DiagnosticFactory1<KtElement, FunctionDescriptor> OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS_WITH_FAKE =
DiagnosticFactory1.create(ERROR, PositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT);
@SuppressWarnings("UnusedDeclaration")
Object _initializer = new Object() {
@@ -16,14 +16,14 @@
package org.jetbrains.kotlin.js.resolve.diagnostics
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
object JsInheritanceChecker : SimpleDeclarationChecker {
override fun check(
@@ -37,10 +37,17 @@ object JsInheritanceChecker : SimpleDeclarationChecker {
) {
diagnosticHolder.report(ErrorsJs.OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS.on(declaration))
}
else if (descriptor is ClassDescriptor && !DescriptorUtils.isEffectivelyExternal(descriptor)) {
val fakeOverriddenMethod = findFakeMethodOverridingExternalWithOptionalParams(descriptor)
if (fakeOverriddenMethod != null) {
diagnosticHolder.report(ErrorsJs.OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS_WITH_FAKE.on(
declaration, fakeOverriddenMethod))
}
}
}
private fun isOverridingExternalWithOptionalParams(function: FunctionDescriptor): Boolean {
if (!function.kind.isReal) return false
if (!function.kind.isReal && function.modality == Modality.ABSTRACT) return false
for (overriddenFunction in function.overriddenDescriptors.filter { DescriptorUtils.isEffectivelyExternal(it) }) {
if (overriddenFunction.valueParameters.any { it.hasDefaultValue() }) return true
@@ -48,4 +55,12 @@ object JsInheritanceChecker : SimpleDeclarationChecker {
return false
}
private fun findFakeMethodOverridingExternalWithOptionalParams(cls: ClassDescriptor): FunctionDescriptor? {
val members = cls.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.CALLABLES)
.mapNotNull { it as? FunctionDescriptor }
.filter { it.containingDeclaration == cls && !it.kind.isReal }
return members.firstOrNull { isOverridingExternalWithOptionalParams(it) }
}
}