From 63cde3a65d10f7f94460547042566f940d5453f0 Mon Sep 17 00:00:00 2001 From: kmb Date: Thu, 1 Mar 2018 16:26:21 -0800 Subject: Android desugar config options to exclude methods from interface emulation RELNOTES: None. PiperOrigin-RevId: 187551970 GitOrigin-RevId: f090082d62c3ea779d2dd33eb0fd7355b0ee9456 Change-Id: Id9ff715440eace84432ae6c5b88f7daaa43f36db --- .../build/android/desugar/CoreLibrarySupport.java | 17 ++++++++- .../devtools/build/android/desugar/Desugar.java | 16 +++++++- .../android/desugar/CoreLibrarySupportTest.java | 44 +++++++++++++++++++++- .../android/desugar/CorePackageRenamerTest.java | 3 +- 4 files changed, 75 insertions(+), 5 deletions(-) diff --git a/java/com/google/devtools/build/android/desugar/CoreLibrarySupport.java b/java/com/google/devtools/build/android/desugar/CoreLibrarySupport.java index c73874e..e22c596 100644 --- a/java/com/google/devtools/build/android/desugar/CoreLibrarySupport.java +++ b/java/com/google/devtools/build/android/desugar/CoreLibrarySupport.java @@ -44,6 +44,7 @@ class CoreLibrarySupport { private final ClassLoader targetLoader; /** Internal name prefixes that we want to move to a custom package. */ private final ImmutableSet renamedPrefixes; + private final ImmutableSet excludeFromEmulation; /** Internal names of interfaces whose default and static interface methods we'll emulate. */ private final ImmutableSet> emulatedInterfaces; /** Map from {@code owner#name} core library members to their new owners. */ @@ -58,13 +59,16 @@ class CoreLibrarySupport { GeneratedClassStore store, List renamedPrefixes, List emulatedInterfaces, - List memberMoves) { + List memberMoves, + List excludeFromEmulation) { this.rewriter = rewriter; this.targetLoader = targetLoader; this.store = store; checkArgument( renamedPrefixes.stream().allMatch(prefix -> prefix.startsWith("java/")), renamedPrefixes); this.renamedPrefixes = ImmutableSet.copyOf(renamedPrefixes); + this.excludeFromEmulation = ImmutableSet.copyOf(excludeFromEmulation); + ImmutableSet.Builder> classBuilder = ImmutableSet.builder(); for (String itf : emulatedInterfaces) { checkArgument(itf.startsWith("java/util/"), itf); @@ -86,6 +90,8 @@ class CoreLibrarySupport { checkArgument(!isRenamedCoreLibrary(pair.get(0).substring(0, sep)), "Original renamed, no need to move it: %s", move); checkArgument(isRenamedCoreLibrary(pair.get(1)), "Target not renamed: %s", move); + checkArgument(!this.excludeFromEmulation.contains(pair.get(0)), + "Retargeted invocation %s shouldn't overlap with excluded", move); movesBuilder.put(pair.get(0), renameCoreLibrary(pair.get(1))); } @@ -245,6 +251,9 @@ class CoreLibrarySupport { // we can only get here if its a default method, and invokestatic we handled above. Method callee = findInterfaceMethod(clazz, name, desc); if (callee != null && callee.isDefault()) { + if (isExcluded(callee)) { + return null; + } Class result = callee.getDeclaringClass(); if (isRenamedCoreLibrary(result.getName().replace('.', '/')) || emulatedInterfaces.stream().anyMatch(emulated -> emulated.isAssignableFrom(result))) { @@ -294,6 +303,12 @@ class CoreLibrarySupport { return null; } + private boolean isExcluded(Method method) { + String unprefixedOwner = + rewriter.unprefix(method.getDeclaringClass().getName().replace('.', '/')); + return excludeFromEmulation.contains(unprefixedOwner + "#" + method.getName()); + } + private Class loadFromInternal(String internalName) { try { return targetLoader.loadClass(internalName.replace('/', '.')); diff --git a/java/com/google/devtools/build/android/desugar/Desugar.java b/java/com/google/devtools/build/android/desugar/Desugar.java index dd1992a..8b8635b 100644 --- a/java/com/google/devtools/build/android/desugar/Desugar.java +++ b/java/com/google/devtools/build/android/desugar/Desugar.java @@ -292,6 +292,17 @@ class Desugar { ) public List retargetCoreLibraryMembers; + /** Members not to rewrite. */ + @Option( + name = "dont_rewrite_core_library_invocation", + defaultValue = "", // ignored + allowMultiple = true, + documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, + effectTags = {OptionEffectTag.UNKNOWN}, + help = "Method invocations not to rewrite, given as \"class/Name#method\"." + ) + public List dontTouchCoreLibraryMembers; + /** Set to work around b/62623509 with JaCoCo versions prior to 0.7.9. */ // TODO(kmb): Remove when Android Studio doesn't need it anymore (see b/37116789) @Option( @@ -409,8 +420,9 @@ class Desugar { store, options.rewriteCoreLibraryPrefixes, options.emulateCoreLibraryInterfaces, - options.retargetCoreLibraryMembers) - : null; + options.retargetCoreLibraryMembers, + options.dontTouchCoreLibraryMembers) + : null; desugarClassesInInput( inputFiles, diff --git a/test/java/com/google/devtools/build/android/desugar/CoreLibrarySupportTest.java b/test/java/com/google/devtools/build/android/desugar/CoreLibrarySupportTest.java index 90350ce..e6f34ba 100644 --- a/test/java/com/google/devtools/build/android/desugar/CoreLibrarySupportTest.java +++ b/test/java/com/google/devtools/build/android/desugar/CoreLibrarySupportTest.java @@ -37,6 +37,7 @@ public class CoreLibrarySupportTest { null, ImmutableList.of("java/time/"), ImmutableList.of(), + ImmutableList.of(), ImmutableList.of()); assertThat(support.isRenamedCoreLibrary("java/time/X")).isTrue(); assertThat(support.isRenamedCoreLibrary("java/time/y/X")).isTrue(); @@ -55,6 +56,7 @@ public class CoreLibrarySupportTest { null, ImmutableList.of("java/time/"), ImmutableList.of(), + ImmutableList.of(), ImmutableList.of()); assertThat(support.isRenamedCoreLibrary("__/java/time/X")).isTrue(); assertThat(support.isRenamedCoreLibrary("__/java/time/y/X")).isTrue(); @@ -63,6 +65,7 @@ public class CoreLibrarySupportTest { assertThat(support.isRenamedCoreLibrary("__/java/io/X$$Lambda$17")).isTrue(); assertThat(support.isRenamedCoreLibrary("com/google/X")).isFalse(); } + @Test public void testRenameCoreLibrary() throws Exception { CoreLibrarySupport support = @@ -72,6 +75,7 @@ public class CoreLibrarySupportTest { null, ImmutableList.of(), ImmutableList.of(), + ImmutableList.of(), ImmutableList.of()); assertThat(support.renameCoreLibrary("java/time/X")).isEqualTo("j$/time/X"); assertThat(support.renameCoreLibrary("com/google/X")).isEqualTo("com/google/X"); @@ -86,6 +90,7 @@ public class CoreLibrarySupportTest { null, ImmutableList.of(), ImmutableList.of(), + ImmutableList.of(), ImmutableList.of()); assertThat(support.renameCoreLibrary("__/java/time/X")).isEqualTo("j$/time/X"); assertThat(support.renameCoreLibrary("com/google/X")).isEqualTo("com/google/X"); @@ -100,7 +105,8 @@ public class CoreLibrarySupportTest { null, ImmutableList.of("java/util/Helper"), ImmutableList.of(), - ImmutableList.of("java/util/Existing#match -> java/util/Helper")); + ImmutableList.of("java/util/Existing#match -> java/util/Helper"), + ImmutableList.of()); assertThat(support.getMoveTarget("__/java/util/Existing", "match")).isEqualTo("j$/util/Helper"); assertThat(support.getMoveTarget("java/util/Existing", "match")).isEqualTo("j$/util/Helper"); assertThat(support.getMoveTarget("__/java/util/Existing", "matchesnot")).isNull(); @@ -116,6 +122,7 @@ public class CoreLibrarySupportTest { null, ImmutableList.of("java/util/concurrent/"), ImmutableList.of("java/util/Map"), + ImmutableList.of(), ImmutableList.of()); assertThat(support.isEmulatedCoreClassOrInterface("java/util/Map")).isTrue(); assertThat(support.isEmulatedCoreClassOrInterface("java/util/Map$$Lambda$17")).isFalse(); @@ -135,6 +142,7 @@ public class CoreLibrarySupportTest { null, ImmutableList.of(), ImmutableList.of("java/util/Collection"), + ImmutableList.of(), ImmutableList.of()); assertThat( support.getCoreInterfaceRewritingTarget( @@ -171,6 +179,7 @@ public class CoreLibrarySupportTest { null, ImmutableList.of(), ImmutableList.of("java/util/Collection"), + ImmutableList.of(), ImmutableList.of()); assertThat( support.getCoreInterfaceRewritingTarget( @@ -199,6 +208,7 @@ public class CoreLibrarySupportTest { null, ImmutableList.of(), ImmutableList.of("java/util/Map"), + ImmutableList.of(), ImmutableList.of()); assertThat( support.getCoreInterfaceRewritingTarget( @@ -235,6 +245,7 @@ public class CoreLibrarySupportTest { null, ImmutableList.of(), ImmutableList.of("java/util/Comparator"), + ImmutableList.of(), ImmutableList.of()); assertThat( support.getCoreInterfaceRewritingTarget( @@ -259,6 +270,7 @@ public class CoreLibrarySupportTest { null, ImmutableList.of("java/util/"), ImmutableList.of(), + ImmutableList.of(), ImmutableList.of()); // regular invocations of default methods: ignored @@ -328,6 +340,7 @@ public class CoreLibrarySupportTest { null, ImmutableList.of("java/util/concurrent/"), // should return null for these ImmutableList.of("java/util/Map"), + ImmutableList.of(), ImmutableList.of()); assertThat( support.getCoreInterfaceRewritingTarget( @@ -346,4 +359,33 @@ public class CoreLibrarySupportTest { true)) .isNull(); } + + @Test + public void testGetCoreInterfaceRewritingTarget_excludedMethodIgnored() throws Exception { + CoreLibrarySupport support = + new CoreLibrarySupport( + new CoreLibraryRewriter(""), + Thread.currentThread().getContextClassLoader(), + null, + ImmutableList.of(), + ImmutableList.of("java/util/Collection"), + ImmutableList.of(), + ImmutableList.of("java/util/Collection#removeIf")); + assertThat( + support.getCoreInterfaceRewritingTarget( + Opcodes.INVOKEINTERFACE, + "java/util/List", + "removeIf", + "(Ljava/util/function/Predicate;)Z", + true)) + .isNull(); + assertThat( + support.getCoreInterfaceRewritingTarget( + Opcodes.INVOKEVIRTUAL, + "java/util/ArrayList", + "removeIf", + "(Ljava/util/function/Predicate;)Z", + false)) + .isNull(); + } } diff --git a/test/java/com/google/devtools/build/android/desugar/CorePackageRenamerTest.java b/test/java/com/google/devtools/build/android/desugar/CorePackageRenamerTest.java index d998aa2..95d7b41 100644 --- a/test/java/com/google/devtools/build/android/desugar/CorePackageRenamerTest.java +++ b/test/java/com/google/devtools/build/android/desugar/CorePackageRenamerTest.java @@ -38,7 +38,8 @@ public class CorePackageRenamerTest { null, ImmutableList.of("java/time/"), ImmutableList.of(), - ImmutableList.of("java/util/A#m->java/time/B"))); + ImmutableList.of("java/util/A#m->java/time/B"), + ImmutableList.of())); MethodVisitor mv = renamer.visitMethod(0, "test", "()V", null, null); mv.visitMethodInsn( -- cgit v1.2.3