From c48c6bc055832da698ed9869119a3a3c57707218 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 9 Feb 2016 19:55:46 +0300 Subject: [PATCH] [KT-4124] Use generated test to avoid duplication of test data of inner classes. Add support of classes contained within objects. --- .../kotlin/generators/tests/GenerateTests.kt | 3 + .../js/test/semantics/NestedTypesTest.java | 12 +-- .../semantics/NestedTypesTestGenerated.java | 73 +++++++++++++++++++ .../abstractClassesForGeneratedTests.kt | 2 + .../translate/context/TranslationContext.java | 34 ++++++++- js/js.translator/testData/kotlin_lib_ecma5.js | 47 ++++++++---- .../nestedTypes/cases/instantiateInDerived.kt | 42 ----------- .../cases/instantiateInDerivedLabeled.kt | 44 ----------- .../cases/instantiateInSameClass.kt | 36 --------- .../nestedTypes/cases/outerCompanion.kt | 29 ++++++++ .../testData/nestedTypes/cases/outerObject.kt | 24 ++++++ .../testData/nestedTypes/cases/properOuter.kt | 17 ----- 12 files changed, 194 insertions(+), 169 deletions(-) create mode 100644 js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTestGenerated.java delete mode 100644 js/js.translator/testData/nestedTypes/cases/instantiateInDerived.kt delete mode 100644 js/js.translator/testData/nestedTypes/cases/instantiateInDerivedLabeled.kt delete mode 100644 js/js.translator/testData/nestedTypes/cases/instantiateInSameClass.kt create mode 100644 js/js.translator/testData/nestedTypes/cases/outerCompanion.kt create mode 100644 js/js.translator/testData/nestedTypes/cases/outerObject.kt delete mode 100644 js/js.translator/testData/nestedTypes/cases/properOuter.kt diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index d5a327d56cd..93789476c78 100644 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -1063,6 +1063,9 @@ fun main(args: Array) { model("codegen/box/secondaryConstructors", targetBackend = TargetBackend.JS) } + testClass() { + model("codegen/box/classes/inner", targetBackend = TargetBackend.JS) + } } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTest.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTest.java index fd3dc1bd07f..2b8460a0fd6 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTest.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTest.java @@ -35,19 +35,11 @@ public class NestedTypesTest extends SingleFileTranslationTest { checkFooBoxIsOk(); } - public void testInstantiateInDerived() throws Exception { + public void testOuterCompanion() throws Exception { checkFooBoxIsOk(); } - public void testInstantiateInDerivedLabeled() throws Exception { - checkFooBoxIsOk(); - } - - public void testInstantiateInSameClass() throws Exception { - checkFooBoxIsOk(); - } - - public void testProperOuter() throws Exception { + public void testOuterObject() throws Exception { checkFooBoxIsOk(); } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTestGenerated.java new file mode 100644 index 00000000000..cdfcde1f5b7 --- /dev/null +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/NestedTypesTestGenerated.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010-2015 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.test.semantics; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/codegen/box/classes/inner") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class NestedTypesTestGenerated extends AbstractNestedTypesTest { + public void testAllFilesPresentInInner() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/classes/inner"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("instantiateInDerived.kt") + public void testInstantiateInDerived() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/inner/instantiateInDerived.kt"); + doTest(fileName); + } + + @TestMetadata("instantiateInDerivedLabeled.kt") + public void testInstantiateInDerivedLabeled() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/inner/instantiateInDerivedLabeled.kt"); + doTest(fileName); + } + + @TestMetadata("instantiateInSameClass.kt") + public void testInstantiateInSameClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/inner/instantiateInSameClass.kt"); + doTest(fileName); + } + + @TestMetadata("kt6708.kt") + public void testKt6708() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/inner/kt6708.kt"); + doTest(fileName); + } + + @TestMetadata("properOuter.kt") + public void testProperOuter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/inner/properOuter.kt"); + doTest(fileName); + } + + @TestMetadata("properSuperLinking.kt") + public void testProperSuperLinking() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/classes/inner/properSuperLinking.kt"); + doTest(fileName); + } +} diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/abstractClassesForGeneratedTests.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/abstractClassesForGeneratedTests.kt index c7360f33c78..8279d8565f8 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/abstractClassesForGeneratedTests.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/abstractClassesForGeneratedTests.kt @@ -51,3 +51,5 @@ abstract class AbstractInlineMultiModuleTest : MultipleModulesTranslationTest("i abstract class AbstractReservedWordTest : SingleFileTranslationTest("reservedWords/") abstract class AbstractSecondaryConstructorTest : AbstractBlackBoxTest("secondaryConstructors/") + +abstract class AbstractNestedTypesTest : AbstractBlackBoxTest("nestedTypes/") diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java index dc48d86740b..77e45e57517 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java @@ -60,6 +60,8 @@ public class TranslationContext { private final DeclarationDescriptor declarationDescriptor; @Nullable private final ClassDescriptor classDescriptor; + @Nullable + private final ClassDescriptor objectDescriptor; @NotNull public static TranslationContext rootContext(@NotNull StaticContext staticContext, JsFunction rootFunction) { @@ -90,9 +92,16 @@ public class TranslationContext { && !DescriptorUtils.isAnonymousObject(declarationDescriptor) && !DescriptorUtils.isObject(declarationDescriptor)) { this.classDescriptor = (ClassDescriptor) declarationDescriptor; - } else { + } + else { this.classDescriptor = parent != null ? parent.classDescriptor : null; } + if (declarationDescriptor instanceof ClassDescriptor && DescriptorUtils.isObject(declarationDescriptor)) { + this.objectDescriptor = (ClassDescriptor) declarationDescriptor; + } + else { + this.objectDescriptor = parent != null ? parent.objectDescriptor : null; + } } @Nullable @@ -126,7 +135,7 @@ public class TranslationContext { DynamicContext dynamicContext = DynamicContext.newContext(fun.getScope(), fun.getBody()); UsageTracker usageTracker = new UsageTracker(this.usageTracker, descriptor, fun.getScope()); return new TranslationContext(this, this.staticContext, dynamicContext, this.aliasingContext.inner(), usageTracker, this.definitionPlace, - this.declarationDescriptor); + descriptor); } @NotNull @@ -341,9 +350,27 @@ public class TranslationContext { if (alias != null) { return alias; } + if (DescriptorUtils.isObject(descriptor.getContainingDeclaration())) { + if (isConstructorOrDirectScope(descriptor.getContainingDeclaration())) { + return JsLiteral.THIS; + } + else { + return getQualifiedReference(descriptor.getContainingDeclaration()); + } + } return getDispatchReceiverPath(getNearestClass(descriptor)); } + private boolean isConstructorOrDirectScope(DeclarationDescriptor descriptor) { + if (descriptor == declarationDescriptor) { + return true; + } + if (declarationDescriptor instanceof ConstructorDescriptor) { + return descriptor == declarationDescriptor.getContainingDeclaration(); + } + return false; + } + @NotNull private JsExpression getDispatchReceiverPath(@Nullable ClassDescriptor cls) { if (cls != null) { @@ -396,8 +423,7 @@ public class TranslationContext { private static ClassDescriptor getNearestClass(@Nullable DeclarationDescriptor declaration) { while (declaration != null) { if (declaration instanceof ClassDescriptor) { - if (!DescriptorUtils.isAnonymousObject(declaration) - && !DescriptorUtils.isObject(declaration)) { + if (!DescriptorUtils.isAnonymousObject(declaration) && !DescriptorUtils.isObject(declaration)) { return (ClassDescriptor) declaration; } } diff --git a/js/js.translator/testData/kotlin_lib_ecma5.js b/js/js.translator/testData/kotlin_lib_ecma5.js index 47d10092121..411ba67a477 100644 --- a/js/js.translator/testData/kotlin_lib_ecma5.js +++ b/js/js.translator/testData/kotlin_lib_ecma5.js @@ -150,20 +150,11 @@ var Kotlin = {}; return object; } - /** - * @param {(Array|Object|null)=} bases - * @param {(function(new: T, ?, ?, ?, ?, ?, ?, ?): T)|null=} constructor - * @param {Object=} properties - * @param {Object=} staticProperties - * @returns {function(new: T): T} - * @template T - */ - Kotlin.createClassNow = function (bases, constructor, properties, staticProperties) { + Kotlin.doCreateClass = function (metadata, constructor) { if (constructor == null) { constructor = emptyFunction(); } - var metadata = computeMetadata(bases, properties, staticProperties); metadata.type = Kotlin.TYPE.CLASS; copyProperties(constructor, metadata.staticMembers); @@ -189,6 +180,19 @@ var Kotlin = {}; return constructor; }; + /** + * @param {(Array|Object|null)=} bases + * @param {(function(new: T, ?, ?, ?, ?, ?, ?, ?): T)|null=} constructor + * @param {Object=} properties + * @param {Object=} staticProperties + * @returns {function(new: T): T} + * @template T + */ + Kotlin.createClassNow = function (bases, constructor, properties, staticProperties) { + var metadata = computeMetadata(bases, properties, staticProperties); + return Kotlin.doCreateClass(metadata, constructor); + }; + Kotlin.defineInnerTypes = function(constructor, types) { for (var innerTypeName in types) { if (types.hasOwnProperty(innerTypeName)) { @@ -202,11 +206,20 @@ var Kotlin = {}; } }; - Kotlin.createObjectNow = function (bases, constructor, functions) { - var noNameClass = Kotlin.createClassNow(bases, constructor, functions); + Kotlin.createObjectNow = function (bases, constructor, functions, staticProperties) { + var metadata = computeMetadata(bases, functions, staticProperties); + var noNameClass = Kotlin.doCreateClass(metadata, constructor); var obj = new noNameClass(); noNameClass.$metadata$.type = Kotlin.TYPE.OBJECT; - return obj; + for (var innerTypeName in metadata.types) { + if (metadata.types.hasOwnProperty(innerTypeName)) { + Object.defineProperty(obj, innerTypeName, { + get : metadata.types[innerTypeName], + configurable: true + }); + } + } + return obj; }; Kotlin.createTraitNow = function (bases, properties, staticProperties) { @@ -243,7 +256,8 @@ var Kotlin = {}; */ Kotlin.createClass = function (basesFun, constructor, properties, staticProperties) { function $o() { - var klass = Kotlin.createClassNow(getBases(basesFun), constructor, properties, staticProperties); + var metadata = computeMetadata(getBases(basesFun), properties, staticProperties); + var klass = Kotlin.doCreateClass(metadata, constructor); Object.defineProperty(this, $o.className, {value: klass}); return klass; } @@ -313,11 +327,12 @@ var Kotlin = {}; * @param {function()|null} basesFun * @param {(function(new: T): T)|null=} constructor * @param {Object=} functions + * @param {Object=} staticProperties * @returns {Object} * @template T */ - Kotlin.createObject = function (basesFun, constructor, functions) { - return Kotlin.createObjectNow(getBases(basesFun), constructor, functions); + Kotlin.createObject = function (basesFun, constructor, functions, staticProperties) { + return Kotlin.createObjectNow(getBases(basesFun), constructor, functions, staticProperties); }; Kotlin.callGetter = function (thisObject, klass, propertyName) { diff --git a/js/js.translator/testData/nestedTypes/cases/instantiateInDerived.kt b/js/js.translator/testData/nestedTypes/cases/instantiateInDerived.kt deleted file mode 100644 index 7c1d58721f6..00000000000 --- a/js/js.translator/testData/nestedTypes/cases/instantiateInDerived.kt +++ /dev/null @@ -1,42 +0,0 @@ -package foo - -open class A(val value: String) { - inner class B(val s: String) { - val result = value + "_" + s - } -} - -class C : A("fromC") { - fun classReceiver() = B("OK") - fun superReceiver() = super.B("OK") - - fun newAReceiver() = A("fromA").B("OK") - fun aReceiver(): B { - val a = A("fromA") - return a.B("OK") - } - - fun A.extReceiver() = this.B("OK") - fun extReceiver() = A("fromA").extReceiver() -} - -fun box(): String { - val receiver = C() - var result = receiver.classReceiver().result - if (result != "fromC_OK") return "fail 1: $result" - - result = receiver.superReceiver().result - if (result != "fromC_OK") return "fail 2: $result" - - - result = receiver.aReceiver().result - if (result != "fromA_OK") return "fail 3: $result" - - result = receiver.newAReceiver().result - if (result != "fromA_OK") return "fail 3: $result" - - result = receiver.extReceiver().result - if (result != "fromA_OK") return "fail 3: $result" - - return "OK" -} \ No newline at end of file diff --git a/js/js.translator/testData/nestedTypes/cases/instantiateInDerivedLabeled.kt b/js/js.translator/testData/nestedTypes/cases/instantiateInDerivedLabeled.kt deleted file mode 100644 index 663cc946fa8..00000000000 --- a/js/js.translator/testData/nestedTypes/cases/instantiateInDerivedLabeled.kt +++ /dev/null @@ -1,44 +0,0 @@ -package foo - -open class A(val value: String) { - inner class B(val s: String) { - val result = value + "_" + s - } -} - -class C : A("fromC") { - - inner class X: A("fromX") { - fun classReceiver() = B("OK") - fun superReceiver() = super.B("OK") - fun superXReceiver() = super@X.B("OK") - fun superXCastReceiver() = (this@X as A).B("OK") - - fun superCReceiver() = super@C.B("OK") - fun superCCastReceiver() = (this@C as A).B("OK") - } -} - -fun box(): String { - val receiver = C().X() - var result = receiver.classReceiver().result - if (result != "fromX_OK") return "fail 1: $result" - - result = receiver.superReceiver().result - if (result != "fromX_OK") return "fail 2: $result" - - result = receiver.superXReceiver().result - if (result != "fromX_OK") return "fail 3: $result" - - result = receiver.superXCastReceiver().result - if (result != "fromX_OK") return "fail 4: $result" - - - result = receiver.superCReceiver().result - if (result != "fromC_OK") return "fail 5: $result" - - result = receiver.superCCastReceiver().result - if (result != "fromC_OK") return "fail 6: $result" - - return "OK" -} \ No newline at end of file diff --git a/js/js.translator/testData/nestedTypes/cases/instantiateInSameClass.kt b/js/js.translator/testData/nestedTypes/cases/instantiateInSameClass.kt deleted file mode 100644 index 60b9915aa4a..00000000000 --- a/js/js.translator/testData/nestedTypes/cases/instantiateInSameClass.kt +++ /dev/null @@ -1,36 +0,0 @@ -package foo - -class C(val value: String = "C") { - - inner class B(val s: String) { - val result = value + "_" + s - } - - fun classReceiver() = B("OK") - - fun newCReceiver() = C("newC").B("OK") - fun cReceiver(): B { - val c = C("newC") - return c.B("OK") - } - - fun C.extReceiver1() = this.B("OK") - fun extReceiver() = C("newC").extReceiver1() -} - -fun box(): String { - val receiver = C() - var result = receiver.classReceiver().result - if (result != "C_OK") return "fail 1: $result" - - result = receiver.cReceiver().result - if (result != "newC_OK") return "fail 3: $result" - - result = receiver.newCReceiver().result - if (result != "newC_OK") return "fail 3: $result" - - result = receiver.extReceiver().result - if (result != "newC_OK") return "fail 3: $result" - - return "OK" -} \ No newline at end of file diff --git a/js/js.translator/testData/nestedTypes/cases/outerCompanion.kt b/js/js.translator/testData/nestedTypes/cases/outerCompanion.kt new file mode 100644 index 00000000000..3c0fc47c633 --- /dev/null +++ b/js/js.translator/testData/nestedTypes/cases/outerCompanion.kt @@ -0,0 +1,29 @@ +package foo + +class A { + inner class B { + val x = foo(); + } + + class C { + val x = foo(); + } + + companion object { + fun foo(): String { + return "foo_result"; + } + } +} + +fun box(): String { + var result = A().B().x + if (result != "foo_result") { + return "fail1_" + result + } + result = A.C().x + if (result != "foo_result") { + return "fail2_" + result + } + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/nestedTypes/cases/outerObject.kt b/js/js.translator/testData/nestedTypes/cases/outerObject.kt new file mode 100644 index 00000000000..3112d8c9c80 --- /dev/null +++ b/js/js.translator/testData/nestedTypes/cases/outerObject.kt @@ -0,0 +1,24 @@ +package foo + +val q = "baz" + +object A { + val x = "foo" + + class B { + val y = x + "_bar" + val z = q + "_bar" + } +} + +fun box(): String { + var result = A.B().y + if (result != "foo_bar") { + return "failed1_" + result + } + result = A.B().z + if (result != "baz_bar") { + return "failed2_" + result + } + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/nestedTypes/cases/properOuter.kt b/js/js.translator/testData/nestedTypes/cases/properOuter.kt deleted file mode 100644 index 660a19b8119..00000000000 --- a/js/js.translator/testData/nestedTypes/cases/properOuter.kt +++ /dev/null @@ -1,17 +0,0 @@ -package foo - -open class A(val s: String) { - open inner class B(val s: String) { - fun testB() = s + this@A.s - } - - open inner class C(): A("C") { - fun testC() = - B("B_").testB() - } -} - -fun box(): String { - val res = A("A").C().testC() - return if (res == "B_C") "OK" else res; -} \ No newline at end of file