JS: test metadata generation
This commit is contained in:
@@ -23,7 +23,8 @@ import java.util.IdentityHashMap
|
||||
import org.jetbrains.kotlin.js.inline.util.collectors.ReferenceNameCollector
|
||||
import org.jetbrains.kotlin.js.inline.util.collectors.NameCollector
|
||||
import org.jetbrains.kotlin.js.inline.util.collectors.InstanceCollector
|
||||
import org.jetbrains.kotlin.js.inline.util.collectors.FunctionCollector
|
||||
import org.jetbrains.kotlin.js.inline.util.collectors.PropertyCollector
|
||||
import org.jetbrains.kotlin.js.translate.expression.*
|
||||
|
||||
public fun collectFunctionReferencesInside(scope: JsNode): List<JsName> =
|
||||
collectReferencesInside(scope) filter { it.staticRef is JsFunction }
|
||||
@@ -44,11 +45,27 @@ public fun collectLocalNames(function: JsFunction): List<JsName> {
|
||||
}
|
||||
}
|
||||
|
||||
public fun collectJsProperties(scope: JsNode): IdentityHashMap<JsName, JsExpression> {
|
||||
val collector = PropertyCollector()
|
||||
collector.accept(scope)
|
||||
return collector.properties
|
||||
}
|
||||
|
||||
public fun collectNamedFunctions(scope: JsNode): IdentityHashMap<JsName, JsFunction> {
|
||||
return with(FunctionCollector()) {
|
||||
accept(scope)
|
||||
functions
|
||||
val namedFunctions = IdentityHashMap<JsName, JsFunction>()
|
||||
|
||||
for ((name, value) in collectJsProperties(scope)) {
|
||||
val function: JsFunction? = when (value) {
|
||||
is JsFunction -> value
|
||||
else -> InlineMetadata.decompose(value)?.function
|
||||
}
|
||||
|
||||
if (function != null) {
|
||||
namedFunctions[name] = function
|
||||
}
|
||||
}
|
||||
|
||||
return namedFunctions
|
||||
}
|
||||
|
||||
public fun collectInstances<T : JsNode>(klass: Class<T>, scope: JsNode): List<T> {
|
||||
|
||||
+3
-10
@@ -21,8 +21,8 @@ import org.jetbrains.kotlin.js.translate.expression.InlineMetadata
|
||||
|
||||
import java.util.IdentityHashMap
|
||||
|
||||
class FunctionCollector : RecursiveJsVisitor() {
|
||||
public val functions: IdentityHashMap<JsName, JsFunction> = IdentityHashMap()
|
||||
class PropertyCollector : RecursiveJsVisitor() {
|
||||
public val properties: IdentityHashMap<JsName, JsExpression> = IdentityHashMap()
|
||||
|
||||
override fun visitPropertyInitializer(x: JsPropertyInitializer?) {
|
||||
super.visitPropertyInitializer(x)
|
||||
@@ -32,13 +32,6 @@ class FunctionCollector : RecursiveJsVisitor() {
|
||||
if (name == null) return
|
||||
|
||||
val value = x?.getValueExpr()
|
||||
val function = when (value) {
|
||||
is JsFunction -> value
|
||||
else -> InlineMetadata.decompose(value)?.function
|
||||
}
|
||||
|
||||
if (function is JsFunction) {
|
||||
functions[name] = function
|
||||
}
|
||||
properties[name] = value
|
||||
}
|
||||
}
|
||||
@@ -252,6 +252,12 @@ public class InlineJsTestGenerated extends AbstractInlineJsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("metadataForPublicFunction.kt")
|
||||
public void testMetadataForPublicFunction() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/inline/cases/metadataForPublicFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noInlineLambda.kt")
|
||||
public void testNoInlineLambda() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/inline/cases/noInlineLambda.kt");
|
||||
|
||||
@@ -16,26 +16,41 @@
|
||||
|
||||
package org.jetbrains.kotlin.js.test.utils;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsFunction;
|
||||
import com.google.dart.compiler.backend.js.ast.JsName;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.kotlin.js.inline.util.UtilPackage.collectNamedFunctions;
|
||||
import static org.jetbrains.kotlin.js.inline.util.UtilPackage.collectJsProperties;
|
||||
|
||||
public class AstSearchUtil {
|
||||
@NotNull
|
||||
public static JsFunction getFunction(@NotNull JsNode searchRoot, String name) {
|
||||
Map<JsName, JsFunction> functions = collectNamedFunctions(searchRoot);
|
||||
JsFunction function = findByIdent(collectNamedFunctions(searchRoot), name);
|
||||
assert function != null: "Function `" + name + "` was not found";
|
||||
return function;
|
||||
}
|
||||
|
||||
for (Map.Entry<JsName, JsFunction> entry : functions.entrySet()) {
|
||||
@NotNull
|
||||
public static JsExpression getProperty(@NotNull JsNode searchRoot, @NotNull String name) {
|
||||
JsExpression property = findByIdent(collectJsProperties(searchRoot), name);
|
||||
assert property != null: "Property `" + name + "` was not found";
|
||||
return property;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static <T extends JsExpression> T findByIdent(@NotNull Map<JsName, T> properties, @NotNull String name) {
|
||||
for (Map.Entry<JsName, T> entry : properties.entrySet()) {
|
||||
if (entry.getKey().getIdent().equals(name)) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
throw new AssertionError("Function `" + name + "` was not found");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.js.test.utils;
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.JsExpression;
|
||||
import com.google.dart.compiler.backend.js.ast.JsFunction;
|
||||
import com.google.dart.compiler.backend.js.ast.JsLabel;
|
||||
import com.google.dart.compiler.backend.js.ast.JsNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.js.translate.expression.InlineMetadata;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -117,6 +119,26 @@ public class DirectiveTestUtils {
|
||||
}
|
||||
};
|
||||
|
||||
private static final DirectiveHandler HAS_INLINE_METADATA = new DirectiveHandler("CHECK_HAS_INLINE_METADATA") {
|
||||
@Override
|
||||
void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
|
||||
String functionName = arguments.getPositionalArgument(0);
|
||||
JsExpression property = AstSearchUtil.getProperty(ast, functionName);
|
||||
String message = "Inline metadata has not been generated for function " + functionName;
|
||||
assertNotNull(message, InlineMetadata.decompose(property));
|
||||
}
|
||||
};
|
||||
|
||||
private static final DirectiveHandler HAS_NO_INLINE_METADATA = new DirectiveHandler("CHECK_HAS_NO_INLINE_METADATA") {
|
||||
@Override
|
||||
void processEntry(@NotNull JsNode ast, @NotNull ArgumentsHelper arguments) throws Exception {
|
||||
String functionName = arguments.getPositionalArgument(0);
|
||||
JsExpression property = AstSearchUtil.getProperty(ast, functionName);
|
||||
String message = "Inline metadata has been generated for not effectively public function " + functionName;
|
||||
assertTrue(message, property instanceof JsFunction);
|
||||
}
|
||||
};
|
||||
|
||||
public static void processDirectives(@NotNull JsNode ast, @NotNull String sourceCode) throws Exception {
|
||||
FUNCTION_CONTAINS_NO_CALLS.process(ast, sourceCode);
|
||||
FUNCTION_NOT_CALLED.process(ast, sourceCode);
|
||||
@@ -124,6 +146,8 @@ public class DirectiveTestUtils {
|
||||
FUNCTION_NOT_CALLED_IN_SCOPE.process(ast, sourceCode);
|
||||
FUNCTIONS_HAVE_SAME_LINES.process(ast, sourceCode);
|
||||
COUNT_LABELS.process(ast, sourceCode);
|
||||
HAS_INLINE_METADATA.process(ast, sourceCode);
|
||||
HAS_NO_INLINE_METADATA.process(ast, sourceCode);
|
||||
}
|
||||
|
||||
public static void checkFunctionContainsNoCalls(JsNode node, String functionName) throws Exception {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package foo
|
||||
|
||||
// CHECK_CONTAINS_NO_CALLS: test1
|
||||
// CHECK_CONTAINS_NO_CALLS: test2
|
||||
// CHECK_CONTAINS_NO_CALLS: test3
|
||||
// CHECK_CONTAINS_NO_CALLS: test4
|
||||
// CHECK_CONTAINS_NO_CALLS: test5
|
||||
// CHECK_HAS_INLINE_METADATA: apply_hiyix$
|
||||
// CHECK_HAS_INLINE_METADATA: applyL_hiyix$
|
||||
// CHECK_HAS_INLINE_METADATA: applyM_hiyix$
|
||||
// CHECK_HAS_NO_INLINE_METADATA: applyN
|
||||
// CHECK_HAS_NO_INLINE_METADATA: applyO_hiyix$
|
||||
|
||||
inline
|
||||
public fun apply<T>(arg: T, func: (T)->T): T = func(arg)
|
||||
|
||||
public open class L {
|
||||
inline
|
||||
protected fun applyL<T>(arg: T, func: (T)->T): T = func(arg)
|
||||
}
|
||||
|
||||
public class M {
|
||||
inline
|
||||
public fun applyM<T>(arg: T, func: (T)->T): T = func(arg)
|
||||
}
|
||||
|
||||
private class N {
|
||||
inline
|
||||
public fun applyN<T>(arg: T, func: (T)->T): T = func(arg)
|
||||
}
|
||||
|
||||
private object O {
|
||||
public object OInner {
|
||||
inline
|
||||
public fun applyO<T>(arg: T, func: (T)->T): T = func(arg)
|
||||
}
|
||||
}
|
||||
|
||||
fun test1(x: Int, y: Int): Int = apply(x) { it * y }
|
||||
|
||||
fun test2(m: M, x: Int, y: Int): Int = m.applyM(x) { it * y }
|
||||
|
||||
fun test3(n: N, x: Int, y: Int): Int = n.applyN(x) { it * y }
|
||||
|
||||
object LTest : L() {
|
||||
fun test4(l: L, x: Int, y: Int): Int = l.applyL(x) { it * y }
|
||||
}
|
||||
|
||||
fun test5(x: Int, y: Int): Int = O.OInner.applyO(x) { it * y }
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(6, test1(2, 3))
|
||||
assertEquals(20, test1(5, 4))
|
||||
|
||||
assertEquals(6, test2(M(), 2, 3))
|
||||
assertEquals(20, test2(M(), 5, 4))
|
||||
|
||||
assertEquals(6, test3(N(), 2, 3))
|
||||
assertEquals(20, test3(N(), 5, 4))
|
||||
|
||||
assertEquals(6, LTest.test4(L(), 2, 3))
|
||||
assertEquals(20, LTest.test4(L(), 5, 4))
|
||||
|
||||
assertEquals(6, test5(2, 3))
|
||||
assertEquals(20, test5(5, 4))
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Reference in New Issue
Block a user