// now we have either a "." indicating the start of a nested type,
// or a "<" indication type arguments, or ";" and we are done.
while (!maybeEat(";")) {
- if (maybeEat(".")) {
+ if (tokenStream[tokenIndex].equals(".")) {
// outer type completed
outerType = new SimpleClassTypeSignature(identifier);
- List<SimpleClassTypeSignature> nestedTypeList = new ArrayList<SimpleClassTypeSignature>();
- do {
- ret.append(".");
- SimpleClassTypeSignature sig = parseSimpleClassTypeSignature();
- ret.append(sig.toString());
- nestedTypeList.add(sig);
- } while (maybeEat("."));
- nestedTypes = new SimpleClassTypeSignature[nestedTypeList.size()];
- nestedTypeList.toArray(nestedTypes);
+ nestedTypes = parseNestedTypesHelper(ret);
} else if (tokenStream[tokenIndex].equals("<")) {
ret.append("<");
TypeArgument[] tArgs = maybeParseTypeArguments();
}
ret.append(">");
outerType = new SimpleClassTypeSignature(identifier, tArgs);
- // now parse possible nesteds...
- List<SimpleClassTypeSignature> nestedTypeList = new ArrayList<SimpleClassTypeSignature>();
- while (maybeEat(".")) {
- ret.append(".");
- SimpleClassTypeSignature sig = parseSimpleClassTypeSignature();
- ret.append(sig.toString());
- nestedTypeList.add(sig);
- }
- nestedTypes = new SimpleClassTypeSignature[nestedTypeList.size()];
- nestedTypeList.toArray(nestedTypes);
+ nestedTypes = parseNestedTypesHelper(ret);
} else {
throw new IllegalStateException("Expecting .,<, or ;, but found " + tokenStream[tokenIndex] + " while unpacking "
+ inputString);
return new ClassTypeSignature(ret.toString(), outerType, nestedTypes);
}
+ /**
+ * Helper method to digest nested types, slightly more complex than necessary to cope with some android related
+ * incorrect classes (see bug 406167)
+ */
+ private SimpleClassTypeSignature[] parseNestedTypesHelper(StringBuffer ret) {
+ boolean brokenSignature = false;
+ SimpleClassTypeSignature[] nestedTypes;
+ List<SimpleClassTypeSignature> nestedTypeList = new ArrayList<SimpleClassTypeSignature>();
+ while (maybeEat(".")) {
+ ret.append(".");
+ SimpleClassTypeSignature sig = parseSimpleClassTypeSignature();
+ if (tokenStream[tokenIndex].equals("/")) {
+ if (!brokenSignature) {
+ System.err.println("[See bug 406167] Bad class file signature encountered, nested types appear package qualified, ignoring those incorrect pieces. Signature: "+inputString);
+ }
+ brokenSignature = true;
+ // hit something like: Lcom/a/a/b/t<TK;TV;>.com/a/a/b/af.com/a/a/b/ag;
+ // and we are looking at the '/' after the com
+ tokenIndex++; // pointing at the next identifier
+ while (tokenStream[tokenIndex+1].equals("/")) {
+ tokenIndex+=2; // jump over an 'identifier' '/' pair
+ }
+ // now tokenIndex is the final bit of the name (which we'll treat as the inner type name)
+ sig = parseSimpleClassTypeSignature();
+ }
+ ret.append(sig.toString());
+ nestedTypeList.add(sig);
+ };
+ nestedTypes = new SimpleClassTypeSignature[nestedTypeList.size()];
+ nestedTypeList.toArray(nestedTypes);
+ return nestedTypes;
+ }
+
private SimpleClassTypeSignature parseSimpleClassTypeSignature() {
String identifier = eatIdentifier();
TypeArgument[] tArgs = maybeParseTypeArguments();
assertEquals("Ljava/util/Comparable<-TE;>;", sig.superInterfaceSignatures[0].toString());
}
+ public void testFunky_406167() {
+ ClassSignature sig = parser
+ .parseAsClassSignature("Lcom/google/android/gms/internal/hb<TT;>.com/google/android/gms/internal/hb$b<Ljava/lang/Boolean;>;");
+ // Note the package prefix on the nested types has been dropped
+ assertEquals("Lcom/google/android/gms/internal/hb<TT;>.hb$b<Ljava/lang/Boolean;>;",sig.superclassSignature.toString());
+ sig = parser
+ .parseAsClassSignature("Lcom/a/a/b/t<TK;TV;>.com/a/a/b/af.com/a/a/b/ag;Ljava/util/ListIterator<TV;>;");
+ // Note the package prefix on the nested types has been dropped
+ assertEquals("Lcom/a/a/b/t<TK;TV;>.af.ag;",sig.superclassSignature.toString());
+ assertEquals("Ljava/util/ListIterator<TV;>;",sig.superInterfaceSignatures[0].toString());
+ sig = parser.parseAsClassSignature("Lcom/google/android/gms/internal/hb.com/google/android/gms/internal/hb$b<Ljava/lang/Boolean;>;");
+ // Note the package prefix on the nested types has been dropped
+ assertEquals("Lcom/google/android/gms/internal/hb.hb$b<Ljava/lang/Boolean;>;",sig.superclassSignature.toString());
+ sig = parser
+ .parseAsClassSignature("Lcom/a/a/b/t.com/a/a/b/af.com/a/a/b/ag;Ljava/util/ListIterator<TV;>;");
+ // Note the package prefix on the nested types has been dropped
+ assertEquals("Lcom/a/a/b/t.af.ag;",sig.superclassSignature.toString());
+ assertEquals("Ljava/util/ListIterator<TV;>;",sig.superInterfaceSignatures[0].toString());
+ }
+
+
public void testFieldSignatureParsingClassType() {
FieldTypeSignature fsig = parser.parseAsFieldSignature("Ljava/lang/String;");
assertTrue("ClassTypeSignature", fsig instanceof ClassTypeSignature);
assertEquals("Ljava/lang/Exception;", mSig.throwsSignatures[0].toString());
assertEquals("Ljava/lang/RuntimeException;", mSig.throwsSignatures[1].toString());
}
-
+
public void testMethodSignaturePrimitiveParams() {
GenericSignature.MethodTypeSignature mSig = parser.parseAsMethodSignature("(ILjava/lang/Object;)V");
assertEquals("2 parameters", 2, mSig.parameters.length);