JS: prohibit dynamic values as handlers of property delegates. Prohibit delegation of classes by dynamic values. See KT-15283

This commit is contained in:
Alexey Andreev
2016-12-26 18:15:20 +03:00
parent a4b2abc7d5
commit 199790276b
14 changed files with 169 additions and 25 deletions
@@ -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()
}
@@ -1,16 +1,27 @@
package
public final class C : Tr {
public constructor C(/*0*/ d: dynamic)
public val x: dynamic = 23
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*/ /*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 toString(): kotlin.String
}
public interface Tr {
public interface I {
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 toString(): kotlin.String
}
@@ -52,6 +52,3 @@ public final fun get(/*0*/ p0: dynamic): dynamic
public final fun divAssign(/*0*/ p0: dynamic): dynamic
public final fun get(/*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
}
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
public var bar: kotlin.Int
public val dyn: dynamic = null
public val foo: kotlin.Int
public fun test(/*0*/ d: dynamic): kotlin.Unit
@@ -1,5 +0,0 @@
interface Tr {
fun foo()
}
class C(d: dynamic) : Tr by d
@@ -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
@@ -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()
}
@@ -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
}
@@ -86,6 +86,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
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")
public void testComparisonToNull() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/comparisonToNull.kt");
@@ -104,12 +110,6 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
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")
public void testDestructuring() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/destructuring.kt");
@@ -242,6 +242,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
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")
public void testProtected() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/dynamicTypes/protected.kt");
@@ -39,6 +39,7 @@ object JsPlatformConfigurator : PlatformConfigurator(
JsNameChecker, JsModuleChecker,
JsExternalChecker, JsInheritanceChecker,
JsRuntimeAnnotationChecker,
JsDynamicDeclarationChecker,
HeaderImplDeclarationChecker()
),
additionalCallCheckers = listOf(ReifiedTypeParameterSubstitutionChecker(), JsModuleCallChecker, JsDynamicCallChecker),
@@ -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.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_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);
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(
ERROR, DECLARATION_SIGNATURE_OR_DEFAULT);
@@ -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))
}
}
}
}
}