1758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross// Copyright 2017 The Bazel Authors. All rights reserved. 2758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross// 3758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross// Licensed under the Apache License, Version 2.0 (the "License"); 4758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross// you may not use this file except in compliance with the License. 5758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross// You may obtain a copy of the License at 6758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross// 7758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross// http://www.apache.org/licenses/LICENSE-2.0 8758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross// 9758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross// Unless required by applicable law or agreed to in writing, software 10758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross// distributed under the License is distributed on an "AS IS" BASIS, 11758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross// See the License for the specific language governing permissions and 13758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross// limitations under the License. 14758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Crosspackage com.google.devtools.build.android.desugar; 15758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 16758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Crossimport java.io.IOException; 17758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Crossimport java.io.InputStream; 18758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Crossimport org.objectweb.asm.Attribute; 19758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Crossimport org.objectweb.asm.ClassReader; 20758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Crossimport org.objectweb.asm.ClassVisitor; 21758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Crossimport org.objectweb.asm.ClassWriter; 22758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Crossimport org.objectweb.asm.Opcodes; 23758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Crossimport org.objectweb.asm.commons.ClassRemapper; 24758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Crossimport org.objectweb.asm.commons.Remapper; 25758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 26758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross/** Utility class to prefix or unprefix class names of core library classes */ 27758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Crossclass CoreLibraryRewriter { 28758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross private final String prefix; 29758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 30758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross public CoreLibraryRewriter(String prefix) { 31758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross this.prefix = prefix; 32758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 33758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 34758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross /** 35758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross * Factory method that returns either a normal ClassReader if prefix is empty, or a ClassReader 36758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross * with a ClassRemapper that prefixes class names of core library classes if prefix is not empty. 37758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross */ 38758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross public ClassReader reader(InputStream content) throws IOException { 394676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb if (prefix.isEmpty()) { 40758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross return new ClassReader(content); 414676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb } else { 424676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb return new PrefixingClassReader(content, prefix); 43758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 44758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 45758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 46758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross /** 47758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross * Factory method that returns a ClassVisitor that delegates to a ClassWriter, removing prefix 48758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross * from core library class names if it is not empty. 49758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross */ 50758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross public UnprefixingClassWriter writer(int flags) { 51758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross return new UnprefixingClassWriter(flags); 52758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 53758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 544676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb static boolean shouldPrefix(String typeName) { 55758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross return (typeName.startsWith("java/") || typeName.startsWith("sun/")) && !except(typeName); 56758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 57758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 58758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross private static boolean except(String typeName) { 59758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross if (typeName.startsWith("java/lang/invoke/")) { 60758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross return true; 61758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 62758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 63758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross switch (typeName) { 64758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross // Autoboxed types 65758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross case "java/lang/Boolean": 66758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross case "java/lang/Byte": 67758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross case "java/lang/Character": 68758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross case "java/lang/Double": 69758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross case "java/lang/Float": 70758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross case "java/lang/Integer": 71758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross case "java/lang/Long": 72758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross case "java/lang/Number": 73758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross case "java/lang/Short": 74758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 75758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross // Special types 76758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross case "java/lang/Class": 77758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross case "java/lang/Object": 78758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross case "java/lang/String": 79758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross case "java/lang/Throwable": 80758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross return true; 81758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 82758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross default: // fall out 83758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 84758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 85758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross return false; 86758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 87758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 88758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross /** Removes prefix from class names */ 89758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross public String unprefix(String typeName) { 904676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb if (prefix.isEmpty() || !typeName.startsWith(prefix)) { 91758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross return typeName; 92758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 93758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross return typeName.substring(prefix.length()); 94758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 95758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 96ee8542f989cffb9c5070c7503a7c40d1e7bbd6b0cnsun /** ClassReader that prefixes core library class names as they are read */ 974676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb private static class PrefixingClassReader extends ClassReader { 984676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb private final String prefix; 994676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb 1004676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb PrefixingClassReader(InputStream content, String prefix) throws IOException { 101758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross super(content); 1024676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb this.prefix = prefix; 103758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 104758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 105758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross @Override 106758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross public void accept(ClassVisitor cv, Attribute[] attrs, int flags) { 107758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross cv = 10820d5bf85394727ffdab6672fa3f2decb5b9b20aacnsun new ClassRemapper( 109758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross cv, 110758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross new Remapper() { 111758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross @Override 112758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross public String map(String typeName) { 113758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross return prefix(typeName); 114758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 115758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross }); 116758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross super.accept(cv, attrs, flags); 117758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 11837ba42132bf5c9afe8f67024b269a7f571b9d999kmb 11937ba42132bf5c9afe8f67024b269a7f571b9d999kmb @Override 12037ba42132bf5c9afe8f67024b269a7f571b9d999kmb public String getClassName() { 12137ba42132bf5c9afe8f67024b269a7f571b9d999kmb return prefix(super.getClassName()); 12237ba42132bf5c9afe8f67024b269a7f571b9d999kmb } 12337ba42132bf5c9afe8f67024b269a7f571b9d999kmb 12437ba42132bf5c9afe8f67024b269a7f571b9d999kmb @Override 12537ba42132bf5c9afe8f67024b269a7f571b9d999kmb public String getSuperName() { 12637ba42132bf5c9afe8f67024b269a7f571b9d999kmb String result = super.getSuperName(); 12737ba42132bf5c9afe8f67024b269a7f571b9d999kmb return result != null ? prefix(result) : null; 12837ba42132bf5c9afe8f67024b269a7f571b9d999kmb } 12937ba42132bf5c9afe8f67024b269a7f571b9d999kmb 13037ba42132bf5c9afe8f67024b269a7f571b9d999kmb @Override 13137ba42132bf5c9afe8f67024b269a7f571b9d999kmb public String[] getInterfaces() { 13237ba42132bf5c9afe8f67024b269a7f571b9d999kmb String[] result = super.getInterfaces(); 13337ba42132bf5c9afe8f67024b269a7f571b9d999kmb for (int i = 0, len = result.length; i < len; ++i) { 13437ba42132bf5c9afe8f67024b269a7f571b9d999kmb result[i] = prefix(result[i]); 13537ba42132bf5c9afe8f67024b269a7f571b9d999kmb } 13637ba42132bf5c9afe8f67024b269a7f571b9d999kmb return result; 13737ba42132bf5c9afe8f67024b269a7f571b9d999kmb } 1384676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb 1394676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb /** Prefixes core library class names with prefix. */ 1404676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb private String prefix(String typeName) { 1414676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb if (shouldPrefix(typeName)) { 1424676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb return prefix + typeName; 1434676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb } 1444676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb return typeName; 1454676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb } 146758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 147758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 148758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross /** 149758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross * ClassVisitor that delegates to a ClassWriter, but removes a prefix as each class is written. 150758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross * The unprefixing is optimized out if prefix is empty. 151758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross */ 152758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross public class UnprefixingClassWriter extends ClassVisitor { 153758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross private final ClassWriter writer; 154758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 155758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross UnprefixingClassWriter(int flags) { 15669113875723a6a265673f9b2d6d5140c20fae7c4cushon super(Opcodes.ASM6); 157758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross this.writer = new ClassWriter(flags); 158758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross this.cv = this.writer; 1594676fd2ac045b62aae0c8d8a70b3a4ae9ebd324ekmb if (!prefix.isEmpty()) { 160758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross this.cv = 16120d5bf85394727ffdab6672fa3f2decb5b9b20aacnsun new ClassRemapper( 162758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross this.cv, 163758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross new Remapper() { 164758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross @Override 165758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross public String map(String typeName) { 166758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross return unprefix(typeName); 167758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 168758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross }); 169758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 170758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 171758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross 172758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross byte[] toByteArray() { 173758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross return writer.toByteArray(); 174758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 175758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross } 176758d2b7ce3ae079c8308c7f1fb9e740cb704f25eColin Cross} 177