From 655986cb7d9fa1e45a3a4130b04feac408184cb1 Mon Sep 17 00:00:00 2001 From: aclement Date: Mon, 20 Oct 2008 18:31:01 +0000 Subject: [PATCH] 246125: promoted generic sig parsing code to util --- .../classfile/GenericSignatureParser.java | 402 ---------- .../apache/bcel/classfile/JavaClass.java | 12 +- .../apache/bcel/classfile/Signature.java | 696 ++++++------------ .../tests/GenericSignatureParserTest.java | 277 ------- 4 files changed, 239 insertions(+), 1148 deletions(-) delete mode 100644 bcel-builder/src/org/aspectj/apache/bcel/classfile/GenericSignatureParser.java delete mode 100644 bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/GenericSignatureParserTest.java diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/GenericSignatureParser.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/GenericSignatureParser.java deleted file mode 100644 index 8717bf4bb..000000000 --- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/GenericSignatureParser.java +++ /dev/null @@ -1,402 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2005 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 - * - * Contributors: - * Adrian Colyer Initial implementation - * ******************************************************************/ -package org.aspectj.apache.bcel.classfile; - -import java.util.ArrayList; -import java.util.List; - -import org.aspectj.apache.bcel.classfile.Signature.ArrayTypeSignature; -import org.aspectj.apache.bcel.classfile.Signature.ClassTypeSignature; -import org.aspectj.apache.bcel.classfile.Signature.FieldTypeSignature; -import org.aspectj.apache.bcel.classfile.Signature.FormalTypeParameter; -import org.aspectj.apache.bcel.classfile.Signature.MethodTypeSignature; -import org.aspectj.apache.bcel.classfile.Signature.SimpleClassTypeSignature; -import org.aspectj.apache.bcel.classfile.Signature.TypeArgument; -import org.aspectj.apache.bcel.classfile.Signature.TypeSignature; -import org.aspectj.apache.bcel.classfile.Signature.TypeVariableSignature; -import org.aspectj.apache.bcel.classfile.Signature.BaseTypeSignature; - -/** - * Parses the generic signature attribute as defined in the JVM spec. - */ -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 Signature.ClassSignature parseAsClassSignature(String sig) { - this.inputString = sig; - tokenStream = tokenize(sig); - tokenIndex = 0; - Signature.ClassSignature classSig = new Signature.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 Signature.BaseTypeSignature(eatIdentifier())); - } - } - TypeSignature[] params = new TypeSignature[paramList.size()]; - paramList.toArray(params); - // return type - returnType = parseFieldTypeSignature(true); - if (returnType == null) returnType = new Signature.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 Signature.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; - } - -} diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java index a087fa53d..230aabe49 100644 --- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/JavaClass.java @@ -79,7 +79,7 @@ import org.aspectj.apache.bcel.util.SyntheticRepository; * The intent of this class is to represent a parsed or otherwise existing class file. Those interested in programatically * generating classes should see the ClassGen class. * - * @version $Id: JavaClass.java,v 1.13 2008/08/28 15:36:59 aclement Exp $ + * @version $Id: JavaClass.java,v 1.14 2008/10/20 18:31:01 aclement Exp $ * @see org.aspectj.apache.bcel.generic.ClassGen * @author M. Dahm */ @@ -939,15 +939,9 @@ public class JavaClass extends Modifiers implements Cloneable, Node { } } - /** - * the parsed version of the above - */ - public final Signature.ClassSignature getGenericClassTypeSignature() { + public final Signature getSignatureAttribute() { loadGenericSignatureInfoIfNecessary(); - if (signatureAttribute != null) { - return signatureAttribute.asClassSignature(); - } - return null; + return signatureAttribute; } } diff --git a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java index 617c4dbae..b627822c3 100644 --- a/bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java +++ b/bcel-builder/src/org/aspectj/apache/bcel/classfile/Signature.java @@ -57,7 +57,6 @@ package org.aspectj.apache.bcel.classfile; * attribute */ - import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -66,465 +65,242 @@ import java.io.IOException; import org.aspectj.apache.bcel.Constants; /** - * This class is derived from Attribute and represents a reference - * to a GJ attribute. - * - * @version $Id: Signature.java,v 1.8 2008/08/26 15:01:23 aclement Exp $ - * @author M. Dahm - * @see Attribute + * This class is derived from Attribute and represents a reference to a GJ + * attribute. + * + * @version $Id: Signature.java,v 1.9 2008/10/20 18:31:01 aclement Exp $ + * @author M. Dahm + * @see Attribute */ public final class Signature extends Attribute { - private int signature_index; - - /** - * Initialize from another object. Note that both objects use the same - * references (shallow copy). Use clone() for a physical copy. - */ - public Signature(Signature c) { - this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool()); - } - - /** - * Construct object from file stream. - * @param name_index Index in constant pool to CONSTANT_Utf8 - * @param length Content length in bytes - * @param file Input stream - * @param constant_pool Array of constants - * @throws IOException - */ - Signature(int name_index, int length, DataInputStream file, - ConstantPool constant_pool) throws IOException - { - this(name_index, length, file.readUnsignedShort(), constant_pool); - } - - /** - * @param name_index Index in constant pool to CONSTANT_Utf8 - * @param length Content length in bytes - * @param constant_pool Array of constants - * @param Signature_index Index in constant pool to CONSTANT_Utf8 - */ - public Signature(int name_index, int length, int signature_index, - ConstantPool constant_pool) - { - super(Constants.ATTR_SIGNATURE, name_index, length, constant_pool); - this.signature_index = signature_index; - } - - /** - * Called by objects that are traversing the nodes of the tree implicitely - * defined by the contents of a Java class. I.e., the hierarchy of methods, - * fields, attributes, etc. spawns a tree of objects. - * - * @param v Visitor object - */ - public void accept(ClassVisitor v) { - System.err.println("Visiting non-standard Signature object"); - v.visitSignature(this); - } - - /** - * Dump source file attribute to file stream in binary format. - * - * @param file Output file stream - * @throws IOException - */ - public final void dump(DataOutputStream file) throws IOException - { - super.dump(file); - file.writeShort(signature_index); - } - - /** - * @return Index in constant pool of source file name. - */ - public final int getSignatureIndex() { return signature_index; } - - /** - * @param Signature_index. - */ - public final void setSignatureIndex(int signature_index) { - this.signature_index = signature_index; - } - - /** - * @return GJ signature. - */ - public final String getSignature() { - ConstantUtf8 c = (ConstantUtf8)constantPool.getConstant(signature_index, - Constants.CONSTANT_Utf8); - return c.getBytes(); - } - - /** - * Extends ByteArrayInputStream to make 'unreading' chars possible. - */ - private static final class MyByteArrayInputStream extends ByteArrayInputStream { - MyByteArrayInputStream(String data) { super(data.getBytes()); } - final int mark() { return pos; } - final String getData() { return new String(buf); } - final void reset(int p) { pos = p; } - final void unread() { if(pos > 0) pos--; } - } - - private static boolean identStart(int ch) { - return ch == 'T' || ch == 'L'; - } - - private static final void matchIdent(MyByteArrayInputStream in, StringBuffer buf) { - int ch; - - if((ch = in.read()) == -1) - throw new RuntimeException("Illegal signature: " + in.getData() + - " no ident, reaching EOF"); - - //System.out.println("return from ident:" + (char)ch); - - if(!identStart(ch)) { - StringBuffer buf2 = new StringBuffer(); - - int count = 1; - while(Character.isJavaIdentifierPart((char)ch)) { - buf2.append((char)ch); - count++; - ch = in.read(); - } - - if(ch == ':') { // Ok, formal parameter - in.skip("Ljava/lang/Object".length()); - buf.append(buf2); - - ch = in.read(); - in.unread(); - //System.out.println("so far:" + buf2 + ":next:" +(char)ch); - } else { - for(int i=0; i < count; i++) - in.unread(); - } - - return; - } - - StringBuffer buf2 = new StringBuffer(); - ch = in.read(); - - do { - buf2.append((char)ch); - ch = in.read(); - //System.out.println("within ident:"+ (char)ch); - - } while((ch != -1) && (Character.isJavaIdentifierPart((char)ch) || (ch == '/'))); - - buf.append(buf2.toString().replace('/', '.')); - - //System.out.println("regular return ident:"+ (char)ch + ":" + buf2); - - if(ch != -1) - in.unread(); - } - - private static final void matchGJIdent(MyByteArrayInputStream in, - StringBuffer buf) - { - int ch; - - matchIdent(in, buf); - - ch = in.read(); - if((ch == '<') || ch == '(') { // Parameterized or method - //System.out.println("Enter <"); - buf.append((char)ch); - matchGJIdent(in, buf); - - while(((ch = in.read()) != '>') && (ch != ')')) { // List of parameters - if(ch == -1) - throw new RuntimeException("Illegal signature: " + in.getData() + - " reaching EOF"); - - //System.out.println("Still no >"); - buf.append(", "); - in.unread(); - matchGJIdent(in, buf); // Recursive call - } - - //System.out.println("Exit >"); - - buf.append((char)ch); - } else - in.unread(); - - ch = in.read(); - if(identStart(ch)) { - in.unread(); - matchGJIdent(in, buf); - } else if(ch == ')') { - in.unread(); - return; - } else if(ch != ';') - throw new RuntimeException("Illegal signature: " + in.getData() + " read " + - (char)ch); - } - - public static String translate(String s) { - //System.out.println("Sig:" + s); - StringBuffer buf = new StringBuffer(); - - matchGJIdent(new MyByteArrayInputStream(s), buf); - - return buf.toString(); - } - - public static final boolean isFormalParameterList(String s) { - return s.startsWith("<") && (s.indexOf(':') > 0); - } - - public static final boolean isActualParameterList(String s) { - return s.startsWith("L") && s.endsWith(">;"); - } - - /** - * @return String representation - */ - public final String toString() { - String s = getSignature(); - - return "Signature(" + s + ")"; - } - - /** - * @return deep copy of this attribute - */ - public Attribute copy(ConstantPool constant_pool) { - return (Signature)clone(); - } - - // ============================================= - // AMC extensions - - private ClassSignature classSig; - private MethodTypeSignature methodSig; - private FieldTypeSignature fieldSig; - - public ClassSignature asClassSignature() { - if (classSig == null) { - GenericSignatureParser parser = new GenericSignatureParser(); - classSig = parser.parseAsClassSignature(getSignature()); - } - return classSig; - } - - public MethodTypeSignature asMethodTypeSignature() { - if (methodSig == null) { - GenericSignatureParser parser = new GenericSignatureParser(); - methodSig = parser.parseAsMethodSignature(getSignature()); - } - return methodSig; - } - - public FieldTypeSignature asFieldTypeSignature() { - if (fieldSig == null) { - GenericSignatureParser parser = new GenericSignatureParser(); - fieldSig = parser.parseAsFieldSignature(getSignature()); - } - return fieldSig; - } - - /** - * 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 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(); - } - } - + private int signature_index; + + /** + * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a physical + * copy. + */ + public Signature(Signature c) { + this(c.getNameIndex(), c.getLength(), c.getSignatureIndex(), c.getConstantPool()); + } + + /** + * Construct object from file stream. + * + * @param name_index Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + * @throws IOException + */ + Signature(int name_index, int length, DataInputStream file, ConstantPool constant_pool) throws IOException { + this(name_index, length, file.readUnsignedShort(), constant_pool); + } + + /** + * @param name_index Index in constant pool to CONSTANT_Utf8 + * @param length Content length in bytes + * @param constant_pool Array of constants + * @param Signature_index Index in constant pool to CONSTANT_Utf8 + */ + public Signature(int name_index, int length, int signature_index, ConstantPool constant_pool) { + super(Constants.ATTR_SIGNATURE, name_index, length, constant_pool); + this.signature_index = signature_index; + } + + /** + * Called by objects that are traversing the nodes of the tree implicitely defined by the contents of a Java class. I.e., the + * hierarchy of methods, fields, attributes, etc. spawns a tree of objects. + * + * @param v Visitor object + */ + public void accept(ClassVisitor v) { + System.err.println("Visiting non-standard Signature object"); + v.visitSignature(this); + } + + /** + * Dump source file attribute to file stream in binary format. + * + * @param file Output file stream + * @throws IOException + */ + public final void dump(DataOutputStream file) throws IOException { + super.dump(file); + file.writeShort(signature_index); + } + + /** + * @return Index in constant pool of source file name. + */ + public final int getSignatureIndex() { + return signature_index; + } + + /** + * @param Signature_index. + */ + public final void setSignatureIndex(int signature_index) { + this.signature_index = signature_index; + } + + /** + * @return GJ signature. + */ + public final String getSignature() { + ConstantUtf8 c = (ConstantUtf8) constantPool.getConstant(signature_index, Constants.CONSTANT_Utf8); + return c.getBytes(); + } + + /** + * Extends ByteArrayInputStream to make 'unreading' chars possible. + */ + private static final class MyByteArrayInputStream extends ByteArrayInputStream { + MyByteArrayInputStream(String data) { + super(data.getBytes()); + } + + final int mark() { + return pos; + } + + final String getData() { + return new String(buf); + } + + final void reset(int p) { + pos = p; + } + + final void unread() { + if (pos > 0) + pos--; + } + } + + private static boolean identStart(int ch) { + return ch == 'T' || ch == 'L'; + } + + private static final void matchIdent(MyByteArrayInputStream in, StringBuffer buf) { + int ch; + + if ((ch = in.read()) == -1) + throw new RuntimeException("Illegal signature: " + in.getData() + " no ident, reaching EOF"); + + // System.out.println("return from ident:" + (char)ch); + + if (!identStart(ch)) { + StringBuffer buf2 = new StringBuffer(); + + int count = 1; + while (Character.isJavaIdentifierPart((char) ch)) { + buf2.append((char) ch); + count++; + ch = in.read(); + } + + if (ch == ':') { // Ok, formal parameter + in.skip("Ljava/lang/Object".length()); + buf.append(buf2); + + ch = in.read(); + in.unread(); + // System.out.println("so far:" + buf2 + ":next:" +(char)ch); + } else { + for (int i = 0; i < count; i++) + in.unread(); + } + + return; + } + + StringBuffer buf2 = new StringBuffer(); + ch = in.read(); + + do { + buf2.append((char) ch); + ch = in.read(); + // System.out.println("within ident:"+ (char)ch); + + } while ((ch != -1) && (Character.isJavaIdentifierPart((char) ch) || (ch == '/'))); + + buf.append(buf2.toString().replace('/', '.')); + + // System.out.println("regular return ident:"+ (char)ch + ":" + buf2); + + if (ch != -1) + in.unread(); + } + + private static final void matchGJIdent(MyByteArrayInputStream in, StringBuffer buf) { + int ch; + + matchIdent(in, buf); + + ch = in.read(); + if ((ch == '<') || ch == '(') { // Parameterized or method + // System.out.println("Enter <"); + buf.append((char) ch); + matchGJIdent(in, buf); + + while (((ch = in.read()) != '>') && (ch != ')')) { // List of parameters + if (ch == -1) + throw new RuntimeException("Illegal signature: " + in.getData() + " reaching EOF"); + + // System.out.println("Still no >"); + buf.append(", "); + in.unread(); + matchGJIdent(in, buf); // Recursive call + } + + // System.out.println("Exit >"); + + buf.append((char) ch); + } else + in.unread(); + + ch = in.read(); + if (identStart(ch)) { + in.unread(); + matchGJIdent(in, buf); + } else if (ch == ')') { + in.unread(); + return; + } else if (ch != ';') + throw new RuntimeException("Illegal signature: " + in.getData() + " read " + (char) ch); + } + + public static String translate(String s) { + // System.out.println("Sig:" + s); + StringBuffer buf = new StringBuffer(); + + matchGJIdent(new MyByteArrayInputStream(s), buf); + + return buf.toString(); + } + + public static final boolean isFormalParameterList(String s) { + return s.startsWith("<") && (s.indexOf(':') > 0); + } + + public static final boolean isActualParameterList(String s) { + return s.startsWith("L") && s.endsWith(">;"); + } + + /** + * @return String representation + */ + public final String toString() { + String s = getSignature(); + + return "Signature(" + s + ")"; + } + + /** + * @return deep copy of this attribute + */ + public Attribute copy(ConstantPool constant_pool) { + return (Signature) clone(); + } + } diff --git a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/GenericSignatureParserTest.java b/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/GenericSignatureParserTest.java deleted file mode 100644 index c217e083e..000000000 --- a/bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/GenericSignatureParserTest.java +++ /dev/null @@ -1,277 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2005 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 - * - * Contributors: - * Adrian Colyer initial implementation - * ******************************************************************/ - -package org.aspectj.apache.bcel.classfile.tests; - - -import org.aspectj.apache.bcel.classfile.GenericSignatureParser; -import org.aspectj.apache.bcel.classfile.JavaClass; -import org.aspectj.apache.bcel.classfile.Method; -import org.aspectj.apache.bcel.classfile.Signature; -import org.aspectj.apache.bcel.classfile.Signature.ClassSignature; -import org.aspectj.apache.bcel.classfile.Signature.ClassTypeSignature; -import org.aspectj.apache.bcel.classfile.Signature.FieldTypeSignature; -import org.aspectj.apache.bcel.classfile.Signature.SimpleClassTypeSignature; -import org.aspectj.apache.bcel.util.SyntheticRepository; - -import junit.framework.TestCase; - -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(""); - 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(";>Ljava/util/List;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;",isig.classSignature); - assertEquals("Ljava/util/List;",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 testClassSignatureParsingInJDK() throws Exception { - SyntheticRepository repository = SyntheticRepository.getInstance(); - String[] testClasses = new String[] { - "java.lang.Comparable", - "java.lang.Iterable", - "java.lang.Class", - "java.lang.Enum", - "java.lang.InheritableThreadLocal", - "java.lang.ThreadLocal", - "java.util.Collection", - "java.util.Comparator", - "java.util.Enumeration", - "java.util.Iterator", - "java.util.List", - "java.util.ListIterator", - "java.util.Map", - "java.util.Map$Entry", - "java.util.Queue", - "java.util.Set", - "java.util.SortedMap", - "java.util.SortedSet" - }; - for (int i = 0; i < testClasses.length; i++) { - JavaClass jc = repository.loadClass(testClasses[i]); - String sig = jc.getGenericSignature(); - parser.parseAsClassSignature(sig); - } - } - - 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 Signature.ArrayTypeSignature); - assertEquals("[Ljava/lang/String;",fsig.toString()); - } - - public void testFieldSignatureParsingTypeVariable() { - FieldTypeSignature fsig = parser.parseAsFieldSignature("TT;"); - assertTrue("TypeVariableSignature",fsig instanceof Signature.TypeVariableSignature); - assertEquals("TT;",fsig.toString()); - } - - public void testSimpleMethodSignatureParsing() { - Signature.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() { - Signature.MethodTypeSignature mSig = parser.parseAsMethodSignature("(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() { - Signature.MethodTypeSignature mSig = parser.parseAsMethodSignature("()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() { - Signature.MethodTypeSignature mSig = parser.parseAsMethodSignature("(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() { - Signature.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 testMethodSignatureParsingInJDK() throws Exception{ - SyntheticRepository repository = SyntheticRepository.getInstance(); - String[] testClasses = new String[] { - "java.lang.Comparable", - "java.lang.Iterable", - "java.lang.Class", - "java.lang.Enum", - "java.lang.InheritableThreadLocal", - "java.lang.ThreadLocal", - "java.util.Collection", - "java.util.Comparator", - "java.util.Enumeration", - "java.util.Iterator", - "java.util.List", - "java.util.ListIterator", - "java.util.Map", - "java.util.Map$Entry", - "java.util.Queue", - "java.util.Set", - "java.util.SortedMap", - "java.util.SortedSet" - }; - for (int i = 0; i < testClasses.length; i++) { - JavaClass jc = repository.loadClass(testClasses[i]); - Method[] methods = jc.getMethods(); - for (int j = 0; j < methods.length; j++) { - String sig = methods[j].getGenericSignature(); - if (sig != null) parser.parseAsMethodSignature(sig); - } - } - } - - public void testFullyQualifiedSuperclassAfterTypeParams() { - try { - Signature.FieldTypeSignature cSig = parser.parseAsFieldSignature("Ljava/util/List;"); - parser.parseAsClassSignature("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(); - } -} -- 2.39.5