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.Opcodes;
032import io.ebean.enhance.asm.signature.SignatureVisitor;
033
034import java.util.ArrayList;
035
036/**
037 * A {@link SignatureVisitor} that remaps types with a {@link Remapper}.
038 *
039 * @author Eugene Kuleshov
040 */
041public class SignatureRemapper extends SignatureVisitor {
042
043  private final SignatureVisitor signatureVisitor;
044
045  private final Remapper remapper;
046
047  private ArrayList<String> classNames = new ArrayList<>();
048
049  /**
050   * Constructs a new {@link SignatureRemapper}. <i>Subclasses must not use this constructor</i>.
051   * Instead, they must use the {@link #SignatureRemapper(int, SignatureVisitor,Remapper)} version.
052   *
053   * @param signatureVisitor the signature visitor this remapper must deleted to.
054   * @param remapper the remapper to use to remap the types in the visited signature.
055   */
056  public SignatureRemapper(final SignatureVisitor signatureVisitor, final Remapper remapper) {
057    this(Opcodes.ASM7, signatureVisitor, remapper);
058  }
059
060  /**
061   * Constructs a new {@link SignatureRemapper}.
062   *
063   * @param api the ASM API version supported by this remapper. Must be one of {@link
064   *     Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link
065   *     Opcodes#ASM6}.
066   * @param signatureVisitor the signature visitor this remapper must deleted to.
067   * @param remapper the remapper to use to remap the types in the visited signature.
068   */
069  protected SignatureRemapper(
070    final int api, final SignatureVisitor signatureVisitor, final Remapper remapper) {
071    super(api);
072    this.signatureVisitor = signatureVisitor;
073    this.remapper = remapper;
074  }
075
076  @Override
077  public void visitClassType(final String name) {
078    classNames.add(name);
079    signatureVisitor.visitClassType(remapper.mapType(name));
080  }
081
082  @Override
083  public void visitInnerClassType(final String name) {
084    String outerClassName = classNames.remove(classNames.size() - 1);
085    String className = outerClassName + '$' + name;
086    classNames.add(className);
087    String remappedOuter = remapper.mapType(outerClassName) + '$';
088    String remappedName = remapper.mapType(className);
089    int index =
090        remappedName.startsWith(remappedOuter)
091            ? remappedOuter.length()
092            : remappedName.lastIndexOf('$') + 1;
093    signatureVisitor.visitInnerClassType(remappedName.substring(index));
094  }
095
096  @Override
097  public void visitFormalTypeParameter(final String name) {
098    signatureVisitor.visitFormalTypeParameter(name);
099  }
100
101  @Override
102  public void visitTypeVariable(final String name) {
103    signatureVisitor.visitTypeVariable(name);
104  }
105
106  @Override
107  public SignatureVisitor visitArrayType() {
108    signatureVisitor.visitArrayType();
109    return this;
110  }
111
112  @Override
113  public void visitBaseType(final char descriptor) {
114    signatureVisitor.visitBaseType(descriptor);
115  }
116
117  @Override
118  public SignatureVisitor visitClassBound() {
119    signatureVisitor.visitClassBound();
120    return this;
121  }
122
123  @Override
124  public SignatureVisitor visitExceptionType() {
125    signatureVisitor.visitExceptionType();
126    return this;
127  }
128
129  @Override
130  public SignatureVisitor visitInterface() {
131    signatureVisitor.visitInterface();
132    return this;
133  }
134
135  @Override
136  public SignatureVisitor visitInterfaceBound() {
137    signatureVisitor.visitInterfaceBound();
138    return this;
139  }
140
141  @Override
142  public SignatureVisitor visitParameterType() {
143    signatureVisitor.visitParameterType();
144    return this;
145  }
146
147  @Override
148  public SignatureVisitor visitReturnType() {
149    signatureVisitor.visitReturnType();
150    return this;
151  }
152
153  @Override
154  public SignatureVisitor visitSuperclass() {
155    signatureVisitor.visitSuperclass();
156    return this;
157  }
158
159  @Override
160  public void visitTypeArgument() {
161    signatureVisitor.visitTypeArgument();
162  }
163
164  @Override
165  public SignatureVisitor visitTypeArgument(final char wildcard) {
166    signatureVisitor.visitTypeArgument(wildcard);
167    return this;
168  }
169
170  @Override
171  public void visitEnd() {
172    signatureVisitor.visitEnd();
173    classNames.remove(classNames.size() - 1);
174  }
175}