• 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 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