1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 /*
  26  * This file is available under and governed by the GNU General Public
  27  * License version 2 only, as published by the Free Software Foundation.
  28  * However, the following notice accompanied the original version of this
  29  * file:
  30  *
  31  * ASM: a very small and fast Java bytecode manipulation framework
  32  * Copyright (c) 2000-2011 INRIA, France Telecom
  33  * All rights reserved.
  34  *
  35  * Redistribution and use in source and binary forms, with or without
  36  * modification, are permitted provided that the following conditions
  37  * are met:
  38  * 1. Redistributions of source code must retain the above copyright
  39  *    notice, this list of conditions and the following disclaimer.
  40  * 2. Redistributions in binary form must reproduce the above copyright
  41  *    notice, this list of conditions and the following disclaimer in the
  42  *    documentation and/or other materials provided with the distribution.
  43  * 3. Neither the name of the copyright holders nor the names of its
  44  *    contributors may be used to endorse or promote products derived from
  45  *    this software without specific prior written permission.
  46  *
  47  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  48  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  50  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  51  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  57  * THE POSSIBILITY OF SUCH DAMAGE.
  58  */
  59 package jdk.internal.org.objectweb.asm.util;
  60 
  61 import java.util.EnumSet;
  62 import jdk.internal.org.objectweb.asm.Opcodes;
  63 import jdk.internal.org.objectweb.asm.signature.SignatureVisitor;
  64 
  65 /**
  66  * A {@link SignatureVisitor} that checks that its methods are properly used.
  67  *
  68  * @author Eric Bruneton
  69  */
  70 public class CheckSignatureAdapter extends SignatureVisitor {
  71 
  72     /**
  73       * Type to be used to check class signatures. See {@link #CheckSignatureAdapter(int,
  74       * SignatureVisitor)}.
  75       */
  76     public static final int CLASS_SIGNATURE = 0;
  77 
  78     /**
  79       * Type to be used to check method signatures. See {@link #CheckSignatureAdapter(int,
  80       * SignatureVisitor)}.
  81       */
  82     public static final int METHOD_SIGNATURE = 1;
  83 
  84     /**
  85       * Type to be used to check type signatures.See {@link #CheckSignatureAdapter(int,
  86       * SignatureVisitor)}.
  87       */
  88     public static final int TYPE_SIGNATURE = 2;
  89 
  90     /** The valid automaton states for a {@link #visitFormalTypeParameter} method call. */
  91     private static final EnumSet<State> VISIT_FORMAL_TYPE_PARAMETER_STATES =
  92             EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND);
  93 
  94     /** The valid automaton states for a {@link #visitClassBound} method call. */
  95     private static final EnumSet<State> VISIT_CLASS_BOUND_STATES = EnumSet.of(State.FORMAL);
  96 
  97     /** The valid automaton states for a {@link #visitInterfaceBound} method call. */
  98     private static final EnumSet<State> VISIT_INTERFACE_BOUND_STATES =
  99             EnumSet.of(State.FORMAL, State.BOUND);
 100 
 101     /** The valid automaton states for a {@link #visitSuperclass} method call. */
 102     private static final EnumSet<State> VISIT_SUPER_CLASS_STATES =
 103             EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND);
 104 
 105     /** The valid automaton states for a {@link #visitInterface} method call. */
 106     private static final EnumSet<State> VISIT_INTERFACE_STATES = EnumSet.of(State.SUPER);
 107 
 108     /** The valid automaton states for a {@link #visitParameterType} method call. */
 109     private static final EnumSet<State> VISIT_PARAMETER_TYPE_STATES =
 110             EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND, State.PARAM);
 111 
 112     /** The valid automaton states for a {@link #visitReturnType} method call. */
 113     private static final EnumSet<State> VISIT_RETURN_TYPE_STATES =
 114             EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND, State.PARAM);
 115 
 116     /** The valid automaton states for a {@link #visitExceptionType} method call. */
 117     private static final EnumSet<State> VISIT_EXCEPTION_TYPE_STATES = EnumSet.of(State.RETURN);
 118 
 119     /** The possible states of the automaton used to check the order of method calls. */
 120     private enum State {
 121         EMPTY,
 122         FORMAL,
 123         BOUND,
 124         SUPER,
 125         PARAM,
 126         RETURN,
 127         SIMPLE_TYPE,
 128         CLASS_TYPE,
 129         END;
 130     }
 131 
 132     private static final String INVALID = "Invalid ";
 133 
 134     /** The type of the visited signature. */
 135     private final int type;
 136 
 137     /** The current state of the automaton used to check the order of method calls. */
 138     private State state;
 139 
 140     /** Whether the visited signature can be 'V'. */
 141     private boolean canBeVoid;
 142 
 143     /** The visitor to which this adapter must delegate calls. May be {@literal null}. */
 144     private final SignatureVisitor signatureVisitor;
 145 
 146     /**
 147       * Constructs a new {@link CheckSignatureAdapter}. <i>Subclasses must not use this
 148       * constructor</i>. Instead, they must use the {@link #CheckSignatureAdapter(int, int,
 149       * SignatureVisitor)} version.
 150       *
 151       * @param type the type of signature to be checked. See {@link #CLASS_SIGNATURE}, {@link
 152       *     #METHOD_SIGNATURE} and {@link #TYPE_SIGNATURE}.
 153       * @param signatureVisitor the visitor to which this adapter must delegate calls. May be {@literal
 154       *     null}.
 155       */
 156     public CheckSignatureAdapter(final int type, final SignatureVisitor signatureVisitor) {
 157         this(Opcodes.ASM7, type, signatureVisitor);
 158     }
 159 
 160     /**
 161       * Constructs a new {@link CheckSignatureAdapter}.
 162       *
 163       * @param api the ASM API version implemented by this visitor. Must be one of {@link
 164       *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
 165       * @param type the type of signature to be checked. See {@link #CLASS_SIGNATURE}, {@link
 166       *     #METHOD_SIGNATURE} and {@link #TYPE_SIGNATURE}.
 167       * @param signatureVisitor the visitor to which this adapter must delegate calls. May be {@literal
 168       *     null}.
 169       */
 170     protected CheckSignatureAdapter(
 171             final int api, final int type, final SignatureVisitor signatureVisitor) {
 172         super(api);
 173         this.type = type;
 174         this.state = State.EMPTY;
 175         this.signatureVisitor = signatureVisitor;
 176     }
 177 
 178     // class and method signatures
 179 
 180     @Override
 181     public void visitFormalTypeParameter(final String name) {
 182         if (type == TYPE_SIGNATURE || !VISIT_FORMAL_TYPE_PARAMETER_STATES.contains(state)) {
 183             throw new IllegalStateException();
 184         }
 185         checkIdentifier(name, "formal type parameter");
 186         state = State.FORMAL;
 187         if (signatureVisitor != null) {
 188             signatureVisitor.visitFormalTypeParameter(name);
 189         }
 190     }
 191 
 192     @Override
 193     public SignatureVisitor visitClassBound() {
 194         if (type == TYPE_SIGNATURE || !VISIT_CLASS_BOUND_STATES.contains(state)) {
 195             throw new IllegalStateException();
 196         }
 197         state = State.BOUND;
 198         return new CheckSignatureAdapter(
 199                 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitClassBound());
 200     }
 201 
 202     @Override
 203     public SignatureVisitor visitInterfaceBound() {
 204         if (type == TYPE_SIGNATURE || !VISIT_INTERFACE_BOUND_STATES.contains(state)) {
 205             throw new IllegalArgumentException();
 206         }
 207         return new CheckSignatureAdapter(
 208                 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitInterfaceBound());
 209     }
 210 
 211     // class signatures
 212 
 213     @Override
 214     public SignatureVisitor visitSuperclass() {
 215         if (type != CLASS_SIGNATURE || !VISIT_SUPER_CLASS_STATES.contains(state)) {
 216             throw new IllegalArgumentException();
 217         }
 218         state = State.SUPER;
 219         return new CheckSignatureAdapter(
 220                 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitSuperclass());
 221     }
 222 
 223     @Override
 224     public SignatureVisitor visitInterface() {
 225         if (type != CLASS_SIGNATURE || !VISIT_INTERFACE_STATES.contains(state)) {
 226             throw new IllegalStateException();
 227         }
 228         return new CheckSignatureAdapter(
 229                 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitInterface());
 230     }
 231 
 232     // method signatures
 233 
 234     @Override
 235     public SignatureVisitor visitParameterType() {
 236         if (type != METHOD_SIGNATURE || !VISIT_PARAMETER_TYPE_STATES.contains(state)) {
 237             throw new IllegalArgumentException();
 238         }
 239         state = State.PARAM;
 240         return new CheckSignatureAdapter(
 241                 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitParameterType());
 242     }
 243 
 244     @Override
 245     public SignatureVisitor visitReturnType() {
 246         if (type != METHOD_SIGNATURE || !VISIT_RETURN_TYPE_STATES.contains(state)) {
 247             throw new IllegalArgumentException();
 248         }
 249         state = State.RETURN;
 250         CheckSignatureAdapter checkSignatureAdapter =
 251                 new CheckSignatureAdapter(
 252                         TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitReturnType());
 253         checkSignatureAdapter.canBeVoid = true;
 254         return checkSignatureAdapter;
 255     }
 256 
 257     @Override
 258     public SignatureVisitor visitExceptionType() {
 259         if (type != METHOD_SIGNATURE || !VISIT_EXCEPTION_TYPE_STATES.contains(state)) {
 260             throw new IllegalStateException();
 261         }
 262         return new CheckSignatureAdapter(
 263                 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitExceptionType());
 264     }
 265 
 266     // type signatures
 267 
 268     @Override
 269     public void visitBaseType(final char descriptor) {
 270         if (type != TYPE_SIGNATURE || state != State.EMPTY) {
 271             throw new IllegalStateException();
 272         }
 273         if (descriptor == 'V') {
 274             if (!canBeVoid) {
 275                 throw new IllegalArgumentException();
 276             }
 277         } else {
 278             if ("ZCBSIFJD".indexOf(descriptor) == -1) {
 279                 throw new IllegalArgumentException();
 280             }
 281         }
 282         state = State.SIMPLE_TYPE;
 283         if (signatureVisitor != null) {
 284             signatureVisitor.visitBaseType(descriptor);
 285         }
 286     }
 287 
 288     @Override
 289     public void visitTypeVariable(final String name) {
 290         if (type != TYPE_SIGNATURE || state != State.EMPTY) {
 291             throw new IllegalStateException();
 292         }
 293         checkIdentifier(name, "type variable");
 294         state = State.SIMPLE_TYPE;
 295         if (signatureVisitor != null) {
 296             signatureVisitor.visitTypeVariable(name);
 297         }
 298     }
 299 
 300     @Override
 301     public SignatureVisitor visitArrayType() {
 302         if (type != TYPE_SIGNATURE || state != State.EMPTY) {
 303             throw new IllegalStateException();
 304         }
 305         state = State.SIMPLE_TYPE;
 306         return new CheckSignatureAdapter(
 307                 TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitArrayType());
 308     }
 309 
 310     @Override
 311     public void visitClassType(final String name) {
 312         if (type != TYPE_SIGNATURE || state != State.EMPTY) {
 313             throw new IllegalStateException();
 314         }
 315         checkClassName(name, "class name");
 316         state = State.CLASS_TYPE;
 317         if (signatureVisitor != null) {
 318             signatureVisitor.visitClassType(name);
 319         }
 320     }
 321 
 322     @Override
 323     public void visitInnerClassType(final String name) {
 324         if (state != State.CLASS_TYPE) {
 325             throw new IllegalStateException();
 326         }
 327         checkIdentifier(name, "inner class name");
 328         if (signatureVisitor != null) {
 329             signatureVisitor.visitInnerClassType(name);
 330         }
 331     }
 332 
 333     @Override
 334     public void visitTypeArgument() {
 335         if (state != State.CLASS_TYPE) {
 336             throw new IllegalStateException();
 337         }
 338         if (signatureVisitor != null) {
 339             signatureVisitor.visitTypeArgument();
 340         }
 341     }
 342 
 343     @Override
 344     public SignatureVisitor visitTypeArgument(final char wildcard) {
 345         if (state != State.CLASS_TYPE) {
 346             throw new IllegalStateException();
 347         }
 348         if ("+-=".indexOf(wildcard) == -1) {
 349             throw new IllegalArgumentException();
 350         }
 351         return new CheckSignatureAdapter(
 352                 TYPE_SIGNATURE,
 353                 signatureVisitor == null ? null : signatureVisitor.visitTypeArgument(wildcard));
 354     }
 355 
 356     @Override
 357     public void visitEnd() {
 358         if (state != State.CLASS_TYPE) {
 359             throw new IllegalStateException();
 360         }
 361         state = State.END;
 362         if (signatureVisitor != null) {
 363             signatureVisitor.visitEnd();
 364         }
 365     }
 366 
 367     private void checkClassName(final String name, final String message) {
 368         if (name == null || name.length() == 0) {
 369             throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)");
 370         }
 371         for (int i = 0; i < name.length(); ++i) {
 372             if (".;[<>:".indexOf(name.charAt(i)) != -1) {
 373                 throw new IllegalArgumentException(
 374                         INVALID + message + " (must not contain . ; [ < > or :): " + name);
 375             }
 376         }
 377     }
 378 
 379     private void checkIdentifier(final String name, final String message) {
 380         if (name == null || name.length() == 0) {
 381             throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)");
 382         }
 383         for (int i = 0; i < name.length(); ++i) {
 384             if (".;[/<>:".indexOf(name.charAt(i)) != -1) {
 385                 throw new IllegalArgumentException(
 386                         INVALID + message + " (must not contain . ; [ / < > or :): " + name);
 387             }
 388         }
 389     }
 390 }