diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index dc58687b2..f5f5d00da 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -20,159 +20,33 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java b/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java
index 1faa252d3..c752a1c4b 100644
--- a/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java
+++ b/core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java
@@ -388,6 +388,19 @@ class DependencyGraphBuilder {
DependencyNode node = nodes[receiver.getIndex()];
if (node != null) {
node.propagate(dependencyChecker.getType("java.lang.Class"));
+ if (!(cst instanceof ValueType.Primitive)) {
+ StringBuilder sb = new StringBuilder();
+ while (cst instanceof ValueType.Array) {
+ cst = ((ValueType.Array) cst).getItemType();
+ sb.append('[');
+ }
+ if (cst instanceof ValueType.Object) {
+ sb.append(((ValueType.Object) cst).getClassName());
+ } else {
+ sb.append(cst.toString());
+ }
+ node.getClassValueNode().propagate(dependencyChecker.getType(sb.toString()));
+ }
}
while (cst instanceof ValueType.Array) {
cst = ((ValueType.Array) cst).getItemType();
@@ -656,6 +669,10 @@ class DependencyGraphBuilder {
invokeVirtual(receiver, instance, method, arguments);
break;
}
+ if (method.getName().equals("getClass") && method.parameterCount() == 0
+ && method.getReturnType().isObject(Class.class) && receiver != null) {
+ nodes[instance.getIndex()].connect(nodes[receiver.getIndex()].getClassValueNode());
+ }
}
}
diff --git a/core/src/main/java/org/teavm/dependency/DependencyNode.java b/core/src/main/java/org/teavm/dependency/DependencyNode.java
index ae2085f99..e3907fef5 100644
--- a/core/src/main/java/org/teavm/dependency/DependencyNode.java
+++ b/core/src/main/java/org/teavm/dependency/DependencyNode.java
@@ -30,6 +30,7 @@ public class DependencyNode implements ValueDependencyInfo {
private List transitions;
private volatile String tag;
private DependencyNode arrayItemNode;
+ private DependencyNode classValueNode;
private int degree;
int index;
boolean locked;
@@ -201,6 +202,18 @@ public class DependencyNode implements ValueDependencyInfo {
return arrayItemNode;
}
+ public DependencyNode getClassValueNode() {
+ if (classValueNode == null) {
+ classValueNode = new DependencyNode(dependencyChecker, dependencyChecker.nodes.size(), degree);
+ dependencyChecker.nodes.add(classValueNode);
+ if (DependencyChecker.shouldLog) {
+ classValueNode.tag = tag + "@";
+ }
+ classValueNode.addConsumer(this::propagate);
+ }
+ return classValueNode;
+ }
+
@Override
public boolean hasArrayType() {
return arrayItemNode != null && (arrayItemNode.types != null || arrayItemNode.smallTypes != null);
diff --git a/core/src/main/java/org/teavm/dependency/DependencyNodeToNodeTransition.java b/core/src/main/java/org/teavm/dependency/DependencyNodeToNodeTransition.java
index e20b478cf..ef4d1b789 100644
--- a/core/src/main/java/org/teavm/dependency/DependencyNodeToNodeTransition.java
+++ b/core/src/main/java/org/teavm/dependency/DependencyNodeToNodeTransition.java
@@ -40,6 +40,9 @@ class DependencyNodeToNodeTransition implements DependencyConsumer {
source.getArrayItem().connect(destination.getArrayItem());
destination.getArrayItem().connect(source.getArrayItem());
}
+ if (type.getName().equals("java.lang.Class")) {
+ source.getClassValueNode().connect(destination.getClassValueNode());
+ }
if (!destination.hasType(type)) {
destination.propagate(type);
}
diff --git a/core/src/main/java/org/teavm/dependency/MethodDependencyInfo.java b/core/src/main/java/org/teavm/dependency/MethodDependencyInfo.java
index f8c334535..df16f04f5 100644
--- a/core/src/main/java/org/teavm/dependency/MethodDependencyInfo.java
+++ b/core/src/main/java/org/teavm/dependency/MethodDependencyInfo.java
@@ -30,9 +30,9 @@ public interface MethodDependencyInfo {
int getParameterCount();
- DependencyNode getResult();
+ ValueDependencyInfo getResult();
- DependencyNode getThrown();
+ ValueDependencyInfo getThrown();
MethodReference getReference();
diff --git a/core/src/main/java/org/teavm/dependency/ValueDependencyInfo.java b/core/src/main/java/org/teavm/dependency/ValueDependencyInfo.java
index 81e878ee6..fb5731c9c 100644
--- a/core/src/main/java/org/teavm/dependency/ValueDependencyInfo.java
+++ b/core/src/main/java/org/teavm/dependency/ValueDependencyInfo.java
@@ -26,5 +26,7 @@ public interface ValueDependencyInfo {
boolean hasArrayType();
- DependencyNode getArrayItem();
+ ValueDependencyInfo getArrayItem();
+
+ ValueDependencyInfo getClassValueNode();
}
diff --git a/tests/pom.xml b/tests/pom.xml
index cdaa41378..5ae754df0 100644
--- a/tests/pom.xml
+++ b/tests/pom.xml
@@ -60,6 +60,12 @@
junit
test
+
+ org.teavm
+ teavm-tooling
+ ${project.version}
+ test
+
diff --git a/tests/src/test/java/org/teavm/dependency/ClassValueTest.java b/tests/src/test/java/org/teavm/dependency/ClassValueTest.java
new file mode 100644
index 000000000..2dbb914ae
--- /dev/null
+++ b/tests/src/test/java/org/teavm/dependency/ClassValueTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2016 Alexey Andreev.
+ *
+ * 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.teavm.dependency;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import org.junit.Test;
+import org.teavm.model.MethodReference;
+import org.teavm.model.ValueType;
+import org.teavm.tooling.TeaVMProblemRenderer;
+import org.teavm.tooling.TeaVMToolLog;
+import org.teavm.vm.TeaVM;
+import org.teavm.vm.TeaVMBuilder;
+
+public class ClassValueTest {
+ @Test
+ public void simple() {
+ ValueDependencyInfo info = runTestWithConsume("simpleSnippet").getClassValueNode();
+ assertTrue("Long must be consumed", info.hasType("java.lang.Long"));
+ assertTrue("String must be consumed", info.hasType("java.lang.String"));
+ assertTrue("Nothing except Long and String expected", info.getTypes().length == 2);
+ }
+
+ @SuppressWarnings("unused")
+ public static void simpleSnippet() {
+ consume(Long.class);
+ consume(String.class);
+ }
+
+ @Test
+ public void fromGetClass() {
+ ValueDependencyInfo info = runTestWithConsume("fromGetClassSnippet").getClassValueNode();
+ assertTrue("Long must be consumed", info.hasType("java.lang.Long"));
+ assertTrue("String must be consumed", info.hasType("java.lang.String"));
+ assertTrue("Nothing except Long and String expected", info.getTypes().length == 2);
+ }
+
+ @SuppressWarnings("unused")
+ public static void fromGetClassSnippet() {
+ consumeClass(23L);
+ consumeClass("foo");
+ }
+
+ private static void consumeClass(Object value) {
+ consume(value.getClass());
+ }
+
+ protected static void consume(@SuppressWarnings("unused") Object value) {
+ // do nothing
+ }
+
+ private ValueDependencyInfo runTestWithConsume(String methodName) {
+ DependencyInfo info = runTest(methodName);
+ MethodDependencyInfo methodInfo = info.getMethod(new MethodReference(ClassValueTest.class, "consume",
+ Object.class, void.class));
+ if (methodInfo == null) {
+ fail("consume method never reached");
+ }
+ return methodInfo.getVariable(1);
+ }
+
+ private DependencyInfo runTest(String methodName) {
+ TeaVM vm = new TeaVMBuilder().build();
+ vm.installPlugins();
+ vm.entryPoint(new MethodReference(getClass().getName(), methodName, ValueType.VOID));
+ vm.build(new StringBuilder(), null);
+ if (!vm.getProblemProvider().getSevereProblems().isEmpty()) {
+ fail("Code compiled with errors:\n" + describeProblems(vm));
+ }
+ return vm.getDependencyInfo();
+ }
+
+ private String describeProblems(TeaVM vm) {
+ Log log = new Log();
+ TeaVMProblemRenderer.describeProblems(vm, log);
+ return log.sb.toString();
+ }
+
+
+ static class Log implements TeaVMToolLog {
+ StringBuilder sb = new StringBuilder();
+
+ @Override
+ public void info(String text) {
+ appendLine(text);
+ }
+
+ @Override
+ public void debug(String text) {
+ appendLine(text);
+ }
+
+ @Override
+ public void warning(String text) {
+ appendLine(text);
+ }
+
+ @Override
+ public void error(String text) {
+ appendLine(text);
+ }
+
+ @Override
+ public void info(String text, Throwable e) {
+ appendLine(text);
+ }
+
+ @Override
+ public void debug(String text, Throwable e) {
+ appendLine(text);
+ }
+
+ @Override
+ public void warning(String text, Throwable e) {
+ appendLine(text);
+ }
+
+ @Override
+ public void error(String text, Throwable e) {
+ appendLine(text);
+ }
+
+ private void appendLine(String text) {
+ sb.append(text).append('\n');
+ }
+ }
+}
diff --git a/tests/teavm-tests.iml b/tests/teavm-tests.iml
index 5e8336242..d0448738c 100644
--- a/tests/teavm-tests.iml
+++ b/tests/teavm-tests.iml
@@ -26,5 +26,6 @@
+
\ No newline at end of file