summaryrefslogtreecommitdiff
path: root/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java')
-rw-r--r--java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java36
1 files changed, 24 insertions, 12 deletions
diff --git a/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java b/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java
index 9b20c9d..1aaf0b6 100644
--- a/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java
+++ b/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java
@@ -43,6 +43,7 @@ public class DefaultMethodClassFixer extends ClassVisitor {
private final ClassReaderFactory classpath;
private final ClassReaderFactory bootclasspath;
private final ClassLoader targetLoader;
+ private final DependencyCollector depsCollector;
private final HashSet<String> instanceMethods = new HashSet<>();
private boolean isInterface;
@@ -55,12 +56,14 @@ public class DefaultMethodClassFixer extends ClassVisitor {
public DefaultMethodClassFixer(
ClassVisitor dest,
ClassReaderFactory classpath,
+ DependencyCollector depsCollector,
ClassReaderFactory bootclasspath,
ClassLoader targetLoader) {
super(Opcodes.ASM6, dest);
this.classpath = classpath;
this.bootclasspath = bootclasspath;
this.targetLoader = targetLoader;
+ this.depsCollector = depsCollector;
}
@Override
@@ -310,8 +313,17 @@ public class DefaultMethodClassFixer extends ClassVisitor {
*/
private boolean defaultMethodsDefined(ImmutableList<String> interfaces) {
for (String implemented : interfaces) {
+ if (bootclasspath.isKnown(implemented)) {
+ continue;
+ }
ClassReader bytecode = classpath.readIfKnown(implemented);
- if (bytecode != null && !bootclasspath.isKnown(implemented)) {
+ if (bytecode == null) {
+ // Interface isn't on the classpath, which indicates incomplete classpaths. Record missing
+ // dependency so we can check it later. If we don't check then we may get runtime failures
+ // or wrong behavior from default methods that should've been stubbed in.
+ // TODO(kmb): Print a warning so people can start fixing their deps?
+ depsCollector.missingImplementedInterface(internalName, implemented);
+ } else {
// Class in classpath and bootclasspath is a bad idea but in any event, assume the
// bootclasspath will take precedence like in a classloader.
// We can skip code attributes as we just need to find default methods to stub.
@@ -321,10 +333,6 @@ public class DefaultMethodClassFixer extends ClassVisitor {
return true;
}
}
- // Else interface isn't on the classpath, which indicates incomplete classpaths. For now
- // we'll just assume the missing interfaces don't declare default methods but if they do
- // we'll end up with concrete classes that don't implement an abstract method, which can
- // cause runtime failures. The classpath needs to be fixed in this case.
}
return false;
}
@@ -377,7 +385,7 @@ public class DefaultMethodClassFixer extends ClassVisitor {
*/
private class DefaultMethodStubber extends ClassVisitor {
- private String interfaceName;
+ private String stubbedInterfaceName;
public DefaultMethodStubber() {
super(Opcodes.ASM6);
@@ -392,8 +400,8 @@ public class DefaultMethodClassFixer extends ClassVisitor {
String superName,
String[] interfaces) {
checkArgument(BitFlags.isSet(access, Opcodes.ACC_INTERFACE));
- checkState(interfaceName == null);
- interfaceName = name;
+ checkState(stubbedInterfaceName == null);
+ stubbedInterfaceName = name;
}
@Override
@@ -405,6 +413,8 @@ public class DefaultMethodClassFixer extends ClassVisitor {
// definitions conflict, but see stubMissingDefaultMethods() for how we deal with default
// methods redefined in interfaces extending another.
recordIfInstanceMethod(access, name, desc);
+ depsCollector.assumeCompanionClass(
+ internalName, InterfaceDesugaring.getCompanionClassName(stubbedInterfaceName));
// Add this method to the class we're desugaring and stub in a body to call the default
// implementation in the interface's companion class. ijar omits these methods when setting
@@ -423,9 +433,9 @@ public class DefaultMethodClassFixer extends ClassVisitor {
}
stubMethod.visitMethodInsn(
Opcodes.INVOKESTATIC,
- interfaceName + InterfaceDesugaring.COMPANION_SUFFIX,
+ InterfaceDesugaring.getCompanionClassName(stubbedInterfaceName),
name,
- InterfaceDesugaring.companionDefaultMethodDescriptor(interfaceName, desc),
+ InterfaceDesugaring.companionDefaultMethodDescriptor(stubbedInterfaceName, desc),
/*itf*/ false);
stubMethod.visitInsn(neededType.getReturnType().getOpcode(Opcodes.IRETURN));
@@ -439,8 +449,10 @@ public class DefaultMethodClassFixer extends ClassVisitor {
// interface methods are correctly handled.
return new InterfaceDesugaring.InterfaceInvocationRewriter(
DefaultMethodClassFixer.this.visitMethod(access, name, desc, (String) null, exceptions),
- interfaceName,
- bootclasspath);
+ stubbedInterfaceName,
+ bootclasspath,
+ depsCollector,
+ internalName);
} else {
return null; // we don't care about the actual code in these methods
}