Adds support of Class.getDeclaringClass method

This commit is contained in:
konsoletyper 2014-02-23 23:17:30 +04:00
parent 9cdc099b1a
commit 3195879467
9 changed files with 76 additions and 4 deletions

View File

@ -24,6 +24,7 @@ import org.teavm.model.*;
*/
public class NewInstanceDependencySupport implements DependencyListener {
private DependencyNode allClassesNode;
private DependencyStack newInstanceStack;
@Override
public void started(DependencyChecker dependencyChecker) {
@ -36,19 +37,31 @@ public class NewInstanceDependencySupport implements DependencyListener {
if (cls.hasModifier(ElementModifier.ABSTRACT) || cls.hasModifier(ElementModifier.INTERFACE)) {
return;
}
if (cls.getMethod(new MethodDescriptor("<init>", ValueType.VOID)) != null) {
MethodReader method = cls.getMethod(new MethodDescriptor("<init>", ValueType.VOID));
if (method != null) {
allClassesNode.propagate(className);
}
}
@Override
public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method) {
public void methodAchieved(final DependencyChecker dependencyChecker, MethodDependency method) {
MethodReader reader = method.getMethod();
if (reader.getOwnerName().equals("java.lang.Class") && reader.getName().equals("newInstance")) {
newInstanceStack = method.getStack();
allClassesNode.connect(method.getResult());
method.getResult().addConsumer(new DependencyConsumer() {
@Override public void consume(String type) {
attachConstructor(dependencyChecker, type);
}
});
}
}
private void attachConstructor(DependencyChecker checker, String type) {
MethodReference ref = new MethodReference(type, new MethodDescriptor("<init>", ValueType.VOID));
checker.linkMethod(ref, newInstanceStack).use();
}
@Override
public void fieldAchieved(DependencyChecker dependencyChecker, FieldDependency field) {
}

View File

@ -47,6 +47,9 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
case "newInstance":
generateNewInstance(context, writer);
break;
case "getDeclaringClass":
generateGetDeclaringClass(context, writer);
break;
}
}
@ -141,8 +144,27 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
writer.append("$rt_throw(ex);").softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("var instance = new cls();").softNewLine();
writer.append("ctor(instance)");
writer.append("return instance");
writer.append("ctor(instance);").softNewLine();
writer.append("return instance;").softNewLine();
}
private void generateGetDeclaringClass(GeneratorContext context, SourceWriter writer) throws IOException {
String self = context.getParameterName(0);
writer.append("if (!").appendClass("java.lang.Class").append(".$$owners$$) {").indent().softNewLine();
writer.appendClass("java.lang.Class").append(".$$owners$$ = true;").softNewLine();
for (String clsName : context.getClassSource().getClassNames()) {
ClassReader cls = context.getClassSource().get(clsName);
writer.appendClass(clsName).append(".$$owner$$ = ");
if (cls.getOwnerName() != null) {
writer.appendClass(cls.getOwnerName());
} else {
writer.append("null");
}
writer.append(";").softNewLine();
}
writer.outdent().append("}").softNewLine();
writer.append("var cls = " + self + ".$data;").softNewLine();
writer.append("return cls.$$owner$$ != null ? $rt_cls(cls.$$owner$$) : null;").softNewLine();
}
@Override
@ -154,6 +176,7 @@ public class ClassNativeGenerator implements Generator, Injector, DependencyPlug
case "getSuperclass":
case "getComponentType0":
case "forNameImpl":
case "getDeclaringClass":
graph.getResult().propagate("java.lang.Class");
break;
}

View File

@ -134,4 +134,8 @@ public class TClass<T extends TObject> extends TObject {
@GeneratedBy(ClassNativeGenerator.class)
public native T newInstance() throws TInstantiationException, TIllegalAccessException;
@GeneratedBy(ClassNativeGenerator.class)
@PluggableDependency(ClassNativeGenerator.class)
public native TClass<?> getDeclaringClass();
}

View File

@ -97,4 +97,12 @@ public class ClassTest {
assertEquals(TestObject.class, instance.getClass());
assertEquals(1, ((TestObject)instance).getCounter());
}
@Test
public void declaringClassFound() {
assertEquals(ClassTest.class, new A().getClass().getDeclaringClass());
}
private static class A {
}
}

View File

@ -26,6 +26,7 @@ public class ClassHolder extends ElementHolder implements ClassReader {
private Set<String> interfaces = new HashSet<>();
private Map<MethodDescriptor, MethodHolder> methods = new HashMap<>();
private Map<String, FieldHolder> fields = new HashMap<>();
private String ownerName;
public ClassHolder(String name) {
super(name);
@ -106,4 +107,13 @@ public class ClassHolder extends ElementHolder implements ClassReader {
fields.remove(field.getName());
field.setOwner(null);
}
@Override
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
}

View File

@ -34,4 +34,6 @@ public interface ClassReader extends ElementReader {
FieldReader getField(String name);
Collection<? extends FieldReader> getFields();
String getOwnerName();
}

View File

@ -59,6 +59,7 @@ public class CopyClassHolderSource implements ClassHolderSource {
for (FieldHolder field : original.getFields()) {
copy.addField(copyField(field));
}
copy.setOwnerName(original.getOwnerName());
copyAnnotations(original.getAnnotations(), copy.getAnnotations());
return copy;
}

View File

@ -57,6 +57,9 @@ class ClassRefsRenamer implements InstructionVisitor {
cls.removeField(field);
renamedCls.addField(field);
}
if (cls.getOwnerName() != null) {
renamedCls.setOwnerName(classNameMapper.map(cls.getOwnerName()));
}
rename(cls.getAnnotations(), renamedCls.getAnnotations());
for (String iface : cls.getInterfaces()) {
renamedCls.getInterfaces().add(classNameMapper.map(iface));

View File

@ -64,6 +64,14 @@ public class Parser {
MethodNode methodNode = (MethodNode)obj;
cls.addMethod(parseMethod(methodNode, node.name));
}
if (node.outerClass != null) {
cls.setOwnerName(node.outerClass.replace('/', '.'));
} else {
int lastIndex = node.name.lastIndexOf('$');
if (lastIndex != -1) {
cls.setOwnerName(node.name.substring(0, lastIndex).replace('/', '.'));
}
}
parseAnnotations(cls.getAnnotations(), node);
return cls;
}