From fcffd190d0bf53bf5a7ecc8f75193142054e046f Mon Sep 17 00:00:00 2001 From: Anton Bannykh Date: Fri, 3 Mar 2017 15:48:29 +0300 Subject: [PATCH] JS: prohibited extension function arguments in external functions; removed extension receiver in jQuery declarations. --- .../extensionFunctionArgumentOrReturnType.kt | 25 ++++++++++++++++ .../extensionFunctionArgumentOrReturnType.txt | 29 +++++++++++++++++++ .../DiagnosticsTestWithJsStdLibGenerated.java | 6 ++++ .../diagnostics/DefaultErrorMessagesJs.kt | 1 + .../js/resolve/diagnostics/ErrorsJs.java | 1 + .../resolve/diagnostics/JsExternalChecker.kt | 19 ++++++++++++ .../src/deprecated/jquery/common.kt | 22 +++++++------- 7 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/diagnostics/testsWithJsStdLib/native/extensionFunctionArgumentOrReturnType.kt create mode 100644 compiler/testData/diagnostics/testsWithJsStdLib/native/extensionFunctionArgumentOrReturnType.txt diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/native/extensionFunctionArgumentOrReturnType.kt b/compiler/testData/diagnostics/testsWithJsStdLib/native/extensionFunctionArgumentOrReturnType.kt new file mode 100644 index 00000000000..d6bb34bf0ff --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/native/extensionFunctionArgumentOrReturnType.kt @@ -0,0 +1,25 @@ +external fun foo(f: Int.() -> Int) + +external fun bar(vararg f: Int.() -> Int) + +external fun baz(): Int.() -> Int + +external val prop: Int.() -> Int + +external var prop2: Int.() -> Int + +external val propGet + get(): Int.() -> Int = definedExternally + +external var propSet + get(): Int.() -> Int = definedExternally + set(v: Int.() -> Int) = definedExternally + +external class A(f: Int.() -> Int) + +external data class B( + val a: Int.() -> Int, + var b: Int.() -> Int +) { + val c: Int.() -> Int +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/native/extensionFunctionArgumentOrReturnType.txt b/compiler/testData/diagnostics/testsWithJsStdLib/native/extensionFunctionArgumentOrReturnType.txt new file mode 100644 index 00000000000..700e1a3f107 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/native/extensionFunctionArgumentOrReturnType.txt @@ -0,0 +1,29 @@ +package + +public external val prop: kotlin.Int.() -> kotlin.Int +public external var prop2: kotlin.Int.() -> kotlin.Int +public external val propGet: kotlin.Int.() -> kotlin.Int +public external var propSet: kotlin.Int.() -> kotlin.Int +public external fun bar(/*0*/ vararg f: kotlin.Int.() -> kotlin.Int /*kotlin.Array kotlin.Int>*/): kotlin.Unit +public external fun baz(): kotlin.Int.() -> kotlin.Int +public external fun foo(/*0*/ f: kotlin.Int.() -> kotlin.Int): kotlin.Unit + +public external final class A { + public constructor A(/*0*/ f: kotlin.Int.() -> kotlin.Int) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public external final data class B { + public constructor B(/*0*/ a: kotlin.Int.() -> kotlin.Int, /*1*/ b: kotlin.Int.() -> kotlin.Int) + public final val a: kotlin.Int.() -> kotlin.Int + public final var b: kotlin.Int.() -> kotlin.Int + public final val c: kotlin.Int.() -> kotlin.Int + public final operator /*synthesized*/ fun component1(): kotlin.Int.() -> kotlin.Int + public final operator /*synthesized*/ fun component2(): kotlin.Int.() -> kotlin.Int + public final /*synthesized*/ fun copy(/*0*/ a: kotlin.Int.() -> kotlin.Int = ..., /*1*/ b: kotlin.Int.() -> kotlin.Int = ...): B + public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java index 0e51e5cdda1..adacf791770 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java @@ -656,6 +656,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes doTest(fileName); } + @TestMetadata("extensionFunctionArgumentOrReturnType.kt") + public void testExtensionFunctionArgumentOrReturnType() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/extensionFunctionArgumentOrReturnType.kt"); + doTest(fileName); + } + @TestMetadata("externalInterfaceNested.kt") public void testExternalInterfaceNested() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/native/externalInterfaceNested.kt"); diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/DefaultErrorMessagesJs.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/DefaultErrorMessagesJs.kt index 8223c16a435..fcad2c56f7b 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/DefaultErrorMessagesJs.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/DefaultErrorMessagesJs.kt @@ -38,6 +38,7 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy { put(ErrorsJs.JSCODE_NO_JAVASCRIPT_PRODUCED, "Argument must be non-empty JavaScript code") put(ErrorsJs.NESTED_EXTERNAL_DECLARATION, "Non top-level `external` declaration") put(ErrorsJs.WRONG_EXTERNAL_DECLARATION, "Declaration of such kind ({0}) can't be external", Renderers.STRING) + put(ErrorsJs.EXTENSION_FUNCTION_IN_EXTERNAL_DECLARATION, "Function types with receiver are prohibited in external declarations") put(ErrorsJs.JS_NAME_CLASH, "JavaScript name ({0}) generated for this declaration clashes with another declaration: {1}", Renderers.STRING, Renderers.COMPACT) diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java index 52c89eb9bbe..43dd6903a02 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/ErrorsJs.java @@ -40,6 +40,7 @@ public interface ErrorsJs { DiagnosticFactory1 NOT_SUPPORTED = DiagnosticFactory1.create(ERROR, DEFAULT); DiagnosticFactory0 JSCODE_NO_JAVASCRIPT_PRODUCED = DiagnosticFactory0.create(ERROR, DEFAULT); DiagnosticFactory1 WRONG_EXTERNAL_DECLARATION = DiagnosticFactory1.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT); + DiagnosticFactory0 EXTENSION_FUNCTION_IN_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT); DiagnosticFactory0 NESTED_EXTERNAL_DECLARATION = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE_OR_DEFAULT); DiagnosticFactory2 JS_NAME_CLASH = DiagnosticFactory2.create( diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsExternalChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsExternalChecker.kt index da16767d37f..18729790e29 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsExternalChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsExternalChecker.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.js.resolve.diagnostics import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.builtins.isExtensionFunctionType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.js.PredefinedAnnotation @@ -29,6 +30,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker import org.jetbrains.kotlin.resolve.descriptorUtil.* +import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.utils.singletonOrEmptyList @@ -90,6 +92,23 @@ object JsExternalChecker : SimpleDeclarationChecker { diagnosticHolder.report(ErrorsJs.INLINE_EXTERNAL_DECLARATION.on(declaration)) } + if (descriptor is CallableMemberDescriptor && !(descriptor is PropertyAccessorDescriptor && descriptor.isDefault)) { + for (p in descriptor.valueParameters) { + if ((p.varargElementType ?: p.type).isExtensionFunctionType) { + val ktParam = p.source.getPsi() as? KtParameter ?: declaration + diagnosticHolder.report(ErrorsJs.EXTENSION_FUNCTION_IN_EXTERNAL_DECLARATION.on(ktParam)) + } + } + + // Only report on properties if there are no custom accessors + val propertyWithCustomAccessors = descriptor is PropertyDescriptor && + !(descriptor.getter?.isDefault ?: true && descriptor.setter?.isDefault ?: true) + + if (!propertyWithCustomAccessors && descriptor.returnType?.isExtensionFunctionType ?: false) { + diagnosticHolder.report(ErrorsJs.EXTENSION_FUNCTION_IN_EXTERNAL_DECLARATION.on(declaration)) + } + } + if (descriptor is CallableMemberDescriptor && descriptor.isNonAbstractMemberOfInterface() && !descriptor.isNullableProperty() ) { diff --git a/js/js.libraries/src/deprecated/jquery/common.kt b/js/js.libraries/src/deprecated/jquery/common.kt index 1ef7e8195f8..24f9a952079 100644 --- a/js/js.libraries/src/deprecated/jquery/common.kt +++ b/js/js.libraries/src/deprecated/jquery/common.kt @@ -5,14 +5,14 @@ import org.w3c.dom.Element @Deprecated("JQuery is going to be removed from the standard library") public external class JQuery() { public fun addClass(className: String): JQuery - public fun addClass(f: Element.(Int, String) -> String): JQuery + public fun addClass(f: (Int, String) -> String): JQuery public fun attr(attrName: String): String public fun attr(attrName: String, value: String): JQuery public fun html(): String public fun html(s: String): JQuery - public fun html(f: Element.(Int, String) -> String): JQuery + public fun html(f: (Int, String) -> String): JQuery public fun hasClass(className: String): Boolean @@ -22,22 +22,22 @@ public external class JQuery() { public fun click(): JQuery - public fun mousedown(handler: Element.(MouseEvent) -> Unit): JQuery - public fun mouseup(handler: Element.(MouseEvent) -> Unit): JQuery - public fun mousemove(handler: Element.(MouseEvent) -> Unit): JQuery + public fun mousedown(handler: (MouseEvent) -> Unit): JQuery + public fun mouseup(handler: (MouseEvent) -> Unit): JQuery + public fun mousemove(handler: (MouseEvent) -> Unit): JQuery - public fun dblclick(handler: Element.(MouseClickEvent) -> Unit): JQuery - public fun click(handler: Element.(MouseClickEvent) -> Unit): JQuery + public fun dblclick(handler: (MouseClickEvent) -> Unit): JQuery + public fun click(handler: (MouseClickEvent) -> Unit): JQuery - public fun load(handler: Element.() -> Unit): JQuery - public fun change(handler: Element.() -> Unit): JQuery + public fun load(handler: () -> Unit): JQuery + public fun change(handler: () -> Unit): JQuery public fun append(str: String): JQuery public fun ready(handler: () -> Unit): JQuery public fun text(text: String): JQuery public fun slideUp(): JQuery - public fun hover(handlerInOut: Element.() -> Unit): JQuery - public fun hover(handlerIn: Element.() -> Unit, handlerOut: Element.() -> Unit): JQuery + public fun hover(handlerInOut: () -> Unit): JQuery + public fun hover(handlerIn: () -> Unit, handlerOut: () -> Unit): JQuery public fun next(): JQuery public fun parent(): JQuery public fun `val`(): String?