diff --git a/teavm-core/src/main/java/org/teavm/callgraph/DefaultCallSite.java b/teavm-core/src/main/java/org/teavm/callgraph/DefaultCallSite.java index 04ea4fe86..badb1d35f 100644 --- a/teavm-core/src/main/java/org/teavm/callgraph/DefaultCallSite.java +++ b/teavm-core/src/main/java/org/teavm/callgraph/DefaultCallSite.java @@ -16,7 +16,6 @@ package org.teavm.callgraph; import java.util.Objects; -import org.teavm.model.CallLocation; import org.teavm.model.InstructionLocation; /** @@ -27,15 +26,11 @@ public class DefaultCallSite implements CallSite { private InstructionLocation location; private DefaultCallGraphNode callee; private DefaultCallGraphNode caller; - private CallLocation exactLocation; DefaultCallSite(InstructionLocation location, DefaultCallGraphNode callee, DefaultCallGraphNode caller) { this.location = location; this.callee = callee; this.caller = caller; - if (caller != null) { - exactLocation = new CallLocation(caller.getMethod(), location); - } } @Override @@ -43,10 +38,6 @@ public class DefaultCallSite implements CallSite { return location; } - public CallLocation getExactLocation() { - return exactLocation; - } - @Override public DefaultCallGraphNode getCallee() { return callee; diff --git a/teavm-core/src/main/java/org/teavm/diagnostics/DefaultProblemTextConsumer.java b/teavm-core/src/main/java/org/teavm/diagnostics/DefaultProblemTextConsumer.java index b1b45ca41..89a708737 100644 --- a/teavm-core/src/main/java/org/teavm/diagnostics/DefaultProblemTextConsumer.java +++ b/teavm-core/src/main/java/org/teavm/diagnostics/DefaultProblemTextConsumer.java @@ -18,6 +18,7 @@ package org.teavm.diagnostics; import org.teavm.model.FieldReference; import org.teavm.model.InstructionLocation; import org.teavm.model.MethodReference; +import org.teavm.model.ValueType; /** * @@ -58,4 +59,9 @@ public class DefaultProblemTextConsumer implements ProblemTextConsumer { public void appendLocation(InstructionLocation location) { sb.append(location); } + + @Override + public void appendType(ValueType type) { + sb.append(type); + } } diff --git a/teavm-core/src/main/java/org/teavm/diagnostics/Problem.java b/teavm-core/src/main/java/org/teavm/diagnostics/Problem.java index 7204922a3..09be05f31 100644 --- a/teavm-core/src/main/java/org/teavm/diagnostics/Problem.java +++ b/teavm-core/src/main/java/org/teavm/diagnostics/Problem.java @@ -16,10 +16,7 @@ package org.teavm.diagnostics; import java.util.Arrays; -import org.teavm.model.CallLocation; -import org.teavm.model.FieldReference; -import org.teavm.model.InstructionLocation; -import org.teavm.model.MethodReference; +import org.teavm.model.*; /** * @@ -81,6 +78,9 @@ public class Problem { case 'c': type = ParamType.CLASS; break; + case 't': + type = ParamType.TYPE; + break; case 'm': type = ParamType.METHOD; break; @@ -113,6 +113,12 @@ public class Problem { } consumer.appendClass((String)param); break; + case TYPE: + if (!(param instanceof ValueType)) { + return index; + } + consumer.appendType((ValueType)param); + break; case METHOD: if (!(param instanceof MethodReference)) { return index; @@ -145,6 +151,7 @@ public class Problem { enum ParamType { CLASS, + TYPE, METHOD, FIELD, LOCATION diff --git a/teavm-core/src/main/java/org/teavm/diagnostics/ProblemTextConsumer.java b/teavm-core/src/main/java/org/teavm/diagnostics/ProblemTextConsumer.java index 8f074787b..eebf4ac06 100644 --- a/teavm-core/src/main/java/org/teavm/diagnostics/ProblemTextConsumer.java +++ b/teavm-core/src/main/java/org/teavm/diagnostics/ProblemTextConsumer.java @@ -18,6 +18,7 @@ package org.teavm.diagnostics; import org.teavm.model.FieldReference; import org.teavm.model.InstructionLocation; import org.teavm.model.MethodReference; +import org.teavm.model.ValueType; /** * @@ -28,6 +29,8 @@ public interface ProblemTextConsumer { void appendClass(String className); + void appendType(ValueType type); + void appendMethod(MethodReference method); void appendField(FieldReference field); diff --git a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectBuilder.java b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectBuilder.java index 9b5fd7bc8..6eccb600c 100644 --- a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectBuilder.java +++ b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectBuilder.java @@ -65,10 +65,6 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder { SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, TICKS_PER_PROFILE); buildProfile(kind, subMonitor, profile, classLoader); } - IMarker[] markers = getProject().findMarkers(TeaVMEclipsePlugin.PROBLEM_MARKER_ID, true, IResource.DEPTH_INFINITE); - for (IMarker marker : markers) { - System.out.println("MARKER INSTALLED: " + marker.getId()); - } } finally { monitor.done(); sourceContainers = null; @@ -131,7 +127,8 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder { monitor.beginTask("Running TeaVM", 10000); tool.generate(); if (!tool.wasCancelled()) { - putMarkers(tool.getDependencyInfo().getCallGraph(), tool.getProblemProvider().getProblems()); + putMarkers(tool.getDependencyInfo().getCallGraph(), tool.getProblemProvider().getProblems(), + profile); setClasses(profile, classesToResources(tool.getClasses())); refreshTarget(tool.getTargetDirectory()); } @@ -235,80 +232,88 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder { for (IMarker marker : markers) { String projectName = (String)marker.getAttribute(TeaVMEclipsePlugin.PROBLEM_MARKER_PROJECT_ATTRIBUTE); String profileName = (String)marker.getAttribute(TeaVMEclipsePlugin.PROBLEM_MARKER_PROFILE_ATTRIBUTE); - if (projectName.equals(getProject().getName()) && profileName.equals(profile.getName())) { + if (projectName.equals(getProject().getName()) && (profileName == null || + profileName.equals(profile.getName()))) { marker.delete(); - System.out.println("MARKER REMOVED: " + marker.getId() + " while building project " + - getProject().getName()); } } } getProject().deleteMarkers(TeaVMEclipsePlugin.CONFIG_MARKER_ID, true, IResource.DEPTH_INFINITE); } - private void putMarkers(CallGraph cg, List problems) throws CoreException { + private void putMarkers(CallGraph cg, List problems, TeaVMProfile profile) throws CoreException { for (Problem problem : problems) { - putMarker(cg, problem); + putMarker(cg, problem, profile); } } - private void putMarker(CallGraph cg, Problem problem) throws CoreException { + private void putMarker(CallGraph cg, Problem problem, TeaVMProfile profile) throws CoreException { if (problem.getLocation() == null || problem.getLocation().getMethod() == null) { - putMarkerAtDefaultLocation(problem); + putMarkerAtDefaultLocation(problem, profile); return; } CallGraphNode problemNode = cg.getNode(problem.getLocation().getMethod()); if (problemNode == null) { - putMarkerAtDefaultLocation(problem); + putMarkerAtDefaultLocation(problem, profile); return; } - Set callSites = new HashSet<>(); - collectCallSites(callSites, problemNode); String messagePrefix = problemAsString(problem); - boolean wasPut = false; - for (CallSite callSite : callSites) { - IResource resource = findResource(new CallLocation(callSite.getCaller().getMethod(), - callSite.getLocation())); - if (resource == null) { - continue; - } - wasPut = true; - CallGraphNode node = problemNode; - StringBuilder sb = new StringBuilder(messagePrefix); - while (node != callSite.getCaller()) { - sb.append(", used by ").append(getFullMethodName(node.getMethod())); - Iterator callerCallSites = node.getCallerCallSites().iterator(); - if (!callerCallSites.hasNext()) { - break; - } - node = callerCallSites.next().getCaller(); - } - putMarker(resource, callSite.getLocation(), callSite.getCaller().getMethod(), sb.toString()); - } IResource resource = findResource(problem.getLocation()); + boolean wasPut = false; if (resource != null) { - putMarker(resource, problem.getLocation().getSourceLocation(), problem.getLocation().getMethod(), - messagePrefix); - wasPut = true; + wasPut |= putMarker(resource, problem.getLocation().getSourceLocation(), problem.getLocation().getMethod(), + messagePrefix, profile, false); } if (!wasPut) { - putMarkerAtDefaultLocation(problem); + wasPut |= putMarkersAtCallSites(problemNode, new HashSet(), messagePrefix, profile, + false); + } + if (!wasPut) { + wasPut |= putMarkersAtCallSites(problemNode, new HashSet(), messagePrefix, profile, true); + } + if (!wasPut) { + putMarkerAtDefaultLocation(problem, profile); } } - private void putMarker(IResource resource, InstructionLocation location, MethodReference method, - String text) throws CoreException { - IMarker marker = resource.createMarker(TeaVMEclipsePlugin.PROBLEM_MARKER_ID); - marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR); - marker.setAttribute(IMarker.MESSAGE, text); - marker.setAttribute(TeaVMEclipsePlugin.PROBLEM_MARKER_PROJECT_ATTRIBUTE, getProject().getName()); + private boolean putMarkersAtCallSites(CallGraphNode node, Set visited, String problem, + TeaVMProfile profile, boolean force) throws CoreException { + if (!visited.add(node)) { + return false; + } + boolean wasPut = true; + for (CallSite callSite : node.getCallerCallSites()) { + IResource resource = findResource(new CallLocation(callSite.getCaller().getMethod(), + callSite.getLocation())); + if (resource != null) { + wasPut = putMarker(resource, callSite.getLocation(), callSite.getCaller().getMethod(), problem, + profile, force); + } + wasPut |= putMarkersAtCallSites(callSite.getCaller(), visited, problem + ", used by " + + getFullMethodName(callSite.getCaller().getMethod()), profile, force); + } + return wasPut; + } + + private boolean putMarker(IResource resource, InstructionLocation location, MethodReference method, + String text, TeaVMProfile profile, boolean force) throws CoreException { Integer lineNumber = location != null ? location.getLine() : null; if (lineNumber == null) { lineNumber = findMethodLocation(method, resource); } if (lineNumber == null) { + if (!force) { + return false; + } lineNumber = 1; } + IMarker marker = resource.createMarker(TeaVMEclipsePlugin.PROBLEM_MARKER_ID); + marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR); + marker.setAttribute(IMarker.MESSAGE, text); + marker.setAttribute(TeaVMEclipsePlugin.PROBLEM_MARKER_PROJECT_ATTRIBUTE, getProject().getName()); + marker.setAttribute(TeaVMEclipsePlugin.PROBLEM_MARKER_PROFILE_ATTRIBUTE, profile.getName()); marker.setAttribute(IMarker.LINE_NUMBER, lineNumber); + return true; } private IResource findResource(CallLocation location) { @@ -334,19 +339,12 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder { return resource; } - private void collectCallSites(Set callSites, CallGraphNode node) { - for (CallSite callSite : node.getCallerCallSites()) { - if (callSites.add(callSite)) { - collectCallSites(callSites, callSite.getCaller()); - } - } - } - - private void putMarkerAtDefaultLocation(Problem problem) throws CoreException { + private void putMarkerAtDefaultLocation(Problem problem, TeaVMProfile profile) throws CoreException { IMarker marker = getProject().createMarker(TeaVMEclipsePlugin.PROBLEM_MARKER_ID); marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR); marker.setAttribute(IMarker.MESSAGE, problemAsString(problem)); marker.setAttribute(TeaVMEclipsePlugin.PROBLEM_MARKER_PROJECT_ATTRIBUTE, getProject().getName()); + marker.setAttribute(TeaVMEclipsePlugin.PROBLEM_MARKER_PROFILE_ATTRIBUTE, profile.getName()); } private Integer findMethodLocation(MethodReference methodRef, IResource resource) throws CoreException { @@ -364,12 +362,12 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder { } for (IMethod method : type.getMethods()) { StringBuilder sb = new StringBuilder(); - sb.append('('); + sb.append(method.getElementName()).append('('); for (String paramType : method.getParameterTypes()) { sb.append(Signature.getTypeErasure(paramType)); } sb.append(')').append(Signature.getTypeErasure(method.getReturnType())); - if (sb.toString().equals(methodRef.toString())) { + if (sb.toString().equals(methodRef.getDescriptor().toString())) { return getLineNumber(method); } } @@ -401,6 +399,9 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder { @Override public void appendClass(String cls) { sb.append(getSimpleClassName(cls)); } + @Override public void appendType(ValueType type) { + sb.append(getTypeName(type)); + } @Override public void append(String text) { sb.append(text); } @@ -472,7 +473,7 @@ public class TeaVMProjectBuilder extends IncrementalProjectBuilder { private String getSimpleClassName(String className) { int index = className.lastIndexOf('.'); - return className.substring(index + 1); + return className.substring(index + 1).replace('$', '.'); } private TeaVMProjectSettings getProjectSettings() { 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 6f4a6bb3b..6c43ad759 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 @@ -95,10 +95,10 @@ class JavascriptNativeProcessor { cutPrefix(method.getName(), 3); } Variable result = invoke.getReceiver() != null ? program.createVariable() : null; - addPropertyGet(propertyName, invoke.getInstance(), result); + addPropertyGet(propertyName, invoke.getInstance(), result, invoke.getLocation()); if (result != null) { result = unwrap(callLocation, result, method.getResultType()); - copyVar(result, invoke.getReceiver()); + copyVar(result, invoke.getReceiver(), invoke.getLocation()); } } else if (isProperSetter(method.getDescriptor())) { String propertyName; @@ -110,28 +110,30 @@ class JavascriptNativeProcessor { } Variable wrapped = wrapArgument(callLocation, invoke.getArguments().get(0), method.parameterType(0)); - addPropertySet(propertyName, invoke.getInstance(), wrapped); + addPropertySet(propertyName, invoke.getInstance(), wrapped, invoke.getLocation()); } else { - diagnostics.error(callLocation, "Method " + invoke.getMethod() + " is not " + - "a proper native JavaScript property declaration"); + diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript property " + + "declaration", invoke.getMethod()); continue; } } else if (method.getAnnotations().get(JSIndexer.class.getName()) != null) { if (isProperGetIndexer(method.getDescriptor())) { Variable result = invoke.getReceiver() != null ? program.createVariable() : null; addIndexerGet(invoke.getInstance(), wrap(invoke.getArguments().get(0), - method.parameterType(0)), result); + method.parameterType(0), invoke.getLocation()), result, invoke.getLocation()); if (result != null) { result = unwrap(callLocation, result, method.getResultType()); - copyVar(result, invoke.getReceiver()); + copyVar(result, invoke.getReceiver(), invoke.getLocation()); } } else if (isProperSetIndexer(method.getDescriptor())) { - Variable index = wrap(invoke.getArguments().get(0), method.parameterType(0)); - Variable value = wrap(invoke.getArguments().get(1), method.parameterType(1)); - addIndexerSet(invoke.getInstance(), index, value); + Variable index = wrap(invoke.getArguments().get(0), method.parameterType(0), + invoke.getLocation()); + Variable value = wrap(invoke.getArguments().get(1), method.parameterType(1), + invoke.getLocation()); + addIndexerSet(invoke.getInstance(), index, value, invoke.getLocation()); } else { - diagnostics.error(callLocation, "Method " + invoke.getMethod() + " is not " + - "a proper native JavaScript indexer declaration"); + diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript indexer " + + "declaration", invoke.getMethod()); continue; } } else { @@ -140,17 +142,17 @@ class JavascriptNativeProcessor { boolean isConstructor = false; if (constructorAnnot != null) { if (!isSupportedType(method.getResultType())) { - diagnostics.error(callLocation, "Method " + invoke.getMethod() + " is not " + - "a proper native JavaScript constructor declaration"); + diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript " + + "constructor declaration", invoke.getMethod()); 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) { - diagnostics.error(callLocation, "Method " + invoke.getMethod() + " is not " + - "declared as a native JavaScript constructor, but its name does " + - "not satisfy conventions"); + diagnostics.error(callLocation, "Method {{m0}} is not declared as a native " + + "JavaScript constructor, but its name does not satisfy conventions", + invoke.getMethod()); continue; } name = method.getName().substring(3); @@ -165,15 +167,15 @@ class JavascriptNativeProcessor { } } if (method.getResultType() != ValueType.VOID && !isSupportedType(method.getResultType())) { - diagnostics.error(callLocation, "Method " + invoke.getMethod() + " is not " + - "a proper native JavaScript method declaration"); + diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript method " + + "declaration", invoke.getMethod()); continue; } } for (ValueType arg : method.getParameterTypes()) { if (!isSupportedType(arg)) { - diagnostics.error(callLocation, "Method " + invoke.getMethod() + " is not " + - "a proper native JavaScript method or constructor declaration"); + diagnostics.error(callLocation, "Method {{m0}} is not a proper native JavaScript method " + + "or constructor declaration", invoke.getMethod()); continue; } } @@ -186,7 +188,9 @@ class JavascriptNativeProcessor { newInvoke.setType(InvocationType.SPECIAL); newInvoke.setReceiver(result); newInvoke.getArguments().add(invoke.getInstance()); - newInvoke.getArguments().add(addStringWrap(addString(name))); + newInvoke.getArguments().add(addStringWrap(addString(name, invoke.getLocation()), + invoke.getLocation())); + newInvoke.setLocation(invoke.getLocation()); for (int k = 0; k < invoke.getArguments().size(); ++k) { Variable arg = wrapArgument(callLocation, invoke.getArguments().get(k), method.parameterType(k)); @@ -195,7 +199,7 @@ class JavascriptNativeProcessor { replacement.add(newInvoke); if (result != null) { result = unwrap(callLocation, result, method.getResultType()); - copyVar(result, invoke.getReceiver()); + copyVar(result, invoke.getReceiver(), invoke.getLocation()); } } block.getInstructions().set(j, replacement.get(0)); @@ -205,19 +209,21 @@ class JavascriptNativeProcessor { } } - private void addPropertyGet(String propertyName, Variable instance, Variable receiver) { - Variable nameVar = addStringWrap(addString(propertyName)); + private void addPropertyGet(String propertyName, Variable instance, Variable receiver, + InstructionLocation location) { + Variable nameVar = addStringWrap(addString(propertyName, location), location); InvokeInstruction insn = new InvokeInstruction(); insn.setType(InvocationType.SPECIAL); insn.setMethod(new MethodReference(JS.class, "get", JSObject.class, JSObject.class, JSObject.class)); insn.setReceiver(receiver); insn.getArguments().add(instance); insn.getArguments().add(nameVar); + insn.setLocation(location); replacement.add(insn); } - private void addPropertySet(String propertyName, Variable instance, Variable value) { - Variable nameVar = addStringWrap(addString(propertyName)); + private void addPropertySet(String propertyName, Variable instance, Variable value, InstructionLocation location) { + Variable nameVar = addStringWrap(addString(propertyName, location), location); InvokeInstruction insn = new InvokeInstruction(); insn.setType(InvocationType.SPECIAL); insn.setMethod(new MethodReference(JS.class, "set", JSObject.class, JSObject.class, @@ -225,20 +231,22 @@ class JavascriptNativeProcessor { insn.getArguments().add(instance); insn.getArguments().add(nameVar); insn.getArguments().add(value); + insn.setLocation(location); replacement.add(insn); } - private void addIndexerGet(Variable array, Variable index, Variable receiver) { + private void addIndexerGet(Variable array, Variable index, Variable receiver, InstructionLocation location) { InvokeInstruction insn = new InvokeInstruction(); insn.setType(InvocationType.SPECIAL); insn.setMethod(new MethodReference(JS.class, "get", JSObject.class, JSObject.class, JSObject.class)); insn.setReceiver(receiver); insn.getArguments().add(array); insn.getArguments().add(index); + insn.setLocation(location); replacement.add(insn); } - private void addIndexerSet(Variable array, Variable index, Variable value) { + private void addIndexerSet(Variable array, Variable index, Variable value, InstructionLocation location) { InvokeInstruction insn = new InvokeInstruction(); insn.setType(InvocationType.SPECIAL); insn.setMethod(new MethodReference(JS.class, "set", JSObject.class, JSObject.class, @@ -246,25 +254,28 @@ class JavascriptNativeProcessor { insn.getArguments().add(array); insn.getArguments().add(index); insn.getArguments().add(value); + insn.setLocation(location); replacement.add(insn); } - private void copyVar(Variable a, Variable b) { + private void copyVar(Variable a, Variable b, InstructionLocation location) { AssignInstruction insn = new AssignInstruction(); insn.setAssignee(a); insn.setReceiver(b); + insn.setLocation(location); replacement.add(insn); } - private Variable addStringWrap(Variable var) { - return wrap(var, ValueType.object("java.lang.String")); + private Variable addStringWrap(Variable var, InstructionLocation location) { + return wrap(var, ValueType.object("java.lang.String"), location); } - private Variable addString(String str) { + private Variable addString(String str, InstructionLocation location) { Variable var = program.createVariable(); StringConstantInstruction nameInsn = new StringConstantInstruction(); nameInsn.setReceiver(var); nameInsn.setConstant(str); + nameInsn.setLocation(location); replacement.add(nameInsn); return var; } @@ -273,19 +284,19 @@ class JavascriptNativeProcessor { if (type instanceof ValueType.Primitive) { switch (((ValueType.Primitive)type).getKind()) { case BOOLEAN: - return unwrap(var, "unwrapBoolean", ValueType.BOOLEAN); + return unwrap(var, "unwrapBoolean", ValueType.BOOLEAN, location.getSourceLocation()); case BYTE: - return unwrap(var, "unwrapByte", ValueType.BYTE); + return unwrap(var, "unwrapByte", ValueType.BYTE, location.getSourceLocation()); case SHORT: - return unwrap(var, "unwrapShort", ValueType.SHORT); + return unwrap(var, "unwrapShort", ValueType.SHORT, location.getSourceLocation()); case INTEGER: - return unwrap(var, "unwrapInt", ValueType.INTEGER); + return unwrap(var, "unwrapInt", ValueType.INTEGER, location.getSourceLocation()); case CHARACTER: - return unwrap(var, "unwrapCharacter", ValueType.CHARACTER); + return unwrap(var, "unwrapCharacter", ValueType.CHARACTER, location.getSourceLocation()); case DOUBLE: - return unwrap(var, "unwrapDouble", ValueType.DOUBLE); + return unwrap(var, "unwrapDouble", ValueType.DOUBLE, location.getSourceLocation()); case FLOAT: - return unwrap(var, "unwrapFloat", ValueType.FLOAT); + return unwrap(var, "unwrapFloat", ValueType.FLOAT, location.getSourceLocation()); case LONG: break; } @@ -294,22 +305,23 @@ class JavascriptNativeProcessor { if (className.equals(JSObject.class.getName())) { return var; } else if (className.equals("java.lang.String")) { - return unwrap(var, "unwrapString", ValueType.object("java.lang.String")); + return unwrap(var, "unwrapString", ValueType.object("java.lang.String"), location.getSourceLocation()); } else { Variable result = program.createVariable(); CastInstruction castInsn = new CastInstruction(); castInsn.setReceiver(result); castInsn.setValue(var); castInsn.setTargetType(type); + castInsn.setLocation(location.getSourceLocation()); replacement.add(castInsn); return result; } } - diagnostics.error(location, "Unsupported type: " + type); + diagnostics.error(location, "Unsupported type: {{t0}}", type); return var; } - private Variable unwrap(Variable var, String methodName, ValueType resultType) { + private Variable unwrap(Variable var, String methodName, ValueType resultType, InstructionLocation location) { Variable result = program.createVariable(); InvokeInstruction insn = new InvokeInstruction(); insn.setMethod(new MethodReference(JS.class.getName(), methodName, ValueType.object(JSObject.class.getName()), @@ -317,6 +329,7 @@ class JavascriptNativeProcessor { insn.getArguments().add(var); insn.setReceiver(result); insn.setType(InvocationType.SPECIAL); + insn.setLocation(location); replacement.add(insn); return result; } @@ -329,28 +342,29 @@ class JavascriptNativeProcessor { return wrapFunctor(location, var, cls); } } - return wrap(var, type); + return wrap(var, type, location.getSourceLocation()); } private Variable wrapFunctor(CallLocation location, Variable var, ClassReader type) { if (!type.hasModifier(ElementModifier.INTERFACE) || type.getMethods().size() != 1) { - diagnostics.error(location, "Wrong functor: " + type.getName()); + diagnostics.error(location, "Wrong functor: {{c0}}", type.getName()); return var; } String name = type.getMethods().iterator().next().getName(); Variable functor = program.createVariable(); - Variable nameVar = addStringWrap(addString(name)); + Variable nameVar = addStringWrap(addString(name, location.getSourceLocation()), location.getSourceLocation()); InvokeInstruction insn = new InvokeInstruction(); insn.setType(InvocationType.SPECIAL); insn.setMethod(new MethodReference(JS.class, "function", JSObject.class, JSObject.class, JSObject.class)); insn.setReceiver(functor); insn.getArguments().add(var); insn.getArguments().add(nameVar); + insn.setLocation(location.getSourceLocation()); replacement.add(insn); return functor; } - private Variable wrap(Variable var, ValueType type) { + private Variable wrap(Variable var, ValueType type, InstructionLocation location) { if (type instanceof ValueType.Object) { String className = ((ValueType.Object)type).getClassName(); if (!className.equals("java.lang.String")) { @@ -364,6 +378,7 @@ class JavascriptNativeProcessor { insn.getArguments().add(var); insn.setReceiver(result); insn.setType(InvocationType.SPECIAL); + insn.setLocation(location); replacement.add(insn); return result; }