• 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;
30 
31 /**
32  * The path to a type argument, wildcard bound, array element type, or static inner type within an
33  * enclosing type.
34  *
35  * @author Eric Bruneton
36  */
37 public final class TypePath {
38 
39   /** A type path step that steps into the element type of an array type. See {@link #getStep}. */
40   public static final int ARRAY_ELEMENT = 0;
41 
42   /** A type path step that steps into the nested type of a class type. See {@link #getStep}. */
43   public static final int INNER_TYPE = 1;
44 
45   /** A type path step that steps into the bound of a wildcard type. See {@link #getStep}. */
46   public static final int WILDCARD_BOUND = 2;
47 
48   /** A type path step that steps into a type argument of a generic type. See {@link #getStep}. */
49   public static final int TYPE_ARGUMENT = 3;
50 
51   /**
52    * The byte array where the 'type_path' structure - as defined in the Java Virtual Machine
53    * Specification (JVMS) - corresponding to this TypePath is stored. The first byte of the
54    * structure in this array is given by {@link #typePathOffset}.
55    *
56    * @see <a
57    *     href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.2">JVMS
58    *     4.7.20.2</a>
59    */
60   private final byte[] typePathContainer;
61 
62   /** The offset of the first byte of the type_path JVMS structure in {@link #typePathContainer}. */
63   private final int typePathOffset;
64 
65   /**
66    * Constructs a new TypePath.
67    *
68    * @param typePathContainer a byte array containing a type_path JVMS structure.
69    * @param typePathOffset the offset of the first byte of the type_path structure in
70    *     typePathContainer.
71    */
TypePath(final byte[] typePathContainer, final int typePathOffset)72   TypePath(final byte[] typePathContainer, final int typePathOffset) {
73     this.typePathContainer = typePathContainer;
74     this.typePathOffset = typePathOffset;
75   }
76 
77   /**
78    * Returns the length of this path, i.e. its number of steps.
79    *
80    * @return the length of this path.
81    */
getLength()82   public int getLength() {
83     // path_length is stored in the first byte of a type_path.
84     return typePathContainer[typePathOffset];
85   }
86 
87   /**
88    * Returns the value of the given step of this path.
89    *
90    * @param index an index between 0 and {@link #getLength()}, exclusive.
91    * @return one of {@link #ARRAY_ELEMENT}, {@link #INNER_TYPE}, {@link #WILDCARD_BOUND}, or {@link
92    *     #TYPE_ARGUMENT}.
93    */
getStep(final int index)94   public int getStep(final int index) {
95     // Returns the type_path_kind of the path element of the given index.
96     return typePathContainer[typePathOffset + 2 * index + 1];
97   }
98 
99   /**
100    * Returns the index of the type argument that the given step is stepping into. This method should
101    * only be used for steps whose value is {@link #TYPE_ARGUMENT}.
102    *
103    * @param index an index between 0 and {@link #getLength()}, exclusive.
104    * @return the index of the type argument that the given step is stepping into.
105    */
getStepArgument(final int index)106   public int getStepArgument(final int index) {
107     // Returns the type_argument_index of the path element of the given index.
108     return typePathContainer[typePathOffset + 2 * index + 2];
109   }
110 
111   /**
112    * Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath
113    * object.
114    *
115    * @param typePath a type path in string form, in the format used by {@link #toString()}. May be
116    *     {@literal null} or empty.
117    * @return the corresponding TypePath object, or {@literal null} if the path is empty.
118    */
fromString(final String typePath)119   public static TypePath fromString(final String typePath) {
120     if (typePath == null || typePath.length() == 0) {
121       return null;
122     }
123     int typePathLength = typePath.length();
124     ByteVector output = new ByteVector(typePathLength);
125     output.putByte(0);
126     int typePathIndex = 0;
127     while (typePathIndex < typePathLength) {
128       char c = typePath.charAt(typePathIndex++);
129       if (c == '[') {
130         output.put11(ARRAY_ELEMENT, 0);
131       } else if (c == '.') {
132         output.put11(INNER_TYPE, 0);
133       } else if (c == '*') {
134         output.put11(WILDCARD_BOUND, 0);
135       } else if (c >= '0' && c <= '9') {
136         int typeArg = c - '0';
137         while (typePathIndex < typePathLength) {
138           c = typePath.charAt(typePathIndex++);
139           if (c >= '0' && c <= '9') {
140             typeArg = typeArg * 10 + c - '0';
141           } else if (c == ';') {
142             break;
143           } else {
144             throw new IllegalArgumentException();
145           }
146         }
147         output.put11(TYPE_ARGUMENT, typeArg);
148       } else {
149         throw new IllegalArgumentException();
150       }
151     }
152     output.data[0] = (byte) (output.length / 2);
153     return new TypePath(output.data, 0);
154   }
155 
156   /**
157    * Returns a string representation of this type path. {@link #ARRAY_ELEMENT} steps are represented
158    * with '[', {@link #INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND} steps with '*' and {@link
159    * #TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'.
160    */
161   @Override
toString()162   public String toString() {
163     int length = getLength();
164     StringBuilder result = new StringBuilder(length * 2);
165     for (int i = 0; i < length; ++i) {
166       switch (getStep(i)) {
167         case ARRAY_ELEMENT:
168           result.append('[');
169           break;
170         case INNER_TYPE:
171           result.append('.');
172           break;
173         case WILDCARD_BOUND:
174           result.append('*');
175           break;
176         case TYPE_ARGUMENT:
177           result.append(getStepArgument(i)).append(';');
178           break;
179         default:
180           throw new AssertionError();
181       }
182     }
183     return result.toString();
184   }
185 
186   /**
187    * Puts the type_path JVMS structure corresponding to the given TypePath into the given
188    * ByteVector.
189    *
190    * @param typePath a TypePath instance, or {@literal null} for empty paths.
191    * @param output where the type path must be put.
192    */
put(final TypePath typePath, final ByteVector output)193   static void put(final TypePath typePath, final ByteVector output) {
194     if (typePath == null) {
195       output.putByte(0);
196     } else {
197       int length = typePath.typePathContainer[typePath.typePathOffset] * 2 + 1;
198       output.putByteArray(typePath.typePathContainer, typePath.typePathOffset, length);
199     }
200   }
201 }
202