001// ASM: a very small and fast Java bytecode manipulation framework
002// Copyright (c) 2000-2011 INRIA, France Telecom
003// All rights reserved.
004//
005// Redistribution and use in source and binary forms, with or without
006// modification, are permitted provided that the following conditions
007// are met:
008// 1. Redistributions of source code must retain the above copyright
009//    notice, this list of conditions and the following disclaimer.
010// 2. Redistributions in binary form must reproduce the above copyright
011//    notice, this list of conditions and the following disclaimer in the
012//    documentation and/or other materials provided with the distribution.
013// 3. Neither the name of the copyright holders nor the names of its
014//    contributors may be used to endorse or promote products derived from
015//    this software without specific prior written permission.
016//
017// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
020// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
021// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
022// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
023// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
024// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
025// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
026// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
027// THE POSSIBILITY OF SUCH DAMAGE.
028
029package io.ebean.enhance.asm.commons;
030
031import io.ebean.enhance.asm.AnnotationVisitor;
032import io.ebean.enhance.asm.Attribute;
033import io.ebean.enhance.asm.ClassVisitor;
034import io.ebean.enhance.asm.FieldVisitor;
035import io.ebean.enhance.asm.MethodVisitor;
036import io.ebean.enhance.asm.ModuleVisitor;
037import io.ebean.enhance.asm.Opcodes;
038import io.ebean.enhance.asm.TypePath;
039
040import java.util.List;
041
042/**
043 * A {@link ClassVisitor} that remaps types with a {@link Remapper}.
044 *
045 * @author Eugene Kuleshov
046 */
047public class ClassRemapper extends ClassVisitor {
048
049  /** The remapper used to remap the types in the visited class. */
050  protected final Remapper remapper;
051
052  /** The internal name of the visited class. */
053  protected String className;
054
055  /**
056   * Constructs a new {@link ClassRemapper}. <i>Subclasses must not use this constructor</i>.
057   * Instead, they must use the {@link #ClassRemapper(int, ClassVisitor, Remapper)} version.
058   *
059   * @param classVisitor the class visitor this remapper must deleted to.
060   * @param remapper the remapper to use to remap the types in the visited class.
061   */
062  public ClassRemapper(final ClassVisitor classVisitor, final Remapper remapper) {
063    this(Opcodes.ASM7, classVisitor, remapper);
064  }
065
066  /**
067   * Constructs a new {@link ClassRemapper}.
068   *
069   * @param api the ASM API version supported by this remapper. Must be one of {@link
070   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link
071   *     Opcodes#ASM6} or {@link Opcodes#ASM7}.
072   * @param classVisitor the class visitor this remapper must deleted to.
073   * @param remapper the remapper to use to remap the types in the visited class.
074   */
075  protected ClassRemapper(final int api, final ClassVisitor classVisitor, final Remapper remapper) {
076    super(api, classVisitor);
077    this.remapper = remapper;
078  }
079
080  @Override
081  public void visit(
082      final int version,
083      final int access,
084      final String name,
085      final String signature,
086      final String superName,
087      final String[] interfaces) {
088    this.className = name;
089    super.visit(
090        version,
091        access,
092        remapper.mapType(name),
093        remapper.mapSignature(signature, false),
094        remapper.mapType(superName),
095        interfaces == null ? null : remapper.mapTypes(interfaces));
096  }
097
098  @Override
099  public ModuleVisitor visitModule(final String name, final int flags, final String version) {
100    ModuleVisitor moduleVisitor = super.visitModule(remapper.mapModuleName(name), flags, version);
101    return moduleVisitor == null ? null : createModuleRemapper(moduleVisitor);
102  }
103
104  @Override
105  public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
106    AnnotationVisitor annotationVisitor =
107        super.visitAnnotation(remapper.mapDesc(descriptor), visible);
108    return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor);
109  }
110
111  @Override
112  public AnnotationVisitor visitTypeAnnotation(
113    final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
114    AnnotationVisitor annotationVisitor =
115        super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
116    return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor);
117  }
118
119  @Override
120  public void visitAttribute(final Attribute attribute) {
121    if (attribute instanceof ModuleHashesAttribute) {
122      ModuleHashesAttribute moduleHashesAttribute = (ModuleHashesAttribute) attribute;
123      List<String> modules = moduleHashesAttribute.modules;
124      for (int i = 0; i < modules.size(); ++i) {
125        modules.set(i, remapper.mapModuleName(modules.get(i)));
126      }
127    }
128    super.visitAttribute(attribute);
129  }
130
131  @Override
132  public FieldVisitor visitField(
133      final int access,
134      final String name,
135      final String descriptor,
136      final String signature,
137      final Object value) {
138    FieldVisitor fieldVisitor =
139        super.visitField(
140            access,
141            remapper.mapFieldName(className, name, descriptor),
142            remapper.mapDesc(descriptor),
143            remapper.mapSignature(signature, true),
144            (value == null) ? null : remapper.mapValue(value));
145    return fieldVisitor == null ? null : createFieldRemapper(fieldVisitor);
146  }
147
148  @Override
149  public MethodVisitor visitMethod(
150      final int access,
151      final String name,
152      final String descriptor,
153      final String signature,
154      final String[] exceptions) {
155    String remappedDescriptor = remapper.mapMethodDesc(descriptor);
156    MethodVisitor methodVisitor =
157        super.visitMethod(
158            access,
159            remapper.mapMethodName(className, name, descriptor),
160            remappedDescriptor,
161            remapper.mapSignature(signature, false),
162            exceptions == null ? null : remapper.mapTypes(exceptions));
163    return methodVisitor == null ? null : createMethodRemapper(methodVisitor);
164  }
165
166  @Override
167  public void visitInnerClass(
168      final String name, final String outerName, final String innerName, final int access) {
169    super.visitInnerClass(
170        remapper.mapType(name),
171        outerName == null ? null : remapper.mapType(outerName),
172        innerName == null ? null : remapper.mapInnerClassName(name, outerName, innerName),
173        access);
174  }
175
176  @Override
177  public void visitOuterClass(final String owner, final String name, final String descriptor) {
178    super.visitOuterClass(
179        remapper.mapType(owner),
180        name == null ? null : remapper.mapMethodName(owner, name, descriptor),
181        descriptor == null ? null : remapper.mapMethodDesc(descriptor));
182  }
183
184  @Override
185  public void visitNestHost(final String nestHost) {
186    super.visitNestHost(remapper.mapType(nestHost));
187  }
188
189  @Override
190  public void visitNestMember(final String nestMember) {
191    super.visitNestMember(remapper.mapType(nestMember));
192  }
193
194  /**
195   * Constructs a new remapper for fields. The default implementation of this method returns a new
196   * {@link FieldRemapper}.
197   *
198   * @param fieldVisitor the FieldVisitor the remapper must delegate to.
199   * @return the newly created remapper.
200   */
201  protected FieldVisitor createFieldRemapper(final FieldVisitor fieldVisitor) {
202    return new FieldRemapper(api, fieldVisitor, remapper);
203  }
204
205  /**
206   * Constructs a new remapper for methods. The default implementation of this method returns a new
207   * {@link MethodRemapper}.
208   *
209   * @param methodVisitor the MethodVisitor the remapper must delegate to.
210   * @return the newly created remapper.
211   */
212  protected MethodVisitor createMethodRemapper(final MethodVisitor methodVisitor) {
213    return new MethodRemapper(api, methodVisitor, remapper);
214  }
215
216  /**
217   * Constructs a new remapper for annotations. The default implementation of this method returns a
218   * new {@link AnnotationRemapper}.
219   *
220   * @param annotationVisitor the AnnotationVisitor the remapper must delegate to.
221   * @return the newly created remapper.
222   */
223  protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) {
224    return new AnnotationRemapper(api, annotationVisitor, remapper);
225  }
226
227  /**
228   * Constructs a new remapper for modules. The default implementation of this method returns a new
229   * {@link ModuleRemapper}.
230   *
231   * @param moduleVisitor the ModuleVisitor the remapper must delegate to.
232   * @return the newly created remapper.
233   */
234  protected ModuleVisitor createModuleRemapper(final ModuleVisitor moduleVisitor) {
235    return new ModuleRemapper(api, moduleVisitor, remapper);
236  }
237}