KT-2752: fix JsName with explicit use target. Add some tests for JsName with use targets

This commit is contained in:
Alexey Andreev
2016-06-03 13:05:52 +03:00
parent be0013d9f2
commit 725d13b72e
20 changed files with 138 additions and 41 deletions
@@ -0,0 +1,5 @@
class A {
@property:JsName("x_") <!JS_NAME_ON_ACCESSOR_AND_PROPERTY!>@get:JsName("getX_")<!> val x: Int = 0
<!JS_NAME_IS_NOT_ON_ALL_ACCESSORS!>@get:JsName("getY_") var y: Int = 0<!>
}
@@ -0,0 +1,10 @@
package
public final class A {
public constructor A()
@property:kotlin.js.JsName(name = "x_") public final val x: kotlin.Int = 0
public final var y: 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
}
@@ -349,6 +349,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes
doTest(fileName);
}
@TestMetadata("jsNameUseTargetOnProperty.kt")
public void testJsNameUseTargetOnProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/jsNameUseTargetOnProperty.kt");
doTest(fileName);
}
@TestMetadata("methodAndMethod.kt")
public void testMethodAndMethod() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/name/methodAndMethod.kt");
@@ -37,7 +37,7 @@ object JsNameChecker : SimpleDeclarationChecker {
}
if (AnnotationsUtils.getJsName(descriptor) == null) return
val jsNamePsi = AnnotationsUtils.getJsNameAnnotationPsi(bindingContext, declaration) ?: return
val jsNamePsi = AnnotationsUtils.getJsNameAnnotationPsi(bindingContext, declaration, descriptor) ?: return
when (descriptor) {
is ConstructorDescriptor -> {
@@ -22,15 +22,13 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.js.PredefinedAnnotation;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.FqNameUnsafe;
import org.jetbrains.kotlin.psi.KtAnnotated;
import org.jetbrains.kotlin.psi.KtAnnotation;
import org.jetbrains.kotlin.psi.KtAnnotationEntry;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
@@ -124,7 +122,8 @@ public final class AnnotationsUtils {
@Nullable
private static AnnotationDescriptor getAnnotationByName(@NotNull DeclarationDescriptor descriptor, @NotNull FqName fqName) {
return descriptor.getAnnotations().findAnnotation(fqName);
AnnotationWithTarget annotationWithTarget = Annotations.Companion.findAnyAnnotation(descriptor.getAnnotations(), (fqName));
return annotationWithTarget != null ? annotationWithTarget.getAnnotation() : null;
}
public static boolean isNativeObject(@NotNull DeclarationDescriptor descriptor) {
@@ -137,15 +136,9 @@ public final class AnnotationsUtils {
@Nullable
public static String getJsName(@NotNull DeclarationDescriptor descriptor) {
AnnotationDescriptor annotation = getAnnotationByName(descriptor, new FqName(JS_NAME));
AnnotationDescriptor annotation = getJsNameAnnotation(descriptor);
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();
assert value != null : "JsName annotation should always declare string parameter";
@@ -155,26 +148,28 @@ public final class AnnotationsUtils {
}
@Nullable
public static KtAnnotationEntry getJsNameAnnotationPsi(@NotNull BindingContext context, @NotNull KtAnnotated annotated) {
return findAnnotationPsi(context, annotated, new FqName(JS_NAME));
private static AnnotationDescriptor getJsNameAnnotation(@NotNull DeclarationDescriptor descriptor) {
AnnotationDescriptor annotation = getAnnotationByName(descriptor, new FqName(JS_NAME));
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;
}
return annotation;
}
@Nullable
private static KtAnnotationEntry findAnnotationPsi(
@NotNull BindingContext context, @NotNull KtAnnotated annotated,
@NotNull FqName nameToFind
) {
FqNameUnsafe nameToFindUnsafe = nameToFind.toUnsafe();
public static KtAnnotationEntry getJsNameAnnotationPsi(@NotNull BindingContext context, @NotNull KtAnnotated annotated,
@NotNull DeclarationDescriptor descriptor) {
AnnotationDescriptor annotation = getJsNameAnnotation(descriptor);
if (annotation == null) return null;
for (KtAnnotationEntry entry : annotated.getAnnotationEntries()) {
AnnotationDescriptor annotationDescriptor = context.get(BindingContext.ANNOTATION, entry);
assert annotationDescriptor != null : "Annotation descriptor expected for annotation entry: " +
PsiUtilsKt.getTextWithLocation(entry);
ClassifierDescriptor typeDescriptor = annotationDescriptor.getType().getConstructor().getDeclarationDescriptor();
assert typeDescriptor instanceof ClassDescriptor : "Annotation type should be ClassDescriptor: " +
PsiUtilsKt.getTextWithLocation(entry);
FqNameUnsafe entryName = DescriptorUtils.getFqName(typeDescriptor);
if (entryName.equals(nameToFindUnsafe)) {
if (annotationDescriptor == annotation) {
return entry;
}
}
+1 -1
View File
@@ -19,7 +19,7 @@ package kotlin.js
import kotlin.annotation.AnnotationTarget.*
@native
@Target(CLASS, FUNCTION, PROPERTY, CONSTRUCTOR, VALUE_PARAMETER)
@Target(CLASS, FUNCTION, PROPERTY, CONSTRUCTOR, VALUE_PARAMETER, PROPERTY_GETTER, PROPERTY_SETTER)
public annotation class native(public val name: String = "")
@native
@@ -1177,6 +1177,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
doTest(fileName);
}
@TestMetadata("jsNamePropertyDelegation.kt")
public void testJsNamePropertyDelegation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/delegation/jsNamePropertyDelegation.kt");
doTest(fileName);
}
@TestMetadata("onObject.kt")
public void testOnObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/delegation/onObject.kt");
@@ -5281,6 +5287,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
doTest(fileName);
}
@TestMetadata("jsNamePropertyAccessors.kt")
public void testJsNamePropertyAccessors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/native/jsNamePropertyAccessors.kt");
doTest(fileName);
}
@TestMetadata("kt1519.kt")
public void testKt1519() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/native/kt1519.kt");
@@ -5880,6 +5892,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
doTest(fileName);
}
@TestMetadata("accessorsWithJsName.kt")
public void testAccessorsWithJsName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/propertyAccess/accessorsWithJsName.kt");
doTest(fileName);
}
public void testAllFilesPresentInPropertyAccess() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/propertyAccess"), Pattern.compile("^([^_](.+))\\.kt$"), true);
}
@@ -5902,6 +5920,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
doTest(fileName);
}
@TestMetadata("defaultAccessorsWithJsName.kt")
public void testDefaultAccessorsWithJsName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/propertyAccess/defaultAccessorsWithJsName.kt");
doTest(fileName);
}
@TestMetadata("enumerable.kt")
public void testEnumerable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/propertyAccess/enumerable.kt");
@@ -5980,6 +6004,18 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
doTest(fileName);
}
@TestMetadata("staticAccessorsWithJsName.kt")
public void testStaticAccessorsWithJsName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/propertyAccess/staticAccessorsWithJsName.kt");
doTest(fileName);
}
@TestMetadata("subclassAccessorsWithJsNameInSuper.kt")
public void testSubclassAccessorsWithJsNameInSuper() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/propertyAccess/subclassAccessorsWithJsNameInSuper.kt");
doTest(fileName);
}
@TestMetadata("twoClassesWithProperties.kt")
public void testTwoClassesWithProperties() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/propertyAccess/twoClassesWithProperties.kt");
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
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.utils.JsAstUtils.fqnWithoutSideEffects
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
import org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure
@@ -42,7 +42,7 @@ object NativeVariableAccessCase : VariableAccessCase() {
val descriptor = resolvedCall.resultingDescriptor
return if (descriptor is PropertyDescriptor && TranslationUtils.shouldGenerateAccessors(descriptor)) {
val methodRef = context.getNameForDescriptor(getAccessDescriptor())
JsInvocation(fqnWithoutSideEffects(methodRef, dispatchReceiver!!), *additionalArguments.toTypedArray())
JsInvocation(pureFqn(methodRef, dispatchReceiver!!), *additionalArguments.toTypedArray())
}
else {
constructAccessExpression(JsNameRef(variableName, dispatchReceiver!!))
@@ -152,8 +152,8 @@ object SuperPropertyAccessCase : VariableAccessCase() {
return if (descriptor is PropertyDescriptor && TranslationUtils.shouldGenerateAccessors(descriptor)) {
val accessor = getAccessDescriptor()
val prototype = fqnWithoutSideEffects(Namer.getPrototypeName(), context.getQualifiedReference(descriptor.containingDeclaration))
val funRef = Namer.getFunctionCallRef(fqnWithoutSideEffects(context.getNameForDescriptor(accessor), prototype))
val prototype = pureFqn(Namer.getPrototypeName(), context.getQualifiedReference(descriptor.containingDeclaration))
val funRef = Namer.getFunctionCallRef(pureFqn(context.getNameForDescriptor(accessor), prototype))
val arguments = listOf(dispatchReceiver!!) + additionalArguments
JsInvocation(funRef, *arguments.toTypedArray())
}
@@ -150,6 +150,7 @@ public final class JsDescriptorUtils {
return !isExtension(propertyDescriptor) &&
isDefaultAccessor(propertyDescriptor.getGetter()) &&
isDefaultAccessor(propertyDescriptor.getSetter()) &&
!TranslationUtils.shouldGenerateAccessors(propertyDescriptor) &&
!ModalityKt.isOverridableOrOverrides(propertyDescriptor);
}
@@ -3,19 +3,23 @@ package foo
import kotlin.reflect.KProperty
class A {
@JsName("xx") val x: Int by B()
@JsName("xx") val x: Int by B(23)
@get:JsName("getYY") val y: Int by B(42)
}
class B {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int = 23
class B(val value: Int) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int = value
}
fun box(): String {
val a = A()
assertEquals(23, a.x)
assertEquals(42, a.y)
val d: dynamic = a
assertEquals(23, d.xx)
assertEquals(42, d.getYY())
return "OK"
}
@@ -3,10 +3,10 @@ package foo
fun bar(x: Int) = x
fun box(): Boolean {
fun box(): String {
assertEquals(23, bar(23))
assertEquals(42, foo.bar.x)
return true
return "OK"
}
// FILE: foobar.kt
@@ -5,12 +5,12 @@ private fun bar() = 23
private val bar = 42
fun box(): Boolean {
fun box(): String {
assertEquals(23, bar())
assertEquals(42, bar)
assertEquals(32, foo.bar.x)
return true
return "OK"
}
// FILE: foobar.kt
@@ -0,0 +1,31 @@
package foo
class A {
@get:JsName("getX_") val x = 23
@get:JsName("getY_") @set:JsName("setY_") var y = 0
@JsName("z_") var z = 0
}
fun box(): String {
val a = A()
assertEquals(23, a.x)
assertEquals(0, a.y)
a.y = 42
assertEquals(42, a.y)
a.z = 99
assertEquals(99, a.z)
val d: dynamic = A()
assertEquals(23, d.getX_())
assertEquals(0, d.getY_())
d.setY_(42)
assertEquals(42, d.getY_())
d.z_ = 99
assertEquals(99, d.z_)
return "OK"
}
@@ -1,4 +1,4 @@
// ONLY_THIS_QUALIFIED_REFERENCES: foo_qltb3l$
// ONLY_THIS_QUALIFIED_REFERENCES: foo_0
package foo
@@ -11,7 +11,11 @@ open class A {
}
}
class B : A() {
interface C {
@get:JsName("getZ_") val z: Int
}
class B : A(), C {
override val x: Int
get() = 42
@@ -20,6 +24,8 @@ class B : A() {
set(value) {
super.y = value + 2
}
override val z = 55
}
fun getPackage() = js("return Kotlin.modules.JS_TESTS.foo")
@@ -31,6 +37,7 @@ fun box(): String {
assertEquals(15, a.y)
a.y = 13
assertEquals(30, a.y)
assertEquals(55, a.z)
val d: dynamic = B()
@@ -38,6 +45,7 @@ fun box(): String {
assertEquals(15, d.getY_())
d.setY_(13)
assertEquals(30, d.getY_())
assertEquals(55, d.getZ_())
return "OK"
}