Further work on diagnostics API

This commit is contained in:
Alexey Andreev 2014-12-09 18:43:23 +04:00
parent 30781bb16e
commit 0945c27f16
7 changed files with 43 additions and 96 deletions

View File

@ -15,9 +15,8 @@
*/
package org.teavm.dependency;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader;
import org.teavm.model.InstructionLocation;
import org.teavm.model.MethodReference;
/**
*
@ -48,9 +47,9 @@ public class ClassDependency implements ClassDependencyInfo {
return classReader;
}
public void initClass(MethodReference caller, InstructionLocation location) {
public void initClass(CallLocation callLocation) {
if (!isMissing()) {
checker.initClass(this, caller, location);
checker.initClass(this, callLocation);
}
}
}

View File

@ -32,11 +32,11 @@ public interface DependencyAgent extends DependencyInfo, ServiceRepository {
void submitClass(ClassHolder cls);
MethodDependency linkMethod(MethodReference methodRef, MethodReference caller, InstructionLocation location);
MethodDependency linkMethod(MethodReference methodRef, CallLocation callLocation);
ClassDependency linkClass(String className, MethodReference caller, InstructionLocation location);
ClassDependency linkClass(String className, CallLocation callLocation);
FieldDependency linkField(FieldReference fieldRef, MethodReference caller, InstructionLocation location);
FieldDependency linkField(FieldReference fieldRef, CallLocation callLocation);
Diagnostics getDiagnostics();
}

View File

@ -47,7 +47,6 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
Set<FieldDependency> missingFields = new HashSet<>();
List<DependencyType> types = new ArrayList<>();
Map<String, DependencyType> typeMap = new HashMap<>();
private DependencyViolations dependencyViolations;
private DependencyCheckerInterruptor interruptor;
private boolean interrupted;
private Diagnostics diagnostics;
@ -188,7 +187,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
if (parameters.length + 1 != argumentTypes.length) {
throw new IllegalArgumentException("argumentTypes length does not match the number of method's arguments");
}
MethodDependency method = linkMethod(methodRef, null, null);
MethodDependency method = linkMethod(methodRef, null);
method.use();
DependencyNode[] varNodes = method.getVariables();
varNodes[0].propagate(getType(methodRef.getClassName()));
@ -216,11 +215,11 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
}
@Override
public ClassDependency linkClass(String className, DependencyStack stack) {
public ClassDependency linkClass(String className, CallLocation callLocation) {
return classCache.map(className);
}
private ClassDependency createClassDependency(String className, DependencyStack stack) {
private ClassDependency createClassDependency(String className, CallLocation callLocation) {
ClassReader cls = classSource.get(className);
ClassDependency dependency = new ClassDependency(this, className, stack, cls);
if (dependency.isMissing()) {
@ -237,26 +236,25 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
}
@Override
public MethodDependency linkMethod(MethodReference methodRef, MethodReference caller,
InstructionLocation location) {
public MethodDependency linkMethod(MethodReference methodRef, CallLocation callLocation) {
if (methodRef == null) {
throw new IllegalArgumentException();
}
callGraph.addNode(methodRef);
if (caller != null) {
callGraph.getNode(methodRef);
if (callLocation != null) {
callGraph.addNode(caller);
callGraph.getNode(caller).addCallSite(methodRef, location);
}
return methodCache.map(methodRef);
}
void initClass(ClassDependency cls, final MethodReference caller, final InstructionLocation location) {
void initClass(ClassDependency cls, final CallLocation callLocation) {
ClassReader reader = cls.getClassReader();
final MethodReader method = reader.getMethod(new MethodDescriptor("<clinit>", void.class));
if (method != null) {
tasks.add(new Runnable() {
@Override public void run() {
linkMethod(method.getReference(), caller, location).use();
linkMethod(method.getReference(), callLocation).use();
}
});
}

View File

@ -17,38 +17,27 @@ package org.teavm.diagnostics;
import java.util.ArrayList;
import java.util.List;
import org.teavm.model.InstructionLocation;
import org.teavm.model.MethodReference;
import org.teavm.model.CallLocation;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
class DependencyDiagnostics implements Diagnostics {
public class AccumulationDiagnostics implements Diagnostics {
private List<Problem> problems = new ArrayList<>();
private List<Problem> severeProblems = new ArrayList<>();
@Override
public void error(MethodReference method, InstructionLocation location, String error, Object[] params) {
Problem violation = new Problem(ProblemSeverity.ERROR, location, error);
problems.add(violation);
severeProblems.add(violation);
public void error(CallLocation location, String error, Object... params) {
Problem problem = new Problem(ProblemSeverity.ERROR, location, error, params);
problems.add(problem);
severeProblems.add(problem);
}
@Override
public void error(String error) {
error(null, error);
}
@Override
public void warning(InstructionLocation location, String error) {
Problem violation = new Problem(ProblemSeverity.WARNING, location, error);
problems.add(violation);
}
@Override
public void warning(String error) {
warning(null, error);
public void warning(CallLocation location, String error, Object... params) {
Problem problem = new Problem(ProblemSeverity.ERROR, location, error, params);
problems.add(problem);
}
public List<Problem> getProblems() {

View File

@ -46,4 +46,8 @@ public class Problem {
public String getText() {
return text;
}
public Object[] getParams() {
return params;
}
}

View File

@ -24,7 +24,6 @@ import org.teavm.cache.DiskRegularMethodNodeCache;
import org.teavm.cache.FileSymbolTable;
import org.teavm.debugging.information.DebugInformation;
import org.teavm.debugging.information.DebugInformationBuilder;
import org.teavm.dependency.DependencyViolations;
import org.teavm.javascript.RenderingContext;
import org.teavm.model.*;
import org.teavm.parsing.ClasspathClassHolderSource;
@ -345,10 +344,6 @@ public class TeaVMTool {
}
}
public DependencyViolations getViolations() {
return vm.getViolations();
}
public void checkForMissingItems() {
vm.checkForViolations();
}
@ -366,7 +361,6 @@ public class TeaVMTool {
private AbstractRendererListener runtimeInjector = new AbstractRendererListener() {
@Override
public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException {
@SuppressWarnings("resource")
StringWriter writer = new StringWriter();
resourceToWriter("org/teavm/javascript/runtime.js", writer);
writer.close();

View File

@ -22,6 +22,7 @@ import org.teavm.common.ServiceRepository;
import org.teavm.debugging.information.DebugInformationEmitter;
import org.teavm.debugging.information.SourceLocation;
import org.teavm.dependency.*;
import org.teavm.diagnostics.AccumulationDiagnostics;
import org.teavm.javascript.*;
import org.teavm.javascript.ast.ClassNode;
import org.teavm.javascript.ni.Generator;
@ -68,6 +69,7 @@ import org.teavm.vm.spi.TeaVMPlugin;
public class TeaVM implements TeaVMHost, ServiceRepository {
private ClassReaderSource classSource;
private DependencyChecker dependencyChecker;
private AccumulationDiagnostics diagnostics = new AccumulationDiagnostics();
private ClassLoader classLoader;
private boolean minifying = true;
private boolean bytecodeLogging;
@ -90,7 +92,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
TeaVM(ClassReaderSource classSource, ClassLoader classLoader) {
this.classSource = classSource;
this.classLoader = classLoader;
dependencyChecker = new DependencyChecker(this.classSource, classLoader, this);
dependencyChecker = new DependencyChecker(this.classSource, classLoader, this, diagnostics);
progressListener = new TeaVMProgressListener() {
@Override public TeaVMProgressFeedback progressReached(int progress) {
return TeaVMProgressFeedback.CONTINUE;
@ -232,9 +234,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
"for method " + ref);
}
}
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, ref,
dependencyChecker.linkMethod(ref, DependencyStack.ROOT));
dependencyChecker.linkClass(ref.getClassName(), DependencyStack.ROOT).initClass(DependencyStack.ROOT);
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, ref, dependencyChecker.linkMethod(ref, null));
dependencyChecker.linkClass(ref.getClassName(), null).initClass(null);
if (name != null) {
entryPoints.put(name, entryPoint);
}
@ -258,9 +259,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
}
public TeaVMEntryPoint linkMethod(MethodReference ref) {
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint("", ref,
dependencyChecker.linkMethod(ref, DependencyStack.ROOT));
dependencyChecker.linkClass(ref.getClassName(), DependencyStack.ROOT).initClass(DependencyStack.ROOT);
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint("", ref, dependencyChecker.linkMethod(ref, null));
dependencyChecker.linkClass(ref.getClassName(), null).initClass(null);
return entryPoint;
}
@ -269,12 +269,12 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
throw new IllegalArgumentException("Class with public name `" + name + "' already defined for class " +
className);
}
dependencyChecker.linkClass(className, DependencyStack.ROOT).initClass(DependencyStack.ROOT);
dependencyChecker.linkClass(className, null).initClass(null);
exportedClasses.put(name, className);
}
public void linkType(String className) {
dependencyChecker.linkClass(className, DependencyStack.ROOT).initClass(DependencyStack.ROOT);
dependencyChecker.linkClass(className, null).initClass(null);
}
/**
@ -285,30 +285,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
return classSource;
}
/**
* <p>After building indicates whether build has failed due to some missing items (classes, methods and fields)
* in the classpath. 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.</p>
*/
public boolean hasMissingItems() {
return dependencyChecker.hasViolations();
}
/**
* <p>After building allows to build report on all items (classes, methods, fields) that are missing.
* 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.</p>
*
* @param target where to append all dependency diagnostics errors.
*/
public void showMissingItems(Appendable target) throws IOException {
dependencyChecker.showViolations(target);
}
public DependencyViolations getViolations() {
return dependencyChecker.getViolations();
}
public Collection<String> getClasses() {
return dependencyChecker.getAchievableClasses();
}
@ -321,16 +297,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
return writtenClasses;
}
/**
* <p>After building checks whether the build has failed due to some missing items (classes, methods and fields).
* If it has failed, throws exception, containing report on all missing items.
* 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.</p>
*/
public void checkForViolations() {
dependencyChecker.checkForViolations();
}
public DebugInformationEmitter getDebugEmitter() {
return debugEmitter;
}
@ -362,22 +328,19 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
return progressListener.progressReached(0) == TeaVMProgressFeedback.CONTINUE;
}
});
dependencyChecker.linkMethod(new MethodReference(Class.class, "createNew", Class.class),
DependencyStack.ROOT).use();
dependencyChecker.linkMethod(new MethodReference(Class.class, "createNew", Class.class), null).use();
dependencyChecker.linkMethod(new MethodReference(String.class, "<init>", char[].class, void.class),
DependencyStack.ROOT).use();
null).use();
dependencyChecker.linkMethod(new MethodReference(String.class, "getChars", int.class, int.class, char[].class,
int.class, void.class), DependencyStack.ROOT).use();
int.class, void.class), null).use();
MethodDependency internDep = dependencyChecker.linkMethod(new MethodReference(String.class, "intern",
String.class), DependencyStack.ROOT);
String.class), null);
internDep.getVariable(0).propagate(dependencyChecker.getType("java.lang.String"));
internDep.use();
dependencyChecker.linkMethod(new MethodReference(String.class, "length", int.class),
DependencyStack.ROOT).use();
dependencyChecker.linkMethod(new MethodReference(Object.class, "clone", Object.class),
DependencyStack.ROOT).use();
dependencyChecker.linkMethod(new MethodReference(String.class, "length", int.class), null).use();
dependencyChecker.linkMethod(new MethodReference(Object.class, "clone", Object.class), null).use();
dependencyChecker.processDependencies();
if (wasCancelled() || hasMissingItems()) {
if (wasCancelled() || !diagnostics.getSevereProblems().isEmpty()) {
return;
}