mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Refactoring of dependency checker in order to achieve better diagnostics
in Eclipse plugin
This commit is contained in:
parent
d9ea3764f8
commit
a26522f959
|
@ -152,6 +152,7 @@ public final class TeaVMRunner {
|
|||
|
||||
try {
|
||||
tool.generate();
|
||||
tool.checkForMissingItems();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(-2);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -35,7 +35,7 @@ public interface DependencyAgent extends DependencyInfo, ServiceRepository {
|
|||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -38,16 +38,16 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
|||
private Map<String, DependencyStack> classStacks = new HashMap<>();
|
||||
private CachedMapper<MethodReference, MethodDependency> methodCache;
|
||||
private CachedMapper<FieldReference, FieldDependency> fieldCache;
|
||||
private Set<String> achievableClasses = new HashSet<>();
|
||||
private Set<String> initializedClasses = new HashSet<>();
|
||||
private CachedMapper<String, ClassDependency> classCache;
|
||||
private List<DependencyListener> listeners = new ArrayList<>();
|
||||
private ServiceRepository services;
|
||||
private Queue<Runnable> tasks = new ArrayDeque<>();
|
||||
Map<MethodReference, DependencyStack> missingMethods = new HashMap<>();
|
||||
Map<String, DependencyStack> missingClasses = new HashMap<>();
|
||||
Map<FieldReference, DependencyStack> missingFields = new HashMap<>();
|
||||
Set<MethodDependency> missingMethods = new HashSet<>();
|
||||
Set<ClassDependency> missingClasses = new HashSet<>();
|
||||
Set<FieldDependency> missingFields = new HashSet<>();
|
||||
List<DependencyType> types = new ArrayList<>();
|
||||
Map<String, DependencyType> typeMap = new HashMap<>();
|
||||
private DependencyViolations dependencyViolations;
|
||||
|
||||
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services) {
|
||||
this.classSource = new DependencyClassSource(classSource);
|
||||
|
@ -83,6 +83,12 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
|||
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>() {
|
||||
@Override public void keyAdded(MethodReference 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
|
||||
|
@ -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);
|
||||
if (!achievableClasses.add(className)) {
|
||||
return false;
|
||||
return classCache.map(className);
|
||||
}
|
||||
|
||||
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) {
|
||||
listener.classAchieved(this, className);
|
||||
if (cls.getParent() != null) {
|
||||
linkClass(cls.getParent(), stack);
|
||||
}
|
||||
return true;
|
||||
for (String ifaceName : cls.getInterfaces()) {
|
||||
linkClass(ifaceName, stack);
|
||||
}
|
||||
return dependency;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -203,44 +229,15 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
|||
return methodCache.map(methodRef);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initClass(String className, final DependencyStack stack) {
|
||||
classStacks.put(className, stack);
|
||||
MethodDescriptor clinitDesc = new MethodDescriptor("<clinit>", ValueType.VOID);
|
||||
while (className != null) {
|
||||
if (!initializedClasses.add(className)) {
|
||||
break;
|
||||
}
|
||||
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);
|
||||
}
|
||||
void initClass(ClassDependency cls, final DependencyStack stack) {
|
||||
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(), stack);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,7 +312,6 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
|||
if (shouldLog) {
|
||||
thrown.setTag(methodRef + ":THROWN");
|
||||
}
|
||||
stack = new DependencyStack(methodRef, stack);
|
||||
final MethodDependency dep = new MethodDependency(this, parameterNodes, paramCount, resultNode, thrown,
|
||||
stack, method, methodRef);
|
||||
if (method != null) {
|
||||
|
@ -325,26 +321,17 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
|||
graphBuilder.buildGraph(dep);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
missingMethods.put(methodRef, stack);
|
||||
}
|
||||
if (method != null) {
|
||||
final DependencyStack callerStack = stack;
|
||||
tasks.add(new Runnable() {
|
||||
@Override public void run() {
|
||||
initClass(dep.getReference().getClassName(), callerStack);
|
||||
linkClass(dep.getMethod().getOwnerName(), dep.getStack());
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
missingMethods.add(dep);
|
||||
}
|
||||
return dep;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMethodAchievable(MethodReference methodRef) {
|
||||
return methodCache.caches(methodRef);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<MethodReference> getAchievableMethods() {
|
||||
return methodCache.getCachedPreimages();
|
||||
|
@ -357,7 +344,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
|||
|
||||
@Override
|
||||
public Collection<String> getAchievableClasses() {
|
||||
return new HashSet<>(achievableClasses);
|
||||
return classCache.getCachedPreimages();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -371,18 +358,28 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
|||
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);
|
||||
if (field == null) {
|
||||
missingFields.put(fieldRef, stack);
|
||||
}
|
||||
if (shouldLog) {
|
||||
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());
|
||||
}
|
||||
if (field != null) {
|
||||
initClass(fieldRef.getClassName(), stack);
|
||||
FieldDependency dep = new FieldDependency(node, stack, field, fieldRef);
|
||||
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) {
|
||||
|
@ -412,53 +409,23 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
|||
return methodCache.getKnown(methodRef);
|
||||
}
|
||||
|
||||
public DependencyViolations getDependencyViolations() {
|
||||
if (dependencyViolations == null) {
|
||||
dependencyViolations = new DependencyViolations(missingMethods, missingClasses, missingFields);
|
||||
}
|
||||
return dependencyViolations;
|
||||
}
|
||||
|
||||
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());
|
||||
getDependencyViolations().checkForMissingItems();
|
||||
}
|
||||
|
||||
public boolean hasMissingItems() {
|
||||
return !missingClasses.isEmpty() || !missingMethods.isEmpty() || !missingFields.isEmpty();
|
||||
return getDependencyViolations().hasMissingItems();
|
||||
}
|
||||
|
||||
public void showMissingItems(Appendable sb) throws IOException {
|
||||
List<String> items = new ArrayList<>();
|
||||
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');
|
||||
}
|
||||
getDependencyViolations().showMissingItems(sb);
|
||||
}
|
||||
|
||||
public void processDependencies() {
|
||||
|
|
|
@ -45,7 +45,6 @@ class DependencyGraphBuilder {
|
|||
if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) {
|
||||
return;
|
||||
}
|
||||
callerStack = dep.getStack();
|
||||
program = method.getProgram();
|
||||
if (DependencyChecker.shouldLog) {
|
||||
System.out.println("Method achieved: " + method.getReference());
|
||||
|
@ -53,6 +52,7 @@ class DependencyGraphBuilder {
|
|||
}
|
||||
resultNode = dep.getResult();
|
||||
nodes = dep.getVariables();
|
||||
callerStack = new DependencyStack(method.getReference(), dep.getStack());
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlockReader block = program.basicBlockAt(i);
|
||||
currentExceptionConsumer = createExceptionConsumer(dep, block);
|
||||
|
@ -66,7 +66,7 @@ class DependencyGraphBuilder {
|
|||
useRunners.add(new Runnable() {
|
||||
@Override public void run() {
|
||||
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() {
|
||||
@Override
|
||||
public void location(InstructionLocation location) {
|
||||
callerStack = new DependencyStack(callerStack.getMethod(), location, callerStack.getCause());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -233,7 +234,7 @@ class DependencyGraphBuilder {
|
|||
final String className = ((ValueType.Object)cst).getClassName();
|
||||
useRunners.add(new Runnable() {
|
||||
@Override public void run() {
|
||||
dependencyChecker.initClass(className, callerStack);
|
||||
dependencyChecker.linkClass(className, callerStack);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -355,7 +356,7 @@ class DependencyGraphBuilder {
|
|||
if (className != null) {
|
||||
useRunners.add(new Runnable() {
|
||||
@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();
|
||||
useRunners.add(new Runnable() {
|
||||
@Override public void run() {
|
||||
dependencyChecker.initClass(className, callerStack);
|
||||
dependencyChecker.linkClass(className, callerStack);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -512,7 +513,7 @@ class DependencyGraphBuilder {
|
|||
public void initClass(final String className) {
|
||||
useRunners.add(new Runnable() {
|
||||
@Override public void run() {
|
||||
dependencyChecker.initClass(className, callerStack);
|
||||
dependencyChecker.linkClass(className, callerStack).initClass(callerStack);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -29,8 +29,6 @@ public interface DependencyInfo {
|
|||
|
||||
ClassLoader getClassLoader();
|
||||
|
||||
boolean isMethodAchievable(MethodReference methodRef);
|
||||
|
||||
Collection<MethodReference> getAchievableMethods();
|
||||
|
||||
Collection<FieldReference> getAchievableFields();
|
||||
|
@ -40,4 +38,6 @@ public interface DependencyInfo {
|
|||
FieldDependencyInfo getField(FieldReference fieldRef);
|
||||
|
||||
MethodDependencyInfo getMethod(MethodReference methodRef);
|
||||
|
||||
ClassDependencyInfo getClass(String className);
|
||||
}
|
||||
|
|
|
@ -74,6 +74,9 @@ public class DependencyStack {
|
|||
break;
|
||||
} else {
|
||||
sb.append(" used by " + stack.method);
|
||||
if (stack.location != null) {
|
||||
sb.append(" : ").append(stack.location.getLine());
|
||||
}
|
||||
stack = stack.cause;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,6 +40,7 @@ public class FieldDependency implements FieldDependencyInfo {
|
|||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencyStack getStack() {
|
||||
return stack;
|
||||
}
|
||||
|
@ -53,6 +54,7 @@ public class FieldDependency implements FieldDependencyInfo {
|
|||
return reference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMissing() {
|
||||
return field == null;
|
||||
}
|
||||
|
|
|
@ -25,4 +25,8 @@ public interface FieldDependencyInfo {
|
|||
ValueDependencyInfo getValue();
|
||||
|
||||
FieldReference getReference();
|
||||
|
||||
boolean isMissing();
|
||||
|
||||
DependencyStack getStack();
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ public class MethodDependency implements MethodDependencyInfo {
|
|||
return thrown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencyStack getStack() {
|
||||
return stack;
|
||||
}
|
||||
|
@ -95,6 +96,7 @@ public class MethodDependency implements MethodDependencyInfo {
|
|||
return method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMissing() {
|
||||
return method == null;
|
||||
}
|
||||
|
|
|
@ -37,4 +37,8 @@ public interface MethodDependencyInfo {
|
|||
MethodReference getReference();
|
||||
|
||||
boolean isUsed();
|
||||
|
||||
boolean isMissing();
|
||||
|
||||
DependencyStack getStack();
|
||||
}
|
||||
|
|
|
@ -180,7 +180,12 @@ public class BasicBlock implements BasicBlockReader {
|
|||
@Override
|
||||
public void readAllInstructions(InstructionReader reader) {
|
||||
InstructionReadVisitor visitor = new InstructionReadVisitor(reader);
|
||||
InstructionLocation location = null;
|
||||
for (Instruction insn : instructions) {
|
||||
if (!Objects.equals(location, insn.getLocation())) {
|
||||
location = insn.getLocation();
|
||||
reader.location(location);
|
||||
}
|
||||
insn.acceptVisitor(visitor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ 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;
|
||||
|
@ -61,6 +62,7 @@ public class TeaVMTool {
|
|||
private FileSymbolTable fileTable;
|
||||
private boolean cancelled;
|
||||
private TeaVMProgressListener progressListener;
|
||||
private TeaVM vm;
|
||||
|
||||
public File getTargetDirectory() {
|
||||
return targetDirectory;
|
||||
|
@ -215,7 +217,7 @@ public class TeaVMTool {
|
|||
} else {
|
||||
vmBuilder.setClassLoader(classLoader).setClassSource(new ClasspathClassHolderSource(classLoader));
|
||||
}
|
||||
TeaVM vm = vmBuilder.build();
|
||||
vm = vmBuilder.build();
|
||||
if (progressListener != null) {
|
||||
vm.setProgressListener(progressListener);
|
||||
}
|
||||
|
@ -271,7 +273,10 @@ public class TeaVMTool {
|
|||
cancelled = true;
|
||||
return;
|
||||
}
|
||||
vm.checkForMissingItems();
|
||||
if (vm.hasMissingItems()) {
|
||||
log.info("Missing items found");
|
||||
return;
|
||||
}
|
||||
log.info("JavaScript file successfully built");
|
||||
if (debugInformationGenerated) {
|
||||
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() {
|
||||
@Override
|
||||
public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException {
|
||||
|
|
|
@ -232,7 +232,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
}
|
||||
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, ref,
|
||||
dependencyChecker.linkMethod(ref, DependencyStack.ROOT));
|
||||
dependencyChecker.initClass(ref.getClassName(), DependencyStack.ROOT);
|
||||
dependencyChecker.linkClass(ref.getClassName(), DependencyStack.ROOT).initClass(DependencyStack.ROOT);
|
||||
if (name != null) {
|
||||
entryPoints.put(name, entryPoint);
|
||||
}
|
||||
|
@ -258,7 +258,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
public TeaVMEntryPoint linkMethod(MethodReference ref) {
|
||||
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint("", ref,
|
||||
dependencyChecker.linkMethod(ref, DependencyStack.ROOT));
|
||||
dependencyChecker.initClass(ref.getClassName(), DependencyStack.ROOT);
|
||||
dependencyChecker.linkClass(ref.getClassName(), DependencyStack.ROOT).initClass(DependencyStack.ROOT);
|
||||
return entryPoint;
|
||||
}
|
||||
|
||||
|
@ -267,12 +267,12 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
throw new IllegalArgumentException("Class with public name `" + name + "' already defined for class " +
|
||||
className);
|
||||
}
|
||||
dependencyChecker.initClass(className, DependencyStack.ROOT);
|
||||
dependencyChecker.linkClass(className, DependencyStack.ROOT).initClass(DependencyStack.ROOT);
|
||||
exportedClasses.put(name, 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);
|
||||
}
|
||||
|
||||
public DependencyViolations getDependencyViolations() {
|
||||
return dependencyChecker.getDependencyViolations();
|
||||
}
|
||||
|
||||
/**
|
||||
* <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.
|
||||
|
|
|
@ -39,6 +39,7 @@ public class TeaVMBuilder extends IncrementalProjectBuilder {
|
|||
tool.setProgressListener(new TeaVMEclipseProgressListener(monitor));
|
||||
try {
|
||||
tool.generate();
|
||||
tool.checkForMissingItems();
|
||||
} catch (TeaVMToolException e) {
|
||||
throw new CoreException(TeaVMEclipsePlugin.makeError(e));
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ public class EntryPointGenerator extends AbstractRendererListener implements Dep
|
|||
@Override
|
||||
public void started(DependencyAgent agent) {
|
||||
for (String className : classesToLoad) {
|
||||
agent.initClass(className, DependencyStack.ROOT);
|
||||
agent.linkClass(className, DependencyStack.ROOT).initClass(DependencyStack.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -210,6 +210,7 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
|||
tool.setDebugInformationGenerated(debugInformationGenerated);
|
||||
tool.setSourceMapsFileGenerated(sourceMapsGenerated);
|
||||
tool.generate();
|
||||
tool.checkForMissingItems();
|
||||
} catch (RuntimeException e) {
|
||||
throw new MojoExecutionException("Unexpected error occured", e);
|
||||
} catch (TeaVMToolException e) {
|
||||
|
|
|
@ -40,6 +40,7 @@ public final class HelloWorld {
|
|||
document = window.getDocument();
|
||||
body = document.getDocumentElement().getElementsByTagName("body").item(0);
|
||||
createButton();
|
||||
new Thread().start();
|
||||
}
|
||||
|
||||
private static void createButton() {
|
||||
|
|
Loading…
Reference in New Issue
Block a user