diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/EnumTransformer.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/EnumTransformer.java index ba5d33fb0..1fbbe3a61 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/EnumTransformer.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/EnumTransformer.java @@ -24,7 +24,7 @@ import org.teavm.model.*; */ public class EnumTransformer implements ClassHolderTransformer { @Override - public void transformClass(ClassHolder cls, ClassReaderSource innerSource) { + public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { if (cls.getParent() != null && !cls.getParent().equals("java.lang.Enum")) { return; } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/JavacSupport.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/JavacSupport.java index def1bef59..ba53ffc09 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/JavacSupport.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/JavacSupport.java @@ -27,7 +27,7 @@ import org.teavm.model.instructions.InvokeInstruction; */ public class JavacSupport implements ClassHolderTransformer { @Override - public void transformClass(ClassHolder cls, ClassReaderSource innerSource) { + public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { if (cls.getName().equals("javax.tools.ToolProvider")) { MethodHolder method = cls.getMethod(new MethodDescriptor("getSystemJavaCompiler", ValueType.object("javax.tools.JavaCompiler"))); diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyAgent.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyAgent.java index b8442f5dc..07cb02d55 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyAgent.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyAgent.java @@ -17,6 +17,7 @@ package org.teavm.dependency; import org.teavm.common.ServiceRepository; import org.teavm.model.ClassHolder; +import org.teavm.model.Diagnostics; import org.teavm.model.FieldReference; import org.teavm.model.MethodReference; @@ -38,4 +39,6 @@ public interface DependencyAgent extends DependencyInfo, ServiceRepository { ClassDependency linkClass(String className, final DependencyStack stack); FieldDependency linkField(FieldReference fieldRef, DependencyStack stack); + + Diagnostics getDiagnostics(); } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java index 955b3e4e6..d2bbfbd50 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java @@ -50,9 +50,12 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent { private DependencyViolations dependencyViolations; private DependencyCheckerInterruptor interruptor; private boolean interrupted; + private Diagnostics diagnostics; - public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services) { - this.classSource = new DependencyClassSource(classSource); + public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services, + Diagnostics diagnostics) { + this.diagnostics = diagnostics; + this.classSource = new DependencyClassSource(classSource, diagnostics); this.classLoader = classLoader; this.services = services; methodReaderCache = new CachedMapper<>(new Mapper() { @@ -431,23 +434,23 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent { return methodCache.getKnown(methodRef); } - public DependencyViolations getDependencyViolations() { + public DependencyViolations getViolations() { if (dependencyViolations == null) { dependencyViolations = new DependencyViolations(missingMethods, missingClasses, missingFields); } return dependencyViolations; } - public void checkForMissingItems() { - getDependencyViolations().checkForMissingItems(); + public void checkForViolations() { + getViolations().checkForViolations(); } - public boolean hasMissingItems() { - return getDependencyViolations().hasMissingItems(); + public boolean hasViolations() { + return getViolations().hasSevereViolations(); } - public void showMissingItems(Appendable sb) throws IOException { - getDependencyViolations().showMissingItems(sb); + public void showViolations(Appendable sb) throws IOException { + getViolations().showViolations(sb); } public void processDependencies() { @@ -469,4 +472,9 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent { public T getService(Class type) { return services.getService(type); } + + @Override + public Diagnostics getDiagnostics() { + return diagnostics; + } } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyClassSource.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyClassSource.java index 0dc82049f..681fb0df8 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyClassSource.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyClassSource.java @@ -22,10 +22,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.teavm.common.CachedMapper; import org.teavm.common.Mapper; -import org.teavm.model.ClassHolder; -import org.teavm.model.ClassHolderTransformer; -import org.teavm.model.ClassReader; -import org.teavm.model.ClassReaderSource; +import org.teavm.model.*; import org.teavm.model.util.ModelUtils; /** @@ -34,6 +31,7 @@ import org.teavm.model.util.ModelUtils; */ class DependencyClassSource implements ClassReaderSource { private ClassReaderSource innerSource; + private Diagnostics diagnostics; private ConcurrentMap generatedClasses = new ConcurrentHashMap<>(); private List transformers = new ArrayList<>(); private CachedMapper cache = new CachedMapper<>( @@ -43,8 +41,9 @@ class DependencyClassSource implements ClassReaderSource { } }); - public DependencyClassSource(ClassReaderSource innerSource) { + public DependencyClassSource(ClassReaderSource innerSource, Diagnostics diagnostics) { this.innerSource = innerSource; + this.diagnostics = diagnostics; } @Override @@ -65,7 +64,7 @@ class DependencyClassSource implements ClassReaderSource { ClassHolder cls = findClass(name); if (cls != null && !transformers.isEmpty()) { for (ClassHolderTransformer transformer : transformers) { - transformer.transformClass(cls, innerSource); + transformer.transformClass(cls, innerSource, diagnostics); } cls = ModelUtils.copyClass(cls); } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyDiagnostics.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyDiagnostics.java new file mode 100644 index 000000000..ac6cb6604 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyDiagnostics.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014 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 java.util.ArrayList; +import java.util.List; +import org.teavm.model.Diagnostics; +import org.teavm.model.InstructionLocation; +import org.teavm.vm.DiagnosticsProblem; +import org.teavm.vm.DiagnosticsProblemSeverity; + +/** + * + * @author Alexey Andreev + */ +class DependencyDiagnostics implements Diagnostics { + private List problems = new ArrayList<>(); + private List severeProblems = new ArrayList<>(); + + @Override + public void error(InstructionLocation location, String error) { + DiagnosticsProblem violation = new DiagnosticsProblem(DiagnosticsProblemSeverity.ERROR, location, error); + problems.add(violation); + severeProblems.add(violation); + } + + @Override + public void error(String error) { + error(null, error); + } + + @Override + public void warning(InstructionLocation location, String error) { + DiagnosticsProblem violation = new DiagnosticsProblem(DiagnosticsProblemSeverity.WARNING, location, error); + problems.add(violation); + } + + @Override + public void warning(String error) { + warning(null, error); + } + + public List getProblems() { + return problems; + } + + public List getSevereProblems() { + return severeProblems; + } +} diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyViolations.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyViolations.java index e04558d86..1e3d5997e 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyViolations.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyViolations.java @@ -47,24 +47,24 @@ public class DependencyViolations { return missingFields; } - public boolean hasMissingItems() { + public boolean hasSevereViolations() { return !missingMethods.isEmpty() || !missingClasses.isEmpty() || !missingFields.isEmpty(); } - public void checkForMissingItems() { - if (!hasMissingItems()) { + public void checkForViolations() { + if (!hasSevereViolations()) { return; } StringBuilder sb = new StringBuilder(); try { - showMissingItems(sb); + showViolations(sb); } catch (IOException e) { throw new AssertionError("StringBuilder should not throw IOException"); } throw new IllegalStateException(sb.toString()); } - public void showMissingItems(Appendable sb) throws IOException { + public void showViolations(Appendable sb) throws IOException { List items = new ArrayList<>(); Map stackMap = new HashMap<>(); for (ClassDependencyInfo cls : missingClasses) { @@ -80,15 +80,15 @@ public class DependencyViolations { items.add(field.getReference().toString()); } Collections.sort(items); - sb.append("Can't compile due to the following items missing:\n"); + sb.append("Can't compile due to the following violations:\n"); for (String item : items) { - sb.append(" ").append(item).append("\n"); + sb.append("Missing ").append(item).append("\n"); DependencyStack stack = stackMap.get(item); if (stack == null) { - sb.append(" at unknown location\n"); + sb.append(" at unknown location\n"); } else { while (stack.getMethod() != null) { - sb.append(" at ").append(stack.getMethod().toString()); + sb.append(" at ").append(stack.getMethod().toString()); if (stack.getLocation() != null) { sb.append(":").append(String.valueOf(stack.getLocation().getLine())); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/NullPointerExceptionTransformer.java b/teavm-core/src/main/java/org/teavm/javascript/NullPointerExceptionTransformer.java index f915886d9..3d66705cb 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/NullPointerExceptionTransformer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/NullPointerExceptionTransformer.java @@ -26,7 +26,7 @@ import org.teavm.model.instructions.NullCheckInstruction; */ public class NullPointerExceptionTransformer implements ClassHolderTransformer { @Override - public void transformClass(ClassHolder cls, ClassReaderSource innerSource) { + public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { for (MethodHolder method : cls.getMethods()) { Program program = method.getProgram(); if (program == null) { diff --git a/teavm-core/src/main/java/org/teavm/model/ClassHolderTransformer.java b/teavm-core/src/main/java/org/teavm/model/ClassHolderTransformer.java index 593360e11..4ae8cdcb0 100644 --- a/teavm-core/src/main/java/org/teavm/model/ClassHolderTransformer.java +++ b/teavm-core/src/main/java/org/teavm/model/ClassHolderTransformer.java @@ -15,10 +15,11 @@ */ package org.teavm.model; + /** * * @author Alexey Andreev */ public interface ClassHolderTransformer { - void transformClass(ClassHolder cls, ClassReaderSource innerSource); + void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics); } diff --git a/teavm-core/src/main/java/org/teavm/model/Diagnostics.java b/teavm-core/src/main/java/org/teavm/model/Diagnostics.java new file mode 100644 index 000000000..f7b046100 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/model/Diagnostics.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 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.model; + + +/** + * + * @author Alexey Andreev + */ +public interface Diagnostics { + void error(InstructionLocation location, String error); + + void error(String error); + + void warning(InstructionLocation location, String error); + + void warning(String error); +} diff --git a/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java b/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java index 634e82edc..979346193 100644 --- a/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java +++ b/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java @@ -345,12 +345,12 @@ public class TeaVMTool { } } - public DependencyViolations getDependencyViolations() { - return vm.getDependencyViolations(); + public DependencyViolations getViolations() { + return vm.getViolations(); } public void checkForMissingItems() { - vm.checkForMissingItems(); + vm.checkForViolations(); } private void copySourceFiles() { diff --git a/teavm-core/src/main/java/org/teavm/vm/DiagnosticsProblem.java b/teavm-core/src/main/java/org/teavm/vm/DiagnosticsProblem.java new file mode 100644 index 000000000..233d17ab7 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/vm/DiagnosticsProblem.java @@ -0,0 +1,46 @@ +/* + * Copyright 2014 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.vm; + +import org.teavm.model.InstructionLocation; + +/** + * + * @author Alexey Andreev + */ +public class DiagnosticsProblem { + private DiagnosticsProblemSeverity severity; + private InstructionLocation location; + private String text; + + public DiagnosticsProblem(DiagnosticsProblemSeverity severity, InstructionLocation location, String text) { + this.severity = severity; + this.location = location; + this.text = text; + } + + public DiagnosticsProblemSeverity getSeverity() { + return severity; + } + + public InstructionLocation getLocation() { + return location; + } + + public String getText() { + return text; + } +} diff --git a/teavm-core/src/main/java/org/teavm/vm/DiagnosticsProblemSeverity.java b/teavm-core/src/main/java/org/teavm/vm/DiagnosticsProblemSeverity.java new file mode 100644 index 000000000..8fa47a89f --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/vm/DiagnosticsProblemSeverity.java @@ -0,0 +1,25 @@ +/* + * Copyright 2014 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.vm; + +/** + * + * @author Alexey Andreev + */ +public enum DiagnosticsProblemSeverity { + ERROR, + WARNING +} diff --git a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java index 812a78191..a2479e3a4 100644 --- a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java @@ -291,7 +291,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { * Java class library methods. The behavior of this method before building is not specified.

*/ public boolean hasMissingItems() { - return dependencyChecker.hasMissingItems(); + return dependencyChecker.hasViolations(); } /** @@ -302,11 +302,11 @@ public class TeaVM implements TeaVMHost, ServiceRepository { * @param target where to append all dependency diagnostics errors. */ public void showMissingItems(Appendable target) throws IOException { - dependencyChecker.showMissingItems(target); + dependencyChecker.showViolations(target); } - public DependencyViolations getDependencyViolations() { - return dependencyChecker.getDependencyViolations(); + public DependencyViolations getViolations() { + return dependencyChecker.getViolations(); } public Collection getClasses() { @@ -327,8 +327,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository { * This can happen when you forgot some items in class path or when your code uses unimplemented * Java class library methods. The behavior of this method before building is not specified.

*/ - public void checkForMissingItems() { - dependencyChecker.checkForMissingItems(); + public void checkForViolations() { + dependencyChecker.checkForViolations(); } public DebugInformationEmitter getDebugEmitter() { @@ -344,7 +344,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { * are specified. This method may fail if there are items (classes, methods and fields) * that are required by entry points, but weren't found in classpath. In this case no * actual generation happens and no exceptions thrown, but you can further call - * {@link #checkForMissingItems()} or {@link #hasMissingItems()} to learn the build state.

+ * {@link #checkForViolations()} or {@link #hasMissingItems()} to learn the build state.

* * @param writer where to generate JavaScript. Should not be null. * @param target where to generate additional resources. Can be null, but if there are diff --git a/teavm-core/src/main/java/org/teavm/vm/Violations.java b/teavm-core/src/main/java/org/teavm/vm/Violations.java new file mode 100644 index 000000000..20d2f0ca1 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/vm/Violations.java @@ -0,0 +1,42 @@ +/* + * Copyright 2014 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.vm; + +import java.util.List; +import java.util.Set; +import org.teavm.dependency.ClassDependencyInfo; +import org.teavm.dependency.FieldDependencyInfo; +import org.teavm.dependency.MethodDependencyInfo; + +/** + * + * @author Alexey Andreev + */ +public interface Violations { + Set getMissingMethods(); + + Set getMissingClasses(); + + Set getMissingFields(); + + List getDiagnosticsProblems(); + + List getSevereDiagnosticsProblems(); + + boolean hasSevereViolations(); + + void checkForViolations(); +} diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JCLHacks.java b/teavm-html4j/src/main/java/org/teavm/html4j/JCLHacks.java index 7a0cbd850..1e4755d63 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JCLHacks.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JCLHacks.java @@ -24,7 +24,7 @@ import org.teavm.model.instructions.*; */ public class JCLHacks implements ClassHolderTransformer { @Override - public void transformClass(ClassHolder cls, ClassReaderSource innerSource) { + public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { if (cls.getName().equals("java.lang.Thread")) { installThreadMethods(cls); } diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyTransformer.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyTransformer.java index 4359fcc42..4298c01f2 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyTransformer.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyTransformer.java @@ -25,7 +25,7 @@ import org.teavm.model.*; */ public class JavaScriptBodyTransformer implements ClassHolderTransformer { @Override - public void transformClass(ClassHolder cls, ClassReaderSource innerSource) { + public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { for (MethodHolder method : cls.getMethods()) { if (method.getAnnotations().get(JavaScriptBody.class.getName()) != null) { AnnotationHolder genAnnot = new AnnotationHolder(GeneratedBy.class.getName()); diff --git a/teavm-jso/src/main/java/org/teavm/jso/plugin/JSObjectClassTransformer.java b/teavm-jso/src/main/java/org/teavm/jso/plugin/JSObjectClassTransformer.java index 6af34c710..cc82e5072 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/plugin/JSObjectClassTransformer.java +++ b/teavm-jso/src/main/java/org/teavm/jso/plugin/JSObjectClassTransformer.java @@ -15,10 +15,7 @@ */ package org.teavm.jso.plugin; -import org.teavm.model.ClassHolder; -import org.teavm.model.ClassHolderTransformer; -import org.teavm.model.ClassReaderSource; -import org.teavm.model.MethodHolder; +import org.teavm.model.*; /** * @@ -28,8 +25,9 @@ class JSObjectClassTransformer implements ClassHolderTransformer { private ThreadLocal processor = new ThreadLocal<>(); @Override - public void transformClass(ClassHolder cls, ClassReaderSource innerSource) { + public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { JavascriptNativeProcessor processor = getProcessor(innerSource); + processor.setDiagnostics(diagnostics); processor.processClass(cls); for (MethodHolder method : cls.getMethods()) { if (method.getProgram() != null) { diff --git a/teavm-jso/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java b/teavm-jso/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java index c3af8a24a..456966d75 100644 --- a/teavm-jso/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java +++ b/teavm-jso/src/main/java/org/teavm/jso/plugin/JavascriptNativeProcessor.java @@ -30,12 +30,17 @@ class JavascriptNativeProcessor { private Program program; private List replacement = new ArrayList<>(); private NativeJavascriptClassRepository nativeRepos; + private Diagnostics diagnostics; public JavascriptNativeProcessor(ClassReaderSource classSource) { this.classSource = classSource; nativeRepos = new NativeJavascriptClassRepository(classSource); } + public void setDiagnostics(Diagnostics diagnostics) { + this.diagnostics = diagnostics; + } + public void processClass(ClassHolder cls) { Set preservedMethods = new HashSet<>(); for (String iface : cls.getInterfaces()) { @@ -90,7 +95,7 @@ class JavascriptNativeProcessor { Variable result = invoke.getReceiver() != null ? program.createVariable() : null; addPropertyGet(propertyName, invoke.getInstance(), result); if (result != null) { - result = unwrap(result, method.getResultType()); + result = unwrap(insn.getLocation(), result, method.getResultType()); copyVar(result, invoke.getReceiver()); } } else if (isProperSetter(method.getDescriptor())) { @@ -101,11 +106,13 @@ class JavascriptNativeProcessor { } else { propertyName = cutPrefix(method.getName(), 3); } - Variable wrapped = wrapArgument(invoke.getArguments().get(0), method.parameterType(0)); + Variable wrapped = wrapArgument(insn.getLocation(), invoke.getArguments().get(0), + method.parameterType(0)); addPropertySet(propertyName, invoke.getInstance(), wrapped); } else { - throw new RuntimeException("Method " + invoke.getMethod() + " is not " + + diagnostics.error(insn.getLocation(), "Method " + invoke.getMethod() + " is not " + "a proper native JavaScript property declaration"); + continue; } } else if (method.getAnnotations().get(JSIndexer.class.getName()) != null) { if (isProperGetIndexer(method.getDescriptor())) { @@ -113,7 +120,7 @@ class JavascriptNativeProcessor { addIndexerGet(invoke.getInstance(), wrap(invoke.getArguments().get(0), method.parameterType(0)), result); if (result != null) { - result = unwrap(result, method.getResultType()); + result = unwrap(insn.getLocation(), result, method.getResultType()); copyVar(result, invoke.getReceiver()); } } else if (isProperSetIndexer(method.getDescriptor())) { @@ -121,8 +128,9 @@ class JavascriptNativeProcessor { Variable value = wrap(invoke.getArguments().get(1), method.parameterType(1)); addIndexerSet(invoke.getInstance(), index, value); } else { - throw new RuntimeException("Method " + invoke.getMethod() + " is not " + + diagnostics.error(insn.getLocation(), "Method " + invoke.getMethod() + " is not " + "a proper native JavaScript indexer declaration"); + continue; } } else { String name = method.getName(); @@ -130,16 +138,18 @@ class JavascriptNativeProcessor { boolean isConstructor = false; if (constructorAnnot != null) { if (!isSupportedType(method.getResultType())) { - throw new RuntimeException("Method " + invoke.getMethod() + " is not " + + diagnostics.error(insn.getLocation(), "Method " + invoke.getMethod() + " is not " + "a proper native JavaScript constructor declaration"); + continue; } AnnotationValue nameVal = constructorAnnot.getValue("value"); name = nameVal != null ? constructorAnnot.getValue("value").getString() : ""; if (name.isEmpty()) { if (!method.getName().startsWith("new") || method.getName().length() == 3) { - throw new RuntimeException("Method " + invoke.getMethod() + " is not " + + diagnostics.error(insn.getLocation(), "Method " + invoke.getMethod() + " is not " + "declared as a native JavaScript constructor, but its name does " + "not satisfy conventions"); + continue; } name = method.getName().substring(3); } @@ -153,14 +163,16 @@ class JavascriptNativeProcessor { } } if (method.getResultType() != ValueType.VOID && !isSupportedType(method.getResultType())) { - throw new RuntimeException("Method " + invoke.getMethod() + " is not " + + diagnostics.error(insn.getLocation(), "Method " + invoke.getMethod() + " is not " + "a proper native JavaScript method declaration"); + continue; } } for (ValueType arg : method.getParameterTypes()) { if (!isSupportedType(arg)) { - throw new RuntimeException("Method " + invoke.getMethod() + " is not " + + diagnostics.error(insn.getLocation(), "Method " + invoke.getMethod() + " is not " + "a proper native JavaScript method or constructor declaration"); + continue; } } Variable result = invoke.getReceiver() != null ? program.createVariable() : null; @@ -174,12 +186,13 @@ class JavascriptNativeProcessor { newInvoke.getArguments().add(invoke.getInstance()); newInvoke.getArguments().add(addStringWrap(addString(name))); for (int k = 0; k < invoke.getArguments().size(); ++k) { - Variable arg = wrapArgument(invoke.getArguments().get(k), method.parameterType(k)); + Variable arg = wrapArgument(insn.getLocation(), invoke.getArguments().get(k), + method.parameterType(k)); newInvoke.getArguments().add(arg); } replacement.add(newInvoke); if (result != null) { - result = unwrap(result, method.getResultType()); + result = unwrap(insn.getLocation(), result, method.getResultType()); copyVar(result, invoke.getReceiver()); } } @@ -254,7 +267,7 @@ class JavascriptNativeProcessor { return var; } - private Variable unwrap(Variable var, ValueType type) { + private Variable unwrap(InstructionLocation location, Variable var, ValueType type) { if (type instanceof ValueType.Primitive) { switch (((ValueType.Primitive)type).getKind()) { case BOOLEAN: @@ -290,7 +303,8 @@ class JavascriptNativeProcessor { return result; } } - throw new IllegalArgumentException("Unsupported type: " + type); + diagnostics.error(location, "Unsupported type: " + type); + return var; } private Variable unwrap(Variable var, String methodName, ValueType resultType) { @@ -305,20 +319,21 @@ class JavascriptNativeProcessor { return result; } - private Variable wrapArgument(Variable var, ValueType type) { + private Variable wrapArgument(InstructionLocation location, Variable var, ValueType type) { if (type instanceof ValueType.Object) { String className = ((ValueType.Object)type).getClassName(); ClassReader cls = classSource.get(className); if (cls.getAnnotations().get(JSFunctor.class.getName()) != null) { - return wrapFunctor(var, cls); + return wrapFunctor(location, var, cls); } } return wrap(var, type); } - private Variable wrapFunctor(Variable var, ClassReader type) { + private Variable wrapFunctor(InstructionLocation location, Variable var, ClassReader type) { if (!type.hasModifier(ElementModifier.INTERFACE) || type.getMethods().size() != 1) { - throw new RuntimeException("Wrong functor: " + type.getName()); + diagnostics.error(location, "Wrong functor: " + type.getName()); + return var; } String name = type.getMethods().iterator().next().getName(); Variable functor = program.createVariable(); diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderTransformer.java index f8d25aadf..bb1a04c61 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderTransformer.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/MetadataProviderTransformer.java @@ -25,7 +25,7 @@ import org.teavm.platform.metadata.MetadataProvider; */ class MetadataProviderTransformer implements ClassHolderTransformer { @Override - public void transformClass(ClassHolder cls, ClassReaderSource innerSource) { + public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { for (MethodHolder method : cls.getMethods()) { AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName()); if (providerAnnot == null) { diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java index 6a3819013..aed4fc2df 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceAccessorTransformer.java @@ -15,10 +15,7 @@ */ package org.teavm.platform.plugin; -import org.teavm.model.ClassHolder; -import org.teavm.model.ClassHolderTransformer; -import org.teavm.model.ClassReaderSource; -import org.teavm.model.MethodHolder; +import org.teavm.model.*; import org.teavm.vm.spi.TeaVMHost; /** @@ -33,7 +30,7 @@ class ResourceAccessorTransformer implements ClassHolderTransformer { } @Override - public void transformClass(ClassHolder cls, ClassReaderSource innerSource) { + public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { if (cls.getName().equals(ResourceAccessor.class.getName())) { ResourceAccessorGenerator generator = new ResourceAccessorGenerator(); for (MethodHolder method : cls.getMethods()) { diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java index f0b8854d2..2b29aae60 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/ResourceTransformer.java @@ -23,7 +23,7 @@ import org.teavm.model.*; */ class ResourceTransformer implements ClassHolderTransformer { @Override - public void transformClass(ClassHolder cls, ClassReaderSource innerSource) { + public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) { for (MethodHolder method : cls.getMethods()) { Program program = method.getProgram(); if (program != null) {