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 package org.objectweb.asm.util; 29 30 import java.util.EnumSet; 31 import org.objectweb.asm.Opcodes; 32 import org.objectweb.asm.signature.SignatureVisitor; 33 34 /** 35 * A {@link SignatureVisitor} that checks that its methods are properly used. 36 * 37 * @author Eric Bruneton 38 */ 39 public class CheckSignatureAdapter extends SignatureVisitor { 40 41 /** 42 * Type to be used to check class signatures. See {@link #CheckSignatureAdapter(int, 43 * SignatureVisitor)}. 44 */ 45 public static final int CLASS_SIGNATURE = 0; 46 47 /** 48 * Type to be used to check method signatures. See {@link #CheckSignatureAdapter(int, 49 * SignatureVisitor)}. 50 */ 51 public static final int METHOD_SIGNATURE = 1; 52 53 /** 54 * Type to be used to check type signatures.See {@link #CheckSignatureAdapter(int, 55 * SignatureVisitor)}. 56 */ 57 public static final int TYPE_SIGNATURE = 2; 58 59 /** The valid automaton states for a {@link #visitFormalTypeParameter} method call. */ 60 private static final EnumSet<State> VISIT_FORMAL_TYPE_PARAMETER_STATES = 61 EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND); 62 63 /** The valid automaton states for a {@link #visitClassBound} method call. */ 64 private static final EnumSet<State> VISIT_CLASS_BOUND_STATES = EnumSet.of(State.FORMAL); 65 66 /** The valid automaton states for a {@link #visitInterfaceBound} method call. */ 67 private static final EnumSet<State> VISIT_INTERFACE_BOUND_STATES = 68 EnumSet.of(State.FORMAL, State.BOUND); 69 70 /** The valid automaton states for a {@link #visitSuperclass} method call. */ 71 private static final EnumSet<State> VISIT_SUPER_CLASS_STATES = 72 EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND); 73 74 /** The valid automaton states for a {@link #visitInterface} method call. */ 75 private static final EnumSet<State> VISIT_INTERFACE_STATES = EnumSet.of(State.SUPER); 76 77 /** The valid automaton states for a {@link #visitParameterType} method call. */ 78 private static final EnumSet<State> VISIT_PARAMETER_TYPE_STATES = 79 EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND, State.PARAM); 80 81 /** The valid automaton states for a {@link #visitReturnType} method call. */ 82 private static final EnumSet<State> VISIT_RETURN_TYPE_STATES = 83 EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND, State.PARAM); 84 85 /** The valid automaton states for a {@link #visitExceptionType} method call. */ 86 private static final EnumSet<State> VISIT_EXCEPTION_TYPE_STATES = EnumSet.of(State.RETURN); 87 88 /** The possible states of the automaton used to check the order of method calls. */ 89 private enum State { 90 EMPTY, 91 FORMAL, 92 BOUND, 93 SUPER, 94 PARAM, 95 RETURN, 96 SIMPLE_TYPE, 97 CLASS_TYPE, 98 END; 99 } 100 101 private static final String INVALID = "Invalid "; 102 103 /** The type of the visited signature. */ 104 private final int type; 105 106 /** The current state of the automaton used to check the order of method calls. */ 107 private State state; 108 109 /** Whether the visited signature can be 'V'. */ 110 private boolean canBeVoid; 111 112 /** The visitor to which this adapter must delegate calls. May be {@literal null}. */ 113 private final SignatureVisitor signatureVisitor; 114 115 /** 116 * Constructs a new {@link CheckSignatureAdapter}. <i>Subclasses must not use this 117 * constructor</i>. Instead, they must use the {@link #CheckSignatureAdapter(int, int, 118 * SignatureVisitor)} version. 119 * 120 * @param type the type of signature to be checked. See {@link #CLASS_SIGNATURE}, {@link 121 * #METHOD_SIGNATURE} and {@link #TYPE_SIGNATURE}. 122 * @param signatureVisitor the visitor to which this adapter must delegate calls. May be {@literal 123 * null}. 124 */ CheckSignatureAdapter(final int type, final SignatureVisitor signatureVisitor)125 public CheckSignatureAdapter(final int type, final SignatureVisitor signatureVisitor) { 126 this(/* latest api = */ Opcodes.ASM9, type, signatureVisitor); 127 } 128 129 /** 130 * Constructs a new {@link CheckSignatureAdapter}. 131 * 132 * @param api the ASM API version implemented by this visitor. Must be one of the {@code 133 * ASM}<i>x</i> values in {@link Opcodes}. 134 * @param type the type of signature to be checked. See {@link #CLASS_SIGNATURE}, {@link 135 * #METHOD_SIGNATURE} and {@link #TYPE_SIGNATURE}. 136 * @param signatureVisitor the visitor to which this adapter must delegate calls. May be {@literal 137 * null}. 138 */ CheckSignatureAdapter( final int api, final int type, final SignatureVisitor signatureVisitor)139 protected CheckSignatureAdapter( 140 final int api, final int type, final SignatureVisitor signatureVisitor) { 141 super(api); 142 this.type = type; 143 this.state = State.EMPTY; 144 this.signatureVisitor = signatureVisitor; 145 } 146 147 // class and method signatures 148 149 @Override visitFormalTypeParameter(final String name)150 public void visitFormalTypeParameter(final String name) { 151 if (type == TYPE_SIGNATURE || !VISIT_FORMAL_TYPE_PARAMETER_STATES.contains(state)) { 152 throw new IllegalStateException(); 153 } 154 checkIdentifier(name, "formal type parameter"); 155 state = State.FORMAL; 156 if (signatureVisitor != null) { 157 signatureVisitor.visitFormalTypeParameter(name); 158 } 159 } 160 161 @Override visitClassBound()162 public SignatureVisitor visitClassBound() { 163 if (type == TYPE_SIGNATURE || !VISIT_CLASS_BOUND_STATES.contains(state)) { 164 throw new IllegalStateException(); 165 } 166 state = State.BOUND; 167 return new CheckSignatureAdapter( 168 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitClassBound()); 169 } 170 171 @Override visitInterfaceBound()172 public SignatureVisitor visitInterfaceBound() { 173 if (type == TYPE_SIGNATURE || !VISIT_INTERFACE_BOUND_STATES.contains(state)) { 174 throw new IllegalStateException(); 175 } 176 return new CheckSignatureAdapter( 177 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitInterfaceBound()); 178 } 179 180 // class signatures 181 182 @Override visitSuperclass()183 public SignatureVisitor visitSuperclass() { 184 if (type != CLASS_SIGNATURE || !VISIT_SUPER_CLASS_STATES.contains(state)) { 185 throw new IllegalStateException(); 186 } 187 state = State.SUPER; 188 return new CheckSignatureAdapter( 189 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitSuperclass()); 190 } 191 192 @Override visitInterface()193 public SignatureVisitor visitInterface() { 194 if (type != CLASS_SIGNATURE || !VISIT_INTERFACE_STATES.contains(state)) { 195 throw new IllegalStateException(); 196 } 197 return new CheckSignatureAdapter( 198 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitInterface()); 199 } 200 201 // method signatures 202 203 @Override visitParameterType()204 public SignatureVisitor visitParameterType() { 205 if (type != METHOD_SIGNATURE || !VISIT_PARAMETER_TYPE_STATES.contains(state)) { 206 throw new IllegalStateException(); 207 } 208 state = State.PARAM; 209 return new CheckSignatureAdapter( 210 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitParameterType()); 211 } 212 213 @Override visitReturnType()214 public SignatureVisitor visitReturnType() { 215 if (type != METHOD_SIGNATURE || !VISIT_RETURN_TYPE_STATES.contains(state)) { 216 throw new IllegalStateException(); 217 } 218 state = State.RETURN; 219 CheckSignatureAdapter checkSignatureAdapter = 220 new CheckSignatureAdapter( 221 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitReturnType()); 222 checkSignatureAdapter.canBeVoid = true; 223 return checkSignatureAdapter; 224 } 225 226 @Override visitExceptionType()227 public SignatureVisitor visitExceptionType() { 228 if (type != METHOD_SIGNATURE || !VISIT_EXCEPTION_TYPE_STATES.contains(state)) { 229 throw new IllegalStateException(); 230 } 231 return new CheckSignatureAdapter( 232 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitExceptionType()); 233 } 234 235 // type signatures 236 237 @Override visitBaseType(final char descriptor)238 public void visitBaseType(final char descriptor) { 239 if (type != TYPE_SIGNATURE || state != State.EMPTY) { 240 throw new IllegalStateException(); 241 } 242 if (descriptor == 'V') { 243 if (!canBeVoid) { 244 throw new IllegalArgumentException("Base type descriptor can't be V"); 245 } 246 } else { 247 if ("ZCBSIFJD".indexOf(descriptor) == -1) { 248 throw new IllegalArgumentException("Base type descriptor must be one of ZCBSIFJD"); 249 } 250 } 251 state = State.SIMPLE_TYPE; 252 if (signatureVisitor != null) { 253 signatureVisitor.visitBaseType(descriptor); 254 } 255 } 256 257 @Override visitTypeVariable(final String name)258 public void visitTypeVariable(final String name) { 259 if (type != TYPE_SIGNATURE || state != State.EMPTY) { 260 throw new IllegalStateException(); 261 } 262 checkIdentifier(name, "type variable"); 263 state = State.SIMPLE_TYPE; 264 if (signatureVisitor != null) { 265 signatureVisitor.visitTypeVariable(name); 266 } 267 } 268 269 @Override visitArrayType()270 public SignatureVisitor visitArrayType() { 271 if (type != TYPE_SIGNATURE || state != State.EMPTY) { 272 throw new IllegalStateException(); 273 } 274 state = State.SIMPLE_TYPE; 275 return new CheckSignatureAdapter( 276 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitArrayType()); 277 } 278 279 @Override visitClassType(final String name)280 public void visitClassType(final String name) { 281 if (type != TYPE_SIGNATURE || state != State.EMPTY) { 282 throw new IllegalStateException(); 283 } 284 checkClassName(name, "class name"); 285 state = State.CLASS_TYPE; 286 if (signatureVisitor != null) { 287 signatureVisitor.visitClassType(name); 288 } 289 } 290 291 @Override visitInnerClassType(final String name)292 public void visitInnerClassType(final String name) { 293 if (state != State.CLASS_TYPE) { 294 throw new IllegalStateException(); 295 } 296 checkIdentifier(name, "inner class name"); 297 if (signatureVisitor != null) { 298 signatureVisitor.visitInnerClassType(name); 299 } 300 } 301 302 @Override visitTypeArgument()303 public void visitTypeArgument() { 304 if (state != State.CLASS_TYPE) { 305 throw new IllegalStateException(); 306 } 307 if (signatureVisitor != null) { 308 signatureVisitor.visitTypeArgument(); 309 } 310 } 311 312 @Override visitTypeArgument(final char wildcard)313 public SignatureVisitor visitTypeArgument(final char wildcard) { 314 if (state != State.CLASS_TYPE) { 315 throw new IllegalStateException(); 316 } 317 if ("+-=".indexOf(wildcard) == -1) { 318 throw new IllegalArgumentException("Wildcard must be one of +-="); 319 } 320 return new CheckSignatureAdapter( 321 TYPE_SIGNATURE, 322 signatureVisitor == null ? null : signatureVisitor.visitTypeArgument(wildcard)); 323 } 324 325 @Override visitEnd()326 public void visitEnd() { 327 if (state != State.CLASS_TYPE) { 328 throw new IllegalStateException(); 329 } 330 state = State.END; 331 if (signatureVisitor != null) { 332 signatureVisitor.visitEnd(); 333 } 334 } 335 checkClassName(final String name, final String message)336 private void checkClassName(final String name, final String message) { 337 if (name == null || name.length() == 0) { 338 throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)"); 339 } 340 for (int i = 0; i < name.length(); ++i) { 341 if (".;[<>:".indexOf(name.charAt(i)) != -1) { 342 throw new IllegalArgumentException( 343 INVALID + message + " (must not contain . ; [ < > or :): " + name); 344 } 345 } 346 } 347 checkIdentifier(final String name, final String message)348 private void checkIdentifier(final String name, final String message) { 349 if (name == null || name.length() == 0) { 350 throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)"); 351 } 352 for (int i = 0; i < name.length(); ++i) { 353 if (".;[/<>:".indexOf(name.charAt(i)) != -1) { 354 throw new IllegalArgumentException( 355 INVALID + message + " (must not contain . ; [ / < > or :): " + name); 356 } 357 } 358 } 359 } 360