KT-2752: declare properties as a pair of functions when accessors are marked with @JsName
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
class A {
|
||||||
|
var x: Int
|
||||||
|
<!JS_NAME_CLASH!>@JsName("xx") get() = 0<!>
|
||||||
|
<!JS_NAME_CLASH!>@JsName("xx") set(value) {}<!>
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
package foo {
|
||||||
|
|
||||||
|
public final class A {
|
||||||
|
public constructor A()
|
||||||
|
public final var x: 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -331,6 +331,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("jsNameOnAccessors.kt")
|
||||||
|
public void testJsNameOnAccessors() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/jsNameOnAccessors.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("jsNameOnPropertyAndAccessor.kt")
|
@TestMetadata("jsNameOnPropertyAndAccessor.kt")
|
||||||
public void testJsNameOnPropertyAndAccessor() throws Exception {
|
public void testJsNameOnPropertyAndAccessor() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/jsNameOnPropertyAndAccessor.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/jsNameOnPropertyAndAccessor.kt");
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ object JsNameChecker : SimpleDeclarationChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (AnnotationsUtils.getJsName(descriptor) == null) return
|
||||||
val jsNamePsi = AnnotationsUtils.getJsNameAnnotationPsi(bindingContext, declaration) ?: return
|
val jsNamePsi = AnnotationsUtils.getJsNameAnnotationPsi(bindingContext, declaration) ?: return
|
||||||
|
|
||||||
when (descriptor) {
|
when (descriptor) {
|
||||||
@@ -45,7 +46,7 @@ object JsNameChecker : SimpleDeclarationChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is PropertyAccessorDescriptor -> {
|
is PropertyAccessorDescriptor -> {
|
||||||
if (!descriptor.isDefault && AnnotationsUtils.getJsName(descriptor.correspondingProperty) != null) {
|
if (AnnotationsUtils.getJsName(descriptor.correspondingProperty) != null) {
|
||||||
diagnosticHolder.report(ErrorsJs.JS_NAME_ON_ACCESSOR_AND_PROPERTY.on(jsNamePsi))
|
diagnosticHolder.report(ErrorsJs.JS_NAME_ON_ACCESSOR_AND_PROPERTY.on(jsNamePsi))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-7
@@ -97,15 +97,17 @@ class JsNameClashChecker : SimpleDeclarationChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun collect(descriptor: DeclarationDescriptor, target: MutableMap<String, DeclarationDescriptor>) {
|
private fun collect(descriptor: DeclarationDescriptor, target: MutableMap<String, DeclarationDescriptor>) {
|
||||||
if (descriptor is PropertyDescriptor && descriptor.isExtension) {
|
if (descriptor is PropertyDescriptor) {
|
||||||
descriptor.accessors.forEach { collect(it, target) }
|
if (descriptor.isExtension || AnnotationsUtils.hasJsNameInAccessors(descriptor)) {
|
||||||
}
|
descriptor.accessors.forEach { collect(it, target) }
|
||||||
else {
|
return
|
||||||
val fqn = fqnGenerator.generate(descriptor)
|
|
||||||
if (fqn.shared && isOpaque(fqn.descriptor)) {
|
|
||||||
target[fqn.names.last()] = fqn.descriptor
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val fqn = fqnGenerator.generate(descriptor)
|
||||||
|
if (fqn.shared && isOpaque(fqn.descriptor)) {
|
||||||
|
target[fqn.names.last()] = fqn.descriptor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isOpaque(descriptor: DeclarationDescriptor) =
|
private fun isOpaque(descriptor: DeclarationDescriptor) =
|
||||||
|
|||||||
@@ -20,10 +20,7 @@ import com.intellij.util.Function;
|
|||||||
import com.intellij.util.containers.ContainerUtil;
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
||||||
import org.jetbrains.kotlin.js.PredefinedAnnotation;
|
import org.jetbrains.kotlin.js.PredefinedAnnotation;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
@@ -143,6 +140,12 @@ public final class AnnotationsUtils {
|
|||||||
AnnotationDescriptor annotation = getAnnotationByName(descriptor, new FqName(JS_NAME));
|
AnnotationDescriptor annotation = getAnnotationByName(descriptor, new FqName(JS_NAME));
|
||||||
if (annotation == null) return null;
|
if (annotation == null) return null;
|
||||||
|
|
||||||
|
if (descriptor instanceof PropertyAccessorDescriptor) {
|
||||||
|
PropertyAccessorDescriptor accessor = (PropertyAccessorDescriptor) descriptor;
|
||||||
|
AnnotationDescriptor propertyAnnotation = getAnnotationByName(accessor.getCorrespondingProperty(), new FqName(JS_NAME));
|
||||||
|
if (propertyAnnotation == annotation) return null;
|
||||||
|
}
|
||||||
|
|
||||||
ConstantValue<?> value = annotation.getAllValueArguments().values().iterator().next();
|
ConstantValue<?> value = annotation.getAllValueArguments().values().iterator().next();
|
||||||
assert value != null : "JsName annotation should always declare string parameter";
|
assert value != null : "JsName annotation should always declare string parameter";
|
||||||
|
|
||||||
@@ -202,4 +205,11 @@ public final class AnnotationsUtils {
|
|||||||
ClassDescriptor containingClass = DescriptorUtils.getContainingClass(descriptor);
|
ClassDescriptor containingClass = DescriptorUtils.getContainingClass(descriptor);
|
||||||
return containingClass != null && hasAnnotationOrInsideAnnotatedClass(containingClass, fqName);
|
return containingClass != null && hasAnnotationOrInsideAnnotatedClass(containingClass, fqName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean hasJsNameInAccessors(@NotNull PropertyDescriptor property) {
|
||||||
|
for (PropertyAccessorDescriptor accessor : property.getAccessors()) {
|
||||||
|
if (getJsName(accessor) != null) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -25,12 +25,11 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer
|
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
|
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
|
||||||
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||||
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||||
import org.jetbrains.kotlin.psi.KtSuperExpression
|
import org.jetbrains.kotlin.psi.KtSuperExpression
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
@@ -67,7 +66,7 @@ fun VariableAccessInfo.isGetAccess(): Boolean = value == null
|
|||||||
|
|
||||||
fun VariableAccessInfo.getAccessDescriptor(): DeclarationDescriptor {
|
fun VariableAccessInfo.getAccessDescriptor(): DeclarationDescriptor {
|
||||||
val descriptor = variableDescriptor
|
val descriptor = variableDescriptor
|
||||||
if (descriptor is PropertyDescriptor && descriptor.isExtension) {
|
if (descriptor is PropertyDescriptor && (descriptor.isExtension || TranslationUtils.shouldGenerateAccessors(descriptor))) {
|
||||||
val propertyAccessorDescriptor = if (isGetAccess()) descriptor.getter else descriptor.setter
|
val propertyAccessorDescriptor = if (isGetAccess()) descriptor.getter else descriptor.setter
|
||||||
return propertyAccessorDescriptor!!
|
return propertyAccessorDescriptor!!
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-21
@@ -24,7 +24,9 @@ import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
|
|||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||||
|
import org.jetbrains.kotlin.js.translate.context.Namer
|
||||||
import org.jetbrains.kotlin.js.translate.context.Namer.getCapturedVarAccessor
|
import org.jetbrains.kotlin.js.translate.context.Namer.getCapturedVarAccessor
|
||||||
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.fqnWithoutSideEffects
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
|
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
|
||||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||||
import org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure
|
import org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure
|
||||||
@@ -37,16 +39,36 @@ object NativeVariableAccessCase : VariableAccessCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun VariableAccessInfo.dispatchReceiver(): JsExpression {
|
override fun VariableAccessInfo.dispatchReceiver(): JsExpression {
|
||||||
return constructAccessExpression(JsNameRef(variableName, dispatchReceiver!!))
|
val descriptor = resolvedCall.resultingDescriptor
|
||||||
|
return if (descriptor is PropertyDescriptor && TranslationUtils.shouldGenerateAccessors(descriptor)) {
|
||||||
|
val methodRef = context.getNameForDescriptor(getAccessDescriptor())
|
||||||
|
JsInvocation(fqnWithoutSideEffects(methodRef, dispatchReceiver!!), *additionalArguments.toTypedArray())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
constructAccessExpression(JsNameRef(variableName, dispatchReceiver!!))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun VariableAccessInfo.noReceivers(): JsExpression {
|
override fun VariableAccessInfo.noReceivers(): JsExpression {
|
||||||
return constructAccessExpression(variableName.makeRef())
|
val descriptor = resolvedCall.resultingDescriptor
|
||||||
|
return if (descriptor is PropertyDescriptor && TranslationUtils.shouldGenerateAccessors(descriptor)) {
|
||||||
|
val methodRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(getAccessDescriptor()) }
|
||||||
|
JsInvocation(methodRef, *additionalArguments.toTypedArray())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
constructAccessExpression(variableName.makeRef())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object DefaultVariableAccessCase : VariableAccessCase() {
|
object DefaultVariableAccessCase : VariableAccessCase() {
|
||||||
override fun VariableAccessInfo.noReceivers(): JsExpression {
|
override fun VariableAccessInfo.noReceivers(): JsExpression {
|
||||||
|
val descriptor = resolvedCall.resultingDescriptor
|
||||||
|
if (descriptor is PropertyDescriptor && TranslationUtils.shouldGenerateAccessors(descriptor)) {
|
||||||
|
val methodRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(getAccessDescriptor()) }
|
||||||
|
return JsInvocation(methodRef, *additionalArguments.toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
val functionRef = context.aliasOrValue(callableDescriptor) {
|
val functionRef = context.aliasOrValue(callableDescriptor) {
|
||||||
context.getQualifiedReference(variableDescriptor)
|
context.getQualifiedReference(variableDescriptor)
|
||||||
}
|
}
|
||||||
@@ -73,30 +95,28 @@ object DefaultVariableAccessCase : VariableAccessCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun VariableAccessInfo.dispatchReceiver(): JsExpression {
|
override fun VariableAccessInfo.dispatchReceiver(): JsExpression {
|
||||||
val accessor = JsNameRef(variableName, dispatchReceiver!!)
|
val descriptor = resolvedCall.resultingDescriptor
|
||||||
val descriptor = callableDescriptor
|
return if (descriptor is PropertyDescriptor && TranslationUtils.shouldGenerateAccessors(descriptor)) {
|
||||||
if (descriptor is PropertyDescriptor && !JsDescriptorUtils.sideEffectsPossibleOnRead(descriptor)) {
|
val callExpr = pureFqn(context.getNameForDescriptor(getAccessDescriptor()), dispatchReceiver!!)
|
||||||
accessor.sideEffects = SideEffectKind.DEPENDS_ON_STATE
|
JsInvocation(callExpr, *additionalArguments.toTypedArray())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val accessor = JsNameRef(variableName, dispatchReceiver!!)
|
||||||
|
if (descriptor is PropertyDescriptor && !JsDescriptorUtils.sideEffectsPossibleOnRead(descriptor)) {
|
||||||
|
accessor.sideEffects = SideEffectKind.DEPENDS_ON_STATE
|
||||||
|
}
|
||||||
|
constructAccessExpression(accessor)
|
||||||
}
|
}
|
||||||
return constructAccessExpression(accessor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun VariableAccessInfo.extensionReceiver(): JsExpression {
|
override fun VariableAccessInfo.extensionReceiver(): JsExpression {
|
||||||
val functionRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(getAccessDescriptor()) }
|
val functionRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(getAccessDescriptor()) }
|
||||||
return if (isGetAccess()) {
|
return JsInvocation(functionRef, extensionReceiver!!, *additionalArguments.toTypedArray())
|
||||||
JsInvocation(functionRef, extensionReceiver!!)
|
|
||||||
} else {
|
|
||||||
JsInvocation(functionRef, extensionReceiver!!, value!!)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun VariableAccessInfo.bothReceivers(): JsExpression {
|
override fun VariableAccessInfo.bothReceivers(): JsExpression {
|
||||||
val funRef = JsNameRef(context.getNameForDescriptor(getAccessDescriptor()), dispatchReceiver!!)
|
val funRef = JsNameRef(context.getNameForDescriptor(getAccessDescriptor()), dispatchReceiver!!)
|
||||||
return if (isGetAccess()) {
|
return JsInvocation(funRef, extensionReceiver!!, *additionalArguments.toTypedArray())
|
||||||
JsInvocation(funRef, extensionReceiver!!)
|
|
||||||
} else {
|
|
||||||
JsInvocation(funRef, extensionReceiver!!, value!!)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,14 +148,25 @@ object DelegatePropertyAccessIntrinsic : DelegateIntrinsic<VariableAccessInfo> {
|
|||||||
object SuperPropertyAccessCase : VariableAccessCase() {
|
object SuperPropertyAccessCase : VariableAccessCase() {
|
||||||
override fun VariableAccessInfo.dispatchReceiver(): JsExpression {
|
override fun VariableAccessInfo.dispatchReceiver(): JsExpression {
|
||||||
val variableName = context.program().getStringLiteral(this.variableName.ident)
|
val variableName = context.program().getStringLiteral(this.variableName.ident)
|
||||||
|
val descriptor = resolvedCall.resultingDescriptor
|
||||||
|
|
||||||
return if (isGetAccess())
|
return if (descriptor is PropertyDescriptor && TranslationUtils.shouldGenerateAccessors(descriptor)) {
|
||||||
JsInvocation(context.namer().callGetProperty, dispatchReceiver!!, calleeOwner, variableName)
|
val accessor = getAccessDescriptor()
|
||||||
else
|
val prototype = fqnWithoutSideEffects(Namer.getPrototypeName(), context.getQualifiedReference(descriptor.containingDeclaration))
|
||||||
JsInvocation(context.namer().callSetProperty, dispatchReceiver!!, calleeOwner, variableName, value!!)
|
val funRef = Namer.getFunctionCallRef(fqnWithoutSideEffects(context.getNameForDescriptor(accessor), prototype))
|
||||||
|
val arguments = listOf(dispatchReceiver!!) + additionalArguments
|
||||||
|
JsInvocation(funRef, *arguments.toTypedArray())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val callExpr = if (isGetAccess()) context.namer().callGetProperty else context.namer().callSetProperty
|
||||||
|
val arguments = listOf(dispatchReceiver!!, calleeOwner, variableName) + additionalArguments
|
||||||
|
JsInvocation(callExpr, *arguments.toTypedArray())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val VariableAccessInfo.additionalArguments: List<JsExpression> get() = value?.let { listOf(it) }.orEmpty()
|
||||||
|
|
||||||
fun VariableAccessInfo.translateVariableAccess(): JsExpression {
|
fun VariableAccessInfo.translateVariableAccess(): JsExpression {
|
||||||
val intrinsic = DelegatePropertyAccessIntrinsic.intrinsic(this)
|
val intrinsic = DelegatePropertyAccessIntrinsic.intrinsic(this)
|
||||||
|
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ public final class StaticContext {
|
|||||||
expression = Namer.kotlinObject();
|
expression = Namer.kotlinObject();
|
||||||
partNames = getNameForFQNPart(part);
|
partNames = getNameForFQNPart(part);
|
||||||
}
|
}
|
||||||
else if (isNativeObject(part.getDescriptor()) && !isNativeObject(part.getScope())) {
|
else if (isNative(part.getDescriptor()) && !isNativeObject(part.getScope())) {
|
||||||
expression = null;
|
expression = null;
|
||||||
partNames = getNameForFQNPart(part);
|
partNames = getNameForFQNPart(part);
|
||||||
}
|
}
|
||||||
@@ -258,6 +258,17 @@ public final class StaticContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isNative(DeclarationDescriptor descriptor) {
|
||||||
|
if (isNativeObject(descriptor)) return true;
|
||||||
|
|
||||||
|
if (descriptor instanceof PropertyAccessorDescriptor) {
|
||||||
|
PropertyAccessorDescriptor accessor = (PropertyAccessorDescriptor) descriptor;
|
||||||
|
return isNative(accessor.getCorrespondingProperty());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JsNameRef getQualifiedReference(@NotNull FqName packageFqName) {
|
public JsNameRef getQualifiedReference(@NotNull FqName packageFqName) {
|
||||||
JsName packageName = getNameForPackage(packageFqName);
|
JsName packageName = getNameForPackage(packageFqName);
|
||||||
|
|||||||
+2
-1
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
|
|||||||
import org.jetbrains.kotlin.js.translate.general.Translation
|
import org.jetbrains.kotlin.js.translate.general.Translation
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
|
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.assignmentToBackingField
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.assignmentToBackingField
|
||||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.backingFieldReference
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.backingFieldReference
|
||||||
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateFunctionAsEcma5PropertyDescriptor
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateFunctionAsEcma5PropertyDescriptor
|
||||||
@@ -72,7 +73,7 @@ fun MutableList<JsPropertyInitializer>.addGetterAndSetter(
|
|||||||
generateSetter: () -> JsPropertyInitializer
|
generateSetter: () -> JsPropertyInitializer
|
||||||
) {
|
) {
|
||||||
val to: MutableList<JsPropertyInitializer>
|
val to: MutableList<JsPropertyInitializer>
|
||||||
if (!descriptor.isExtension) {
|
if (!descriptor.isExtension && !TranslationUtils.shouldGenerateAccessors(descriptor)) {
|
||||||
to = SmartList<JsPropertyInitializer>()
|
to = SmartList<JsPropertyInitializer>()
|
||||||
this.add(JsPropertyInitializer(context.getNameForDescriptor(descriptor).makeRef(), JsObjectLiteral(to, true)))
|
this.add(JsPropertyInitializer(context.getNameForDescriptor(descriptor).makeRef(), JsObjectLiteral(to, true)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,10 @@ public final class TranslationUtils {
|
|||||||
public static JsPropertyInitializer translateFunctionAsEcma5PropertyDescriptor(@NotNull JsFunction function,
|
public static JsPropertyInitializer translateFunctionAsEcma5PropertyDescriptor(@NotNull JsFunction function,
|
||||||
@NotNull FunctionDescriptor descriptor,
|
@NotNull FunctionDescriptor descriptor,
|
||||||
@NotNull TranslationContext context) {
|
@NotNull TranslationContext context) {
|
||||||
if (DescriptorUtils.isExtension(descriptor)) {
|
if (DescriptorUtils.isExtension(descriptor) ||
|
||||||
|
descriptor instanceof PropertyAccessorDescriptor &&
|
||||||
|
shouldGenerateAccessors(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty())
|
||||||
|
) {
|
||||||
return translateExtensionFunctionAsEcma5DataDescriptor(function, descriptor, context);
|
return translateExtensionFunctionAsEcma5DataDescriptor(function, descriptor, context);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -299,4 +302,24 @@ public final class TranslationUtils {
|
|||||||
DeclarationDescriptor descriptor = context.bindingContext().get(BindingContext.REFERENCE_TARGET, ((KtSimpleNameExpression) expression));
|
DeclarationDescriptor descriptor = context.bindingContext().get(BindingContext.REFERENCE_TARGET, ((KtSimpleNameExpression) expression));
|
||||||
return !(descriptor instanceof LocalVariableDescriptor) || !((LocalVariableDescriptor) descriptor).isDelegated();
|
return !(descriptor instanceof LocalVariableDescriptor) || !((LocalVariableDescriptor) descriptor).isDelegated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean shouldGenerateAccessors(@NotNull CallableDescriptor descriptor) {
|
||||||
|
if (descriptor instanceof PropertyDescriptor) {
|
||||||
|
return shouldGenerateAccessors((PropertyDescriptor) descriptor);
|
||||||
|
}
|
||||||
|
else if (descriptor instanceof PropertyAccessorDescriptor) {
|
||||||
|
return shouldGenerateAccessors(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean shouldGenerateAccessors(@NotNull PropertyDescriptor property) {
|
||||||
|
if (AnnotationsUtils.hasJsNameInAccessors(property)) return true;
|
||||||
|
for (PropertyDescriptor overriddenProperty : property.getOverriddenDescriptors()) {
|
||||||
|
if (shouldGenerateAccessors(overriddenProperty)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
class A {
|
||||||
|
@JsName("xx") val x: Int by B()
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int = 23
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val a = A()
|
||||||
|
assertEquals(23, a.x)
|
||||||
|
|
||||||
|
val d: dynamic = a
|
||||||
|
assertEquals(23, d.xx)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
@native class A {
|
||||||
|
val xx: Int
|
||||||
|
@JsName("getX") get
|
||||||
|
|
||||||
|
var yy: Int
|
||||||
|
@JsName("getY") get
|
||||||
|
@JsName("setY") set
|
||||||
|
}
|
||||||
|
|
||||||
|
@native var zz: Int
|
||||||
|
@JsName("getZ") get
|
||||||
|
@JsName("setZ") set
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val a = A()
|
||||||
|
|
||||||
|
assertEquals(23, a.xx)
|
||||||
|
assertEquals(0, a.yy)
|
||||||
|
a.yy = 42
|
||||||
|
assertEquals(42, a.yy)
|
||||||
|
|
||||||
|
assertEquals(32, zz)
|
||||||
|
zz = 232
|
||||||
|
assertEquals(232, zz)
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
function A() {
|
||||||
|
this.y_ = 0;
|
||||||
|
}
|
||||||
|
A.prototype.getX = function() {
|
||||||
|
return 23;
|
||||||
|
};
|
||||||
|
A.prototype.getY = function() {
|
||||||
|
return this.y_;
|
||||||
|
};
|
||||||
|
A.prototype.setY = function(y) {
|
||||||
|
return this.y_ = y;
|
||||||
|
};
|
||||||
|
|
||||||
|
var z_ = 32;
|
||||||
|
function getZ() {
|
||||||
|
return z_;
|
||||||
|
}
|
||||||
|
function setZ(z) {
|
||||||
|
z_ = z;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
class A {
|
||||||
|
val x: Int
|
||||||
|
@JsName("getX_") get() = 23
|
||||||
|
|
||||||
|
var y: Int = 0
|
||||||
|
@JsName("getY_") get() = field + 10
|
||||||
|
@JsName("setY_") set(value) {
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val A.z: Int
|
||||||
|
@JsName("getZ_") get() = 42
|
||||||
|
|
||||||
|
fun getPackage() = js("return Kotlin.modules.JS_TESTS.foo")
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val a = A()
|
||||||
|
|
||||||
|
assertEquals(23, a.x)
|
||||||
|
assertEquals(10, a.y)
|
||||||
|
a.y = 13
|
||||||
|
assertEquals(23, a.y)
|
||||||
|
assertEquals(42, a.z)
|
||||||
|
|
||||||
|
val d: dynamic = A()
|
||||||
|
|
||||||
|
assertEquals(23, d.getX_())
|
||||||
|
assertEquals(10, d.getY_())
|
||||||
|
d.setY_(13)
|
||||||
|
assertEquals(23, d.getY_())
|
||||||
|
assertEquals(42, getPackage().getZ_(d))
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
val x: Int
|
||||||
|
@JsName("getX_") get() = 23
|
||||||
|
|
||||||
|
var y: Int = 0
|
||||||
|
@JsName("getY_") get() = field + 10
|
||||||
|
@JsName("setY_") set(value) {
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun getPackage() = js("return Kotlin.modules.JS_TESTS.foo")
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
assertEquals(23, x)
|
||||||
|
assertEquals(10, y)
|
||||||
|
y = 13
|
||||||
|
assertEquals(23, y)
|
||||||
|
|
||||||
|
y = 0
|
||||||
|
val d = getPackage()
|
||||||
|
|
||||||
|
assertEquals(23, d.getX_())
|
||||||
|
assertEquals(10, d.getY_())
|
||||||
|
d.setY_(13)
|
||||||
|
assertEquals(23, d.getY_())
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
open class A {
|
||||||
|
open val x: Int
|
||||||
|
@JsName("getX_") get() = 23
|
||||||
|
|
||||||
|
open var y: Int = 0
|
||||||
|
@JsName("getY_") get() = field + 10
|
||||||
|
@JsName("setY_") set(value) {
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A() {
|
||||||
|
override val x: Int
|
||||||
|
get() = 42
|
||||||
|
|
||||||
|
override var y: Int
|
||||||
|
get() = super.y + 5
|
||||||
|
set(value) {
|
||||||
|
super.y = value + 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPackage() = js("return Kotlin.modules.JS_TESTS.foo")
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val a = B()
|
||||||
|
|
||||||
|
assertEquals(42, a.x)
|
||||||
|
assertEquals(15, a.y)
|
||||||
|
a.y = 13
|
||||||
|
assertEquals(30, a.y)
|
||||||
|
|
||||||
|
val d: dynamic = B()
|
||||||
|
|
||||||
|
assertEquals(42, d.getX_())
|
||||||
|
assertEquals(15, d.getY_())
|
||||||
|
d.setY_(13)
|
||||||
|
assertEquals(30, d.getY_())
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user