1/*** 2 * ASM: a very small and fast Java bytecode manipulation framework 3 * Copyright (c) 2000-2007 INRIA, France Telecom 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the copyright holders nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 28 * THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30package org.mockito.asm.signature; 31 32/** 33 * A type signature parser to make a signature visitor visit an existing 34 * signature. 35 * 36 * @author Thomas Hallgren 37 * @author Eric Bruneton 38 */ 39public class SignatureReader { 40 41 /** 42 * The signature to be read. 43 */ 44 private final String signature; 45 46 /** 47 * Constructs a {@link SignatureReader} for the given signature. 48 * 49 * @param signature A <i>ClassSignature</i>, <i>MethodTypeSignature</i>, 50 * or <i>FieldTypeSignature</i>. 51 */ 52 public SignatureReader(final String signature) { 53 this.signature = signature; 54 } 55 56 /** 57 * Makes the given visitor visit the signature of this 58 * {@link SignatureReader}. This signature is the one specified in the 59 * constructor (see {@link #SignatureReader(String) SignatureReader}). This 60 * method is intended to be called on a {@link SignatureReader} that was 61 * created using a <i>ClassSignature</i> (such as the 62 * <code>signature</code> parameter of the 63 * {@link org.mockito.asm.ClassVisitor#visit ClassVisitor.visit} method) 64 * or a <i>MethodTypeSignature</i> (such as the <code>signature</code> 65 * parameter of the 66 * {@link org.mockito.asm.ClassVisitor#visitMethod ClassVisitor.visitMethod} 67 * method). 68 * 69 * @param v the visitor that must visit this signature. 70 */ 71 public void accept(final SignatureVisitor v) { 72 String signature = this.signature; 73 int len = signature.length(); 74 int pos; 75 char c; 76 77 if (signature.charAt(0) == '<') { 78 pos = 2; 79 do { 80 int end = signature.indexOf(':', pos); 81 v.visitFormalTypeParameter(signature.substring(pos - 1, end)); 82 pos = end + 1; 83 84 c = signature.charAt(pos); 85 if (c == 'L' || c == '[' || c == 'T') { 86 pos = parseType(signature, pos, v.visitClassBound()); 87 } 88 89 while ((c = signature.charAt(pos++)) == ':') { 90 pos = parseType(signature, pos, v.visitInterfaceBound()); 91 } 92 } while (c != '>'); 93 } else { 94 pos = 0; 95 } 96 97 if (signature.charAt(pos) == '(') { 98 pos++; 99 while (signature.charAt(pos) != ')') { 100 pos = parseType(signature, pos, v.visitParameterType()); 101 } 102 pos = parseType(signature, pos + 1, v.visitReturnType()); 103 while (pos < len) { 104 pos = parseType(signature, pos + 1, v.visitExceptionType()); 105 } 106 } else { 107 pos = parseType(signature, pos, v.visitSuperclass()); 108 while (pos < len) { 109 pos = parseType(signature, pos, v.visitInterface()); 110 } 111 } 112 } 113 114 /** 115 * Makes the given visitor visit the signature of this 116 * {@link SignatureReader}. This signature is the one specified in the 117 * constructor (see {@link #SignatureReader(String) SignatureReader}). This 118 * method is intended to be called on a {@link SignatureReader} that was 119 * created using a <i>FieldTypeSignature</i>, such as the 120 * <code>signature</code> parameter of the 121 * {@link org.mockito.asm.ClassVisitor#visitField 122 * ClassVisitor.visitField} or {@link 123 * org.mockito.asm.MethodVisitor#visitLocalVariable 124 * MethodVisitor.visitLocalVariable} methods. 125 * 126 * @param v the visitor that must visit this signature. 127 */ 128 public void acceptType(final SignatureVisitor v) { 129 parseType(this.signature, 0, v); 130 } 131 132 /** 133 * Parses a field type signature and makes the given visitor visit it. 134 * 135 * @param signature a string containing the signature that must be parsed. 136 * @param pos index of the first character of the signature to parsed. 137 * @param v the visitor that must visit this signature. 138 * @return the index of the first character after the parsed signature. 139 */ 140 private static int parseType( 141 final String signature, 142 int pos, 143 final SignatureVisitor v) 144 { 145 char c; 146 int start, end; 147 boolean visited, inner; 148 String name; 149 150 switch (c = signature.charAt(pos++)) { 151 case 'Z': 152 case 'C': 153 case 'B': 154 case 'S': 155 case 'I': 156 case 'F': 157 case 'J': 158 case 'D': 159 case 'V': 160 v.visitBaseType(c); 161 return pos; 162 163 case '[': 164 return parseType(signature, pos, v.visitArrayType()); 165 166 case 'T': 167 end = signature.indexOf(';', pos); 168 v.visitTypeVariable(signature.substring(pos, end)); 169 return end + 1; 170 171 default: // case 'L': 172 start = pos; 173 visited = false; 174 inner = false; 175 for (;;) { 176 switch (c = signature.charAt(pos++)) { 177 case '.': 178 case ';': 179 if (!visited) { 180 name = signature.substring(start, pos - 1); 181 if (inner) { 182 v.visitInnerClassType(name); 183 } else { 184 v.visitClassType(name); 185 } 186 } 187 if (c == ';') { 188 v.visitEnd(); 189 return pos; 190 } 191 start = pos; 192 visited = false; 193 inner = true; 194 break; 195 196 case '<': 197 name = signature.substring(start, pos - 1); 198 if (inner) { 199 v.visitInnerClassType(name); 200 } else { 201 v.visitClassType(name); 202 } 203 visited = true; 204 top: for (;;) { 205 switch (c = signature.charAt(pos)) { 206 case '>': 207 break top; 208 case '*': 209 ++pos; 210 v.visitTypeArgument(); 211 break; 212 case '+': 213 case '-': 214 pos = parseType(signature, 215 pos + 1, 216 v.visitTypeArgument(c)); 217 break; 218 default: 219 pos = parseType(signature, 220 pos, 221 v.visitTypeArgument('=')); 222 break; 223 } 224 } 225 } 226 } 227 } 228 } 229} 230