diff --git a/html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java b/html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java
index e58bb6fe5..f974bdffd 100644
--- a/html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java
+++ b/html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java
@@ -140,21 +140,101 @@ public class JavaScriptBodyDependency extends AbstractDependencyListener {
agent.linkMethod(JavaScriptConvGenerator.valueOfLongMethod, location).use();
}
- private static MethodReader findMethod(ClassReaderSource classSource, String clsName, MethodDescriptor desc) {
- while (clsName != null) {
- ClassReader cls = classSource.get(clsName);
- if (cls == null) {
- return null;
- }
- for (MethodReader method : cls.getMethods()) {
- if (method.getName().equals(desc.getName()) && sameParams(method.getDescriptor(), desc)) {
- return method;
- }
- }
- clsName = cls.getParent();
+ class GeneratorJsCallback extends JsCallback {
+ private DependencyAgent agent;
+ private MethodDependency caller;
+ private CallLocation location;
+
+ GeneratorJsCallback(DependencyAgent agent, MethodDependency caller, CallLocation location) {
+ this.agent = agent;
+ this.caller = caller;
+ this.location = location;
}
+
+ @Override
+ protected CharSequence callMethod(String ident, String fqn, String method, String params) {
+ MethodDescriptor desc = MethodDescriptor.parse(method + params + "V");
+ MethodReference methodRef = new MethodReference(fqn, desc);
+
+ MethodReader reader = findMethod(agent.getClassSource(), fqn, desc);
+ if (reader == null) {
+ agent.getDiagnostics().error(location, "Can't resolve method {{m0}}", methodRef);
+ }
+
+ methodRef = reader.getReference();
+ MethodDependency methodDep = agent.linkMethod(methodRef, location);
+ if (ident == null) {
+ reachedMethods.get(caller.getReference()).add(methodRef);
+ methodDep.use();
+ for (int i = 0; i < methodDep.getParameterCount(); ++i) {
+ allClassesNode.connect(methodDep.getVariable(i));
+ }
+ } else {
+ allClassesNode.addConsumer(new VirtualCallbackConsumer(agent, methodRef, location));
+ }
+
+ return "";
+ }
+ }
+
+ class VirtualCallbackConsumer implements DependencyConsumer {
+ private DependencyAgent agent;
+ private MethodReference superMethod;
+ private CallLocation location;
+
+ VirtualCallbackConsumer(DependencyAgent agent, MethodReference superMethod, CallLocation location) {
+ this.agent = agent;
+ this.superMethod = superMethod;
+ this.location = location;
+ }
+
+ @Override
+ public void consume(DependencyType type) {
+ if (!agent.getClassSource().isSuperType(superMethod.getClassName(), type.getName()).orElse(false)) {
+ return;
+ }
+ MethodReader method = agent.getClassSource().resolveImplementation(new MethodReference(
+ type.getName(), superMethod.getDescriptor()));
+ if (method == null) {
+ return;
+ }
+ MethodDependency methodDep = agent.linkMethod(method.getReference(), location);
+ methodDep.use();
+ for (int i = 0; i < methodDep.getParameterCount(); ++i) {
+ allClassesNode.connect(methodDep.getVariable(i));
+ }
+ }
+ }
+
+ static MethodReader findMethod(ClassReaderSource classSource, String clsName, MethodDescriptor desc) {
+ ClassReader cls = classSource.get(clsName);
+ if (cls == null) {
+ return null;
+ }
+
+ for (MethodReader method : cls.getMethods()) {
+ if (method.getName().equals(desc.getName()) && sameParams(method.getDescriptor(), desc)) {
+ return method;
+ }
+ }
+
+ if (cls.getParent() != null) {
+ MethodReader result = findMethod(classSource, cls.getParent(), desc);
+ if (result != null) {
+ return result;
+ }
+ }
+
+ for (String iface : cls.getInterfaces()) {
+ MethodReader result = findMethod(classSource, iface, desc);
+ if (result != null) {
+ return result;
+ }
+ }
+
return null;
}
+
private static boolean sameParams(MethodDescriptor a, MethodDescriptor b) {
if (a.parameterCount() != b.parameterCount()) {
return false;
@@ -166,57 +246,4 @@ public class JavaScriptBodyDependency extends AbstractDependencyListener {
}
return true;
}
-
- class GeneratorJsCallback extends JsCallback {
- private DependencyAgent agent;
- private MethodDependency caller;
- private CallLocation location;
- GeneratorJsCallback(DependencyAgent agent, MethodDependency caller, CallLocation location) {
- this.agent = agent;
- this.caller = caller;
- this.location = location;
- }
- @Override protected CharSequence callMethod(String ident, String fqn, String method, String params) {
- MethodDescriptor desc = MethodDescriptor.parse(method + params + "V");
- MethodReader reader = findMethod(agent.getClassSource(), fqn, desc);
- MethodReference ref = reader != null ? reader.getReference() : new MethodReference(fqn, desc);
- MethodDependency methodDep = agent.linkMethod(ref, location);
- reachedMethods.get(caller.getReference()).add(ref);
- if (!methodDep.isMissing()) {
- if (reader.hasModifier(ElementModifier.STATIC) || reader.hasModifier(ElementModifier.FINAL)) {
- methodDep.use();
- for (int i = 0; i < methodDep.getParameterCount(); ++i) {
- allClassesNode.connect(methodDep.getVariable(i));
- }
- } else {
- allClassesNode.addConsumer(new VirtualCallbackConsumer(agent, reader, caller));
- }
- }
- return "";
- }
- }
-
- class VirtualCallbackConsumer implements DependencyConsumer {
- private DependencyAgent agent;
- private MethodReader superMethod;
- private ClassReader superClass;
- private MethodDependency caller;
- VirtualCallbackConsumer(DependencyAgent agent, MethodReader superMethod, MethodDependency caller) {
- this.agent = agent;
- this.superMethod = superMethod;
- this.caller = caller;
- this.superClass = agent.getClassSource().get(superMethod.getOwnerName());
- }
- @Override public void consume(DependencyType type) {
- if (!agent.getClassSource().isSuperType(superClass.getName(), type.getName()).orElse(false)) {
- return;
- }
- MethodReference methodRef = new MethodReference(type.getName(), superMethod.getDescriptor());
- MethodDependency method = agent.linkMethod(methodRef, new CallLocation(caller.getReference()));
- method.use();
- for (int i = 0; i < method.getParameterCount(); ++i) {
- allClassesNode.connect(method.getVariable(i));
- }
- }
- }
}
diff --git a/html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java b/html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java
index cc5db7a61..0455afe3b 100644
--- a/html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java
+++ b/html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java
@@ -24,7 +24,6 @@ import org.teavm.backend.javascript.spi.Generator;
import org.teavm.backend.javascript.spi.GeneratorContext;
import org.teavm.model.AnnotationReader;
import org.teavm.model.AnnotationValue;
-import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.MethodDescriptor;
@@ -63,7 +62,7 @@ public class JavaScriptBodyGenerator implements Generator {
}
writer.append(");").softNewLine();
writer.append("return ");
- unwrapValue(context, writer, method.getResultType(), "result");
+ unwrapValue(context, writer, method.getResultType());
writer.append(";").softNewLine();
}
@@ -72,10 +71,10 @@ public class JavaScriptBodyGenerator implements Generator {
writer.append("(").append(param).append(")");
}
- private void unwrapValue(GeneratorContext context, SourceWriter writer, ValueType type, String param)
+ private void unwrapValue(GeneratorContext context, SourceWriter writer, ValueType type)
throws IOException {
writer.appendMethodBody(JavaScriptConvGenerator.fromJsMethod);
- writer.append("(").append(param).append(",").ws().append(context.typeToClassString(type))
+ writer.append("(").append("result").append(",").ws().append(context.typeToClassString(type))
.append(")");
}
@@ -83,20 +82,28 @@ public class JavaScriptBodyGenerator implements Generator {
private GeneratorContext context;
private ClassReaderSource classSource;
private NamingStrategy naming;
- public GeneratorJsCallback(GeneratorContext context, ClassReaderSource classSource, NamingStrategy naming) {
+
+ GeneratorJsCallback(GeneratorContext context, ClassReaderSource classSource, NamingStrategy naming) {
this.context = context;
this.classSource = classSource;
this.naming = naming;
}
- @Override protected CharSequence callMethod(String ident, String fqn, String method, String params) {
+
+ @Override
+ protected CharSequence callMethod(String ident, String fqn, String method, String params) {
MethodDescriptor desc = MethodDescriptor.parse(method + params + "V");
- MethodReader reader = findMethod(fqn, desc);
+ MethodReader reader = JavaScriptBodyDependency.findMethod(classSource, fqn, desc);
+ if (reader == null) {
+ return "";
+ }
+ desc = reader.getDescriptor();
+
StringBuilder sb = new StringBuilder();
sb.append("(function(");
if (ident != null) {
sb.append("$this");
}
- for (int i = 0; i < reader.parameterCount(); ++i) {
+ for (int i = 0; i < desc.parameterCount(); ++i) {
if (ident != null || i > 0) {
sb.append(", ");
}
@@ -106,14 +113,14 @@ public class JavaScriptBodyGenerator implements Generator {
if (ident == null) {
sb.append(naming.getFullNameFor(reader.getReference()));
} else {
- sb.append("$this.").append(naming.getNameFor(reader.getDescriptor()));
+ sb.append("$this.").append(naming.getNameFor(desc));
}
sb.append("(");
- for (int i = 0; i < reader.parameterCount(); ++i) {
+ for (int i = 0; i < desc.parameterCount(); ++i) {
if (i > 0) {
sb.append(", ");
}
- ValueType paramType = simplifyParamType(reader.parameterType(i));
+ ValueType paramType = simplifyParamType(desc.parameterType(i));
sb.append(naming.getFullNameFor(JavaScriptConvGenerator.fromJsMethod)).append("(p").append(i)
.append(", ")
.append(context.typeToClassString(paramType)).append(")");
@@ -124,6 +131,7 @@ public class JavaScriptBodyGenerator implements Generator {
}
return sb.toString();
}
+
private ValueType simplifyParamType(ValueType type) {
if (type instanceof ValueType.Object) {
return ValueType.object("java.lang.Object");
@@ -134,28 +142,5 @@ public class JavaScriptBodyGenerator implements Generator {
return type;
}
}
- private MethodReader findMethod(String clsName, MethodDescriptor desc) {
- while (clsName != null) {
- ClassReader cls = classSource.get(clsName);
- for (MethodReader method : cls.getMethods()) {
- if (method.getName().equals(desc.getName()) && sameParams(method.getDescriptor(), desc)) {
- return method;
- }
- }
- clsName = cls.getParent();
- }
- return null;
- }
- private boolean sameParams(MethodDescriptor a, MethodDescriptor b) {
- if (a.parameterCount() != b.parameterCount()) {
- return false;
- }
- for (int i = 0; i < a.parameterCount(); ++i) {
- if (!a.parameterType(i).equals(b.parameterType(i))) {
- return false;
- }
- }
- return true;
- }
}
}
diff --git a/html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyTest.java b/html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyTest.java
index 69077b7ee..727298153 100644
--- a/html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyTest.java
+++ b/html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyTest.java
@@ -21,7 +21,6 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
-import java.util.Calendar;
import net.java.html.js.JavaScriptBody;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -79,12 +78,9 @@ public class JavaScriptBodyTest {
@Test
public void unusedArgumentIgnored() {
- final int[] array = new int[1];
- invokeCallback(new Callback() {
- @Override
- public void exec(Calendar input) {
- array[0] = 23;
- }
+ int[] array = new int[1];
+ invokeCallback(input -> {
+ array[0] = 23;
});
assertEquals(23, array[0]);
}