Skip to content

Commit

Permalink
Limit instrumentation on interfaces
Browse files Browse the repository at this point in the history
Previously, Robolectric enabled some of its instrumentation on interfaces
in order to support hooking up interceptors on default interface methods.
This is because there are now some default interface methods that invoke
System.logW (e.g. android.compat.Compatibility$BehaviorChangeDelegate)

However, the instrumentation step that makes classes public
was also applied to interfaces, and this seems to confuse Mockito/ByteBuddy,
but only in certain environments.

As a fix, restrict the instrumentation to only rewrite interface method
bodies, as well as extends 'InstrumentedInterface', so Robolectric does
not re-instrument interfaces when the preinstrumented jars are used.

A test case will be added after the preinstrumented jar version is
bumped.

Fixes #6858

PiperOrigin-RevId: 410440888
  • Loading branch information
hoisie committed Nov 17, 2021
1 parent 326991f commit 0f1c9be
Showing 1 changed file with 12 additions and 12 deletions.
Expand Up @@ -143,18 +143,6 @@ private void recordPackageStats(PerfStatsCollector perfStats, MutableClass mutab

public void instrument(MutableClass mutableClass) {
try {
makeClassPublic(mutableClass.classNode);
if ((mutableClass.classNode.access & Opcodes.ACC_FINAL) == Opcodes.ACC_FINAL) {
mutableClass
.classNode
.visitAnnotation("Lcom/google/errorprone/annotations/DoNotMock;", true)
.visit(
"value",
"This class is final. Consider using the real thing, or "
+ "adding/enhancing a Robolectric shadow for it.");
}
mutableClass.classNode.access = mutableClass.classNode.access & ~Opcodes.ACC_FINAL;

// Need Java version >=7 to allow invokedynamic
mutableClass.classNode.version = Math.max(mutableClass.classNode.version, Opcodes.V1_7);

Expand All @@ -163,6 +151,18 @@ public void instrument(MutableClass mutableClass) {
if (mutableClass.isInterface()) {
mutableClass.addInterface(Type.getInternalName(InstrumentedInterface.class));
} else {
makeClassPublic(mutableClass.classNode);
if ((mutableClass.classNode.access & Opcodes.ACC_FINAL) == Opcodes.ACC_FINAL) {
mutableClass
.classNode
.visitAnnotation("Lcom/google/errorprone/annotations/DoNotMock;", true)
.visit(
"value",
"This class is final. Consider using the real thing, or "
+ "adding/enhancing a Robolectric shadow for it.");
}
mutableClass.classNode.access = mutableClass.classNode.access & ~Opcodes.ACC_FINAL;

// If there is no constructor, adds one
addNoArgsConstructor(mutableClass);

Expand Down

0 comments on commit 0f1c9be

Please sign in to comment.