Refactoring of dependency checker in order to achieve better diagnostics

in Eclipse plugin
This commit is contained in:
konsoletyper 2014-09-15 17:52:55 +04:00
parent d9ea3764f8
commit a26522f959
20 changed files with 326 additions and 126 deletions

View File

@ -152,6 +152,7 @@ public final class TeaVMRunner {
try { try {
tool.generate(); tool.generate();
tool.checkForMissingItems();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(System.err); e.printStackTrace(System.err);
System.exit(-2); System.exit(-2);

View File

@ -0,0 +1,61 @@
/*
* 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 org.teavm.model.ClassReader;
/**
*
* @author Alexey Andreev
*/
public class ClassDependency implements ClassDependencyInfo {
private DependencyChecker checker;
private String className;
private DependencyStack stack;
private ClassReader classReader;
ClassDependency(DependencyChecker checker, String className, DependencyStack stack, ClassReader classReader) {
this.checker = checker;
this.className = className;
this.stack = stack;
this.classReader = classReader;
}
@Override
public String getClassName() {
return className;
}
@Override
public boolean isMissing() {
return classReader == null;
}
public ClassReader getClassReader() {
return classReader;
}
@Override
public DependencyStack getStack() {
return stack;
}
public void initClass(DependencyStack stack) {
if (!isMissing()) {
checker.initClass(this, stack);
}
}
}

View File

@ -0,0 +1,28 @@
/*
* 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;
/**
*
* @author Alexey Andreev
*/
public interface ClassDependencyInfo {
String getClassName();
boolean isMissing();
DependencyStack getStack();
}

View File

@ -35,7 +35,7 @@ public interface DependencyAgent extends DependencyInfo, ServiceRepository {
MethodDependency linkMethod(MethodReference methodRef, DependencyStack stack); MethodDependency linkMethod(MethodReference methodRef, DependencyStack stack);
void initClass(String className, final DependencyStack stack); ClassDependency linkClass(String className, final DependencyStack stack);
FieldDependency linkField(FieldReference fieldRef, DependencyStack stack); FieldDependency linkField(FieldReference fieldRef, DependencyStack stack);
} }

View File

@ -38,16 +38,16 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
private Map<String, DependencyStack> classStacks = new HashMap<>(); private Map<String, DependencyStack> classStacks = new HashMap<>();
private CachedMapper<MethodReference, MethodDependency> methodCache; private CachedMapper<MethodReference, MethodDependency> methodCache;
private CachedMapper<FieldReference, FieldDependency> fieldCache; private CachedMapper<FieldReference, FieldDependency> fieldCache;
private Set<String> achievableClasses = new HashSet<>(); private CachedMapper<String, ClassDependency> classCache;
private Set<String> initializedClasses = new HashSet<>();
private List<DependencyListener> listeners = new ArrayList<>(); private List<DependencyListener> listeners = new ArrayList<>();
private ServiceRepository services; private ServiceRepository services;
private Queue<Runnable> tasks = new ArrayDeque<>(); private Queue<Runnable> tasks = new ArrayDeque<>();
Map<MethodReference, DependencyStack> missingMethods = new HashMap<>(); Set<MethodDependency> missingMethods = new HashSet<>();
Map<String, DependencyStack> missingClasses = new HashMap<>(); Set<ClassDependency> missingClasses = new HashSet<>();
Map<FieldReference, DependencyStack> missingFields = new HashMap<>(); Set<FieldDependency> missingFields = new HashSet<>();
List<DependencyType> types = new ArrayList<>(); List<DependencyType> types = new ArrayList<>();
Map<String, DependencyType> typeMap = new HashMap<>(); Map<String, DependencyType> typeMap = new HashMap<>();
private DependencyViolations dependencyViolations;
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services) { public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services) {
this.classSource = new DependencyClassSource(classSource); this.classSource = new DependencyClassSource(classSource);
@ -83,6 +83,12 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
return createFieldNode(preimage, field, fieldStacks.get(preimage)); return createFieldNode(preimage, field, fieldStacks.get(preimage));
} }
}); });
classCache = new CachedMapper<>(new Mapper<String, ClassDependency>() {
@Override public ClassDependency map(String preimage) {
return createClassDependency(preimage, classStacks.get(preimage));
}
});
methodCache.addKeyListener(new KeyListener<MethodReference>() { methodCache.addKeyListener(new KeyListener<MethodReference>() {
@Override public void keyAdded(MethodReference key) { @Override public void keyAdded(MethodReference key) {
MethodDependency graph = methodCache.getKnown(key); MethodDependency graph = methodCache.getKnown(key);
@ -104,6 +110,16 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
} }
} }
}); });
classCache.addKeyListener(new KeyListener<String>() {
@Override public void keyAdded(String key) {
ClassDependency classDep = classCache.getKnown(key);
if (!classDep.isMissing()) {
for (DependencyListener listener : listeners) {
listener.classAchieved(DependencyChecker.this, key);
}
}
}
});
} }
@Override @Override
@ -183,15 +199,25 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
}); });
} }
boolean achieveClass(String className, DependencyStack stack) { @Override
public ClassDependency linkClass(String className, DependencyStack stack) {
classStacks.put(className, stack); classStacks.put(className, stack);
if (!achievableClasses.add(className)) { return classCache.map(className);
return false; }
private ClassDependency createClassDependency(String className, DependencyStack stack) {
ClassReader cls = classSource.get(className);
ClassDependency dependency = new ClassDependency(this, className, stack, cls);
if (dependency.isMissing()) {
missingClasses.add(dependency);
} }
for (DependencyListener listener : listeners) { if (cls.getParent() != null) {
listener.classAchieved(this, className); linkClass(cls.getParent(), stack);
} }
return true; for (String ifaceName : cls.getInterfaces()) {
linkClass(ifaceName, stack);
}
return dependency;
} }
@Override @Override
@ -203,44 +229,15 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
return methodCache.map(methodRef); return methodCache.map(methodRef);
} }
@Override void initClass(ClassDependency cls, final DependencyStack stack) {
public void initClass(String className, final DependencyStack stack) { ClassReader reader = cls.getClassReader();
classStacks.put(className, stack); final MethodReader method = reader.getMethod(new MethodDescriptor("<clinit>", void.class));
MethodDescriptor clinitDesc = new MethodDescriptor("<clinit>", ValueType.VOID); if (method != null) {
while (className != null) { tasks.add(new Runnable() {
if (!initializedClasses.add(className)) { @Override public void run() {
break; linkMethod(method.getReference(), stack);
} }
achieveClass(className, stack); });
achieveInterfaces(className, stack);
ClassReader cls = classSource.get(className);
if (cls == null) {
missingClasses.put(className, stack);
return;
}
if (cls.getMethod(clinitDesc) != null) {
final MethodReference methodRef = new MethodReference(className, clinitDesc);
tasks.add(new Runnable() {
@Override public void run() {
linkMethod(methodRef, new DependencyStack(methodRef, stack)).use();
}
});
}
className = cls.getParent();
}
}
private void achieveInterfaces(String className, DependencyStack stack) {
classStacks.put(className, stack);
ClassReader cls = classSource.get(className);
if (cls == null) {
missingClasses.put(className, stack);
return;
}
for (String iface : cls.getInterfaces()) {
if (achieveClass(iface, stack)) {
achieveInterfaces(iface, stack);
}
} }
} }
@ -315,7 +312,6 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
if (shouldLog) { if (shouldLog) {
thrown.setTag(methodRef + ":THROWN"); thrown.setTag(methodRef + ":THROWN");
} }
stack = new DependencyStack(methodRef, stack);
final MethodDependency dep = new MethodDependency(this, parameterNodes, paramCount, resultNode, thrown, final MethodDependency dep = new MethodDependency(this, parameterNodes, paramCount, resultNode, thrown,
stack, method, methodRef); stack, method, methodRef);
if (method != null) { if (method != null) {
@ -325,26 +321,17 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
graphBuilder.buildGraph(dep); graphBuilder.buildGraph(dep);
} }
}); });
} else {
missingMethods.put(methodRef, stack);
}
if (method != null) {
final DependencyStack callerStack = stack;
tasks.add(new Runnable() { tasks.add(new Runnable() {
@Override public void run() { @Override public void run() {
initClass(dep.getReference().getClassName(), callerStack); linkClass(dep.getMethod().getOwnerName(), dep.getStack());
} }
}); });
} else {
missingMethods.add(dep);
} }
return dep; return dep;
} }
@Override
public boolean isMethodAchievable(MethodReference methodRef) {
return methodCache.caches(methodRef);
}
@Override @Override
public Collection<MethodReference> getAchievableMethods() { public Collection<MethodReference> getAchievableMethods() {
return methodCache.getCachedPreimages(); return methodCache.getCachedPreimages();
@ -357,7 +344,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
@Override @Override
public Collection<String> getAchievableClasses() { public Collection<String> getAchievableClasses() {
return new HashSet<>(achievableClasses); return classCache.getCachedPreimages();
} }
@Override @Override
@ -371,18 +358,28 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
return fieldCache.getKnown(fieldRef); return fieldCache.getKnown(fieldRef);
} }
private FieldDependency createFieldNode(FieldReference fieldRef, FieldReader field, DependencyStack stack) { @Override
public ClassDependency getClass(String className) {
return classCache.getKnown(className);
}
private FieldDependency createFieldNode(final FieldReference fieldRef, FieldReader field,
final DependencyStack stack) {
DependencyNode node = new DependencyNode(this); DependencyNode node = new DependencyNode(this);
if (field == null) {
missingFields.put(fieldRef, stack);
}
if (shouldLog) { if (shouldLog) {
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName()); node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());
} }
if (field != null) { FieldDependency dep = new FieldDependency(node, stack, field, fieldRef);
initClass(fieldRef.getClassName(), stack); if (dep.isMissing()) {
missingFields.add(dep);
} else {
tasks.add(new Runnable() {
@Override public void run() {
linkClass(fieldRef.getClassName(), stack).initClass(stack);
}
});
} }
return new FieldDependency(node, stack, field, fieldRef); return dep;
} }
private void activateDependencyPlugin(MethodDependency methodDep) { private void activateDependencyPlugin(MethodDependency methodDep) {
@ -412,53 +409,23 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
return methodCache.getKnown(methodRef); return methodCache.getKnown(methodRef);
} }
public DependencyViolations getDependencyViolations() {
if (dependencyViolations == null) {
dependencyViolations = new DependencyViolations(missingMethods, missingClasses, missingFields);
}
return dependencyViolations;
}
public void checkForMissingItems() { public void checkForMissingItems() {
if (!hasMissingItems()) { getDependencyViolations().checkForMissingItems();
return;
}
StringBuilder sb = new StringBuilder();
try {
showMissingItems(sb);
} catch (IOException e) {
throw new AssertionError("StringBuilder should not throw IOException");
}
throw new IllegalStateException(sb.toString());
} }
public boolean hasMissingItems() { public boolean hasMissingItems() {
return !missingClasses.isEmpty() || !missingMethods.isEmpty() || !missingFields.isEmpty(); return getDependencyViolations().hasMissingItems();
} }
public void showMissingItems(Appendable sb) throws IOException { public void showMissingItems(Appendable sb) throws IOException {
List<String> items = new ArrayList<>(); getDependencyViolations().showMissingItems(sb);
Map<String, DependencyStack> stackMap = new HashMap<>();
for (String cls : missingClasses.keySet()) {
stackMap.put(cls, missingClasses.get(cls));
items.add(cls);
}
for (MethodReference method : missingMethods.keySet()) {
stackMap.put(method.toString(), missingMethods.get(method));
items.add(method.toString());
}
for (FieldReference field : missingFields.keySet()) {
stackMap.put(field.toString(), missingFields.get(field));
items.add(field.toString());
}
Collections.sort(items);
sb.append("Can't compile due to the following items missing:\n");
for (String item : items) {
sb.append(" ").append(item).append("\n");
DependencyStack stack = stackMap.get(item);
if (stack == null) {
sb.append(" at unknown location\n");
} else {
while (stack.getMethod() != null) {
sb.append(" at " + stack.getMethod() + "\n");
stack = stack.getCause();
}
}
sb.append('\n');
}
} }
public void processDependencies() { public void processDependencies() {

View File

@ -45,7 +45,6 @@ class DependencyGraphBuilder {
if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) { if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) {
return; return;
} }
callerStack = dep.getStack();
program = method.getProgram(); program = method.getProgram();
if (DependencyChecker.shouldLog) { if (DependencyChecker.shouldLog) {
System.out.println("Method achieved: " + method.getReference()); System.out.println("Method achieved: " + method.getReference());
@ -53,6 +52,7 @@ class DependencyGraphBuilder {
} }
resultNode = dep.getResult(); resultNode = dep.getResult();
nodes = dep.getVariables(); nodes = dep.getVariables();
callerStack = new DependencyStack(method.getReference(), dep.getStack());
for (int i = 0; i < program.basicBlockCount(); ++i) { for (int i = 0; i < program.basicBlockCount(); ++i) {
BasicBlockReader block = program.basicBlockAt(i); BasicBlockReader block = program.basicBlockAt(i);
currentExceptionConsumer = createExceptionConsumer(dep, block); currentExceptionConsumer = createExceptionConsumer(dep, block);
@ -66,7 +66,7 @@ class DependencyGraphBuilder {
useRunners.add(new Runnable() { useRunners.add(new Runnable() {
@Override public void run() { @Override public void run() {
if (tryCatch.getExceptionType() != null) { if (tryCatch.getExceptionType() != null) {
dependencyChecker.initClass(tryCatch.getExceptionType(), callerStack); dependencyChecker.linkClass(tryCatch.getExceptionType(), callerStack);
} }
} }
}); });
@ -216,6 +216,7 @@ class DependencyGraphBuilder {
private InstructionReader reader = new InstructionReader() { private InstructionReader reader = new InstructionReader() {
@Override @Override
public void location(InstructionLocation location) { public void location(InstructionLocation location) {
callerStack = new DependencyStack(callerStack.getMethod(), location, callerStack.getCause());
} }
@Override @Override
@ -233,7 +234,7 @@ class DependencyGraphBuilder {
final String className = ((ValueType.Object)cst).getClassName(); final String className = ((ValueType.Object)cst).getClassName();
useRunners.add(new Runnable() { useRunners.add(new Runnable() {
@Override public void run() { @Override public void run() {
dependencyChecker.initClass(className, callerStack); dependencyChecker.linkClass(className, callerStack);
} }
}); });
} }
@ -355,7 +356,7 @@ class DependencyGraphBuilder {
if (className != null) { if (className != null) {
useRunners.add(new Runnable() { useRunners.add(new Runnable() {
@Override public void run() { @Override public void run() {
dependencyChecker.initClass(className, callerStack); dependencyChecker.linkClass(className, callerStack);
} }
}); });
} }
@ -502,7 +503,7 @@ class DependencyGraphBuilder {
final String className = ((ValueType.Object)type).getClassName(); final String className = ((ValueType.Object)type).getClassName();
useRunners.add(new Runnable() { useRunners.add(new Runnable() {
@Override public void run() { @Override public void run() {
dependencyChecker.initClass(className, callerStack); dependencyChecker.linkClass(className, callerStack);
} }
}); });
} }
@ -512,7 +513,7 @@ class DependencyGraphBuilder {
public void initClass(final String className) { public void initClass(final String className) {
useRunners.add(new Runnable() { useRunners.add(new Runnable() {
@Override public void run() { @Override public void run() {
dependencyChecker.initClass(className, callerStack); dependencyChecker.linkClass(className, callerStack).initClass(callerStack);
} }
}); });
} }

View File

@ -29,8 +29,6 @@ public interface DependencyInfo {
ClassLoader getClassLoader(); ClassLoader getClassLoader();
boolean isMethodAchievable(MethodReference methodRef);
Collection<MethodReference> getAchievableMethods(); Collection<MethodReference> getAchievableMethods();
Collection<FieldReference> getAchievableFields(); Collection<FieldReference> getAchievableFields();
@ -40,4 +38,6 @@ public interface DependencyInfo {
FieldDependencyInfo getField(FieldReference fieldRef); FieldDependencyInfo getField(FieldReference fieldRef);
MethodDependencyInfo getMethod(MethodReference methodRef); MethodDependencyInfo getMethod(MethodReference methodRef);
ClassDependencyInfo getClass(String className);
} }

View File

@ -74,6 +74,9 @@ public class DependencyStack {
break; break;
} else { } else {
sb.append(" used by " + stack.method); sb.append(" used by " + stack.method);
if (stack.location != null) {
sb.append(" : ").append(stack.location.getLine());
}
stack = stack.cause; stack = stack.cause;
} }
} }

View File

@ -0,0 +1,102 @@
/*
* 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.io.IOException;
import java.util.*;
/**
*
* @author Alexey Andreev
*/
public class DependencyViolations {
private final Set<MethodDependencyInfo> missingMethods;
private final Set<ClassDependencyInfo> missingClasses;
private final Set<FieldDependencyInfo> missingFields;
DependencyViolations(Collection<? extends MethodDependencyInfo> missingMethods,
Collection<? extends ClassDependencyInfo> missingClasses,
Collection<? extends FieldDependencyInfo> missingFields) {
this.missingMethods = Collections.unmodifiableSet(new HashSet<>(missingMethods));
this.missingClasses = Collections.unmodifiableSet(new HashSet<>(missingClasses));
this.missingFields = Collections.unmodifiableSet(new HashSet<>(missingFields));
}
public Set<MethodDependencyInfo> getMissingMethods() {
return missingMethods;
}
public Set<ClassDependencyInfo> getMissingClasses() {
return missingClasses;
}
public Set<FieldDependencyInfo> getMissingFields() {
return missingFields;
}
public boolean hasMissingItems() {
return !missingMethods.isEmpty() || !missingClasses.isEmpty() || !missingFields.isEmpty();
}
public void checkForMissingItems() {
if (!hasMissingItems()) {
return;
}
StringBuilder sb = new StringBuilder();
try {
showMissingItems(sb);
} catch (IOException e) {
throw new AssertionError("StringBuilder should not throw IOException");
}
throw new IllegalStateException(sb.toString());
}
public void showMissingItems(Appendable sb) throws IOException {
List<String> items = new ArrayList<>();
Map<String, DependencyStack> stackMap = new HashMap<>();
for (ClassDependencyInfo cls : missingClasses) {
stackMap.put(cls.getClassName(), cls.getStack());
items.add(cls.getClassName());
}
for (MethodDependencyInfo method : missingMethods) {
stackMap.put(method.getReference().toString(), method.getStack());
items.add(method.getReference().toString());
}
for (FieldDependencyInfo field : missingFields) {
stackMap.put(field.getReference().toString(), field.getStack());
items.add(field.getReference().toString());
}
Collections.sort(items);
sb.append("Can't compile due to the following items missing:\n");
for (String item : items) {
sb.append(" ").append(item).append("\n");
DependencyStack stack = stackMap.get(item);
if (stack == null) {
sb.append(" at unknown location\n");
} else {
while (stack.getMethod() != null) {
sb.append(" at ").append(stack.getMethod().toString());
if (stack.getLocation() != null) {
sb.append(":").append(String.valueOf(stack.getLocation().getLine()));
}
sb.append("\n");
stack = stack.getCause();
}
}
sb.append('\n');
}
}
}

View File

@ -40,6 +40,7 @@ public class FieldDependency implements FieldDependencyInfo {
return value; return value;
} }
@Override
public DependencyStack getStack() { public DependencyStack getStack() {
return stack; return stack;
} }
@ -53,6 +54,7 @@ public class FieldDependency implements FieldDependencyInfo {
return reference; return reference;
} }
@Override
public boolean isMissing() { public boolean isMissing() {
return field == null; return field == null;
} }

View File

@ -25,4 +25,8 @@ public interface FieldDependencyInfo {
ValueDependencyInfo getValue(); ValueDependencyInfo getValue();
FieldReference getReference(); FieldReference getReference();
boolean isMissing();
DependencyStack getStack();
} }

View File

@ -82,6 +82,7 @@ public class MethodDependency implements MethodDependencyInfo {
return thrown; return thrown;
} }
@Override
public DependencyStack getStack() { public DependencyStack getStack() {
return stack; return stack;
} }
@ -95,6 +96,7 @@ public class MethodDependency implements MethodDependencyInfo {
return method; return method;
} }
@Override
public boolean isMissing() { public boolean isMissing() {
return method == null; return method == null;
} }

View File

@ -37,4 +37,8 @@ public interface MethodDependencyInfo {
MethodReference getReference(); MethodReference getReference();
boolean isUsed(); boolean isUsed();
boolean isMissing();
DependencyStack getStack();
} }

View File

@ -180,7 +180,12 @@ public class BasicBlock implements BasicBlockReader {
@Override @Override
public void readAllInstructions(InstructionReader reader) { public void readAllInstructions(InstructionReader reader) {
InstructionReadVisitor visitor = new InstructionReadVisitor(reader); InstructionReadVisitor visitor = new InstructionReadVisitor(reader);
InstructionLocation location = null;
for (Instruction insn : instructions) { for (Instruction insn : instructions) {
if (!Objects.equals(location, insn.getLocation())) {
location = insn.getLocation();
reader.location(location);
}
insn.acceptVisitor(visitor); insn.acceptVisitor(visitor);
} }
} }

View File

@ -26,6 +26,7 @@ import org.teavm.cache.DiskRegularMethodNodeCache;
import org.teavm.cache.FileSymbolTable; import org.teavm.cache.FileSymbolTable;
import org.teavm.debugging.information.DebugInformation; import org.teavm.debugging.information.DebugInformation;
import org.teavm.debugging.information.DebugInformationBuilder; import org.teavm.debugging.information.DebugInformationBuilder;
import org.teavm.dependency.DependencyViolations;
import org.teavm.javascript.RenderingContext; import org.teavm.javascript.RenderingContext;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.parsing.ClasspathClassHolderSource; import org.teavm.parsing.ClasspathClassHolderSource;
@ -61,6 +62,7 @@ public class TeaVMTool {
private FileSymbolTable fileTable; private FileSymbolTable fileTable;
private boolean cancelled; private boolean cancelled;
private TeaVMProgressListener progressListener; private TeaVMProgressListener progressListener;
private TeaVM vm;
public File getTargetDirectory() { public File getTargetDirectory() {
return targetDirectory; return targetDirectory;
@ -215,7 +217,7 @@ public class TeaVMTool {
} else { } else {
vmBuilder.setClassLoader(classLoader).setClassSource(new ClasspathClassHolderSource(classLoader)); vmBuilder.setClassLoader(classLoader).setClassSource(new ClasspathClassHolderSource(classLoader));
} }
TeaVM vm = vmBuilder.build(); vm = vmBuilder.build();
if (progressListener != null) { if (progressListener != null) {
vm.setProgressListener(progressListener); vm.setProgressListener(progressListener);
} }
@ -271,7 +273,10 @@ public class TeaVMTool {
cancelled = true; cancelled = true;
return; return;
} }
vm.checkForMissingItems(); if (vm.hasMissingItems()) {
log.info("Missing items found");
return;
}
log.info("JavaScript file successfully built"); log.info("JavaScript file successfully built");
if (debugInformationGenerated) { if (debugInformationGenerated) {
DebugInformation debugInfo = debugEmitter.getDebugInformation(); DebugInformation debugInfo = debugEmitter.getDebugInformation();
@ -319,6 +324,14 @@ public class TeaVMTool {
} }
} }
public DependencyViolations getDependencyViolations() {
return vm.getDependencyViolations();
}
public void checkForMissingItems() {
vm.checkForMissingItems();
}
private AbstractRendererListener runtimeInjector = new AbstractRendererListener() { private AbstractRendererListener runtimeInjector = new AbstractRendererListener() {
@Override @Override
public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException { public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException {

View File

@ -232,7 +232,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
} }
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, ref, TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, ref,
dependencyChecker.linkMethod(ref, DependencyStack.ROOT)); dependencyChecker.linkMethod(ref, DependencyStack.ROOT));
dependencyChecker.initClass(ref.getClassName(), DependencyStack.ROOT); dependencyChecker.linkClass(ref.getClassName(), DependencyStack.ROOT).initClass(DependencyStack.ROOT);
if (name != null) { if (name != null) {
entryPoints.put(name, entryPoint); entryPoints.put(name, entryPoint);
} }
@ -258,7 +258,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
public TeaVMEntryPoint linkMethod(MethodReference ref) { public TeaVMEntryPoint linkMethod(MethodReference ref) {
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint("", ref, TeaVMEntryPoint entryPoint = new TeaVMEntryPoint("", ref,
dependencyChecker.linkMethod(ref, DependencyStack.ROOT)); dependencyChecker.linkMethod(ref, DependencyStack.ROOT));
dependencyChecker.initClass(ref.getClassName(), DependencyStack.ROOT); dependencyChecker.linkClass(ref.getClassName(), DependencyStack.ROOT).initClass(DependencyStack.ROOT);
return entryPoint; return entryPoint;
} }
@ -267,12 +267,12 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
throw new IllegalArgumentException("Class with public name `" + name + "' already defined for class " + throw new IllegalArgumentException("Class with public name `" + name + "' already defined for class " +
className); className);
} }
dependencyChecker.initClass(className, DependencyStack.ROOT); dependencyChecker.linkClass(className, DependencyStack.ROOT).initClass(DependencyStack.ROOT);
exportedClasses.put(name, className); exportedClasses.put(name, className);
} }
public void linkType(String className) { public void linkType(String className) {
dependencyChecker.initClass(className, DependencyStack.ROOT); dependencyChecker.linkClass(className, DependencyStack.ROOT).initClass(DependencyStack.ROOT);
} }
/** /**
@ -303,6 +303,10 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
dependencyChecker.showMissingItems(target); dependencyChecker.showMissingItems(target);
} }
public DependencyViolations getDependencyViolations() {
return dependencyChecker.getDependencyViolations();
}
/** /**
* <p>After building checks whether the build has failed due to some missing items (classes, methods and fields). * <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. * If it has failed, throws exception, containing report on all missing items.

View File

@ -39,6 +39,7 @@ public class TeaVMBuilder extends IncrementalProjectBuilder {
tool.setProgressListener(new TeaVMEclipseProgressListener(monitor)); tool.setProgressListener(new TeaVMEclipseProgressListener(monitor));
try { try {
tool.generate(); tool.generate();
tool.checkForMissingItems();
} catch (TeaVMToolException e) { } catch (TeaVMToolException e) {
throw new CoreException(TeaVMEclipsePlugin.makeError(e)); throw new CoreException(TeaVMEclipsePlugin.makeError(e));
} }

View File

@ -69,7 +69,7 @@ public class EntryPointGenerator extends AbstractRendererListener implements Dep
@Override @Override
public void started(DependencyAgent agent) { public void started(DependencyAgent agent) {
for (String className : classesToLoad) { for (String className : classesToLoad) {
agent.initClass(className, DependencyStack.ROOT); agent.linkClass(className, DependencyStack.ROOT).initClass(DependencyStack.ROOT);
} }
} }

View File

@ -210,6 +210,7 @@ public class BuildJavascriptMojo extends AbstractMojo {
tool.setDebugInformationGenerated(debugInformationGenerated); tool.setDebugInformationGenerated(debugInformationGenerated);
tool.setSourceMapsFileGenerated(sourceMapsGenerated); tool.setSourceMapsFileGenerated(sourceMapsGenerated);
tool.generate(); tool.generate();
tool.checkForMissingItems();
} catch (RuntimeException e) { } catch (RuntimeException e) {
throw new MojoExecutionException("Unexpected error occured", e); throw new MojoExecutionException("Unexpected error occured", e);
} catch (TeaVMToolException e) { } catch (TeaVMToolException e) {

View File

@ -40,6 +40,7 @@ public final class HelloWorld {
document = window.getDocument(); document = window.getDocument();
body = document.getDocumentElement().getElementsByTagName("body").item(0); body = document.getDocumentElement().getElementsByTagName("body").item(0);
createButton(); createButton();
new Thread().start();
} }
private static void createButton() { private static void createButton() {