Author: britter Date: Tue Sep 12 16:36:55 2017 New Revision: 1808131 URL: http://svn.apache.org/viewvc?rev=1808131&view=rev Log: BCEL-286: Utility.signatureToString fails if a method has multiple type arguments. Thanks to Mark Roberts.
Modified: commons/proper/bcel/trunk/src/changes/changes.xml commons/proper/bcel/trunk/src/main/java/org/apache/bcel/classfile/Utility.java commons/proper/bcel/trunk/src/test/java/org/apache/bcel/classfile/UtilityTestCase.java Modified: commons/proper/bcel/trunk/src/changes/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/bcel/trunk/src/changes/changes.xml?rev=1808131&r1=1808130&r2=1808131&view=diff ============================================================================== --- commons/proper/bcel/trunk/src/changes/changes.xml [utf-8] (original) +++ commons/proper/bcel/trunk/src/changes/changes.xml [utf-8] Tue Sep 12 16:36:55 2017 @@ -63,6 +63,7 @@ The <action> type attribute can be add,u <body> <release version="6.1" date="tba" description="tba"> + <action issue="BCEL-286" type="fix" dev="britter" due-to="Mark Roberts">Utility.signatureToString fails if a method has multiple type arguments</action> <action issue="BCEL-287" type="fix" dev="britter" due-to="Mark Roberts">IINC does not handle -128 properly</action> <action issue="BCEL-283" type="fix" dev="britter" due-to="Mark Roberts">Support for StackMap should be different from StackMapTable</action> <action issue="BCEL-289" type="fix" dev="kinow">Crash when parsing constructor of inner classes with parameters annotated</action> Modified: commons/proper/bcel/trunk/src/main/java/org/apache/bcel/classfile/Utility.java URL: http://svn.apache.org/viewvc/commons/proper/bcel/trunk/src/main/java/org/apache/bcel/classfile/Utility.java?rev=1808131&r1=1808130&r2=1808131&view=diff ============================================================================== --- commons/proper/bcel/trunk/src/main/java/org/apache/bcel/classfile/Utility.java (original) +++ commons/proper/bcel/trunk/src/main/java/org/apache/bcel/classfile/Utility.java Tue Sep 12 16:36:55 2017 @@ -849,6 +849,7 @@ public abstract class Utility { if (index < 0) { throw new ClassFormatException("Invalid signature: " + signature); } + // check to see if there are any TypeArguments final int bracketIndex = signature.substring(0, index).indexOf('<'); if (bracketIndex < 0) { @@ -856,6 +857,16 @@ public abstract class Utility { wrap(consumed_chars, index + 1); // "Lblabla;" `L' and `;' are removed return compactClassName(signature.substring(1, index), chopit); } + // but make sure we are not looking past the end of the current item + fromIndex = signature.indexOf(';'); + if (fromIndex < 0) { + throw new ClassFormatException("Invalid signature: " + signature); + } + if (fromIndex < bracketIndex) { + // just a class identifier + wrap(consumed_chars, fromIndex + 1); // "Lblabla;" `L' and `;' are removed + return compactClassName(signature.substring(1, fromIndex), chopit); + } // we have TypeArguments; build up partial result // as we recurse for each TypeArgument @@ -869,37 +880,63 @@ public abstract class Utility { } else if (signature.charAt(consumed_chars) == '-') { type.append("? super "); consumed_chars++; - } else if (signature.charAt(consumed_chars) == '*') { - // must be at end of signature - if (signature.charAt(consumed_chars + 1) != '>') { - throw new ClassFormatException("Invalid signature: " + signature); - } - if (signature.charAt(consumed_chars + 2) != ';') { - throw new ClassFormatException("Invalid signature: " + signature); - } - wrap(Utility.consumed_chars, consumed_chars + 3); // remove final "*>;" - return type + "?>..."; } // get the first TypeArgument - type.append(signatureToString(signature.substring(consumed_chars), chopit)); - // update our consumed count by the number of characters the for type argument - consumed_chars = unwrap(Utility.consumed_chars) + consumed_chars; - wrap(Utility.consumed_chars, consumed_chars); + if (signature.charAt(consumed_chars) == '*') { + type.append("?"); + consumed_chars++; + } else { + type.append(signatureToString(signature.substring(consumed_chars), chopit)); + // update our consumed count by the number of characters the for type argument + consumed_chars = unwrap(Utility.consumed_chars) + consumed_chars; + wrap(Utility.consumed_chars, consumed_chars); + } // are there more TypeArguments? while (signature.charAt(consumed_chars) != '>') { - type.append(", ").append(signatureToString(signature.substring(consumed_chars), chopit)); + type.append(", "); + // check for wildcards + if (signature.charAt(consumed_chars) == '+') { + type.append("? extends "); + consumed_chars++; + } else if (signature.charAt(consumed_chars) == '-') { + type.append("? super "); + consumed_chars++; + } + if (signature.charAt(consumed_chars) == '*') { + type.append("?"); + consumed_chars++; + } else { + type.append(signatureToString(signature.substring(consumed_chars), chopit)); + // update our consumed count by the number of characters the for type argument + consumed_chars = unwrap(Utility.consumed_chars) + consumed_chars; + wrap(Utility.consumed_chars, consumed_chars); + } + } + + // process the closing ">" + consumed_chars++; + type.append(">"); + + if (signature.charAt(consumed_chars) == '.') { + // we have a ClassTypeSignatureSuffix + type.append("."); + // convert SimpleClassTypeSignature to fake ClassTypeSignature + // and then recurse to parse it + type.append(signatureToString("L" + signature.substring(consumed_chars+1), chopit)); // update our consumed count by the number of characters the for type argument + // note that this count includes the "L" we added, but that is ok + // as it accounts for the "." we didn't consume consumed_chars = unwrap(Utility.consumed_chars) + consumed_chars; wrap(Utility.consumed_chars, consumed_chars); + return type.toString(); } - - if (signature.charAt(consumed_chars + 1) != ';') { + if (signature.charAt(consumed_chars) != ';') { throw new ClassFormatException("Invalid signature: " + signature); } - wrap(Utility.consumed_chars, consumed_chars + 2); // remove final ">;" - return type.append(">").toString(); + wrap(Utility.consumed_chars, consumed_chars + 1); // remove final ";" + return type.toString(); } case 'S': return "short"; Modified: commons/proper/bcel/trunk/src/test/java/org/apache/bcel/classfile/UtilityTestCase.java URL: http://svn.apache.org/viewvc/commons/proper/bcel/trunk/src/test/java/org/apache/bcel/classfile/UtilityTestCase.java?rev=1808131&r1=1808130&r2=1808131&view=diff ============================================================================== --- commons/proper/bcel/trunk/src/test/java/org/apache/bcel/classfile/UtilityTestCase.java (original) +++ commons/proper/bcel/trunk/src/test/java/org/apache/bcel/classfile/UtilityTestCase.java Tue Sep 12 16:36:55 2017 @@ -22,6 +22,7 @@ import junit.framework.TestCase; public class UtilityTestCase extends TestCase { public void testSignatureToStringWithGenerics() throws Exception { + // tests for BCEL-197 assertEquals("generic signature", "java.util.Map<X, java.util.List<Y>>", Utility.signatureToString("Ljava/util/Map<TX;Ljava/util/List<TY;>;>;")); @@ -29,7 +30,17 @@ public class UtilityTestCase extends Tes "java.util.Set<? extends java.nio.file.OpenOption>" , Utility.signatureToString("Ljava/util/Set<+Ljava/nio/file/OpenOption;>;")); assertEquals("generic signature", - "java.nio.file.attribute.FileAttribute<?>...[]", + "java.nio.file.attribute.FileAttribute<?>[]", Utility.signatureToString("[Ljava/nio/file/attribute/FileAttribute<*>;")); + // tests for BCEL-286 + assertEquals("generic signature", + "boofcv.alg.tracker.tld.TldTracker<boofcv.struct.image.ImageGray<boofcv.struct.image.GrayU8>, boofcv.struct.image.GrayI<boofcv.struct.image.GrayU8>>", + Utility.signatureToString("Lboofcv/alg/tracker/tld/TldTracker<Lboofcv/struct/image/ImageGray<Lboofcv/struct/image/GrayU8;>;Lboofcv/struct/image/GrayI<Lboofcv/struct/image/GrayU8;>;>;")); + assertEquals("generic signature", + "java.util.Map<?, ?>", + Utility.signatureToString("Ljava/util/Map<**>;")); + assertEquals("generic signature", + "com.jme3.util.IntMap<T>.IntMapIterator", + Utility.signatureToString("Lcom/jme3/util/IntMap<TT;>.IntMapIterator;")); } }