From ac4ffd7d2cf4cc646f2ed262fd7fd587ba0ce9a6 Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Thu, 7 Aug 2014 22:48:20 +0400 Subject: [PATCH] JS backend: fixed accessing to nested native "elements". #KT-4298 fixed --- .../test/semantics/NativeInteropTest.java | 4 + .../callTranslator/FunctionCallCases.kt | 11 +- .../k2js/translate/context/StaticContext.java | 32 +-- .../translate/utils/AnnotationsUtils.java | 2 +- .../testData/native/cases/nestedElements.kt | 218 ++++++++++++++++++ .../testData/native/native/nestedElements.js | 66 ++++++ 6 files changed, 311 insertions(+), 22 deletions(-) create mode 100644 js/js.translator/testData/native/cases/nestedElements.kt create mode 100644 js/js.translator/testData/native/native/nestedElements.js diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/NativeInteropTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/NativeInteropTest.java index db6c33197e1..17593eb3b82 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/NativeInteropTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/NativeInteropTest.java @@ -116,4 +116,8 @@ public final class NativeInteropTest extends SingleFileTranslationTest { public void testPassTopLevelFunctionFromNative() throws Exception { checkFooBoxIsOk(); } + + public void testNestedElements() throws Exception { + checkFooBoxIsOk(); + } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/callTranslator/FunctionCallCases.kt b/js/js.translator/src/org/jetbrains/k2js/translate/callTranslator/FunctionCallCases.kt index f9b19d28b78..e8ff43ba563 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/callTranslator/FunctionCallCases.kt +++ b/js/js.translator/src/org/jetbrains/k2js/translate/callTranslator/FunctionCallCases.kt @@ -170,13 +170,10 @@ object ConstructorCallCase : FunctionCallCase { } override fun FunctionCallInfo.noReceivers(): JsExpression { - if (isNative()) { - return JsNew(JsNameRef(functionName), argumentsInfo.getTranslateArguments()) - } + val fqName = context.getQualifiedReference(callableDescriptor) + + val functionRef = if (isNative()) fqName else context.aliasOrValue(callableDescriptor) { fqName } - val functionRef = context.aliasOrValue(callableDescriptor) { - context.getQualifiedReference(it) - } return JsNew(functionRef, argumentsInfo.getTranslateArguments()) } } @@ -209,4 +206,4 @@ fun FunctionCallInfo.translateFunctionCall(): JsExpression { else -> DefaultFunctionCallCase.translate(this) } -} \ No newline at end of file +} diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java index b9e5c2c6670..2aa470d019f 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/context/StaticContext.java @@ -32,14 +32,12 @@ import org.jetbrains.k2js.config.LibrarySourcesConfig; import org.jetbrains.k2js.translate.context.generator.Generator; import org.jetbrains.k2js.translate.context.generator.Rule; import org.jetbrains.k2js.translate.intrinsic.Intrinsics; -import org.jetbrains.k2js.translate.utils.AnnotationsUtils; import org.jetbrains.k2js.translate.utils.JsAstUtils; import java.util.Map; import static org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils.descriptorToDeclaration; -import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.getNameForAnnotatedObjectWithOverrides; -import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.isLibraryObject; +import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.*; import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.*; import static org.jetbrains.k2js.translate.utils.TranslationUtils.getMangledName; import static org.jetbrains.k2js.translate.utils.TranslationUtils.getSuggestedName; @@ -436,6 +434,8 @@ public final class StaticContext { Rule packageLevelDeclarationsHaveEnclosingPackagesNamesAsQualifier = new Rule() { @Override public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) { + if (isNativeObject(descriptor)) return null; + DeclarationDescriptor containingDescriptor = getContainingDeclaration(descriptor); if (!(containingDescriptor instanceof PackageFragmentDescriptor)) { return null; @@ -489,10 +489,25 @@ public final class StaticContext { return null; } }; + Rule nativeObjectsHaveNativePartOfFullQualifier = new Rule() { + @Override + public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) { + if (descriptor instanceof ConstructorDescriptor || !isNativeObject(descriptor)) return null; + + DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); + if (containingDeclaration != null && isNativeObject(containingDeclaration)) { + return getQualifiedReference(containingDeclaration); + } + + return null; + } + }; + addRule(libraryObjectsHaveKotlinQualifier); addRule(constructorHaveTheSameQualifierAsTheClass); addRule(standardObjectsHaveKotlinQualifier); addRule(packageLevelDeclarationsHaveEnclosingPackagesNamesAsQualifier); + addRule(nativeObjectsHaveNativePartOfFullQualifier); } } @@ -508,18 +523,7 @@ public final class StaticContext { return null; } }; - //TODO: hack! it seems like needed, only for Inheritance from native class - Rule nativeObjectsHaveNoQualifiers = new Rule() { - @Override - public Boolean apply(@NotNull DeclarationDescriptor descriptor) { - if (!AnnotationsUtils.isNativeObject(descriptor)) { - return null; - } - return true; - } - }; addRule(propertiesInClassHaveNoQualifiers); - addRule(nativeObjectsHaveNoQualifiers); } } } diff --git a/js/js.translator/src/org/jetbrains/k2js/translate/utils/AnnotationsUtils.java b/js/js.translator/src/org/jetbrains/k2js/translate/utils/AnnotationsUtils.java index d59ce0ad91c..273cc2d082f 100644 --- a/js/js.translator/src/org/jetbrains/k2js/translate/utils/AnnotationsUtils.java +++ b/js/js.translator/src/org/jetbrains/k2js/translate/utils/AnnotationsUtils.java @@ -143,6 +143,6 @@ public final class AnnotationsUtils { return true; } ClassDescriptor containingClass = getContainingClass(descriptor); - return containingClass != null && getAnnotationByName(containingClass, fqn) != null; + return containingClass != null && hasAnnotationOrInsideAnnotatedClass(containingClass, fqn); } } diff --git a/js/js.translator/testData/native/cases/nestedElements.kt b/js/js.translator/testData/native/cases/nestedElements.kt new file mode 100644 index 00000000000..ac3c763ba2a --- /dev/null +++ b/js/js.translator/testData/native/cases/nestedElements.kt @@ -0,0 +1,218 @@ +package foo + +fun box(): String { + // in object + + assertEquals("Object.Object.a", Object.Object.a) + assertEquals("Object.Object.b", Object.Object.b) + assertEquals(123, Object.Object.test()) + + assertEquals("Object.Object.Class().a", Object.Object.Class("Object.Object.Class().a").a) + assertEquals("Object.Object.Class().b", Object.Object.Class("something").b) + assertEquals(42, Object.Object.Class("something").test()) + assertEquals("Object.Object.Class.a", Object.Object.Class.a) + assertEquals("Object.Object.Class.b", Object.Object.Class.b) + assertEquals(142, Object.Object.Class.test()) + + assertEquals("Object.Class().a", Object.Class("Object.Class().a").a) + assertEquals("Object.Class().b", Object.Class("something").b) + assertEquals(42, Object.Class("something").test()) + assertEquals("Object.Class.a", Object.Class.a) + assertEquals("Object.Class.b", Object.Class.b) + assertEquals(142, Object.Class.test()) + + assertEquals("Object.Trait.a", Object.Trait.a) + assertEquals("Object.Trait.b", Object.Trait.b) + assertEquals(324, Object.Trait.test()) + + assertEquals("Object.a.a", Object.a.a) + assertEquals("Object.a.b", Object.a.b) + assertEquals(34, Object.a.test()) + assertEquals("Object.b", Object.b) + assertEquals(23, Object.test()) + + // in class + + assertEquals("Class.Object.a", Class.Object.a) + assertEquals("Class.Object.b", Class.Object.b) + assertEquals(55, Class.Object.test()) + + assertEquals("Class.Class().a", Class.Class("Class.Class().a").a) + assertEquals("Class.Class().b", Class.Class("something").b) + assertEquals(66, Class.Class("something").test()) + assertEquals("Class.Class.a", Class.Class.a) + assertEquals("Class.Class.b", Class.Class.b) + assertEquals(88, Class.Class.test()) + + //TODO inner class +// assertEquals("Class.InnerClass().a", Class().InnerClass("Class.InnerClass().a").a) +// assertEquals("Class.InnerClass().b", Class().InnerClass("something").b) +// assertEquals(66, Class().InnerClass("something").test()) + + assertEquals("Class.Trait.a", Class.Trait.a) + assertEquals("Class.Trait.b", Class.Trait.b) + assertEquals(55, Class.Trait.test()) + + assertEquals("Class.a.a", Class.a.a) + assertEquals("Class.a.b", Class.a.b) + assertEquals(22, Class.a.test()) + assertEquals("Class.b", Class.b) + assertEquals(77, Class.test()) + + // in trit + + assertEquals("Trait.Object.a", Trait.Object.a) + assertEquals("Trait.Object.b", Trait.Object.b) + assertEquals(90, Trait.Object.test()) + + assertEquals("Trait.Class().a", Trait.Class("Trait.Class().a").a) + assertEquals("Trait.Class().b", Trait.Class("something").b) + assertEquals(66, Trait.Class("something").test()) + assertEquals("Trait.Class.a", Trait.Class.a) + assertEquals("Trait.Class.b", Trait.Class.b) + assertEquals(88, Trait.Class.test()) + + assertEquals("Trait.Trait.a", Trait.Trait.a) + assertEquals("Trait.Trait.b", Trait.Trait.b) + assertEquals(55, Trait.Trait.test()) + + assertEquals("Trait.a.a", Trait.a.a) + assertEquals("Trait.a.b", Trait.a.b) + assertEquals(22, Trait.a.test()) + assertEquals("Trait.b", Trait.b) + assertEquals(277, Trait.test()) + + return "OK"; +} + +native +object Object { + object Object { + val a: String = noImpl + var b: String = noImpl + fun test(): Int = noImpl + + native("AnotherClass") + class Class(val a: String) { + var b: String = noImpl + fun test(): Int = noImpl + + class object { + val a: String = noImpl + var b: String = noImpl + fun test(): Int = noImpl + } + } + } + + class Class(val a: String) { + var b: String = noImpl + fun test(): Int = noImpl + + class object { + val a: String = noImpl + var b: String = noImpl + fun test(): Int = noImpl + } + } + + trait Trait { + val a: String + var b: String + fun test(): Int = noImpl + + class object { + val a: String = noImpl + var b: String = noImpl + fun test(): Int = noImpl + } + } + + val a: Trait = noImpl + var b: String = noImpl + fun test(): Int = noImpl +} + +native("SomeClass") +class Class { + object Object { + val a: String = noImpl + var b: String = noImpl + fun test(): Int = noImpl + } + + class Class(val a: String) { + var b: String = noImpl + fun test(): Int = noImpl + + class object { + val a: String = noImpl + var b: String = noImpl + fun test(): Int = noImpl + } + } + + inner class InnerClass(val a: String) { + var b: String = noImpl + fun test(): Int = noImpl + } + + trait Trait { + val a: String + var b: String + fun test(): Int = noImpl + + class object { + val a: String = noImpl + var b: String = noImpl + fun test(): Int = noImpl + } + } + + class object { + native("aaa") + val a: Trait = noImpl + var b: String = noImpl + fun test(): Int = noImpl + } +} + +native +trait Trait { + native("SomeObject") + object Object { + val a: String = noImpl + var b: String = noImpl + fun test(): Int = noImpl + } + + class Class(val a: String) { + var b: String = noImpl + fun test(): Int = noImpl + + class object { + val a: String = noImpl + var b: String = noImpl + fun test(): Int = noImpl + } + } + + native("SomeTrait") + trait Trait { + val a: String + var b: String + fun test(): Int = noImpl + + class object { + val a: String = noImpl + var b: String = noImpl + fun test(): Int = noImpl + } + } + + class object { + val a: Trait = noImpl + var b: String = noImpl + fun test(): Int = noImpl + } +} diff --git a/js/js.translator/testData/native/native/nestedElements.js b/js/js.translator/testData/native/native/nestedElements.js new file mode 100644 index 00000000000..cf25f28481d --- /dev/null +++ b/js/js.translator/testData/native/native/nestedElements.js @@ -0,0 +1,66 @@ +var Object = createTestObject("Object", 23); +extend(Object, { + Object: extend(createTestObject("Object.Object", 123), { AnotherClass : createTestClass("Object.Object.Class", 42, 142) }), + Class: createTestClass("Object.Class", 42, 142), + Trait : createTestObject("Object.Trait", 324), + a: createTestObject("Object.a", 34) +}); + +var SomeClass = function () {}; +extend(SomeClass, createTestObject("Class", 77)); +extend(SomeClass, { + Object: createTestObject("Class.Object", 55), + Class: createTestClass("Class.Class", 66, 88), + InnerClass: createTestInnerClass("Class.InnerClass", 57), + Trait: createTestObject("Class.Trait", 55), + aaa: createTestObject("Class.a", 22) +}); + +var Trait = createTestObject("Trait", 277); +extend(Trait, { + SomeObject: createTestObject("Trait.Object", 90), + Class: createTestClass("Trait.Class", 66, 88), + SomeTrait: createTestObject("Trait.Trait", 55), + a: createTestObject("Trait.a", 22) +}); + +// Helpers + +function extend(destination, source) { + for (var property in source) { + if (source.hasOwnProperty(property)) { + destination[property] = source[property]; + } + } + return destination; +} + +function createTestClass(fqName, memberFunResult, staticFunResult) { + function Class(a) { + this.a = a; + this.b = fqName + "().b" + } + + Class.prototype.test = function () { return memberFunResult }; + + extend(Class, createTestObject(fqName, staticFunResult)); + + return Class; +} + +function createTestInnerClass(fqName, memberFunResult) { + function Class(parent, a) { + this.a = a; + this.b = fqName + "().b" + } + + Class.prototype.test = function () { return memberFunResult }; +} + +function createTestObject(fqName, funResult) { + return { + a: fqName + ".a", + b: fqName + ".b", + test: function () { return funResult } + } +}