--- /dev/null
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.util;
+
+/**
+ * Encapsulate generic signature parsing
+ *
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public class GenericSignature {
+
+ /**
+ * structure holding a parsed class signature
+ */
+ public static class ClassSignature {
+ public FormalTypeParameter[] formalTypeParameters = new FormalTypeParameter[0];
+ public ClassTypeSignature superclassSignature;
+ public ClassTypeSignature[] superInterfaceSignatures = new ClassTypeSignature[0];
+
+ public String toString() {
+ StringBuffer ret = new StringBuffer();
+ ret.append(formalTypeParameters.toString());
+ ret.append(superclassSignature.toString());
+ for (int i = 0; i < superInterfaceSignatures.length; i++) {
+ ret.append(superInterfaceSignatures[i].toString());
+ }
+ return ret.toString();
+ }
+ }
+
+ public static class MethodTypeSignature {
+ public FormalTypeParameter[] formalTypeParameters = new FormalTypeParameter[0];
+ public TypeSignature[] parameters = new TypeSignature[0];
+ public TypeSignature returnType;
+ public FieldTypeSignature[] throwsSignatures = new FieldTypeSignature[0];
+
+ public MethodTypeSignature(FormalTypeParameter[] aFormalParameterList, TypeSignature[] aParameterList,
+ TypeSignature aReturnType, FieldTypeSignature[] aThrowsSignatureList) {
+ this.formalTypeParameters = aFormalParameterList;
+ this.parameters = aParameterList;
+ this.returnType = aReturnType;
+ this.throwsSignatures = aThrowsSignatureList;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ if (formalTypeParameters.length > 0) {
+ sb.append("<");
+ for (int i = 0; i < formalTypeParameters.length; i++) {
+ sb.append(formalTypeParameters[i].toString());
+ }
+ sb.append(">");
+ }
+ sb.append("(");
+ for (int i = 0; i < parameters.length; i++) {
+ sb.append(parameters[i].toString());
+ }
+ sb.append(")");
+ sb.append(returnType.toString());
+ for (int i = 0; i < throwsSignatures.length; i++) {
+ sb.append("^");
+ sb.append(throwsSignatures[i].toString());
+ }
+ return sb.toString();
+ }
+ }
+
+ /**
+ * structure capturing a FormalTypeParameter from the Signature grammar
+ */
+ public static class FormalTypeParameter {
+ public String identifier;
+ public FieldTypeSignature classBound;
+ public FieldTypeSignature[] interfaceBounds;
+
+ public String toString() {
+ StringBuffer ret = new StringBuffer();
+ ret.append("T");
+ ret.append(identifier);
+ ret.append(":");
+ ret.append(classBound.toString());
+ for (int i = 0; i < interfaceBounds.length; i++) {
+ ret.append(":");
+ ret.append(interfaceBounds[i].toString());
+ }
+ return ret.toString();
+ }
+ }
+
+ public static abstract class TypeSignature {
+ public boolean isBaseType() {
+ return false;
+ }
+ }
+
+ public static class BaseTypeSignature extends TypeSignature {
+ private final String sig;
+
+ public BaseTypeSignature(String aPrimitiveType) {
+ sig = aPrimitiveType;
+ }
+
+ public boolean isBaseType() {
+ return true;
+ }
+
+ public String toString() {
+ return sig;
+ }
+ }
+
+ public static abstract class FieldTypeSignature extends TypeSignature {
+ public boolean isClassTypeSignature() {
+ return false;
+ }
+
+ public boolean isTypeVariableSignature() {
+ return false;
+ }
+
+ public boolean isArrayTypeSignature() {
+ return false;
+ }
+ }
+
+ public static class ClassTypeSignature extends FieldTypeSignature {
+ public String classSignature;
+ public SimpleClassTypeSignature outerType;
+ public SimpleClassTypeSignature[] nestedTypes;
+
+ public ClassTypeSignature(String sig, String identifier) {
+ this.classSignature = sig;
+ this.outerType = new SimpleClassTypeSignature(identifier);
+ this.nestedTypes = new SimpleClassTypeSignature[0];
+ }
+
+ public ClassTypeSignature(String sig, SimpleClassTypeSignature outer, SimpleClassTypeSignature[] inners) {
+ this.classSignature = sig;
+ this.outerType = outer;
+ this.nestedTypes = inners;
+ }
+
+ public boolean isClassTypeSignature() {
+ return true;
+ }
+
+ public String toString() {
+ return classSignature;
+ }
+ }
+
+ public static class TypeVariableSignature extends FieldTypeSignature {
+ public String typeVariableName;
+
+ public TypeVariableSignature(String typeVarToken) {
+ this.typeVariableName = typeVarToken.substring(1);
+ }
+
+ public boolean isTypeVariableSignature() {
+ return true;
+ }
+
+ public String toString() {
+ return "T" + typeVariableName + ";";
+ }
+ }
+
+ public static class ArrayTypeSignature extends FieldTypeSignature {
+ public TypeSignature typeSig;
+
+ public ArrayTypeSignature(TypeSignature aTypeSig) {
+ this.typeSig = aTypeSig;
+ }
+
+ public boolean isArrayTypeSignature() {
+ return true;
+ }
+
+ public String toString() {
+ return "[" + typeSig.toString();
+ }
+ }
+
+ public static class SimpleClassTypeSignature {
+ public String identifier;
+ public TypeArgument[] typeArguments;
+
+ public SimpleClassTypeSignature(String identifier) {
+ this.identifier = identifier;
+ this.typeArguments = new TypeArgument[0];
+ }
+
+ public SimpleClassTypeSignature(String identifier, TypeArgument[] args) {
+ this.identifier = identifier;
+ this.typeArguments = args;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(identifier);
+ if (typeArguments.length > 0) {
+ sb.append("<");
+ for (int i = 0; i < typeArguments.length; i++) {
+ sb.append(typeArguments[i].toString());
+ }
+ sb.append(">");
+ }
+ return sb.toString();
+ }
+ }
+
+ public static class TypeArgument {
+ public boolean isWildcard = false;
+ public boolean isPlus = false;
+ public boolean isMinus = false;
+ public FieldTypeSignature signature; // null if isWildcard
+
+ public TypeArgument() {
+ isWildcard = true;
+ }
+
+ public TypeArgument(boolean plus, boolean minus, FieldTypeSignature aSig) {
+ this.isPlus = plus;
+ this.isMinus = minus;
+ this.signature = aSig;
+ }
+
+ public String toString() {
+ if (isWildcard)
+ return "*";
+ StringBuffer sb = new StringBuffer();
+ if (isPlus)
+ sb.append("+");
+ if (isMinus)
+ sb.append("-");
+ sb.append(signature.toString());
+ return sb.toString();
+ }
+ }
+}
--- /dev/null
+/* *******************************************************************
+ * Copyright (c) 2005-2008 Contributors.
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+package org.aspectj.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.aspectj.util.GenericSignature.ArrayTypeSignature;
+import org.aspectj.util.GenericSignature.BaseTypeSignature;
+import org.aspectj.util.GenericSignature.ClassTypeSignature;
+import org.aspectj.util.GenericSignature.FieldTypeSignature;
+import org.aspectj.util.GenericSignature.FormalTypeParameter;
+import org.aspectj.util.GenericSignature.MethodTypeSignature;
+import org.aspectj.util.GenericSignature.SimpleClassTypeSignature;
+import org.aspectj.util.GenericSignature.TypeArgument;
+import org.aspectj.util.GenericSignature.TypeSignature;
+import org.aspectj.util.GenericSignature.TypeVariableSignature;
+
+/**
+ * Parses the generic signature attribute as defined in the JVM spec.
+ *
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public class GenericSignatureParser {
+
+ private String inputString;
+ private String[] tokenStream; // for parse in flight
+ private int tokenIndex = 0;
+
+ /**
+ * AMC. Parse the signature string interpreting it as a ClassSignature according to the grammar defined in Section 4.4.4 of the
+ * JVM specification.
+ */
+ public GenericSignature.ClassSignature parseAsClassSignature(String sig) {
+ this.inputString = sig;
+ tokenStream = tokenize(sig);
+ tokenIndex = 0;
+ GenericSignature.ClassSignature classSig = new GenericSignature.ClassSignature();
+ // FormalTypeParameters-opt
+ if (maybeEat("<")) {
+ List formalTypeParametersList = new ArrayList();
+ do {
+ formalTypeParametersList.add(parseFormalTypeParameter());
+ } while (!maybeEat(">"));
+ classSig.formalTypeParameters = new FormalTypeParameter[formalTypeParametersList.size()];
+ formalTypeParametersList.toArray(classSig.formalTypeParameters);
+ }
+ classSig.superclassSignature = parseClassTypeSignature();
+ List superIntSigs = new ArrayList();
+ while (tokenIndex < tokenStream.length) {
+ superIntSigs.add(parseClassTypeSignature());
+ }
+ classSig.superInterfaceSignatures = new ClassTypeSignature[superIntSigs.size()];
+ superIntSigs.toArray(classSig.superInterfaceSignatures);
+ return classSig;
+ }
+
+ /**
+ * AMC. Parse the signature string interpreting it as a MethodTypeSignature according to the grammar defined in Section 4.4.4 of
+ * the JVM specification.
+ */
+ public MethodTypeSignature parseAsMethodSignature(String sig) {
+ this.inputString = sig;
+ tokenStream = tokenize(sig);
+ tokenIndex = 0;
+ FormalTypeParameter[] formals = new FormalTypeParameter[0];
+ TypeSignature returnType = null;
+ // FormalTypeParameters-opt
+ if (maybeEat("<")) {
+ List formalTypeParametersList = new ArrayList();
+ do {
+ formalTypeParametersList.add(parseFormalTypeParameter());
+ } while (!maybeEat(">"));
+ formals = new FormalTypeParameter[formalTypeParametersList.size()];
+ formalTypeParametersList.toArray(formals);
+ }
+ // Parameters
+ eat("(");
+ List paramList = new ArrayList();
+ while (!maybeEat(")")) {
+ FieldTypeSignature fsig = parseFieldTypeSignature(true);
+ if (fsig != null) {
+ paramList.add(fsig);
+ } else {
+ paramList.add(new GenericSignature.BaseTypeSignature(eatIdentifier()));
+ }
+ }
+ TypeSignature[] params = new TypeSignature[paramList.size()];
+ paramList.toArray(params);
+ // return type
+ returnType = parseFieldTypeSignature(true);
+ if (returnType == null)
+ returnType = new GenericSignature.BaseTypeSignature(eatIdentifier());
+ // throws
+ List throwsList = new ArrayList();
+ while (maybeEat("^")) {
+ FieldTypeSignature fsig = parseFieldTypeSignature(false);
+ throwsList.add(fsig);
+ }
+ FieldTypeSignature[] throwsSigs = new FieldTypeSignature[throwsList.size()];
+ throwsList.toArray(throwsSigs);
+ return new GenericSignature.MethodTypeSignature(formals, params, returnType, throwsSigs);
+ }
+
+ /**
+ * AMC. Parse the signature string interpreting it as a FieldTypeSignature according to the grammar defined in Section 4.4.4 of
+ * the JVM specification.
+ */
+ public FieldTypeSignature parseAsFieldSignature(String sig) {
+ this.inputString = sig;
+ tokenStream = tokenize(sig);
+ tokenIndex = 0;
+ return parseFieldTypeSignature(false);
+ }
+
+ private FormalTypeParameter parseFormalTypeParameter() {
+ FormalTypeParameter ftp = new FormalTypeParameter();
+ // Identifier
+ ftp.identifier = eatIdentifier();
+ // ClassBound
+ eat(":");
+ ftp.classBound = parseFieldTypeSignature(true);
+ if (ftp.classBound == null) {
+ ftp.classBound = new ClassTypeSignature("Ljava/lang/Object;", "Ljava/lang/Object");
+ }
+ // Optional InterfaceBounds
+ List optionalBounds = new ArrayList();
+ while (maybeEat(":")) {
+ optionalBounds.add(parseFieldTypeSignature(false));
+ }
+ ftp.interfaceBounds = new FieldTypeSignature[optionalBounds.size()];
+ optionalBounds.toArray(ftp.interfaceBounds);
+ return ftp;
+ }
+
+ private FieldTypeSignature parseFieldTypeSignature(boolean isOptional) {
+ if (isOptional) {
+ // anything other than 'L', 'T' or '[' and we're out of here
+ if (!tokenStream[tokenIndex].startsWith("L") && !tokenStream[tokenIndex].startsWith("T")
+ && !tokenStream[tokenIndex].startsWith("[")) {
+ return null;
+ }
+ }
+ if (maybeEat("[")) {
+ return parseArrayTypeSignature();
+ } else if (tokenStream[tokenIndex].startsWith("L")) {
+ return parseClassTypeSignature();
+ } else if (tokenStream[tokenIndex].startsWith("T")) {
+ return parseTypeVariableSignature();
+ } else {
+ throw new IllegalStateException("Expecting [,L, or T, but found " + tokenStream[tokenIndex] + " while unpacking "
+ + inputString);
+ }
+ }
+
+ private ArrayTypeSignature parseArrayTypeSignature() {
+ // opening [ already eaten
+ FieldTypeSignature fieldType = parseFieldTypeSignature(true);
+ if (fieldType != null) {
+ return new ArrayTypeSignature(fieldType);
+ } else {
+ // must be BaseType array
+ return new ArrayTypeSignature(new BaseTypeSignature(eatIdentifier()));
+ }
+ }
+
+ // L PackageSpecifier* SimpleClassTypeSignature ClassTypeSignature* ;
+ private ClassTypeSignature parseClassTypeSignature() {
+ SimpleClassTypeSignature outerType = null;
+ SimpleClassTypeSignature[] nestedTypes = new SimpleClassTypeSignature[0];
+ StringBuffer ret = new StringBuffer();
+ String identifier = eatIdentifier();
+ ret.append(identifier);
+ while (maybeEat("/")) {
+ ret.append("/"); // dont forget this...
+ ret.append(eatIdentifier());
+ }
+ identifier = ret.toString();
+ // 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(".")) {
+ // outer type completed
+ outerType = new SimpleClassTypeSignature(identifier);
+ List nestedTypeList = new ArrayList();
+ do {
+ ret.append(".");
+ SimpleClassTypeSignature sig = parseSimpleClassTypeSignature();
+ ret.append(sig.toString());
+ nestedTypeList.add(sig);
+ } while (maybeEat("."));
+ nestedTypes = new SimpleClassTypeSignature[nestedTypeList.size()];
+ nestedTypeList.toArray(nestedTypes);
+ } else if (tokenStream[tokenIndex].equals("<")) {
+ ret.append("<");
+ TypeArgument[] tArgs = maybeParseTypeArguments();
+ for (int i = 0; i < tArgs.length; i++) {
+ ret.append(tArgs[i].toString());
+ }
+ ret.append(">");
+ outerType = new SimpleClassTypeSignature(identifier, tArgs);
+ // now parse possible nesteds...
+ List nestedTypeList = new ArrayList();
+ while (maybeEat(".")) {
+ ret.append(".");
+ SimpleClassTypeSignature sig = parseSimpleClassTypeSignature();
+ ret.append(sig.toString());
+ nestedTypeList.add(sig);
+ }
+ nestedTypes = new SimpleClassTypeSignature[nestedTypeList.size()];
+ nestedTypeList.toArray(nestedTypes);
+ } else {
+ throw new IllegalStateException("Expecting .,<, or ;, but found " + tokenStream[tokenIndex] + " while unpacking "
+ + inputString);
+ }
+ }
+ ret.append(";");
+ if (outerType == null)
+ outerType = new SimpleClassTypeSignature(ret.toString());
+ return new ClassTypeSignature(ret.toString(), outerType, nestedTypes);
+ }
+
+ private SimpleClassTypeSignature parseSimpleClassTypeSignature() {
+ String identifier = eatIdentifier();
+ TypeArgument[] tArgs = maybeParseTypeArguments();
+ if (tArgs != null) {
+ return new SimpleClassTypeSignature(identifier, tArgs);
+ } else {
+ return new SimpleClassTypeSignature(identifier);
+ }
+ }
+
+ private TypeArgument parseTypeArgument() {
+ boolean isPlus = false;
+ boolean isMinus = false;
+ if (maybeEat("*")) {
+ return new TypeArgument();
+ } else if (maybeEat("+")) {
+ isPlus = true;
+ } else if (maybeEat("-")) {
+ isMinus = true;
+ }
+ FieldTypeSignature sig = parseFieldTypeSignature(false);
+ return new TypeArgument(isPlus, isMinus, sig);
+ }
+
+ private TypeArgument[] maybeParseTypeArguments() {
+ if (maybeEat("<")) {
+ List typeArgs = new ArrayList();
+ do {
+ TypeArgument arg = parseTypeArgument();
+ typeArgs.add(arg);
+ } while (!maybeEat(">"));
+ TypeArgument[] tArgs = new TypeArgument[typeArgs.size()];
+ typeArgs.toArray(tArgs);
+ return tArgs;
+ } else {
+ return null;
+ }
+ }
+
+ private TypeVariableSignature parseTypeVariableSignature() {
+ TypeVariableSignature tv = new TypeVariableSignature(eatIdentifier());
+ eat(";");
+ return tv;
+ }
+
+ private boolean maybeEat(String token) {
+ if (tokenStream.length <= tokenIndex)
+ return false;
+ if (tokenStream[tokenIndex].equals(token)) {
+ tokenIndex++;
+ return true;
+ }
+ return false;
+ }
+
+ private void eat(String token) {
+ if (!tokenStream[tokenIndex].equals(token)) {
+ throw new IllegalStateException("Expecting " + token + " but found " + tokenStream[tokenIndex] + " while unpacking "
+ + inputString);
+ }
+ tokenIndex++;
+ }
+
+ private String eatIdentifier() {
+ return tokenStream[tokenIndex++];
+ }
+
+ /**
+ * non-private for test visibility Splits a string containing a generic signature into tokens for consumption by the parser.
+ */
+ public String[] tokenize(String signatureString) {
+ char[] chars = signatureString.toCharArray();
+ int index = 0;
+ List tokens = new ArrayList();
+ StringBuffer identifier = new StringBuffer();
+ boolean inParens = false;
+ boolean inArray = false;
+ boolean couldSeePrimitive = false;
+ do {
+ switch (chars[index]) {
+ case '<':
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ identifier = new StringBuffer();
+ tokens.add("<");
+ break;
+ case '>':
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ identifier = new StringBuffer();
+ tokens.add(">");
+ break;
+ case ':':
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ identifier = new StringBuffer();
+ tokens.add(":");
+ break;
+ case '/':
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ identifier = new StringBuffer();
+ tokens.add("/");
+ couldSeePrimitive = false;
+ break;
+ case ';':
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ identifier = new StringBuffer();
+ tokens.add(";");
+ couldSeePrimitive = true;
+ inArray = false;
+ break;
+ case '^':
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ identifier = new StringBuffer();
+ tokens.add("^");
+ break;
+ case '+':
+ tokens.add("+");
+ break;
+ case '-':
+ tokens.add("-");
+ break;
+ case '*':
+ tokens.add("*");
+ break;
+ case '.':
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ identifier = new StringBuffer();
+ couldSeePrimitive = false;
+ tokens.add(".");
+ break;
+ case '(':
+ tokens.add("(");
+ inParens = true;
+ couldSeePrimitive = true;
+ break;
+ case ')':
+ tokens.add(")");
+ inParens = false;
+ break;
+ case '[':
+ tokens.add("[");
+ couldSeePrimitive = true;
+ inArray = true;
+ break;
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'F':
+ case 'I':
+ case 'J':
+ case 'S':
+ case 'V':
+ case 'Z':
+ if ((inParens || inArray) && couldSeePrimitive && identifier.length() == 0) {
+ tokens.add(new String("" + chars[index]));
+ } else {
+ identifier.append(chars[index]);
+ }
+ inArray = false;
+ break;
+ case 'L':
+ couldSeePrimitive = false;
+ // deliberate fall-through
+ default:
+ identifier.append(chars[index]);
+ }
+ } while ((++index) < chars.length);
+ if (identifier.length() > 0)
+ tokens.add(identifier.toString());
+ String[] tokenArray = new String[tokens.size()];
+ tokens.toArray(tokenArray);
+ return tokenArray;
+ }
+
+}
--- /dev/null
+/* *******************************************************************
+ * Copyright (c) 2005-2008 Contributors
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * ******************************************************************/
+
+package org.aspectj.util;
+
+import junit.framework.TestCase;
+
+import org.aspectj.util.GenericSignature.ClassSignature;
+import org.aspectj.util.GenericSignature.ClassTypeSignature;
+import org.aspectj.util.GenericSignature.FieldTypeSignature;
+import org.aspectj.util.GenericSignature.SimpleClassTypeSignature;
+
+/**
+ * @author Adrian Colyer
+ * @author Andy Clement
+ */
+public class GenericSignatureParserTest extends TestCase {
+
+ GenericSignatureParser parser;
+
+ public void testSimpleTokenize() {
+ String[] tokens = parser.tokenize("Ljava/lang/String;");
+ assertEquals(new String[] { "Ljava", "/", "lang", "/", "String", ";" }, tokens);
+ }
+
+ public void testTokenizeWithWildTypeArguments() {
+ String[] tokens = parser.tokenize("Ljava/lang/String<*>;");
+ assertEquals(new String[] { "Ljava", "/", "lang", "/", "String", "<", "*", ">", ";" }, tokens);
+ }
+
+ public void testTokenizeWithExtendsTypeArguments() {
+ String[] tokens = parser.tokenize("Ljava/util/List<+TE>;");
+ assertEquals(new String[] { "Ljava", "/", "util", "/", "List", "<", "+", "TE", ">", ";" }, tokens);
+ }
+
+ public void testTokenizeWithSuperTypeArguments() {
+ String[] tokens = parser.tokenize("Ljava/util/List<-TE>;");
+ assertEquals(new String[] { "Ljava", "/", "util", "/", "List", "<", "-", "TE", ">", ";" }, tokens);
+ }
+
+ public void testTokenizeArrayType() {
+ String[] tokens = parser.tokenize("[Ljava/lang/String;");
+ assertEquals(new String[] { "[", "Ljava", "/", "lang", "/", "String", ";" }, tokens);
+ }
+
+ public void testTokenizeFormalTypeParameters() {
+ String[] tokens = parser.tokenize("<T:Ljava/lang/String;:Ljava/util/Comparable;>");
+ assertEquals(new String[] { "<", "T", ":", "Ljava", "/", "lang", "/", "String", ";", ":", "Ljava", "/", "util", "/",
+ "Comparable", ";", ">" }, tokens);
+ }
+
+ public void testParseClassSignatureSimple() {
+ ClassSignature sig = parser.parseAsClassSignature("Ljava/lang/String;");
+ assertEquals("No type parameters", 0, sig.formalTypeParameters.length);
+ assertEquals("No superinterfaces", 0, sig.superInterfaceSignatures.length);
+ assertEquals("Ljava/lang/String;", sig.superclassSignature.classSignature);
+ SimpleClassTypeSignature outerType = sig.superclassSignature.outerType;
+ assertEquals("Ljava/lang/String;", outerType.identifier);
+ assertEquals("No type args", 0, outerType.typeArguments.length);
+ }
+
+ public void testParseClassSignatureTypeArgs() {
+ ClassSignature sig = parser.parseAsClassSignature("Ljava/util/List<+Ljava/lang/String;>;");
+ assertEquals("No type parameters", 0, sig.formalTypeParameters.length);
+ assertEquals("No superinterfaces", 0, sig.superInterfaceSignatures.length);
+ assertEquals("Ljava/util/List<+Ljava/lang/String;>;", sig.superclassSignature.classSignature);
+ SimpleClassTypeSignature outerType = sig.superclassSignature.outerType;
+ assertEquals("Ljava/util/List", outerType.identifier);
+ assertEquals("One type arg", 1, outerType.typeArguments.length);
+ assertTrue(outerType.typeArguments[0].isPlus);
+ assertEquals("+Ljava/lang/String;", outerType.typeArguments[0].toString());
+ }
+
+ public void testParseClassSignatureTheFullMonty() {
+ ClassSignature sig = parser
+ .parseAsClassSignature("<E:Ljava/lang/String;:Ljava/lang/Number<TE;>;>Ljava/util/List<TE;>;Ljava/util/Comparable<-TE;>;");
+ assertEquals("1 formal parameter", 1, sig.formalTypeParameters.length);
+ assertEquals("E", sig.formalTypeParameters[0].identifier);
+ ClassTypeSignature fsig = (ClassTypeSignature) sig.formalTypeParameters[0].classBound;
+ assertEquals("Ljava/lang/String;", fsig.classSignature);
+ assertEquals("1 interface bound", 1, sig.formalTypeParameters[0].interfaceBounds.length);
+ ClassTypeSignature isig = (ClassTypeSignature) sig.formalTypeParameters[0].interfaceBounds[0];
+ assertEquals("Ljava/lang/Number<TE;>;", isig.classSignature);
+ assertEquals("Ljava/util/List<TE;>;", sig.superclassSignature.classSignature);
+ assertEquals("1 type argument", 1, sig.superclassSignature.outerType.typeArguments.length);
+ assertEquals("TE;", sig.superclassSignature.outerType.typeArguments[0].toString());
+ assertEquals("1 super interface", 1, sig.superInterfaceSignatures.length);
+ assertEquals("Ljava/util/Comparable<-TE;>;", sig.superInterfaceSignatures[0].toString());
+ }
+
+ public void testFieldSignatureParsingClassType() {
+ FieldTypeSignature fsig = parser.parseAsFieldSignature("Ljava/lang/String;");
+ assertTrue("ClassTypeSignature", fsig instanceof ClassTypeSignature);
+ assertEquals("Ljava/lang/String;", fsig.toString());
+ }
+
+ public void testFieldSignatureParsingArrayType() {
+ FieldTypeSignature fsig = parser.parseAsFieldSignature("[Ljava/lang/String;");
+ assertTrue("ArrayTypeSignature", fsig instanceof GenericSignature.ArrayTypeSignature);
+ assertEquals("[Ljava/lang/String;", fsig.toString());
+ }
+
+ public void testFieldSignatureParsingTypeVariable() {
+ FieldTypeSignature fsig = parser.parseAsFieldSignature("TT;");
+ assertTrue("TypeVariableSignature", fsig instanceof GenericSignature.TypeVariableSignature);
+ assertEquals("TT;", fsig.toString());
+ }
+
+ public void testSimpleMethodSignatureParsing() {
+ GenericSignature.MethodTypeSignature mSig = parser.parseAsMethodSignature("()V");
+ assertEquals("No type parameters", 0, mSig.formalTypeParameters.length);
+ assertEquals("No parameters", 0, mSig.parameters.length);
+ assertEquals("Void return type", "V", mSig.returnType.toString());
+ assertEquals("No throws", 0, mSig.throwsSignatures.length);
+ }
+
+ public void testMethodSignatureTypeParams() {
+ GenericSignature.MethodTypeSignature mSig = parser.parseAsMethodSignature("<T:>(TT;)V");
+ assertEquals("One type parameter", 1, mSig.formalTypeParameters.length);
+ assertEquals("T", mSig.formalTypeParameters[0].identifier);
+ assertEquals("Ljava/lang/Object;", mSig.formalTypeParameters[0].classBound.toString());
+ assertEquals("One parameter", 1, mSig.parameters.length);
+ assertEquals("TT;", mSig.parameters[0].toString());
+ assertEquals("Void return type", "V", mSig.returnType.toString());
+ assertEquals("No throws", 0, mSig.throwsSignatures.length);
+ }
+
+ public void testMethodSignatureGenericReturn() {
+ GenericSignature.MethodTypeSignature mSig = parser.parseAsMethodSignature("<T:>()TT;");
+ assertEquals("One type parameter", 1, mSig.formalTypeParameters.length);
+ assertEquals("T", mSig.formalTypeParameters[0].identifier);
+ assertEquals("Ljava/lang/Object;", mSig.formalTypeParameters[0].classBound.toString());
+ assertEquals("No parameters", 0, mSig.parameters.length);
+ assertEquals("'T' return type", "TT;", mSig.returnType.toString());
+ assertEquals("No throws", 0, mSig.throwsSignatures.length);
+ }
+
+ public void testMethodSignatureThrows() {
+ GenericSignature.MethodTypeSignature mSig = parser
+ .parseAsMethodSignature("<T:>(TT;)V^Ljava/lang/Exception;^Ljava/lang/RuntimeException;");
+ assertEquals("One type parameter", 1, mSig.formalTypeParameters.length);
+ assertEquals("T", mSig.formalTypeParameters[0].identifier);
+ assertEquals("Ljava/lang/Object;", mSig.formalTypeParameters[0].classBound.toString());
+ assertEquals("One parameter", 1, mSig.parameters.length);
+ assertEquals("TT;", mSig.parameters[0].toString());
+ assertEquals("Void return type", "V", mSig.returnType.toString());
+ assertEquals("2 throws", 2, mSig.throwsSignatures.length);
+ 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);
+ assertEquals("I", mSig.parameters[0].toString());
+ assertEquals("Ljava/lang/Object;", mSig.parameters[1].toString());
+ }
+
+ public void testFullyQualifiedSuperclassAfterTypeParams() {
+ try {
+ GenericSignature.FieldTypeSignature cSig = parser.parseAsFieldSignature("Ljava/util/List</;");
+ fail("Expected IllegalStateException");
+ } catch (IllegalStateException ex) {
+ assertTrue(ex.getMessage().indexOf("Ljava/util/List</;") != -1);
+ }
+ }
+
+ public void testPr107784() {
+ parser
+ .parseAsMethodSignature("(Lcom/cibc/responders/mapping/CommonDataBeanScenario;Ljava/lang/Object;)Lcom/cibc/responders/response/Formatter<[BLjava/lang/Object;>;");
+ parser.parseAsClassSignature("<Parent:Ljava/lang/Object;Child:Ljava/lang/Object;>Ljava/lang/Object;");
+ }
+
+ private void assertEquals(String[] expected, String[] actual) {
+ if (actual.length != expected.length) {
+ int shorter = Math.min(expected.length, actual.length);
+ for (int i = 0; i < shorter; i++) {
+ if (!actual[i].equals(expected[i])) {
+ fail("Expected " + expected[i] + " at position " + i + " but found " + actual[i]);
+ }
+ }
+ fail("Expected " + expected.length + " tokens but got " + actual.length + tokensToString(actual));
+ }
+ for (int i = 0; i < actual.length; i++) {
+ if (!actual[i].equals(expected[i])) {
+ fail("Expected " + expected[i] + " at position " + i + " but found " + actual[i]);
+ }
+ }
+ }
+
+ private String tokensToString(String[] tokens) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(tokens[0]);
+ for (int i = 1; i < tokens.length; i++) {
+ sb.append(",");
+ sb.append(tokens[i]);
+ }
+ return sb.toString();
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ parser = new GenericSignatureParser();
+ }
+}
* Xerox/PARC initial implementation
* ******************************************************************/
-
package org.aspectj.util;
-import junit.framework.*;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
public class UtilTests extends TestCase {
- public static Test suite() {
- TestSuite suite = new TestSuite(UtilTests.class.getName());
- //$JUnit-BEGIN$
- suite.addTestSuite(FileUtilTest.class);
- suite.addTestSuite(LangUtilTest.class);
- //$JUnit-END$
- return suite;
- }
+ public static Test suite() {
+ TestSuite suite = new TestSuite(UtilTests.class.getName());
+ // $JUnit-BEGIN$
+ suite.addTestSuite(FileUtilTest.class);
+ suite.addTestSuite(LangUtilTest.class);
+ suite.addTestSuite(GenericSignatureParserTest.class);
+ // $JUnit-END$
+ return suite;
+ }
- public UtilTests(String name) { super(name); }
+ public UtilTests(String name) {
+ super(name);
+ }
-}
+}