Make JSBody report about wrong parameter/returning type/instance type to

avoid confusion like this:
https://github.com/konsoletyper/teavm/issues/164
This commit is contained in:
Alexey Andreev 2015-12-25 19:04:54 +03:00
parent 5ae384538d
commit 0369d100c6
2 changed files with 134 additions and 0 deletions
jso/impl/src/main/java/org/teavm/jso/impl
tests/src/test/java/org/teavm/tests

View File

@ -356,6 +356,34 @@ class JSClassProcessor {
private boolean processJSBodyInvocation(MethodReader method, CallLocation callLocation, InvokeInstruction invoke,
MethodHolder methodToProcess) {
boolean valid = true;
for (int i = 0; i < method.parameterCount(); ++i) {
ValueType arg = method.parameterType(i);
if (!typeHelper.isSupportedType(arg)) {
diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript method "
+ " declaration. Its parameter #" + (i + 1) + " has invalid type {{t1}}", invoke.getMethod(),
arg);
valid = false;
}
}
if (invoke.getInstance() != null) {
if (!typeHelper.isSupportedType(ValueType.object(method.getOwnerName()))) {
diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript method "
+ " declaration. It is non-static and declared on a non-overlay class {{c1}}",
invoke.getMethod(), method.getOwnerName());
valid = false;
}
}
if (method.getResultType() != ValueType.VOID && !typeHelper.isSupportedType(method.getResultType())) {
diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript method "
+ " declaration, since it returns invalid type {{t1}}", invoke.getMethod(),
method.getResultType());
valid = false;
}
if (!valid) {
return false;
}
requireJSBody(diagnostics, method);
MethodReference delegate = repository.methodMap.get(method.getReference());
if (delegate == null) {

View File

@ -0,0 +1,106 @@
/*
* Copyright 2015 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.tests;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Test;
import org.teavm.diagnostics.Problem;
import org.teavm.jso.JSBody;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.vm.TeaVM;
import org.teavm.vm.TeaVMBuilder;
/**
*
* @author Alexey Andreev
*/
public class JSOTest {
@Test
public void reportsAboutWrongParameterOfJSBody() {
Problem foundProblem = build("callJSBodyWithWrongParameter").stream().filter(problem -> {
return problem.getLocation().getMethod().getName().equals("callJSBodyWithWrongParameter")
&& problem.getText().equals("Method {{m0}} is not a proper native JavaScript method "
+ " declaration. Its parameter #1 has invalid type {{t1}}");
}).findAny().orElse(null);
assertNotNull(foundProblem);
Object[] params = foundProblem.getParams();
assertThat(params[0], is(new MethodReference(JSOTest.class, "jsBodyWithWrongParameter",
Object.class, void.class)));
assertThat(params[1], is(ValueType.parse(Object.class)));
}
private static void callJSBodyWithWrongParameter() {
jsBodyWithWrongParameter(23);
}
@JSBody(params = "param", script = "alert(param.toString());")
private static native void jsBodyWithWrongParameter(Object param);
@Test
public void reportsAboutWrongNonStaticJSBody() {
Problem foundProblem = build("callWrongNonStaticJSBody").stream().filter(problem -> {
return problem.getLocation().getMethod().getName().equals("callWrongNonStaticJSBody")
&& problem.getText().equals("Method {{m0}} is not a proper native JavaScript method "
+ " declaration. It is non-static and declared on a non-overlay class {{c1}}");
}).findAny().orElse(null);
assertNotNull(foundProblem);
Object[] params = foundProblem.getParams();
assertThat(params[0], is(new MethodReference(JSOTest.class, "wrongNonStaticJSBody", void.class)));
assertThat(params[1], is(JSOTest.class.getName()));
}
private static void callWrongNonStaticJSBody() {
new JSOTest().wrongNonStaticJSBody();
}
@JSBody(params = {}, script = "alert(this.toString());")
private native void wrongNonStaticJSBody();
@Test
public void reportsAboutJSBodyWithWrongReturningType() {
Problem foundProblem = build("callJSBodyWithWrongReturningType").stream().filter(problem -> {
return problem.getLocation().getMethod().getName().equals("callJSBodyWithWrongReturningType")
&& problem.getText().equals("Method {{m0}} is not a proper native JavaScript method "
+ " declaration, since it returns invalid type {{t1}}");
}).findAny().orElse(null);
assertNotNull(foundProblem);
Object[] params = foundProblem.getParams();
assertThat(params[0], is(new MethodReference(JSOTest.class, "jsBodyWithWrongReturningType", String.class,
Object.class)));
assertThat(params[1], is(ValueType.parse(Object.class)));
}
private static void callJSBodyWithWrongReturningType() {
jsBodyWithWrongReturningType("foo");
}
@JSBody(params = "value", script = "return value;")
private static native Object jsBodyWithWrongReturningType(String value);
private List<Problem> build(String methodName) {
TeaVM vm = new TeaVMBuilder().build();
vm.installPlugins();
vm.entryPoint("test", new MethodReference(JSOTest.class, methodName, void.class));
vm.build(new StringBuilder(), null);
return vm.getProblemProvider().getSevereProblems();
}
}