• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 org.objectweb.asm.ConstantDynamic;
32 import org.objectweb.asm.Handle;
33 import org.objectweb.asm.Opcodes;
34 import org.objectweb.asm.Type;
35 import org.objectweb.asm.signature.SignatureReader;
36 import org.objectweb.asm.signature.SignatureVisitor;
37 import org.objectweb.asm.signature.SignatureWriter;
38 
39 /**
40  * A class responsible for remapping types and names.
41  *
42  * @author Eugene Kuleshov
43  */
44 public abstract class Remapper {
45 
46   /**
47    * Returns the given descriptor, remapped with {@link #map(String)}.
48    *
49    * @param descriptor a type descriptor.
50    * @return the given descriptor, with its [array element type] internal name remapped with {@link
51    *     #map(String)} (if the descriptor corresponds to an array or object type, otherwise the
52    *     descriptor is returned as is). See {@link Type#getInternalName()}.
53    */
mapDesc(final String descriptor)54   public String mapDesc(final String descriptor) {
55     return mapType(Type.getType(descriptor)).getDescriptor();
56   }
57 
58   /**
59    * Returns the given {@link Type}, remapped with {@link #map(String)} or {@link
60    * #mapMethodDesc(String)}.
61    *
62    * @param type a type, which can be a method type.
63    * @return the given type, with its [array element type] internal name remapped with {@link
64    *     #map(String)} (if the type is an array or object type, otherwise the type is returned as
65    *     is) or, of the type is a method type, with its descriptor remapped with {@link
66    *     #mapMethodDesc(String)}. See {@link Type#getInternalName()}.
67    */
mapType(final Type type)68   private Type mapType(final Type type) {
69     switch (type.getSort()) {
70       case Type.ARRAY:
71         StringBuilder remappedDescriptor = new StringBuilder();
72         for (int i = 0; i < type.getDimensions(); ++i) {
73           remappedDescriptor.append('[');
74         }
75         remappedDescriptor.append(mapType(type.getElementType()).getDescriptor());
76         return Type.getType(remappedDescriptor.toString());
77       case Type.OBJECT:
78         String remappedInternalName = map(type.getInternalName());
79         return remappedInternalName != null ? Type.getObjectType(remappedInternalName) : type;
80       case Type.METHOD:
81         return Type.getMethodType(mapMethodDesc(type.getDescriptor()));
82       default:
83         return type;
84     }
85   }
86 
87   /**
88    * Returns the given internal name, remapped with {@link #map(String)}.
89    *
90    * @param internalName the internal name (or array type descriptor) of some (array) class (see
91    *     {@link Type#getInternalName()}).
92    * @return the given internal name, remapped with {@link #map(String)} (see {@link
93    *     Type#getInternalName()}).
94    */
mapType(final String internalName)95   public String mapType(final String internalName) {
96     if (internalName == null) {
97       return null;
98     }
99     return mapType(Type.getObjectType(internalName)).getInternalName();
100   }
101 
102   /**
103    * Returns the given internal names, remapped with {@link #map(String)}.
104    *
105    * @param internalNames the internal names (or array type descriptors) of some (array) classes
106    *     (see {@link Type#getInternalName()}).
107    * @return the given internal name, remapped with {@link #map(String)} (see {@link
108    *     Type#getInternalName()}).
109    */
mapTypes(final String[] internalNames)110   public String[] mapTypes(final String[] internalNames) {
111     String[] remappedInternalNames = null;
112     for (int i = 0; i < internalNames.length; ++i) {
113       String internalName = internalNames[i];
114       String remappedInternalName = mapType(internalName);
115       if (remappedInternalName != null) {
116         if (remappedInternalNames == null) {
117           remappedInternalNames = internalNames.clone();
118         }
119         remappedInternalNames[i] = remappedInternalName;
120       }
121     }
122     return remappedInternalNames != null ? remappedInternalNames : internalNames;
123   }
124 
125   /**
126    * Returns the given method descriptor, with its argument and return type descriptors remapped
127    * with {@link #mapDesc(String)}.
128    *
129    * @param methodDescriptor a method descriptor.
130    * @return the given method descriptor, with its argument and return type descriptors remapped
131    *     with {@link #mapDesc(String)}.
132    */
mapMethodDesc(final String methodDescriptor)133   public String mapMethodDesc(final String methodDescriptor) {
134     if ("()V".equals(methodDescriptor)) {
135       return methodDescriptor;
136     }
137 
138     StringBuilder stringBuilder = new StringBuilder("(");
139     for (Type argumentType : Type.getArgumentTypes(methodDescriptor)) {
140       stringBuilder.append(mapType(argumentType).getDescriptor());
141     }
142     Type returnType = Type.getReturnType(methodDescriptor);
143     if (returnType == Type.VOID_TYPE) {
144       stringBuilder.append(")V");
145     } else {
146       stringBuilder.append(')').append(mapType(returnType).getDescriptor());
147     }
148     return stringBuilder.toString();
149   }
150 
151   /**
152    * Returns the given value, remapped with this remapper. Possible values are {@link Boolean},
153    * {@link Byte}, {@link Short}, {@link Character}, {@link Integer}, {@link Long}, {@link Double},
154    * {@link Float}, {@link String}, {@link Type}, {@link Handle}, {@link ConstantDynamic} or arrays
155    * of primitive types .
156    *
157    * @param value an object. Only {@link Type}, {@link Handle} and {@link ConstantDynamic} values
158    *     are remapped.
159    * @return the given value, remapped with this remapper.
160    */
mapValue(final Object value)161   public Object mapValue(final Object value) {
162     if (value instanceof Type) {
163       return mapType((Type) value);
164     }
165     if (value instanceof Handle) {
166       Handle handle = (Handle) value;
167       boolean isFieldHandle = handle.getTag() <= Opcodes.H_PUTSTATIC;
168 
169       return new Handle(
170           handle.getTag(),
171           mapType(handle.getOwner()),
172           isFieldHandle
173               ? mapFieldName(handle.getOwner(), handle.getName(), handle.getDesc())
174               : mapMethodName(handle.getOwner(), handle.getName(), handle.getDesc()),
175           isFieldHandle ? mapDesc(handle.getDesc()) : mapMethodDesc(handle.getDesc()),
176           handle.isInterface());
177     }
178     if (value instanceof ConstantDynamic) {
179       ConstantDynamic constantDynamic = (ConstantDynamic) value;
180       int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();
181       Object[] remappedBootstrapMethodArguments = new Object[bootstrapMethodArgumentCount];
182       for (int i = 0; i < bootstrapMethodArgumentCount; ++i) {
183         remappedBootstrapMethodArguments[i] =
184             mapValue(constantDynamic.getBootstrapMethodArgument(i));
185       }
186       String descriptor = constantDynamic.getDescriptor();
187       return new ConstantDynamic(
188           mapInvokeDynamicMethodName(constantDynamic.getName(), descriptor),
189           mapDesc(descriptor),
190           (Handle) mapValue(constantDynamic.getBootstrapMethod()),
191           remappedBootstrapMethodArguments);
192     }
193     return value;
194   }
195 
196   /**
197    * Returns the given signature, remapped with the {@link SignatureVisitor} returned by {@link
198    * #createSignatureRemapper(SignatureVisitor)}.
199    *
200    * @param signature a <i>JavaTypeSignature</i>, <i>ClassSignature</i> or <i>MethodSignature</i>.
201    * @param typeSignature whether the given signature is a <i>JavaTypeSignature</i>.
202    * @return signature the given signature, remapped with the {@link SignatureVisitor} returned by
203    *     {@link #createSignatureRemapper(SignatureVisitor)}.
204    */
mapSignature(final String signature, final boolean typeSignature)205   public String mapSignature(final String signature, final boolean typeSignature) {
206     if (signature == null) {
207       return null;
208     }
209     SignatureReader signatureReader = new SignatureReader(signature);
210     SignatureWriter signatureWriter = new SignatureWriter();
211     SignatureVisitor signatureRemapper = createSignatureRemapper(signatureWriter);
212     if (typeSignature) {
213       signatureReader.acceptType(signatureRemapper);
214     } else {
215       signatureReader.accept(signatureRemapper);
216     }
217     return signatureWriter.toString();
218   }
219 
220   /**
221    * Constructs a new remapper for signatures. The default implementation of this method returns a
222    * new {@link SignatureRemapper}.
223    *
224    * @param signatureVisitor the SignatureVisitor the remapper must delegate to.
225    * @return the newly created remapper.
226    * @deprecated use {@link #createSignatureRemapper} instead.
227    */
228   @Deprecated
createRemappingSignatureAdapter( final SignatureVisitor signatureVisitor)229   protected SignatureVisitor createRemappingSignatureAdapter(
230       final SignatureVisitor signatureVisitor) {
231     return createSignatureRemapper(signatureVisitor);
232   }
233 
234   /**
235    * Constructs a new remapper for signatures. The default implementation of this method returns a
236    * new {@link SignatureRemapper}.
237    *
238    * @param signatureVisitor the SignatureVisitor the remapper must delegate to.
239    * @return the newly created remapper.
240    */
createSignatureRemapper(final SignatureVisitor signatureVisitor)241   protected SignatureVisitor createSignatureRemapper(final SignatureVisitor signatureVisitor) {
242     return new SignatureRemapper(signatureVisitor, this);
243   }
244 
245   /**
246    * Maps an annotation attribute name. The default implementation of this method returns the given
247    * name, unchanged. Subclasses can override.
248    *
249    * @param descriptor the descriptor of the annotation class.
250    * @param name the name of the annotation attribute.
251    * @return the new name of the annotation attribute.
252    */
mapAnnotationAttributeName(final String descriptor, final String name)253   public String mapAnnotationAttributeName(final String descriptor, final String name) {
254     return name;
255   }
256 
257   /**
258    * Maps an inner class name to its new name. The default implementation of this method provides a
259    * strategy that will work for inner classes produced by Java, but not necessarily other
260    * languages. Subclasses can override.
261    *
262    * @param name the fully-qualified internal name of the inner class (see {@link
263    *     Type#getInternalName()}).
264    * @param ownerName the internal name of the owner class of the inner class (see {@link
265    *     Type#getInternalName()}).
266    * @param innerName the internal name of the inner class (see {@link Type#getInternalName()}).
267    * @return the new inner name of the inner class.
268    */
mapInnerClassName( final String name, final String ownerName, final String innerName)269   public String mapInnerClassName(
270       final String name, final String ownerName, final String innerName) {
271     final String remappedInnerName = this.mapType(name);
272 
273     if (remappedInnerName.equals(name)) {
274       return innerName;
275     } else {
276       int originSplit = name.lastIndexOf('/');
277       int remappedSplit = remappedInnerName.lastIndexOf('/');
278       if (originSplit != -1 && remappedSplit != -1) {
279         if (name.substring(originSplit).equals(remappedInnerName.substring(remappedSplit))) {
280           // class name not changed
281           return innerName;
282         }
283       }
284     }
285 
286     if (remappedInnerName.contains("$")) {
287       int index = remappedInnerName.lastIndexOf('$') + 1;
288       while (index < remappedInnerName.length()
289           && Character.isDigit(remappedInnerName.charAt(index))) {
290         index++;
291       }
292       return remappedInnerName.substring(index);
293     } else {
294       return innerName;
295     }
296   }
297 
298   /**
299    * Maps a method name to its new name. The default implementation of this method returns the given
300    * name, unchanged. Subclasses can override.
301    *
302    * @param owner the internal name of the owner class of the method (see {@link
303    *     Type#getInternalName()}).
304    * @param name the name of the method.
305    * @param descriptor the descriptor of the method.
306    * @return the new name of the method.
307    */
mapMethodName(final String owner, final String name, final String descriptor)308   public String mapMethodName(final String owner, final String name, final String descriptor) {
309     return name;
310   }
311 
312   /**
313    * Maps an invokedynamic or a constant dynamic method name to its new name. The default
314    * implementation of this method returns the given name, unchanged. Subclasses can override.
315    *
316    * @param name the name of the method.
317    * @param descriptor the descriptor of the method.
318    * @return the new name of the method.
319    */
mapInvokeDynamicMethodName(final String name, final String descriptor)320   public String mapInvokeDynamicMethodName(final String name, final String descriptor) {
321     return name;
322   }
323 
324   /**
325    * Maps a record component name to its new name. The default implementation of this method returns
326    * the given name, unchanged. Subclasses can override.
327    *
328    * @param owner the internal name of the owner class of the field (see {@link
329    *     Type#getInternalName()}).
330    * @param name the name of the field.
331    * @param descriptor the descriptor of the field.
332    * @return the new name of the field.
333    */
mapRecordComponentName( final String owner, final String name, final String descriptor)334   public String mapRecordComponentName(
335       final String owner, final String name, final String descriptor) {
336     return name;
337   }
338 
339   /**
340    * Maps a field name to its new name. The default implementation of this method returns the given
341    * name, unchanged. Subclasses can override.
342    *
343    * @param owner the internal name of the owner class of the field (see {@link
344    *     Type#getInternalName()}).
345    * @param name the name of the field.
346    * @param descriptor the descriptor of the field.
347    * @return the new name of the field.
348    */
mapFieldName(final String owner, final String name, final String descriptor)349   public String mapFieldName(final String owner, final String name, final String descriptor) {
350     return name;
351   }
352 
353   /**
354    * Maps a package name to its new name. The default implementation of this method returns the
355    * given name, unchanged. Subclasses can override.
356    *
357    * @param name the fully qualified name of the package (using dots).
358    * @return the new name of the package.
359    */
mapPackageName(final String name)360   public String mapPackageName(final String name) {
361     return name;
362   }
363 
364   /**
365    * Maps a module name to its new name. The default implementation of this method returns the given
366    * name, unchanged. Subclasses can override.
367    *
368    * @param name the fully qualified name (using dots) of a module.
369    * @return the new name of the module.
370    */
mapModuleName(final String name)371   public String mapModuleName(final String name) {
372     return name;
373   }
374 
375   /**
376    * Maps the internal name of a class to its new name. The default implementation of this method
377    * returns the given name, unchanged. Subclasses can override.
378    *
379    * @param internalName the internal name of a class (see {@link Type#getInternalName()}).
380    * @return the new internal name (see {@link Type#getInternalName()}).
381    */
map(final String internalName)382   public String map(final String internalName) {
383     return internalName;
384   }
385 }
386