Преглед изворни кода

246125: promoted generic sig parsing code to util

tags/V1_6_3rc1
aclement пре 15 година
родитељ
комит
655986cb7d

+ 0
- 402
bcel-builder/src/org/aspectj/apache/bcel/classfile/GenericSignatureParser.java Прегледај датотеку

@@ -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;
}
}

+ 3
- 9
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 <a href="../generic/ClassGen.html">ClassGen</a> 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 <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
*/
@@ -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;
}

}

+ 236
- 460
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 <em>Attribute</em> and represents a reference
* to a <href="http://wwwipd.ira.uka.de/~pizza/gj/">GJ</a> attribute.
*
* @version $Id: Signature.java,v 1.8 2008/08/26 15:01:23 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
* @see Attribute
* This class is derived from <em>Attribute</em> and represents a reference to a <href="http://wwwipd.ira.uka.de/~pizza/gj/">GJ</a>
* attribute.
*
* @version $Id: Signature.java,v 1.9 2008/10/20 18:31:01 aclement Exp $
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
* @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();
}

}

+ 0
- 277
bcel-builder/testsrc/org/aspectj/apache/bcel/classfile/tests/GenericSignatureParserTest.java Прегледај датотеку

@@ -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("<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 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("<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() {
Signature.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() {
Signature.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() {
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</;");
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();
}
}

Loading…
Откажи
Сачувај