aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java
diff options
context:
space:
mode:
authorGravatar kmb <kmb@google.com>2017-10-03 02:14:25 +0200
committerGravatar Klaus Aehlig <aehlig@google.com>2017-10-06 19:42:37 +0200
commitbdb12ceeb7c23d7d2293e8006d0aa7127a91b973 (patch)
tree6b2a83baa22f5a8523fe33fb3706932e5c37d0b2 /src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java
parent36e2a1c80c0d2bd4455c960833c27b19c0cb6586 (diff)
add flags to desugar to emit metadata that can be used for double-checking correctness of default and static interface desugaring.
RELNOTES: none PiperOrigin-RevId: 170779637
Diffstat (limited to 'src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java')
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java24
1 files changed, 18 insertions, 6 deletions
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java b/src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java
index d7d46a1919..2d89e8b2b1 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java
+++ b/src/tools/android/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.ASM5, 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;
}
@@ -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(interfaceName));
// 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,7 +433,7 @@ public class DefaultMethodClassFixer extends ClassVisitor {
}
stubMethod.visitMethodInsn(
Opcodes.INVOKESTATIC,
- interfaceName + InterfaceDesugaring.COMPANION_SUFFIX,
+ InterfaceDesugaring.getCompanionClassName(interfaceName),
name,
InterfaceDesugaring.companionDefaultMethodDescriptor(interfaceName, desc),
/*itf*/ false);
@@ -434,6 +444,8 @@ public class DefaultMethodClassFixer extends ClassVisitor {
return null;
} else if (shouldStubAsBridgeDefaultMethod(access, name, desc)) {
recordIfInstanceMethod(access, name, desc);
+ depsCollector.assumeCompanionClass(
+ internalName, InterfaceDesugaring.getCompanionClassName(interfaceName));
// For bridges we just copy their bodies instead of going through the companion class.
// Meanwhile, we also need to desugar the copied method bodies, so that any calls to
// interface methods are correctly handled.