JS property accessors inlining (KT-13456)

This commit is contained in:
Anton Bannykh
2016-10-28 16:28:21 +03:00
parent 56ef09c09c
commit 0dc9121a91
24 changed files with 719 additions and 28 deletions
@@ -4505,6 +4505,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
doTest(fileName);
}
@TestMetadata("property.kt")
public void testProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/property.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inlineMultiModule/simple.kt");
@@ -0,0 +1,68 @@
/*
* 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.test.semantics;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
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/boxInline/property")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class PropertyAccessorsInlineTestsGenerated extends AbstractPropertyAccessorsInlineTests {
public void testAllFilesPresentInProperty() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/property"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("property.kt")
public void testProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/property/property.kt");
doTest(fileName);
}
@TestMetadata("reifiedVal.kt")
public void testReifiedVal() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/property/reifiedVal.kt");
doTest(fileName);
}
@TestMetadata("reifiedVar.kt")
public void testReifiedVar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/property/reifiedVar.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/property/simple.kt");
doTest(fileName);
}
@TestMetadata("simpleExtension.kt")
public void testSimpleExtension() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/property/simpleExtension.kt");
doTest(fileName);
}
}
@@ -29,6 +29,8 @@ abstract class BorrowedInlineTest(relativePath: String) : BasicBoxTest(
abstract class AbstractNonLocalReturnsTest : BorrowedInlineTest("nonLocalReturns/")
abstract class AbstractPropertyAccessorsInlineTests : BorrowedInlineTest("property/")
abstract class AbstractBoxJsTest() : BasicBoxTest(
BasicBoxTest.TEST_DATA_DIR_PATH + "box/",
BasicBoxTest.TEST_DATA_DIR_PATH + "out/box/"
@@ -53,6 +53,27 @@ public class DirectiveTestUtils {
}
};
private static final DirectiveHandler PROPERTY_NOT_USED = new DirectiveHandler("PROPERTY_NOT_USED") {
@Override
void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
checkPropertyNotUsed(ast, arguments.getFirst(), false, false);
}
};
private static final DirectiveHandler PROPERTY_NOT_READ_FROM = new DirectiveHandler("PROPERTY_NOT_READ_FROM") {
@Override
void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
checkPropertyNotUsed(ast, arguments.getFirst(), false, true);
}
};
private static final DirectiveHandler PROPERTY_NOT_WRITTEN_TO = new DirectiveHandler("PROPERTY_NOT_WRITTEN_TO") {
@Override
void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
checkPropertyNotUsed(ast, arguments.getFirst(), true, false);
}
};
private static final DirectiveHandler FUNCTION_CALLED_IN_SCOPE = new DirectiveHandler("CHECK_CALLED_IN_SCOPE") {
@Override
void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
@@ -232,6 +253,9 @@ public class DirectiveTestUtils {
private static final List<DirectiveHandler> DIRECTIVE_HANDLERS = Arrays.asList(
FUNCTION_CONTAINS_NO_CALLS,
FUNCTION_NOT_CALLED,
PROPERTY_NOT_USED,
PROPERTY_NOT_READ_FROM,
PROPERTY_NOT_WRITTEN_TO,
FUNCTION_CALLED_IN_SCOPE,
FUNCTION_NOT_CALLED_IN_SCOPE,
FUNCTIONS_HAVE_SAME_LINES,
@@ -261,6 +285,17 @@ public class DirectiveTestUtils {
assertEquals(errorMessage, 0, callsCount);
}
public static void checkPropertyNotUsed(JsNode node, String propertyName, boolean isGetAllowed, boolean isSetAllowed) throws Exception {
PropertyReferenceCollector counter = PropertyReferenceCollector.Companion.collect(node);
if (!isGetAllowed) {
assertFalse("inline property getter for `" + propertyName + "` is called", counter.hasUnqualifiedReads(propertyName));
}
if (!isSetAllowed) {
assertFalse("inline property setter for `" + propertyName + "` is called", counter.hasUnqualifiedWrites(propertyName));
}
}
public static void checkFunctionNotCalled(JsNode node, String functionName) throws Exception {
CallCounter counter = CallCounter.countCalls(node);
int functionCalledCount = counter.getQualifiedCallsCount(functionName);
@@ -0,0 +1,57 @@
/*
* 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.test.utils
import com.google.dart.compiler.backend.js.ast.*
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
class PropertyReferenceCollector : RecursiveJsVisitor() {
private val identReadSet = hashSetOf<String>()
private val identWriteSet = hashSetOf<String>()
fun hasUnqualifiedReads(expectedIdent: String) = expectedIdent in identReadSet
fun hasUnqualifiedWrites(expectedIdent: String) = expectedIdent in identWriteSet
override fun visitNameRef(nameRef: JsNameRef) {
super.visitNameRef(nameRef)
identReadSet.add(nameRef.ident)
}
override fun visitBinaryExpression(x: JsBinaryOperation) {
var assignmentToProperty = false
JsAstUtils.decomposeAssignment(x)?.let { (left, right) ->
(left as? JsNameRef)?.let { nameRef ->
assignmentToProperty = true
identWriteSet.add(nameRef.ident)
nameRef.qualifier?.accept(this)
right.accept(this)
}
}
if (!assignmentToProperty) {
super.visitBinaryExpression(x)
}
}
companion object {
fun collect(node: JsNode): PropertyReferenceCollector {
val visitor = PropertyReferenceCollector()
node.accept(visitor)
return visitor
}
}
}