Unified interface table creation logic. No more duplication.

This commit is contained in:
Izzat Bahadirov 2013-04-28 17:30:11 -04:00
parent 389c3a6afa
commit e3b5efd7d8

View File

@ -34,7 +34,6 @@ package org.jf.dexlib2.analysis;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.jf.dexlib2.AccessFlags; import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.analysis.util.TypeProtoUtils; import org.jf.dexlib2.analysis.util.TypeProtoUtils;
import org.jf.dexlib2.iface.ClassDef; import org.jf.dexlib2.iface.ClassDef;
@ -43,7 +42,6 @@ import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodReference; import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.util.FieldUtil; import org.jf.dexlib2.util.FieldUtil;
import org.jf.dexlib2.util.MethodUtil;
import org.jf.util.ExceptionWithContext; import org.jf.util.ExceptionWithContext;
import org.jf.util.SparseArray; import org.jf.util.SparseArray;
@ -59,8 +57,7 @@ public class ClassProto implements TypeProto {
@Nonnull protected final ClassPath classPath; @Nonnull protected final ClassPath classPath;
@Nonnull protected final String type; @Nonnull protected final String type;
@Nullable protected ClassDef classDef; @Nullable protected ClassDef classDef;
@Nullable protected Set<String> interfaces; @Nullable protected LinkedHashMap<String, ClassDef> interfaces;
@Nullable protected LinkedHashMap<String, ClassDef> interfaceTable;
@Nullable protected Method[] vtable; @Nullable protected Method[] vtable;
@Nullable protected SparseArray<FieldReference> instanceFields; @Nullable protected SparseArray<FieldReference> instanceFields;
protected boolean interfacesFullyResolved = true; protected boolean interfacesFullyResolved = true;
@ -99,13 +96,6 @@ public class ClassProto implements TypeProto {
return instanceFields; return instanceFields;
} }
LinkedHashMap<String, ClassDef> getInterfaceTable() {
if (interfaceTable == null) {
interfaceTable = loadInterfaceTable();
}
return interfaceTable;
}
/** /**
* Returns true if this class is an interface. * Returns true if this class is an interface.
* *
@ -118,47 +108,31 @@ public class ClassProto implements TypeProto {
return (classDef.getAccessFlags() & AccessFlags.INTERFACE.getValue()) != 0; return (classDef.getAccessFlags() & AccessFlags.INTERFACE.getValue()) != 0;
} }
private void addInterfacesRecursively(@Nonnull ClassDef classDef) {
assert interfaces != null;
for (String iface: classDef.getInterfaces()) {
interfaces.add(iface);
addInterfacesRecursively(iface);
}
}
private void addInterfacesRecursively(@Nonnull String cls) {
ClassDef classDef;
try {
classDef = classPath.getClassDef(cls);
addInterfacesRecursively(classDef);
} catch (UnresolvedClassException ex) {
interfacesFullyResolved = false;
}
}
@Nonnull @Nonnull
protected Set<String> getInterfaces() { protected LinkedHashMap<String, ClassDef> getInterfaces() {
if (interfaces != null) { if (interfaces != null) {
return interfaces; return interfaces;
} }
interfaces = Sets.newHashSet(); interfaces = Maps.newLinkedHashMap();
try { try {
ClassDef classDef = getClassDef(); for (String interfaceType: getClassDef().getInterfaces()) {
if (!interfaces.containsKey(interfaceType)) {
ClassDef interfaceDef;
try {
interfaceDef = classPath.getClassDef(interfaceType);
interfaces.put(interfaceType, interfaceDef);
} catch (UnresolvedClassException ex) {
interfacesFullyResolved = false;
}
if (isInterface()) { ClassProto interfaceProto = (ClassProto) classPath.getClass(interfaceType);
interfaces.add(getType()); for (ClassDef superInterface: interfaceProto.getInterfaces().values()) {
} if (!interfaces.containsKey(superInterface.getType())) {
interfaces.put(superInterface.getType(), superInterface);
while (true) { }
addInterfacesRecursively(classDef); }
String superclass = classDef.getSuperclass();
if (superclass != null) {
classDef = classPath.getClassDef(superclass);
} else {
break;
} }
} }
} catch (UnresolvedClassException ex) { } catch (UnresolvedClassException ex) {
@ -179,10 +153,8 @@ public class ClassProto implements TypeProto {
*/ */
@Override @Override
public boolean implementsInterface(@Nonnull String iface) { public boolean implementsInterface(@Nonnull String iface) {
for (String implementIface: getInterfaces()) { if (getInterfaces().containsKey(iface)) {
if (implementIface.equals(iface)) { return true;
return true;
}
} }
if (!interfacesFullyResolved) { if (!interfacesFullyResolved) {
throw new UnresolvedClassException("Interfaces for class %s not fully resolved", getType()); throw new UnresolvedClassException("Interfaces for class %s not fully resolved", getType());
@ -541,11 +513,8 @@ public class ClassProto implements TypeProto {
if (!isInterface()) { if (!isInterface()) {
addToVtable(getClassDef().getVirtualMethods(), virtualMethodList); addToVtable(getClassDef().getVirtualMethods(), virtualMethodList);
LinkedHashMap<String, ClassDef> interfaceTable = loadInterfaceTable(); for (ClassDef interfaceDef: getInterfaces().values()) {
if (interfaceTable != null) { addToVtable(interfaceDef.getVirtualMethods(), virtualMethodList);
for (ClassDef interfaceDef: interfaceTable.values()) {
addToVtable(interfaceDef.getVirtualMethods(), virtualMethodList);
}
} }
} }
@ -557,32 +526,6 @@ public class ClassProto implements TypeProto {
return vtable; return vtable;
} }
private LinkedHashMap<String, ClassDef> loadInterfaceTable() {
LinkedHashMap<String, ClassDef> interfaceTable = Maps.newLinkedHashMap();
for (String interfaceType: getClassDef().getInterfaces()) {
if (!interfaceTable.containsKey(interfaceType)) {
ClassDef interfaceDef;
try {
interfaceDef = classPath.getClassDef(interfaceType);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex,
String.format("Could not find interface %s", interfaceType));
}
interfaceTable.put(interfaceType, interfaceDef);
ClassProto interfaceProto = (ClassProto) classPath.getClass(interfaceType);
for (ClassDef superInterface: interfaceProto.getInterfaceTable().values()) {
if (!interfaceTable.containsKey(superInterface.getType())) {
interfaceTable.put(superInterface.getType(), superInterface);
}
}
}
}
return interfaceTable;
}
private void addToVtable(Iterable<? extends Method> localMethods, List<Method> vtable) { private void addToVtable(Iterable<? extends Method> localMethods, List<Method> vtable) {
for (Method virtualMethod: localMethods) { for (Method virtualMethod: localMethods) {
boolean found = false; boolean found = false;