aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/android/java/com/google/devtools/build/android/desugar
diff options
context:
space:
mode:
authorGravatar kmb <kmb@google.com>2018-02-15 10:43:41 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2018-02-15 10:45:16 -0800
commitc8e8749adc7b98c272b2421569dc97a88d487771 (patch)
tree169217203a3b86676ddae282f0f9df479eea6116 /src/tools/android/java/com/google/devtools/build/android/desugar
parent0588ba0445560ea9503ed623d1f231cb65aa20c8 (diff)
Resolve the owner of interface.super calls to inherited default methods for android desugaring
RELNOTES: None. PiperOrigin-RevId: 185863194
Diffstat (limited to 'src/tools/android/java/com/google/devtools/build/android/desugar')
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/desugar/DefaultMethodClassFixer.java1
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java2
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/desugar/InterfaceDesugaring.java42
3 files changed, 43 insertions, 2 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 2eda141fb9..52964b7f70 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
@@ -502,6 +502,7 @@ public class DefaultMethodClassFixer extends ClassVisitor {
DefaultMethodClassFixer.this.visitMethod(access, name, desc, (String) null, exceptions),
stubbedInterfaceName,
bootclasspath,
+ targetLoader,
depsCollector,
internalName);
} else {
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java b/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
index 053e55e760..58b9b885cf 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
@@ -697,6 +697,7 @@ class Desugar {
interfaceCache,
depsCollector,
bootclasspathReader,
+ loader,
store,
options.legacyJacocoFix);
}
@@ -776,6 +777,7 @@ class Desugar {
interfaceCache,
depsCollector,
bootclasspathReader,
+ loader,
store,
options.legacyJacocoFix);
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/InterfaceDesugaring.java b/src/tools/android/java/com/google/devtools/build/android/desugar/InterfaceDesugaring.java
index 3524fae710..f17f114884 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/InterfaceDesugaring.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/InterfaceDesugaring.java
@@ -17,6 +17,7 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
+import java.lang.reflect.Method;
import javax.annotation.Nullable;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
@@ -47,6 +48,7 @@ class InterfaceDesugaring extends ClassVisitor {
private final ClassVsInterface interfaceCache;
private final DependencyCollector depsCollector;
private final ClassReaderFactory bootclasspath;
+ private final ClassLoader targetLoader;
private final GeneratedClassStore store;
private final boolean legacyJaCoCo;
@@ -62,12 +64,14 @@ class InterfaceDesugaring extends ClassVisitor {
ClassVsInterface interfaceCache,
DependencyCollector depsCollector,
ClassReaderFactory bootclasspath,
+ ClassLoader targetLoader,
GeneratedClassStore store,
boolean legacyJaCoCo) {
super(Opcodes.ASM6, dest);
this.interfaceCache = interfaceCache;
this.depsCollector = depsCollector;
this.bootclasspath = bootclasspath;
+ this.targetLoader = targetLoader;
this.store = store;
this.legacyJaCoCo = legacyJaCoCo;
}
@@ -234,7 +238,12 @@ class InterfaceDesugaring extends ClassVisitor {
}
return result != null
? new InterfaceInvocationRewriter(
- result, isInterface() ? internalName : null, bootclasspath, depsCollector, codeOwner)
+ result,
+ isInterface() ? internalName : null,
+ bootclasspath,
+ targetLoader,
+ depsCollector,
+ codeOwner)
: null;
}
@@ -354,6 +363,7 @@ class InterfaceDesugaring extends ClassVisitor {
@Nullable private final String interfaceName;
private final ClassReaderFactory bootclasspath;
+ private final ClassLoader targetLoader;
private final DependencyCollector depsCollector;
/** Internal name that'll be used to record any dependencies on interface methods. */
private final String declaringClass;
@@ -362,11 +372,13 @@ class InterfaceDesugaring extends ClassVisitor {
MethodVisitor dest,
@Nullable String knownInterfaceName,
ClassReaderFactory bootclasspath,
+ ClassLoader targetLoader,
DependencyCollector depsCollector,
String declaringClass) {
super(Opcodes.ASM6, dest);
this.interfaceName = knownInterfaceName;
this.bootclasspath = bootclasspath;
+ this.targetLoader = targetLoader;
this.depsCollector = depsCollector;
this.declaringClass = declaringClass;
}
@@ -409,7 +421,16 @@ class InterfaceDesugaring extends ClassVisitor {
checkArgument(!owner.endsWith(DependencyCollector.INTERFACE_COMPANION_SUFFIX),
"shouldn't consider %s an interface", owner);
if (opcode == Opcodes.INVOKESPECIAL) {
- // Turn Interface.super.m() into Interface$$CC.m(receiver)
+ // Turn Interface.super.m() into DefiningInterface$$CC.m(receiver). Note that owner
+ // always refers to the current type's immediate super-interface, but the default method
+ // may be inherited by that interface, so we have to figure out where the method is
+ // defined and invoke it in the corresponding companion class (b/73355452). Note that
+ // we're always dealing with interfaces here, and all interface methods are public,
+ // so using Class.getMethods should suffice to find inherited methods. Also note this
+ // can only be a default method invocation, no abstract method invocation.
+ owner =
+ findDefaultMethod(owner, name, desc)
+ .getDeclaringClass().getName().replace('.', '/');
opcode = Opcodes.INVOKESTATIC;
desc = companionDefaultMethodDescriptor(owner, desc);
}
@@ -421,6 +442,23 @@ class InterfaceDesugaring extends ClassVisitor {
}
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
+
+ private Method findDefaultMethod(String owner, String name, String desc) {
+ try {
+ Class<?> clazz = targetLoader.loadClass(owner.replace('/', '.'));
+ // otherwise getting public methods with getMethods() below isn't enough
+ checkArgument(clazz.isInterface(), "Not an interface: %s", owner);
+ for (Method m : clazz.getMethods()) {
+ if (m.getName().equals(name) && Type.getMethodDescriptor(m).equals(desc)) {
+ checkState(m.isDefault(), "Found non-default method: %s", m);
+ return m;
+ }
+ }
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Couldn't load " + owner, e);
+ }
+ throw new IllegalArgumentException("Method not found: " + owner + "." + name + desc);
+ }
}
/**