JS: prohibit dynamic values as handlers of property delegates. Prohibit delegation of classes by dynamic values. See KT-15283
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
|||||||
|
val x: dynamic = 23
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
fun foo(): String
|
||||||
|
}
|
||||||
|
|
||||||
|
class C : I by <!DELEGATION_BY_DYNAMIC!>x<!>
|
||||||
|
|
||||||
|
object O : I by <!DELEGATION_BY_DYNAMIC!>x<!>
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
return object : I by <!DELEGATION_BY_DYNAMIC!>x<!> {}.foo()
|
||||||
|
}
|
||||||
+16
-5
@@ -1,16 +1,27 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
public final class C : Tr {
|
public val x: dynamic = 23
|
||||||
public constructor C(/*0*/ d: dynamic)
|
public fun box(): kotlin.String
|
||||||
|
|
||||||
|
public final class C : I {
|
||||||
|
public constructor C()
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
public open override /*1*/ /*delegation*/ fun foo(): kotlin.Unit
|
public open override /*1*/ /*delegation*/ fun foo(): kotlin.String
|
||||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Tr {
|
public interface I {
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
public abstract fun foo(): kotlin.Unit
|
public abstract fun foo(): kotlin.String
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public object O : I {
|
||||||
|
private constructor O()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*delegation*/ fun foo(): kotlin.String
|
||||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
}
|
}
|
||||||
-3
@@ -52,6 +52,3 @@ public final fun get(/*0*/ p0: dynamic): dynamic
|
|||||||
public final fun divAssign(/*0*/ p0: dynamic): dynamic
|
public final fun divAssign(/*0*/ p0: dynamic): dynamic
|
||||||
public final fun get(/*0*/ p0: dynamic): dynamic
|
public final fun get(/*0*/ p0: dynamic): dynamic
|
||||||
public final fun remAssign(/*0*/ p0: dynamic): dynamic
|
public final fun remAssign(/*0*/ p0: dynamic): dynamic
|
||||||
public final fun getValue(/*0*/ p0: dynamic, /*1*/ p1: dynamic): dynamic
|
|
||||||
public final fun getValue(/*0*/ p0: dynamic, /*1*/ p1: dynamic): dynamic
|
|
||||||
public final fun setValue(/*0*/ p0: dynamic, /*1*/ p1: dynamic, /*2*/ p2: dynamic): dynamic
|
|
||||||
|
|||||||
@@ -81,6 +81,3 @@ fun test(d: dynamic) {
|
|||||||
<!DEBUG_INFO_DYNAMIC!>d[1]<!> <!DEBUG_INFO_DYNAMIC!>%=<!> 1
|
<!DEBUG_INFO_DYNAMIC!>d[1]<!> <!DEBUG_INFO_DYNAMIC!>%=<!> 1
|
||||||
}
|
}
|
||||||
|
|
||||||
val dyn: dynamic = null
|
|
||||||
val foo : Int <!DEBUG_INFO_DYNAMIC!>by dyn<!>
|
|
||||||
var bar : Int <!DEBUG_INFO_DYNAMIC, DEBUG_INFO_DYNAMIC!>by dyn<!>
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
public var bar: kotlin.Int
|
|
||||||
public val dyn: dynamic = null
|
|
||||||
public val foo: kotlin.Int
|
|
||||||
public fun test(/*0*/ d: dynamic): kotlin.Unit
|
public fun test(/*0*/ d: dynamic): kotlin.Unit
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
interface Tr {
|
|
||||||
fun foo()
|
|
||||||
}
|
|
||||||
|
|
||||||
class C(d: dynamic) : Tr by d
|
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
public final fun getValue(/*0*/ p0: dynamic, /*1*/ p1: dynamic): dynamic
|
||||||
|
public final fun setValue(/*0*/ p0: dynamic, /*1*/ p1: dynamic, /*2*/ p2: dynamic): dynamic
|
||||||
|
public final fun getValue(/*0*/ p0: dynamic, /*1*/ p1: dynamic): dynamic
|
||||||
|
public final fun getValue(/*0*/ p0: dynamic, /*1*/ p1: dynamic): dynamic
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||||
|
|
||||||
|
external val x: dynamic
|
||||||
|
|
||||||
|
var y: Any? by <!PROPERTY_DELEGATION_BY_DYNAMIC!>x<!>
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val a: Any by <!PROPERTY_DELEGATION_BY_DYNAMIC!>x<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
val a: dynamic by <!PROPERTY_DELEGATION_BY_DYNAMIC!>x<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
operator fun provideDelegate(host: Any?, p: Any): dynamic = TODO("")
|
||||||
|
}
|
||||||
|
|
||||||
|
val z: Any? by <!PROPERTY_DELEGATION_BY_DYNAMIC!>A()<!>
|
||||||
|
|
||||||
|
class DynamicHandler {
|
||||||
|
operator fun getValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>): dynamic = 23
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
val x: dynamic by DynamicHandler()
|
||||||
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public external val x: dynamic
|
||||||
|
public var y: kotlin.Any?
|
||||||
|
public val z: kotlin.Any?
|
||||||
|
public fun foo(): kotlin.Unit
|
||||||
|
|
||||||
|
public final class A {
|
||||||
|
public constructor A()
|
||||||
|
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 final operator fun provideDelegate(/*0*/ host: kotlin.Any?, /*1*/ p: kotlin.Any): dynamic
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class B {
|
||||||
|
public constructor B()
|
||||||
|
public final val x: dynamic
|
||||||
|
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 final class C {
|
||||||
|
public constructor C()
|
||||||
|
public final val a: dynamic
|
||||||
|
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 final class DynamicHandler {
|
||||||
|
public constructor DynamicHandler()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public final operator fun getValue(/*0*/ thisRef: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): dynamic
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
+12
-6
@@ -86,6 +86,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classDelegateBy.kt")
|
||||||
|
public void testClassDelegateBy() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/classDelegateBy.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("comparisonToNull.kt")
|
@TestMetadata("comparisonToNull.kt")
|
||||||
public void testComparisonToNull() throws Exception {
|
public void testComparisonToNull() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/comparisonToNull.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/comparisonToNull.kt");
|
||||||
@@ -104,12 +110,6 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("delegationBy.kt")
|
|
||||||
public void testDelegationBy() throws Exception {
|
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/delegationBy.kt");
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("destructuring.kt")
|
@TestMetadata("destructuring.kt")
|
||||||
public void testDestructuring() throws Exception {
|
public void testDestructuring() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/destructuring.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/destructuring.kt");
|
||||||
@@ -242,6 +242,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("propertyDelegateBy.kt")
|
||||||
|
public void testPropertyDelegateBy() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/propertyDelegateBy.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("protected.kt")
|
@TestMetadata("protected.kt")
|
||||||
public void testProtected() throws Exception {
|
public void testProtected() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/protected.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/protected.kt");
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ object JsPlatformConfigurator : PlatformConfigurator(
|
|||||||
JsNameChecker, JsModuleChecker,
|
JsNameChecker, JsModuleChecker,
|
||||||
JsExternalChecker, JsInheritanceChecker,
|
JsExternalChecker, JsInheritanceChecker,
|
||||||
JsRuntimeAnnotationChecker,
|
JsRuntimeAnnotationChecker,
|
||||||
|
JsDynamicDeclarationChecker,
|
||||||
HeaderImplDeclarationChecker()
|
HeaderImplDeclarationChecker()
|
||||||
),
|
),
|
||||||
additionalCallCheckers = listOf(ReifiedTypeParameterSubstitutionChecker(), JsModuleCallChecker, JsDynamicCallChecker),
|
additionalCallCheckers = listOf(ReifiedTypeParameterSubstitutionChecker(), JsModuleCallChecker, JsDynamicCallChecker),
|
||||||
|
|||||||
+2
@@ -71,6 +71,8 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
|
|||||||
|
|
||||||
put(ErrorsJs.WRONG_OPERATION_WITH_DYNAMIC, "Wrong operation with dynamic value: {0}", Renderers.STRING)
|
put(ErrorsJs.WRONG_OPERATION_WITH_DYNAMIC, "Wrong operation with dynamic value: {0}", Renderers.STRING)
|
||||||
put(ErrorsJs.SPREAD_OPERATOR_IN_DYNAMIC_CALL, "Can't apply spread operator in dynamic call")
|
put(ErrorsJs.SPREAD_OPERATOR_IN_DYNAMIC_CALL, "Can't apply spread operator in dynamic call")
|
||||||
|
put(ErrorsJs.DELEGATION_BY_DYNAMIC, "Can't delegate to dynamic value")
|
||||||
|
put(ErrorsJs.PROPERTY_DELEGATION_BY_DYNAMIC, "Can't apply property delegation by dynamic handler")
|
||||||
|
|
||||||
put(ErrorsJs.RUNTIME_ANNOTATION_ON_EXTERNAL_DECLARATION, "Runtime annotation can't be put on external declaration")
|
put(ErrorsJs.RUNTIME_ANNOTATION_ON_EXTERNAL_DECLARATION, "Runtime annotation can't be put on external declaration")
|
||||||
put(ErrorsJs.RUNTIME_ANNOTATION_NOT_SUPPORTED, "Reflection is not supported in JavaScript target, therefore you won't be able " +
|
put(ErrorsJs.RUNTIME_ANNOTATION_NOT_SUPPORTED, "Reflection is not supported in JavaScript target, therefore you won't be able " +
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ public interface ErrorsJs {
|
|||||||
|
|
||||||
DiagnosticFactory1<PsiElement, String> WRONG_OPERATION_WITH_DYNAMIC = DiagnosticFactory1.create(ERROR);
|
DiagnosticFactory1<PsiElement, String> WRONG_OPERATION_WITH_DYNAMIC = DiagnosticFactory1.create(ERROR);
|
||||||
DiagnosticFactory0<PsiElement> SPREAD_OPERATOR_IN_DYNAMIC_CALL = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<PsiElement> SPREAD_OPERATOR_IN_DYNAMIC_CALL = DiagnosticFactory0.create(ERROR);
|
||||||
|
DiagnosticFactory0<PsiElement> DELEGATION_BY_DYNAMIC = DiagnosticFactory0.create(ERROR);
|
||||||
|
DiagnosticFactory0<PsiElement> PROPERTY_DELEGATION_BY_DYNAMIC = DiagnosticFactory0.create(ERROR);
|
||||||
|
|
||||||
DiagnosticFactory0<PsiElement> RUNTIME_ANNOTATION_ON_EXTERNAL_DECLARATION = DiagnosticFactory0.create(
|
DiagnosticFactory0<PsiElement> RUNTIME_ANNOTATION_ON_EXTERNAL_DECLARATION = DiagnosticFactory0.create(
|
||||||
ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
|
||||||
|
|||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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.js.resolve.diagnostics
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||||
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
|
import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
|
||||||
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.checkers.SimpleDeclarationChecker
|
||||||
|
import org.jetbrains.kotlin.types.isDynamic
|
||||||
|
|
||||||
|
object JsDynamicDeclarationChecker : SimpleDeclarationChecker {
|
||||||
|
override fun check(
|
||||||
|
declaration: KtDeclaration, descriptor: DeclarationDescriptor,
|
||||||
|
diagnosticHolder: DiagnosticSink, bindingContext: BindingContext
|
||||||
|
) {
|
||||||
|
if (declaration is KtProperty && descriptor is VariableDescriptorWithAccessors) {
|
||||||
|
declaration.delegateExpression?.let { delegateExpression ->
|
||||||
|
val provideDelegateCall = bindingContext[BindingContext.PROVIDE_DELEGATE_RESOLVED_CALL, descriptor]
|
||||||
|
if (provideDelegateCall != null && provideDelegateCall.resultingDescriptor.returnType?.isDynamic() == true ||
|
||||||
|
bindingContext.getType(delegateExpression)?.isDynamic() == true
|
||||||
|
) {
|
||||||
|
diagnosticHolder.report(ErrorsJs.PROPERTY_DELEGATION_BY_DYNAMIC.on(delegateExpression))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (declaration is KtClassOrObject) {
|
||||||
|
for (delegateDecl in declaration.superTypeListEntries.filterIsInstance<KtDelegatedSuperTypeEntry>()) {
|
||||||
|
val delegateExpr = delegateDecl.delegateExpression ?: continue
|
||||||
|
if (bindingContext.getType(delegateExpr)?.isDynamic() == true) {
|
||||||
|
diagnosticHolder.report(ErrorsJs.DELEGATION_BY_DYNAMIC.on(delegateExpr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user