Fix up the post-default interface generation

This commit is contained in:
Ben Gruver 2016-09-26 23:29:55 -07:00
parent 37f5436932
commit ab20c37fd0
2 changed files with 68 additions and 41 deletions

View File

@ -166,6 +166,7 @@ public class ClassProto implements TypeProto {
}
}
} catch (UnresolvedClassException ex) {
interfaces.put(type, null);
unresolvedInterfaces.add(type);
interfacesFullyResolved = false;
}
@ -230,10 +231,20 @@ public class ClassProto implements TypeProto {
for (String interfaceType: getClassDef().getInterfaces()) {
if (!interfaces.containsKey(interfaceType)) {
ClassProto interfaceProto = (ClassProto)classPath.getClass(interfaceType);
for (Entry<String, ClassDef> entry: interfaceProto.getInterfaces().entrySet()) {
if (!interfaces.containsKey(entry.getKey())) {
interfaces.put(entry.getKey(), entry.getValue());
try {
for (Entry<String, ClassDef> entry: interfaceProto.getInterfaces().entrySet()) {
if (!interfaces.containsKey(entry.getKey())) {
interfaces.put(entry.getKey(), entry.getValue());
}
}
} catch (UnresolvedClassException ex) {
interfaces.put(interfaceType, null);
unresolvedInterfaces.add(interfaceType);
interfacesFullyResolved = false;
}
if (!interfaceProto.interfacesFullyResolved) {
unresolvedInterfaces.addAll(interfaceProto.getUnresolvedInterfaces());
interfacesFullyResolved = false;
}
try {
ClassDef interfaceDef = classPath.getClassDef(interfaceType);
@ -246,6 +257,7 @@ public class ClassProto implements TypeProto {
}
}
} catch (UnresolvedClassException ex) {
interfaces.put(type, null);
unresolvedInterfaces.add(type);
interfacesFullyResolved = false;
}

View File

@ -32,8 +32,10 @@
package org.jf.dexlib2.analysis;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import junit.framework.Assert;
import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.immutable.ImmutableDexFile;
import org.junit.Test;
@ -51,49 +53,53 @@ public class CommonSuperclassTest {
// fivetwothree
// fivethree
private final ClassPath classPath;
private final ClassPath oldClassPath;
private final ClassPath newClassPath;
public CommonSuperclassTest() throws IOException {
classPath = new ClassPath(new DexClassProvider(new ImmutableDexFile(Opcodes.getDefault(),
ImmutableSet.of(
TestUtils.makeClassDef("Ljava/lang/Object;", null),
TestUtils.makeClassDef("Ltest/one;", "Ljava/lang/Object;"),
TestUtils.makeClassDef("Ltest/two;", "Ljava/lang/Object;"),
TestUtils.makeClassDef("Ltest/onetwo;", "Ltest/one;"),
TestUtils.makeClassDef("Ltest/onetwothree;", "Ltest/onetwo;"),
TestUtils.makeClassDef("Ltest/onethree;", "Ltest/one;"),
TestUtils.makeClassDef("Ltest/fivetwo;", "Ltest/five;"),
TestUtils.makeClassDef("Ltest/fivetwothree;", "Ltest/fivetwo;"),
TestUtils.makeClassDef("Ltest/fivethree;", "Ltest/five;"),
TestUtils.makeInterfaceDef("Ljava/lang/Cloneable;"),
TestUtils.makeInterfaceDef("Ljava/io/Serializable;"),
ImmutableSet<ClassDef> classes = ImmutableSet.of(
TestUtils.makeClassDef("Ljava/lang/Object;", null),
TestUtils.makeClassDef("Ltest/one;", "Ljava/lang/Object;"),
TestUtils.makeClassDef("Ltest/two;", "Ljava/lang/Object;"),
TestUtils.makeClassDef("Ltest/onetwo;", "Ltest/one;"),
TestUtils.makeClassDef("Ltest/onetwothree;", "Ltest/onetwo;"),
TestUtils.makeClassDef("Ltest/onethree;", "Ltest/one;"),
TestUtils.makeClassDef("Ltest/fivetwo;", "Ltest/five;"),
TestUtils.makeClassDef("Ltest/fivetwothree;", "Ltest/fivetwo;"),
TestUtils.makeClassDef("Ltest/fivethree;", "Ltest/five;"),
TestUtils.makeInterfaceDef("Ljava/lang/Cloneable;"),
TestUtils.makeInterfaceDef("Ljava/io/Serializable;"),
// basic class and interface
TestUtils.makeClassDef("Liface/classiface1;", "Ljava/lang/Object;", "Liface/iface1;"),
TestUtils.makeInterfaceDef("Liface/iface1;"),
// basic class and interface
TestUtils.makeClassDef("Liface/classiface1;", "Ljava/lang/Object;", "Liface/iface1;"),
TestUtils.makeInterfaceDef("Liface/iface1;"),
// a more complex interface tree
TestUtils.makeInterfaceDef("Liface/base1;"),
// implements undefined interface
TestUtils.makeInterfaceDef("Liface/sub1;", "Liface/base1;", "Liface/base2;"),
// this implements sub1, so that its interfaces can't be fully resolved either
TestUtils.makeInterfaceDef("Liface/sub2;", "Liface/base1;", "Liface/sub1;"),
TestUtils.makeInterfaceDef("Liface/sub3;", "Liface/base1;"),
TestUtils.makeInterfaceDef("Liface/sub4;", "Liface/base1;", "Liface/sub3;"),
TestUtils.makeClassDef("Liface/classsub1;", "Ljava/lang/Object;", "Liface/sub1;"),
TestUtils.makeClassDef("Liface/classsub2;", "Ljava/lang/Object;", "Liface/sub2;"),
TestUtils.makeClassDef("Liface/classsub3;", "Ljava/lang/Object;", "Liface/sub3;",
"Liface/base;"),
TestUtils.makeClassDef("Liface/classsub4;", "Ljava/lang/Object;", "Liface/sub3;",
"Liface/sub4;"),
TestUtils.makeClassDef("Liface/classsubsub4;", "Liface/classsub4;"),
TestUtils.makeClassDef("Liface/classsub1234;", "Ljava/lang/Object;", "Liface/sub1;",
"Liface/sub2;", "Liface/sub3;", "Liface/sub4;")
))));
// a more complex interface tree
TestUtils.makeInterfaceDef("Liface/base1;"),
// implements undefined interface
TestUtils.makeInterfaceDef("Liface/sub1;", "Liface/base1;", "Liface/base2;"),
// this implements sub1, so that its interfaces can't be fully resolved either
TestUtils.makeInterfaceDef("Liface/sub2;", "Liface/base1;", "Liface/sub1;"),
TestUtils.makeInterfaceDef("Liface/sub3;", "Liface/base1;"),
TestUtils.makeInterfaceDef("Liface/sub4;", "Liface/base1;", "Liface/sub3;"),
TestUtils.makeClassDef("Liface/classsub1;", "Ljava/lang/Object;", "Liface/sub1;"),
TestUtils.makeClassDef("Liface/classsub2;", "Ljava/lang/Object;", "Liface/sub2;"),
TestUtils.makeClassDef("Liface/classsub3;", "Ljava/lang/Object;", "Liface/sub3;",
"Liface/base;"),
TestUtils.makeClassDef("Liface/classsub4;", "Ljava/lang/Object;", "Liface/sub3;",
"Liface/sub4;"),
TestUtils.makeClassDef("Liface/classsubsub4;", "Liface/classsub4;"),
TestUtils.makeClassDef("Liface/classsub1234;", "Ljava/lang/Object;", "Liface/sub1;",
"Liface/sub2;", "Liface/sub3;", "Liface/sub4;"));
oldClassPath = new ClassPath(new DexClassProvider(new ImmutableDexFile(Opcodes.getDefault(), classes)));
newClassPath = new ClassPath(Lists.newArrayList(new DexClassProvider(
new ImmutableDexFile(Opcodes.forArtVersion(72), classes))), true, 72);
}
public void superclassTest(String commonSuperclass,
String type1, String type2) {
public void superclassTest(ClassPath classPath, String commonSuperclass,
String type1, String type2) {
TypeProto commonSuperclassProto = classPath.getClass(commonSuperclass);
TypeProto type1Proto = classPath.getClass(type1);
TypeProto type2Proto = classPath.getClass(type2);
@ -102,6 +108,11 @@ public class CommonSuperclassTest {
Assert.assertSame(commonSuperclassProto, type2Proto.getCommonSuperclass(type1Proto));
}
public void superclassTest(String commonSuperclass, String type1, String type2) {
superclassTest(oldClassPath, commonSuperclass, type1, type2);
superclassTest(newClassPath, commonSuperclass, type1, type2);
}
@Test
public void testGetCommonSuperclass() throws IOException {
String object = "Ljava/lang/Object;";
@ -131,7 +142,11 @@ public class CommonSuperclassTest {
// same value, but different object
Assert.assertEquals(
onetwo,
classPath.getClass(onetwo).getCommonSuperclass(new ClassProto(classPath, onetwo)).getType());
oldClassPath.getClass(onetwo).getCommonSuperclass(new ClassProto(oldClassPath, onetwo)).getType());
Assert.assertEquals(
onetwo,
newClassPath.getClass(onetwo).getCommonSuperclass(new ClassProto(newClassPath, onetwo)).getType());
// other object is superclass
superclassTest(object, object, one);