You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by th...@apache.org on 2018/11/29 00:33:55 UTC

[08/46] tapestry-5 git commit: TAP5-2588: upgrading from ASM 6 to 7 for Java 9+ support

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckModuleAdapter.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckModuleAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckModuleAdapter.java
old mode 100644
new mode 100755
index cdc2531..0d6d28d
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckModuleAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckModuleAdapter.java
@@ -1,151 +1,212 @@
-/***
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
 package org.apache.tapestry5.internal.plastic.asm.util;
 
 import java.util.HashSet;
-
 import org.apache.tapestry5.internal.plastic.asm.ModuleVisitor;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 
 /**
+ * A {@link ModuleVisitor} that checks that its methods are properly used.
+ *
  * @author Remi Forax
  */
-public final class CheckModuleAdapter extends ModuleVisitor {
-    private boolean end;
-    private final boolean isOpen;
-
-    private final HashSet<String> requireNames = new HashSet<String>();
-    private final HashSet<String> exportNames = new HashSet<String>();
-    private final HashSet<String> openNames = new HashSet<String>();
-    private final HashSet<String> useNames = new HashSet<String>();
-    private final HashSet<String> provideNames = new HashSet<String>();
-    
-    public CheckModuleAdapter(final ModuleVisitor mv, final boolean isOpen) {
-        super(Opcodes.ASM6, mv);
-        this.isOpen = isOpen;
+public class CheckModuleAdapter extends ModuleVisitor {
+  /** Whether the visited module is open. */
+  private final boolean isOpen;
+
+  /** The fully qualified names of the dependencies of the visited module. */
+  private final NameSet requiredModules = new NameSet("Modules requires");
+
+  /** The internal names of the packages exported by the visited module. */
+  private final NameSet exportedPackages = new NameSet("Module exports");
+
+  /** The internal names of the packages opened by the visited module. */
+  private final NameSet openedPackages = new NameSet("Module opens");
+
+  /** The internal names of the services used by the visited module. */
+  private final NameSet usedServices = new NameSet("Module uses");
+
+  /** The internal names of the services provided by the visited module. */
+  private final NameSet providedServices = new NameSet("Module provides");
+
+  /** The class version number. */
+  int classVersion;
+
+  /** Whether the {@link #visitEnd} method has been called. */
+  private boolean visitEndCalled;
+
+  /**
+   * Constructs a new {@link CheckModuleAdapter}. <i>Subclasses must not use this constructor</i>.
+   * Instead, they must use the {@link #CheckModuleAdapter(int, ModuleVisitor, boolean)} version.
+   *
+   * @param moduleVisitor the module visitor to which this adapter must delegate calls.
+   * @param isOpen whether the visited module is open. Open modules have their {@link
+   *     Opcodes#ACC_OPEN} access flag set in {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitModule}.
+   * @throws IllegalStateException If a subclass calls this constructor.
+   */
+  public CheckModuleAdapter(final ModuleVisitor moduleVisitor, final boolean isOpen) {
+    this(Opcodes.ASM7, moduleVisitor, isOpen);
+    if (getClass() != CheckModuleAdapter.class) {
+      throw new IllegalStateException();
     }
-    
-    @Override
-    public void visitRequire(String module, int access, String version) {
-        checkEnd();
-        if (module == null) {
-            throw new IllegalArgumentException("require cannot be null");
-        }
-        checkDeclared("requires", requireNames, module);
-        CheckClassAdapter.checkAccess(access, Opcodes.ACC_STATIC_PHASE
-                + Opcodes.ACC_TRANSITIVE + Opcodes.ACC_SYNTHETIC + Opcodes.ACC_MANDATED);
-        super.visitRequire(module, access, version);
+  }
+
+  /**
+   * Constructs a new {@link CheckModuleAdapter}.
+   *
+   * @param api the ASM API version implemented by this visitor. Must be one of {@link
+   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * @param moduleVisitor the module visitor to which this adapter must delegate calls.
+   * @param isOpen whether the visited module is open. Open modules have their {@link
+   *     Opcodes#ACC_OPEN} access flag set in {@link org.apache.tapestry5.internal.plastic.asm.ClassVisitor#visitModule}.
+   */
+  protected CheckModuleAdapter(
+      final int api, final ModuleVisitor moduleVisitor, final boolean isOpen) {
+    super(api, moduleVisitor);
+    this.isOpen = isOpen;
+  }
+
+  @Override
+  public void visitMainClass(final String mainClass) {
+    // Modules can only appear in V9 or more classes.
+    CheckMethodAdapter.checkInternalName(Opcodes.V9, mainClass, "module main class");
+    super.visitMainClass(mainClass);
+  }
+
+  @Override
+  public void visitPackage(final String packaze) {
+    CheckMethodAdapter.checkInternalName(Opcodes.V9, packaze, "module package");
+    super.visitPackage(packaze);
+  }
+
+  @Override
+  public void visitRequire(final String module, final int access, final String version) {
+    checkVisitEndNotCalled();
+    CheckClassAdapter.checkFullyQualifiedName(Opcodes.V9, module, "required module");
+    requiredModules.checkNameNotAlreadyDeclared(module);
+    CheckClassAdapter.checkAccess(
+        access,
+        Opcodes.ACC_STATIC_PHASE
+            | Opcodes.ACC_TRANSITIVE
+            | Opcodes.ACC_SYNTHETIC
+            | Opcodes.ACC_MANDATED);
+    if (classVersion >= Opcodes.V10
+        && module.equals("java.base")
+        && (access & (Opcodes.ACC_STATIC_PHASE | Opcodes.ACC_TRANSITIVE)) != 0) {
+      throw new IllegalArgumentException(
+          "Invalid access flags: "
+              + access
+              + " java.base can not be declared ACC_TRANSITIVE or ACC_STATIC_PHASE");
     }
-    
-    @Override
-    public void visitExport(String packaze, int access, String... modules) {
-        checkEnd();
-        if (packaze == null) {
-            throw new IllegalArgumentException("packaze cannot be null");
-        }
-        CheckMethodAdapter.checkInternalName(packaze, "package name");
-        checkDeclared("exports", exportNames, packaze);
-        CheckClassAdapter.checkAccess(access, Opcodes.ACC_SYNTHETIC
-                + Opcodes.ACC_MANDATED);
-        if (modules != null) {
-            for (int i = 0; i < modules.length; i++) {
-                if (modules[i] == null) {
-                    throw new IllegalArgumentException("module at index " + i + " cannot be null");
-                }
-            }
-        }
-        super.visitExport(packaze, access, modules);
+    super.visitRequire(module, access, version);
+  }
+
+  @Override
+  public void visitExport(final String packaze, final int access, final String... modules) {
+    checkVisitEndNotCalled();
+    CheckMethodAdapter.checkInternalName(Opcodes.V9, packaze, "package name");
+    exportedPackages.checkNameNotAlreadyDeclared(packaze);
+    CheckClassAdapter.checkAccess(access, Opcodes.ACC_SYNTHETIC | Opcodes.ACC_MANDATED);
+    if (modules != null) {
+      for (String module : modules) {
+        CheckClassAdapter.checkFullyQualifiedName(Opcodes.V9, module, "module export to");
+      }
     }
-    
-    @Override
-    public void visitOpen(String packaze, int access, String... modules) {
-        checkEnd();
-        if (isOpen) {
-            throw new IllegalArgumentException("an open module can not use open directive");
-        }
-        if (packaze == null) {
-            throw new IllegalArgumentException("packaze cannot be null");
-        }
-        CheckMethodAdapter.checkInternalName(packaze, "package name");
-        checkDeclared("opens", openNames, packaze);
-        CheckClassAdapter.checkAccess(access, Opcodes.ACC_SYNTHETIC
-                + Opcodes.ACC_MANDATED);
-        if (modules != null) {
-            for (int i = 0; i < modules.length; i++) {
-                if (modules[i] == null) {
-                    throw new IllegalArgumentException("module at index " + i + " cannot be null");
-                }
-            }
-        }
-        super.visitOpen(packaze, access, modules);
+    super.visitExport(packaze, access, modules);
+  }
+
+  @Override
+  public void visitOpen(final String packaze, final int access, final String... modules) {
+    checkVisitEndNotCalled();
+    if (isOpen) {
+      throw new UnsupportedOperationException("An open module can not use open directive");
     }
-    
-    @Override
-    public void visitUse(String service) {
-        checkEnd();
-        CheckMethodAdapter.checkInternalName(service, "service");
-        checkDeclared("uses", useNames, service);
-        super.visitUse(service);
+    CheckMethodAdapter.checkInternalName(Opcodes.V9, packaze, "package name");
+    openedPackages.checkNameNotAlreadyDeclared(packaze);
+    CheckClassAdapter.checkAccess(access, Opcodes.ACC_SYNTHETIC | Opcodes.ACC_MANDATED);
+    if (modules != null) {
+      for (String module : modules) {
+        CheckClassAdapter.checkFullyQualifiedName(Opcodes.V9, module, "module open to");
+      }
     }
-    
-    @Override
-    public void visitProvide(String service, String... providers) {
-        checkEnd();
-        CheckMethodAdapter.checkInternalName(service, "service");
-        checkDeclared("provides", provideNames, service);
-        if (providers == null || providers.length == 0) {
-            throw new IllegalArgumentException("providers cannot be null or empty");
-        }
-        for (int i = 0; i < providers.length; i++) {
-            CheckMethodAdapter.checkInternalName(providers[i], "provider");
-        }
-        super.visitProvide(service, providers);
+    super.visitOpen(packaze, access, modules);
+  }
+
+  @Override
+  public void visitUse(final String service) {
+    checkVisitEndNotCalled();
+    CheckMethodAdapter.checkInternalName(Opcodes.V9, service, "service");
+    usedServices.checkNameNotAlreadyDeclared(service);
+    super.visitUse(service);
+  }
+
+  @Override
+  public void visitProvide(final String service, final String... providers) {
+    checkVisitEndNotCalled();
+    CheckMethodAdapter.checkInternalName(Opcodes.V9, service, "service");
+    providedServices.checkNameNotAlreadyDeclared(service);
+    if (providers == null || providers.length == 0) {
+      throw new IllegalArgumentException("Providers cannot be null or empty");
     }
-    
-    @Override
-    public void visitEnd() {
-        checkEnd();
-        end = true;
-        super.visitEnd();
+    for (String provider : providers) {
+      CheckMethodAdapter.checkInternalName(Opcodes.V9, provider, "provider");
     }
+    super.visitProvide(service, providers);
+  }
 
-    private void checkEnd() {
-        if (end) {
-            throw new IllegalStateException(
-                    "Cannot call a visit method after visitEnd has been called");
-        }
+  @Override
+  public void visitEnd() {
+    checkVisitEndNotCalled();
+    visitEndCalled = true;
+    super.visitEnd();
+  }
+
+  private void checkVisitEndNotCalled() {
+    if (visitEndCalled) {
+      throw new IllegalStateException("Cannot call a visit method after visitEnd has been called");
+    }
+  }
+
+  private static class NameSet {
+
+    private final String type;
+    private final HashSet<String> names;
+
+    NameSet(final String type) {
+      this.type = type;
+      this.names = new HashSet<String>();
     }
-    
-    private static void checkDeclared(String directive, HashSet<String> names, String name) {
-        if (!names.add(name)) {
-            throw new IllegalArgumentException(directive + " " + name + " already declared");
-        }
+
+    void checkNameNotAlreadyDeclared(final String name) {
+      if (!names.add(name)) {
+        throw new IllegalArgumentException(type + " " + name + " already declared");
+      }
     }
+  }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/1c71aec7/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckSignatureAdapter.java
----------------------------------------------------------------------
diff --git a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckSignatureAdapter.java b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckSignatureAdapter.java
old mode 100644
new mode 100755
index bca5dd7..8103a10
--- a/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckSignatureAdapter.java
+++ b/plastic/src/external/java/org/apache/tapestry5/internal/plastic/asm/util/CheckSignatureAdapter.java
@@ -1,356 +1,359 @@
-/***
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
+// ASM: a very small and fast Java bytecode manipulation framework
+// Copyright (c) 2000-2011 INRIA, France Telecom
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+// 3. Neither the name of the copyright holders nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+// THE POSSIBILITY OF SUCH DAMAGE.
 package org.apache.tapestry5.internal.plastic.asm.util;
 
+import java.util.EnumSet;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.signature.SignatureVisitor;
 
 /**
  * A {@link SignatureVisitor} that checks that its methods are properly used.
- * 
+ *
  * @author Eric Bruneton
  */
 public class CheckSignatureAdapter extends SignatureVisitor {
 
-    /**
-     * Type to be used to check class signatures. See
-     * {@link #CheckSignatureAdapter(int, SignatureVisitor)
-     * CheckSignatureAdapter}.
-     */
-    public static final int CLASS_SIGNATURE = 0;
-
-    /**
-     * Type to be used to check method signatures. See
-     * {@link #CheckSignatureAdapter(int, SignatureVisitor)
-     * CheckSignatureAdapter}.
-     */
-    public static final int METHOD_SIGNATURE = 1;
-
-    /**
-     * Type to be used to check type signatures.See
-     * {@link #CheckSignatureAdapter(int, SignatureVisitor)
-     * CheckSignatureAdapter}.
-     */
-    public static final int TYPE_SIGNATURE = 2;
-
-    private static final int EMPTY = 1;
-
-    private static final int FORMAL = 2;
-
-    private static final int BOUND = 4;
-
-    private static final int SUPER = 8;
-
-    private static final int PARAM = 16;
-
-    private static final int RETURN = 32;
-
-    private static final int SIMPLE_TYPE = 64;
-
-    private static final int CLASS_TYPE = 128;
-
-    private static final int END = 256;
-
-    /**
-     * Type of the signature to be checked.
-     */
-    private final int type;
-
-    /**
-     * State of the automaton used to check the order of method calls.
-     */
-    private int state;
-
-    /**
-     * <tt>true</tt> if the checked type signature can be 'V'.
-     */
-    private boolean canBeVoid;
-
-    /**
-     * The visitor to which this adapter must delegate calls. May be
-     * <tt>null</tt>.
-     */
-    private final SignatureVisitor sv;
-
-    /**
-     * Creates a new {@link CheckSignatureAdapter} object. <i>Subclasses must
-     * not use this constructor</i>. Instead, they must use the
-     * {@link #CheckSignatureAdapter(int, int, SignatureVisitor)} version.
-     * 
-     * @param type
-     *            the type of signature to be checked. See
-     *            {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and
-     *            {@link #TYPE_SIGNATURE}.
-     * @param sv
-     *            the visitor to which this adapter must delegate calls. May be
-     *            <tt>null</tt>.
-     */
-    public CheckSignatureAdapter(final int type, final SignatureVisitor sv) {
-        this(Opcodes.ASM6, type, sv);
+  /**
+   * Type to be used to check class signatures. See {@link #CheckSignatureAdapter(int,
+   * SignatureVisitor)}.
+   */
+  public static final int CLASS_SIGNATURE = 0;
+
+  /**
+   * Type to be used to check method signatures. See {@link #CheckSignatureAdapter(int,
+   * SignatureVisitor)}.
+   */
+  public static final int METHOD_SIGNATURE = 1;
+
+  /**
+   * Type to be used to check type signatures.See {@link #CheckSignatureAdapter(int,
+   * SignatureVisitor)}.
+   */
+  public static final int TYPE_SIGNATURE = 2;
+
+  /** The valid automaton states for a {@link #visitFormalTypeParameter} method call. */
+  private static final EnumSet<State> VISIT_FORMAL_TYPE_PARAMETER_STATES =
+      EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND);
+
+  /** The valid automaton states for a {@link #visitClassBound} method call. */
+  private static final EnumSet<State> VISIT_CLASS_BOUND_STATES = EnumSet.of(State.FORMAL);
+
+  /** The valid automaton states for a {@link #visitInterfaceBound} method call. */
+  private static final EnumSet<State> VISIT_INTERFACE_BOUND_STATES =
+      EnumSet.of(State.FORMAL, State.BOUND);
+
+  /** The valid automaton states for a {@link #visitSuperclass} method call. */
+  private static final EnumSet<State> VISIT_SUPER_CLASS_STATES =
+      EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND);
+
+  /** The valid automaton states for a {@link #visitInterface} method call. */
+  private static final EnumSet<State> VISIT_INTERFACE_STATES = EnumSet.of(State.SUPER);
+
+  /** The valid automaton states for a {@link #visitParameterType} method call. */
+  private static final EnumSet<State> VISIT_PARAMETER_TYPE_STATES =
+      EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND, State.PARAM);
+
+  /** The valid automaton states for a {@link #visitReturnType} method call. */
+  private static final EnumSet<State> VISIT_RETURN_TYPE_STATES =
+      EnumSet.of(State.EMPTY, State.FORMAL, State.BOUND, State.PARAM);
+
+  /** The valid automaton states for a {@link #visitExceptionType} method call. */
+  private static final EnumSet<State> VISIT_EXCEPTION_TYPE_STATES = EnumSet.of(State.RETURN);
+
+  /** The possible states of the automaton used to check the order of method calls. */
+  private enum State {
+    EMPTY,
+    FORMAL,
+    BOUND,
+    SUPER,
+    PARAM,
+    RETURN,
+    SIMPLE_TYPE,
+    CLASS_TYPE,
+    END;
+  }
+
+  private static final String INVALID = "Invalid ";
+
+  /** The type of the visited signature. */
+  private final int type;
+
+  /** The current state of the automaton used to check the order of method calls. */
+  private State state;
+
+  /** Whether the visited signature can be 'V'. */
+  private boolean canBeVoid;
+
+  /** The visitor to which this adapter must delegate calls. May be {@literal null}. */
+  private final SignatureVisitor signatureVisitor;
+
+  /**
+   * Constructs a new {@link CheckSignatureAdapter}. <i>Subclasses must not use this
+   * constructor</i>. Instead, they must use the {@link #CheckSignatureAdapter(int, int,
+   * SignatureVisitor)} version.
+   *
+   * @param type the type of signature to be checked. See {@link #CLASS_SIGNATURE}, {@link
+   *     #METHOD_SIGNATURE} and {@link #TYPE_SIGNATURE}.
+   * @param signatureVisitor the visitor to which this adapter must delegate calls. May be {@literal
+   *     null}.
+   */
+  public CheckSignatureAdapter(final int type, final SignatureVisitor signatureVisitor) {
+    this(Opcodes.ASM7, type, signatureVisitor);
+  }
+
+  /**
+   * Constructs a new {@link CheckSignatureAdapter}.
+   *
+   * @param api the ASM API version implemented by this visitor. Must be one of {@link
+   *     Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
+   * @param type the type of signature to be checked. See {@link #CLASS_SIGNATURE}, {@link
+   *     #METHOD_SIGNATURE} and {@link #TYPE_SIGNATURE}.
+   * @param signatureVisitor the visitor to which this adapter must delegate calls. May be {@literal
+   *     null}.
+   */
+  protected CheckSignatureAdapter(
+      final int api, final int type, final SignatureVisitor signatureVisitor) {
+    super(api);
+    this.type = type;
+    this.state = State.EMPTY;
+    this.signatureVisitor = signatureVisitor;
+  }
+
+  // class and method signatures
+
+  @Override
+  public void visitFormalTypeParameter(final String name) {
+    if (type == TYPE_SIGNATURE || !VISIT_FORMAL_TYPE_PARAMETER_STATES.contains(state)) {
+      throw new IllegalStateException();
     }
-
-    /**
-     * Creates a new {@link CheckSignatureAdapter} object.
-     * 
-     * @param api
-     *            the ASM API version implemented by this visitor. Must be one
-     *            of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
-     * @param type
-     *            the type of signature to be checked. See
-     *            {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and
-     *            {@link #TYPE_SIGNATURE}.
-     * @param sv
-     *            the visitor to which this adapter must delegate calls. May be
-     *            <tt>null</tt>.
-     */
-    protected CheckSignatureAdapter(final int api, final int type,
-            final SignatureVisitor sv) {
-        super(api);
-        this.type = type;
-        this.state = EMPTY;
-        this.sv = sv;
+    checkIdentifier(name, "formal type parameter");
+    state = State.FORMAL;
+    if (signatureVisitor != null) {
+      signatureVisitor.visitFormalTypeParameter(name);
     }
+  }
 
-    // class and method signatures
-
-    @Override
-    public void visitFormalTypeParameter(final String name) {
-        if (type == TYPE_SIGNATURE
-                || (state != EMPTY && state != FORMAL && state != BOUND)) {
-            throw new IllegalStateException();
-        }
-        checkIdentifier(name, "formal type parameter");
-        state = FORMAL;
-        if (sv != null) {
-            sv.visitFormalTypeParameter(name);
-        }
+  @Override
+  public SignatureVisitor visitClassBound() {
+    if (type == TYPE_SIGNATURE || !VISIT_CLASS_BOUND_STATES.contains(state)) {
+      throw new IllegalStateException();
     }
-
-    @Override
-    public SignatureVisitor visitClassBound() {
-        if (state != FORMAL) {
-            throw new IllegalStateException();
-        }
-        state = BOUND;
-        SignatureVisitor v = sv == null ? null : sv.visitClassBound();
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+    state = State.BOUND;
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitClassBound());
+  }
+
+  @Override
+  public SignatureVisitor visitInterfaceBound() {
+    if (type == TYPE_SIGNATURE || !VISIT_INTERFACE_BOUND_STATES.contains(state)) {
+      throw new IllegalArgumentException();
     }
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitInterfaceBound());
+  }
 
-    @Override
-    public SignatureVisitor visitInterfaceBound() {
-        if (state != FORMAL && state != BOUND) {
-            throw new IllegalArgumentException();
-        }
-        SignatureVisitor v = sv == null ? null : sv.visitInterfaceBound();
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+  // class signatures
+
+  @Override
+  public SignatureVisitor visitSuperclass() {
+    if (type != CLASS_SIGNATURE || !VISIT_SUPER_CLASS_STATES.contains(state)) {
+      throw new IllegalArgumentException();
+    }
+    state = State.SUPER;
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitSuperclass());
+  }
+
+  @Override
+  public SignatureVisitor visitInterface() {
+    if (type != CLASS_SIGNATURE || !VISIT_INTERFACE_STATES.contains(state)) {
+      throw new IllegalStateException();
     }
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitInterface());
+  }
 
-    // class signatures
+  // method signatures
 
-    @Override
-    public SignatureVisitor visitSuperclass() {
-        if (type != CLASS_SIGNATURE || (state & (EMPTY | FORMAL | BOUND)) == 0) {
-            throw new IllegalArgumentException();
-        }
-        state = SUPER;
-        SignatureVisitor v = sv == null ? null : sv.visitSuperclass();
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+  @Override
+  public SignatureVisitor visitParameterType() {
+    if (type != METHOD_SIGNATURE || !VISIT_PARAMETER_TYPE_STATES.contains(state)) {
+      throw new IllegalArgumentException();
     }
-
-    @Override
-    public SignatureVisitor visitInterface() {
-        if (state != SUPER) {
-            throw new IllegalStateException();
-        }
-        SignatureVisitor v = sv == null ? null : sv.visitInterface();
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+    state = State.PARAM;
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitParameterType());
+  }
+
+  @Override
+  public SignatureVisitor visitReturnType() {
+    if (type != METHOD_SIGNATURE || !VISIT_RETURN_TYPE_STATES.contains(state)) {
+      throw new IllegalArgumentException();
     }
-
-    // method signatures
-
-    @Override
-    public SignatureVisitor visitParameterType() {
-        if (type != METHOD_SIGNATURE
-                || (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) {
-            throw new IllegalArgumentException();
-        }
-        state = PARAM;
-        SignatureVisitor v = sv == null ? null : sv.visitParameterType();
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+    state = State.RETURN;
+    CheckSignatureAdapter checkSignatureAdapter =
+        new CheckSignatureAdapter(
+            TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitReturnType());
+    checkSignatureAdapter.canBeVoid = true;
+    return checkSignatureAdapter;
+  }
+
+  @Override
+  public SignatureVisitor visitExceptionType() {
+    if (type != METHOD_SIGNATURE || !VISIT_EXCEPTION_TYPE_STATES.contains(state)) {
+      throw new IllegalStateException();
     }
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitExceptionType());
+  }
 
-    @Override
-    public SignatureVisitor visitReturnType() {
-        if (type != METHOD_SIGNATURE
-                || (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) {
-            throw new IllegalArgumentException();
-        }
-        state = RETURN;
-        SignatureVisitor v = sv == null ? null : sv.visitReturnType();
-        CheckSignatureAdapter cv = new CheckSignatureAdapter(TYPE_SIGNATURE, v);
-        cv.canBeVoid = true;
-        return cv;
-    }
+  // type signatures
 
-    @Override
-    public SignatureVisitor visitExceptionType() {
-        if (state != RETURN) {
-            throw new IllegalStateException();
-        }
-        SignatureVisitor v = sv == null ? null : sv.visitExceptionType();
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+  @Override
+  public void visitBaseType(final char descriptor) {
+    if (type != TYPE_SIGNATURE || state != State.EMPTY) {
+      throw new IllegalStateException();
     }
-
-    // type signatures
-
-    @Override
-    public void visitBaseType(final char descriptor) {
-        if (type != TYPE_SIGNATURE || state != EMPTY) {
-            throw new IllegalStateException();
-        }
-        if (descriptor == 'V') {
-            if (!canBeVoid) {
-                throw new IllegalArgumentException();
-            }
-        } else {
-            if ("ZCBSIFJD".indexOf(descriptor) == -1) {
-                throw new IllegalArgumentException();
-            }
-        }
-        state = SIMPLE_TYPE;
-        if (sv != null) {
-            sv.visitBaseType(descriptor);
-        }
+    if (descriptor == 'V') {
+      if (!canBeVoid) {
+        throw new IllegalArgumentException();
+      }
+    } else {
+      if ("ZCBSIFJD".indexOf(descriptor) == -1) {
+        throw new IllegalArgumentException();
+      }
     }
-
-    @Override
-    public void visitTypeVariable(final String name) {
-        if (type != TYPE_SIGNATURE || state != EMPTY) {
-            throw new IllegalStateException();
-        }
-        checkIdentifier(name, "type variable");
-        state = SIMPLE_TYPE;
-        if (sv != null) {
-            sv.visitTypeVariable(name);
-        }
+    state = State.SIMPLE_TYPE;
+    if (signatureVisitor != null) {
+      signatureVisitor.visitBaseType(descriptor);
     }
+  }
 
-    @Override
-    public SignatureVisitor visitArrayType() {
-        if (type != TYPE_SIGNATURE || state != EMPTY) {
-            throw new IllegalStateException();
-        }
-        state = SIMPLE_TYPE;
-        SignatureVisitor v = sv == null ? null : sv.visitArrayType();
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+  @Override
+  public void visitTypeVariable(final String name) {
+    if (type != TYPE_SIGNATURE || state != State.EMPTY) {
+      throw new IllegalStateException();
     }
-
-    @Override
-    public void visitClassType(final String name) {
-        if (type != TYPE_SIGNATURE || state != EMPTY) {
-            throw new IllegalStateException();
-        }
-        checkClassName(name, "class name");
-        state = CLASS_TYPE;
-        if (sv != null) {
-            sv.visitClassType(name);
-        }
+    checkIdentifier(name, "type variable");
+    state = State.SIMPLE_TYPE;
+    if (signatureVisitor != null) {
+      signatureVisitor.visitTypeVariable(name);
     }
+  }
 
-    @Override
-    public void visitInnerClassType(final String name) {
-        if (state != CLASS_TYPE) {
-            throw new IllegalStateException();
-        }
-        checkIdentifier(name, "inner class name");
-        if (sv != null) {
-            sv.visitInnerClassType(name);
-        }
+  @Override
+  public SignatureVisitor visitArrayType() {
+    if (type != TYPE_SIGNATURE || state != State.EMPTY) {
+      throw new IllegalStateException();
+    }
+    state = State.SIMPLE_TYPE;
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitArrayType());
+  }
+
+  @Override
+  public void visitClassType(final String name) {
+    if (type != TYPE_SIGNATURE || state != State.EMPTY) {
+      throw new IllegalStateException();
     }
+    checkClassName(name, "class name");
+    state = State.CLASS_TYPE;
+    if (signatureVisitor != null) {
+      signatureVisitor.visitClassType(name);
+    }
+  }
 
-    @Override
-    public void visitTypeArgument() {
-        if (state != CLASS_TYPE) {
-            throw new IllegalStateException();
-        }
-        if (sv != null) {
-            sv.visitTypeArgument();
-        }
+  @Override
+  public void visitInnerClassType(final String name) {
+    if (state != State.CLASS_TYPE) {
+      throw new IllegalStateException();
+    }
+    checkIdentifier(name, "inner class name");
+    if (signatureVisitor != null) {
+      signatureVisitor.visitInnerClassType(name);
     }
+  }
 
-    @Override
-    public SignatureVisitor visitTypeArgument(final char wildcard) {
-        if (state != CLASS_TYPE) {
-            throw new IllegalStateException();
-        }
-        if ("+-=".indexOf(wildcard) == -1) {
-            throw new IllegalArgumentException();
-        }
-        SignatureVisitor v = sv == null ? null : sv.visitTypeArgument(wildcard);
-        return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
+  @Override
+  public void visitTypeArgument() {
+    if (state != State.CLASS_TYPE) {
+      throw new IllegalStateException();
+    }
+    if (signatureVisitor != null) {
+      signatureVisitor.visitTypeArgument();
     }
+  }
 
-    @Override
-    public void visitEnd() {
-        if (state != CLASS_TYPE) {
-            throw new IllegalStateException();
-        }
-        state = END;
-        if (sv != null) {
-            sv.visitEnd();
-        }
+  @Override
+  public SignatureVisitor visitTypeArgument(final char wildcard) {
+    if (state != State.CLASS_TYPE) {
+      throw new IllegalStateException();
     }
+    if ("+-=".indexOf(wildcard) == -1) {
+      throw new IllegalArgumentException();
+    }
+    return new CheckSignatureAdapter(
+        TYPE_SIGNATURE,
+        signatureVisitor == null ? null : signatureVisitor.visitTypeArgument(wildcard));
+  }
+
+  @Override
+  public void visitEnd() {
+    if (state != State.CLASS_TYPE) {
+      throw new IllegalStateException();
+    }
+    state = State.END;
+    if (signatureVisitor != null) {
+      signatureVisitor.visitEnd();
+    }
+  }
 
-    private void checkClassName(final String name, final String msg) {
-        if (name == null || name.length() == 0) {
-            throw new IllegalArgumentException("Invalid " + msg
-                    + " (must not be null or empty)");
-        }
-        for (int i = 0; i < name.length(); ++i) {
-            if (".;[<>:".indexOf(name.charAt(i)) != -1) {
-                throw new IllegalArgumentException("Invalid " + msg
-                        + " (must not contain . ; [ < > or :): " + name);
-            }
-        }
+  private void checkClassName(final String name, final String message) {
+    if (name == null || name.length() == 0) {
+      throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)");
     }
+    for (int i = 0; i < name.length(); ++i) {
+      if (".;[<>:".indexOf(name.charAt(i)) != -1) {
+        throw new IllegalArgumentException(
+            INVALID + message + " (must not contain . ; [ < > or :): " + name);
+      }
+    }
+  }
 
-    private void checkIdentifier(final String name, final String msg) {
-        if (name == null || name.length() == 0) {
-            throw new IllegalArgumentException("Invalid " + msg
-                    + " (must not be null or empty)");
-        }
-        for (int i = 0; i < name.length(); ++i) {
-            if (".;[/<>:".indexOf(name.charAt(i)) != -1) {
-                throw new IllegalArgumentException("Invalid " + msg
-                        + " (must not contain . ; [ / < > or :): " + name);
-            }
-        }
+  private void checkIdentifier(final String name, final String message) {
+    if (name == null || name.length() == 0) {
+      throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)");
+    }
+    for (int i = 0; i < name.length(); ++i) {
+      if (".;[/<>:".indexOf(name.charAt(i)) != -1) {
+        throw new IllegalArgumentException(
+            INVALID + message + " (must not contain . ; [ / < > or :): " + name);
+      }
     }
+  }
 }