diff options
Diffstat (limited to 'asm/src')
-rw-r--r-- | asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java | 33 | ||||
-rw-r--r-- | asm/src/test/java/org/objectweb/asm/signature/SignaturesProviders.java | 15 |
2 files changed, 35 insertions, 13 deletions
diff --git a/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java b/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java index 2217a88a..df5f61d0 100644 --- a/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java +++ b/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java @@ -41,7 +41,7 @@ import org.objectweb.asm.Opcodes; public class SignatureWriter extends SignatureVisitor { /** The builder used to construct the visited signature. */ - private final StringBuilder stringBuilder = new StringBuilder(); + private final StringBuilder stringBuilder; /** Whether the visited signature contains formal type parameters. */ private boolean hasFormals; @@ -51,8 +51,9 @@ public class SignatureWriter extends SignatureVisitor { /** * The stack used to keep track of class types that have arguments. Each element of this stack is - * a boolean encoded in one bit. The top of the stack is the least significant bit. Pushing false - * = *2, pushing true = *2+1, popping = /2. + * a boolean encoded in one bit. The top of the stack is the least significant bit. The bottom of + * the stack is a sentinel element always equal to 1 (used to detect when the stack is full). + * Pushing false = {@code <<= 1}, pushing true = {@code '( <<= 1) | 1}, popping = {@code >>>= 1}. * * <p>Class type arguments must be surrounded with '<' and '>' and, because * @@ -62,15 +63,20 @@ public class SignatureWriter extends SignatureVisitor { * SignatureWriter instances), * </ol> * - * <p>we need a stack to properly balance these 'parentheses'. A new element is pushed on this - * stack for each new visited type, and popped when the visit of this type ends (either is + * <p>we need a stack to properly balance these angle brackets. A new element is pushed on this + * stack for each new visited type, and popped when the visit of this type ends (either in * visitEnd, or because visitInnerClassType is called). */ - private int argumentStack; + private int argumentStack = 1; /** Constructs a new {@link SignatureWriter}. */ public SignatureWriter() { + this(new StringBuilder()); + } + + private SignatureWriter(final StringBuilder stringBuilder) { super(/* latest api =*/ Opcodes.ASM9); + this.stringBuilder = stringBuilder; } // ----------------------------------------------------------------------------------------------- @@ -159,7 +165,7 @@ public class SignatureWriter extends SignatureVisitor { stringBuilder.append(name); // Pushes 'false' on the stack, meaning that this type does not have type arguments (as far as // we can tell at this point). - argumentStack *= 2; + argumentStack <<= 1; } @Override @@ -169,7 +175,7 @@ public class SignatureWriter extends SignatureVisitor { stringBuilder.append(name); // Pushes 'false' on the stack, meaning that this type does not have type arguments (as far as // we can tell at this point). - argumentStack *= 2; + argumentStack <<= 1; } @Override @@ -177,7 +183,7 @@ public class SignatureWriter extends SignatureVisitor { // If the top of the stack is 'false', this means we are visiting the first type argument of the // currently visited type. We therefore need to append a '<', and to replace the top stack // element with 'true' (meaning that the current type does have type arguments). - if (argumentStack % 2 == 0) { + if ((argumentStack & 1) == 0) { argumentStack |= 1; stringBuilder.append('<'); } @@ -189,14 +195,15 @@ public class SignatureWriter extends SignatureVisitor { // If the top of the stack is 'false', this means we are visiting the first type argument of the // currently visited type. We therefore need to append a '<', and to replace the top stack // element with 'true' (meaning that the current type does have type arguments). - if (argumentStack % 2 == 0) { + if ((argumentStack & 1) == 0) { argumentStack |= 1; stringBuilder.append('<'); } if (wildcard != '=') { stringBuilder.append(wildcard); } - return this; + // If the stack is full, start a nested one by returning a new SignatureWriter. + return (argumentStack & (1 << 31)) == 0 ? this : new SignatureWriter(stringBuilder); } @Override @@ -232,9 +239,9 @@ public class SignatureWriter extends SignatureVisitor { // If the top of the stack is 'true', this means that some type arguments have been visited for // the type whose visit is now ending. We therefore need to append a '>', and to pop one element // from the stack. - if (argumentStack % 2 == 1) { + if ((argumentStack & 1) == 1) { stringBuilder.append('>'); } - argumentStack /= 2; + argumentStack >>>= 1; } } diff --git a/asm/src/test/java/org/objectweb/asm/signature/SignaturesProviders.java b/asm/src/test/java/org/objectweb/asm/signature/SignaturesProviders.java index ce6cf22a..a04d5801 100644 --- a/asm/src/test/java/org/objectweb/asm/signature/SignaturesProviders.java +++ b/asm/src/test/java/org/objectweb/asm/signature/SignaturesProviders.java @@ -32,6 +32,9 @@ public final class SignaturesProviders { assertFalse(CLASS_SIGNATURES.isEmpty()); assertFalse(FIELD_SIGNATURES.isEmpty()); assertFalse(METHOD_SIGNATURES.isEmpty()); + for (int depth = 0; depth < 48; ++depth) { + METHOD_SIGNATURES.add(buildDeepSignature(new StringBuilder(), depth).toString()); + } } private SignaturesProviders() {} @@ -82,6 +85,18 @@ public final class SignaturesProviders { 0); } + private static StringBuilder buildDeepSignature(final StringBuilder signature, final int depth) { + signature.append("LGeneric"); + if (depth == 0) { + signature.append(';'); + } else { + signature.append("<LOpen;"); + buildDeepSignature(signature, depth - 1); + signature.append("LClose;>;"); + } + return signature; + } + static Stream<String> classSignatures() { return CLASS_SIGNATURES.stream(); } |