1 // ASM: a very small and fast Java bytecode manipulation framework 2 // Copyright (c) 2000-2011 INRIA, France Telecom 3 // All rights reserved. 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions 7 // are met: 8 // 1. Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // 2. Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // 3. Neither the name of the copyright holders nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 // THE POSSIBILITY OF SUCH DAMAGE. 28 29 package org.objectweb.asm.commons; 30 31 import java.util.List; 32 import org.objectweb.asm.AnnotationVisitor; 33 import org.objectweb.asm.Attribute; 34 import org.objectweb.asm.ClassVisitor; 35 import org.objectweb.asm.FieldVisitor; 36 import org.objectweb.asm.MethodVisitor; 37 import org.objectweb.asm.ModuleVisitor; 38 import org.objectweb.asm.Opcodes; 39 import org.objectweb.asm.RecordComponentVisitor; 40 import org.objectweb.asm.TypePath; 41 42 /** 43 * A {@link ClassVisitor} that remaps types with a {@link Remapper}. 44 * 45 * <p><i>This visitor has several limitations</i>. A non-exhaustive list is the following: 46 * 47 * <ul> 48 * <li>it cannot remap type names in dynamically computed strings (remapping of type names in 49 * static values is supported). 50 * <li>it cannot remap values derived from type names at compile time, such as 51 * <ul> 52 * <li>type name hashcodes used by some Java compilers to implement the string switch 53 * statement. 54 * <li>some compound strings used by some Java compilers to implement lambda 55 * deserialization. 56 * </ul> 57 * </ul> 58 * 59 * @author Eugene Kuleshov 60 */ 61 public class ClassRemapper extends ClassVisitor { 62 63 /** The remapper used to remap the types in the visited class. */ 64 protected final Remapper remapper; 65 66 /** The internal name of the visited class. */ 67 protected String className; 68 69 /** 70 * Constructs a new {@link ClassRemapper}. <i>Subclasses must not use this constructor</i>. 71 * Instead, they must use the {@link #ClassRemapper(int,ClassVisitor,Remapper)} version. 72 * 73 * @param classVisitor the class visitor this remapper must delegate to. 74 * @param remapper the remapper to use to remap the types in the visited class. 75 */ ClassRemapper(final ClassVisitor classVisitor, final Remapper remapper)76 public ClassRemapper(final ClassVisitor classVisitor, final Remapper remapper) { 77 this(/* latest api = */ Opcodes.ASM9, classVisitor, remapper); 78 } 79 80 /** 81 * Constructs a new {@link ClassRemapper}. 82 * 83 * @param api the ASM API version supported by this remapper. Must be one of the {@code 84 * ASM}<i>x</i> values in {@link Opcodes}. 85 * @param classVisitor the class visitor this remapper must delegate to. 86 * @param remapper the remapper to use to remap the types in the visited class. 87 */ ClassRemapper(final int api, final ClassVisitor classVisitor, final Remapper remapper)88 protected ClassRemapper(final int api, final ClassVisitor classVisitor, final Remapper remapper) { 89 super(api, classVisitor); 90 this.remapper = remapper; 91 } 92 93 @Override visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces)94 public void visit( 95 final int version, 96 final int access, 97 final String name, 98 final String signature, 99 final String superName, 100 final String[] interfaces) { 101 this.className = name; 102 super.visit( 103 version, 104 access, 105 remapper.mapType(name), 106 remapper.mapSignature(signature, false), 107 remapper.mapType(superName), 108 interfaces == null ? null : remapper.mapTypes(interfaces)); 109 } 110 111 @Override visitModule(final String name, final int flags, final String version)112 public ModuleVisitor visitModule(final String name, final int flags, final String version) { 113 ModuleVisitor moduleVisitor = super.visitModule(remapper.mapModuleName(name), flags, version); 114 return moduleVisitor == null ? null : createModuleRemapper(moduleVisitor); 115 } 116 117 @Override visitAnnotation(final String descriptor, final boolean visible)118 public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { 119 AnnotationVisitor annotationVisitor = 120 super.visitAnnotation(remapper.mapDesc(descriptor), visible); 121 return annotationVisitor == null 122 ? null 123 : createAnnotationRemapper(descriptor, annotationVisitor); 124 } 125 126 @Override visitTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)127 public AnnotationVisitor visitTypeAnnotation( 128 final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 129 AnnotationVisitor annotationVisitor = 130 super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible); 131 return annotationVisitor == null 132 ? null 133 : createAnnotationRemapper(descriptor, annotationVisitor); 134 } 135 136 @Override visitAttribute(final Attribute attribute)137 public void visitAttribute(final Attribute attribute) { 138 if (attribute instanceof ModuleHashesAttribute) { 139 ModuleHashesAttribute moduleHashesAttribute = (ModuleHashesAttribute) attribute; 140 List<String> modules = moduleHashesAttribute.modules; 141 for (int i = 0; i < modules.size(); ++i) { 142 modules.set(i, remapper.mapModuleName(modules.get(i))); 143 } 144 } 145 super.visitAttribute(attribute); 146 } 147 148 @Override visitRecordComponent( final String name, final String descriptor, final String signature)149 public RecordComponentVisitor visitRecordComponent( 150 final String name, final String descriptor, final String signature) { 151 RecordComponentVisitor recordComponentVisitor = 152 super.visitRecordComponent( 153 remapper.mapRecordComponentName(className, name, descriptor), 154 remapper.mapDesc(descriptor), 155 remapper.mapSignature(signature, true)); 156 return recordComponentVisitor == null 157 ? null 158 : createRecordComponentRemapper(recordComponentVisitor); 159 } 160 161 @Override visitField( final int access, final String name, final String descriptor, final String signature, final Object value)162 public FieldVisitor visitField( 163 final int access, 164 final String name, 165 final String descriptor, 166 final String signature, 167 final Object value) { 168 FieldVisitor fieldVisitor = 169 super.visitField( 170 access, 171 remapper.mapFieldName(className, name, descriptor), 172 remapper.mapDesc(descriptor), 173 remapper.mapSignature(signature, true), 174 (value == null) ? null : remapper.mapValue(value)); 175 return fieldVisitor == null ? null : createFieldRemapper(fieldVisitor); 176 } 177 178 @Override visitMethod( final int access, final String name, final String descriptor, final String signature, final String[] exceptions)179 public MethodVisitor visitMethod( 180 final int access, 181 final String name, 182 final String descriptor, 183 final String signature, 184 final String[] exceptions) { 185 String remappedDescriptor = remapper.mapMethodDesc(descriptor); 186 MethodVisitor methodVisitor = 187 super.visitMethod( 188 access, 189 remapper.mapMethodName(className, name, descriptor), 190 remappedDescriptor, 191 remapper.mapSignature(signature, false), 192 exceptions == null ? null : remapper.mapTypes(exceptions)); 193 return methodVisitor == null ? null : createMethodRemapper(methodVisitor); 194 } 195 196 @Override visitInnerClass( final String name, final String outerName, final String innerName, final int access)197 public void visitInnerClass( 198 final String name, final String outerName, final String innerName, final int access) { 199 super.visitInnerClass( 200 remapper.mapType(name), 201 outerName == null ? null : remapper.mapType(outerName), 202 innerName == null ? null : remapper.mapInnerClassName(name, outerName, innerName), 203 access); 204 } 205 206 @Override visitOuterClass(final String owner, final String name, final String descriptor)207 public void visitOuterClass(final String owner, final String name, final String descriptor) { 208 super.visitOuterClass( 209 remapper.mapType(owner), 210 name == null ? null : remapper.mapMethodName(owner, name, descriptor), 211 descriptor == null ? null : remapper.mapMethodDesc(descriptor)); 212 } 213 214 @Override visitNestHost(final String nestHost)215 public void visitNestHost(final String nestHost) { 216 super.visitNestHost(remapper.mapType(nestHost)); 217 } 218 219 @Override visitNestMember(final String nestMember)220 public void visitNestMember(final String nestMember) { 221 super.visitNestMember(remapper.mapType(nestMember)); 222 } 223 224 @Override visitPermittedSubclass(final String permittedSubclass)225 public void visitPermittedSubclass(final String permittedSubclass) { 226 super.visitPermittedSubclass(remapper.mapType(permittedSubclass)); 227 } 228 229 /** 230 * Constructs a new remapper for fields. The default implementation of this method returns a new 231 * {@link FieldRemapper}. 232 * 233 * @param fieldVisitor the FieldVisitor the remapper must delegate to. 234 * @return the newly created remapper. 235 */ createFieldRemapper(final FieldVisitor fieldVisitor)236 protected FieldVisitor createFieldRemapper(final FieldVisitor fieldVisitor) { 237 return new FieldRemapper(api, fieldVisitor, remapper); 238 } 239 240 /** 241 * Constructs a new remapper for methods. The default implementation of this method returns a new 242 * {@link MethodRemapper}. 243 * 244 * @param methodVisitor the MethodVisitor the remapper must delegate to. 245 * @return the newly created remapper. 246 */ createMethodRemapper(final MethodVisitor methodVisitor)247 protected MethodVisitor createMethodRemapper(final MethodVisitor methodVisitor) { 248 return new MethodRemapper(api, methodVisitor, remapper); 249 } 250 251 /** 252 * Constructs a new remapper for annotations. The default implementation of this method returns a 253 * new {@link AnnotationRemapper}. 254 * 255 * @param annotationVisitor the AnnotationVisitor the remapper must delegate to. 256 * @return the newly created remapper. 257 * @deprecated use {@link #createAnnotationRemapper(String, AnnotationVisitor)} instead. 258 */ 259 @Deprecated createAnnotationRemapper(final AnnotationVisitor annotationVisitor)260 protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) { 261 return new AnnotationRemapper(api, /* descriptor = */ null, annotationVisitor, remapper); 262 } 263 264 /** 265 * Constructs a new remapper for annotations. The default implementation of this method returns a 266 * new {@link AnnotationRemapper}. 267 * 268 * @param descriptor the descriptor of the visited annotation. 269 * @param annotationVisitor the AnnotationVisitor the remapper must delegate to. 270 * @return the newly created remapper. 271 */ createAnnotationRemapper( final String descriptor, final AnnotationVisitor annotationVisitor)272 protected AnnotationVisitor createAnnotationRemapper( 273 final String descriptor, final AnnotationVisitor annotationVisitor) { 274 return new AnnotationRemapper(api, descriptor, annotationVisitor, remapper) 275 .orDeprecatedValue(createAnnotationRemapper(annotationVisitor)); 276 } 277 278 /** 279 * Constructs a new remapper for modules. The default implementation of this method returns a new 280 * {@link ModuleRemapper}. 281 * 282 * @param moduleVisitor the ModuleVisitor the remapper must delegate to. 283 * @return the newly created remapper. 284 */ createModuleRemapper(final ModuleVisitor moduleVisitor)285 protected ModuleVisitor createModuleRemapper(final ModuleVisitor moduleVisitor) { 286 return new ModuleRemapper(api, moduleVisitor, remapper); 287 } 288 289 /** 290 * Constructs a new remapper for record components. The default implementation of this method 291 * returns a new {@link RecordComponentRemapper}. 292 * 293 * @param recordComponentVisitor the RecordComponentVisitor the remapper must delegate to. 294 * @return the newly created remapper. 295 */ createRecordComponentRemapper( final RecordComponentVisitor recordComponentVisitor)296 protected RecordComponentVisitor createRecordComponentRemapper( 297 final RecordComponentVisitor recordComponentVisitor) { 298 return new RecordComponentRemapper(api, recordComponentVisitor, remapper); 299 } 300 } 301