blob: b5b1752b2aa53ad29e169e1efacaf43d2d2702bf [file] [log] [blame]
package org.eclipse.jdt.internal.debug.eval.ast.engine;
/*
* (c) Copyright IBM Corp. 2002.
* All Rights Reserved.
*/
import java.util.Iterator;
import java.util.List;
import org.eclipse.debug.core.DebugException;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.internal.debug.core.model.JDIClassType;
import org.eclipse.jdt.internal.debug.core.model.JDIObjectValue;
import org.eclipse.jdt.internal.debug.core.model.JDIStackFrame;
import com.sun.jdi.ClassNotPreparedException;
import com.sun.jdi.ClassType;
import com.sun.jdi.Field;
import com.sun.jdi.InterfaceType;
import com.sun.jdi.Method;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.Type;
public class BinaryBasedSourceGenerator {
private static final String RUN_METHOD_NAME= "___run"; //$NON-NLS-1$
private static final String EVAL_METHOD_NAME= "___eval"; //$NON-NLS-1$
private static final String ANONYMOUS_CLASS_NAME= "___EvalClass"; //$NON-NLS-1$
private String[] fLocalVariableTypeNames;
private String[] fLocalVariableNames;
private boolean fIsInStaticMethod;
private StringBuffer fSource;
private int fRunMethodStartOffset;
private int fRunMethodLength;
private int fCodeSnippetPosition;
private String fCompilationUnitName;
public BinaryBasedSourceGenerator(String[] localTypesNames, String[] localVariables, boolean isInStaticMethod) throws DebugException {
fLocalVariableTypeNames= localTypesNames;
fLocalVariableNames= localVariables;
fIsInStaticMethod= isInStaticMethod;
}
/**
* Build source for an object value (instance context)
*/
public void buildSource(JDIObjectValue object) {
ObjectReference reference= object.getUnderlyingObject();
fSource= buildTypeDeclaration(reference, buildRunMethod(reference.referenceType()), null);
}
/**
* Build source for a class type (static context)
*/
public void buildSource(JDIClassType type) {
Type underlyingType= type.getUnderlyingType();
if (!(underlyingType instanceof ReferenceType)) {
return;
}
ReferenceType refType= (ReferenceType)underlyingType;
fSource= buildTypeDeclaration(refType, buildRunMethod(refType), null, false);
String packageName = getPackageName(refType.name());
if (packageName != null) {
fSource.insert(0, "package " + packageName + ";\n"); //$NON-NLS-1$ //$NON-NLS-2$
fCodeSnippetPosition += 10 + packageName.length();
}
fCompilationUnitName= getSimpleName(refType.name());
}
protected String getUniqueMethodName(String methodName, ReferenceType type) {
List methods= type.methodsByName(methodName);
while (!methods.isEmpty()) {
methodName += '_';
methods= type.methodsByName(methodName);
}
return methodName;
}
private StringBuffer buildRunMethod(ReferenceType type) {
StringBuffer source = new StringBuffer();
if (isInStaticMethod()) {
source.append("static "); //$NON-NLS-1$
}
source.append("void "); //$NON-NLS-1$
source.append(getUniqueMethodName(RUN_METHOD_NAME, type));
source.append('(');
for(int i= 0, length= fLocalVariableNames.length; i < length; i++) {
source.append(getDotName(fLocalVariableTypeNames[i]));
source.append(' ');
source.append(fLocalVariableNames[i]);
if (i + 1 < length)
source.append(", "); //$NON-NLS-1$
}
source.append(") throws Throwable {"); //$NON-NLS-1$
source.append('\n');
fCodeSnippetPosition= source.length();
fRunMethodStartOffset= fCodeSnippetPosition;
source.append('\n');
source.append('}').append('\n');
fRunMethodLength= source.length();
return source;
}
private StringBuffer buildTypeDeclaration(ObjectReference object, StringBuffer buffer, String nestedTypeName) {
ReferenceType referenceType = object.referenceType();
Field thisField= null;
List fields= referenceType.visibleFields();
for (Iterator iterator= fields.iterator(); iterator.hasNext();) {
Field field= (Field) iterator.next();
if (field.name().startsWith("this$")) { //$NON-NLS-1$
thisField = field;
break;
}
}
StringBuffer source = buildTypeDeclaration(referenceType, buffer, nestedTypeName, thisField != null);
if (thisField == null) {
String packageName = getPackageName(referenceType.name());
if (packageName != null) {
source.insert(0, "package " + packageName + ";\n"); //$NON-NLS-1$ //$NON-NLS-2$
fCodeSnippetPosition += 10 + packageName.length();
}
if (isAnonymousTypeName(referenceType.name())) {
fCompilationUnitName= ANONYMOUS_CLASS_NAME;
} else {
fCompilationUnitName= getSimpleName(referenceType.name());
}
} else {
ObjectReference thisObject= (ObjectReference)object.getValue(thisField);
return buildTypeDeclaration(thisObject, source, referenceType.name());
}
return source;
}
private StringBuffer buildTypeDeclaration(ReferenceType referenceType, StringBuffer buffer, String nestedTypeName, boolean hasEnclosingInstance) {
StringBuffer source= new StringBuffer();
String typeName= referenceType.name();
boolean isAnonymousType= isAnonymousTypeName(typeName);
if (isAnonymousType) {
ClassType classType= (ClassType) referenceType;
List interfaceList= classType.interfaces();
String superClassName= classType.superclass().name();
if (hasEnclosingInstance) {
source.append("void "); //$NON-NLS-1$
source.append(getUniqueMethodName(EVAL_METHOD_NAME, referenceType));
source.append("() {\nnew "); //$NON-NLS-1$
if (interfaceList.size() != 0) {
source.append(getDotName(((InterfaceType)interfaceList.get(0)).name()));
} else {
source.append(getDotName(superClassName));
}
source.append("()"); //$NON-NLS-1$
} else {
source.append("public class ").append(ANONYMOUS_CLASS_NAME).append(" "); //$NON-NLS-1$ //$NON-NLS-2$
if (interfaceList.size() != 0) {
source.append(" implements ").append(getDotName(((InterfaceType)interfaceList.get(0)).name())); //$NON-NLS-1$
} else {
source.append(" implements ").append(getDotName(superClassName)); //$NON-NLS-1$
}
}
} else {
if (referenceType.isFinal()) {
source.append("final "); //$NON-NLS-1$
}
if (referenceType.isStatic()) {
source.append("static "); //$NON-NLS-1$
}
if (referenceType instanceof ClassType) {
ClassType classType= (ClassType) referenceType;
if (classType.isAbstract()) {
source.append("abstract "); //$NON-NLS-1$
}
source.append("class "); //$NON-NLS-1$
source.append(getSimpleName(typeName)).append(' ');
ClassType superClass= classType.superclass();
if (superClass != null) {
source.append("extends ").append(getDotName(superClass.name())).append(' '); //$NON-NLS-1$
}
List interfaces;
try {
interfaces= classType.interfaces();
} catch (ClassNotPreparedException e) {
return new StringBuffer();
}
if (interfaces.size() != 0) {
source.append("implements "); //$NON-NLS-1$
Iterator iterator= interfaces.iterator();
InterfaceType interface_= (InterfaceType)iterator.next();
source.append(getDotName(interface_.name()));
while (iterator.hasNext()) {
source.append(',').append(getDotName(((InterfaceType)iterator.next()).name()));
}
}
} else if (referenceType instanceof InterfaceType) {
InterfaceType interfaceType= (InterfaceType) referenceType;
source.append("interface "); //$NON-NLS-1$
source.append(getSimpleName(typeName)).append(' ');
List interfaces;
try {
interfaces= interfaceType.superinterfaces();
} catch (ClassNotPreparedException e) {
return new StringBuffer();
}
if (interfaces.size() != 0) {
source.append("extends "); //$NON-NLS-1$
Iterator iterator= interfaces.iterator();
InterfaceType interface_= (InterfaceType)iterator.next();
source.append(getDotName(interface_.name()));
while (iterator.hasNext()) {
source.append(',').append(getDotName(((InterfaceType)iterator.next()).name()));
}
}
}
}
source.append(" {\n"); //$NON-NLS-1$
if (buffer != null) {
fCodeSnippetPosition += source.length();
source.append(buffer);
}
List fields= referenceType.fields();
for (Iterator iterator= fields.iterator(); iterator.hasNext();) {
Field field= (Field) iterator.next();
if (!field.name().startsWith("this$")) { //$NON-NLS-1$
source.append(buildFieldDeclaration(field));
}
}
List methods= referenceType.methods();
for (Iterator iterator = methods.iterator(); iterator.hasNext();) {
Method method= (Method) iterator.next();
if (!method.isConstructor() && !method.isStaticInitializer()) {
source.append(buildMethodDeclaration(method));
}
}
List nestedTypes= referenceType.nestedTypes();
if (nestedTypeName == null) {
for (Iterator iterator = nestedTypes.iterator(); iterator.hasNext();) {
ReferenceType nestedType= (ReferenceType) iterator.next();
if (isADirectInnerType(typeName, nestedType.name())) {
source.append(buildTypeDeclaration(nestedType, null, null, true));
}
}
} else {
for (Iterator iterator = nestedTypes.iterator(); iterator.hasNext();) {
ReferenceType nestedType= (ReferenceType) iterator.next();
if (!nestedTypeName.equals(nestedType.name()) && isADirectInnerType(typeName, nestedType.name())) {
source.append(buildTypeDeclaration(nestedType, null, null, true));
}
}
}
if (isAnonymousType & hasEnclosingInstance) {
source.append("};\n"); //$NON-NLS-1$
}
source.append("}\n"); //$NON-NLS-1$
return source;
}
private StringBuffer buildFieldDeclaration(Field field) {
StringBuffer source = new StringBuffer();
if (field.isFinal()) {
source.append("final "); //$NON-NLS-1$
}
if (field.isStatic()) {
source.append("static "); //$NON-NLS-1$
}
if (field.isPublic()) {
source.append("public "); //$NON-NLS-1$
} else if (field.isPrivate()) {
source.append("private "); //$NON-NLS-1$
} else if (field.isProtected()) {
source.append("protected "); //$NON-NLS-1$
}
source.append(getDotName(field.typeName())).append(' ').append(field.name()).append(';').append('\n');
return source;
}
private StringBuffer buildMethodDeclaration(Method method) {
StringBuffer source= new StringBuffer();
if (method.isFinal()) {
source.append("final "); //$NON-NLS-1$
}
if (method.isStatic()) {
source.append("static "); //$NON-NLS-1$
}
if (method.isNative()) {
source.append("native "); //$NON-NLS-1$
} else if (method.isAbstract()) {
source.append("abstract "); //$NON-NLS-1$
}
if (method.isPublic()) {
source.append("public "); //$NON-NLS-1$
} else if (method.isPrivate()) {
source.append("private "); //$NON-NLS-1$
} else if (method.isProtected()) {
source.append("protected "); //$NON-NLS-1$
}
source.append(getDotName(method.returnTypeName())).append(' ').append(method.name()).append('(');
List arguments= method.argumentTypeNames();
int i= 0;
if (arguments.size() != 0) {
Iterator iterator= arguments.iterator();
source.append(getDotName((String) iterator.next())).append(" arg").append(i++); //$NON-NLS-1$
while (iterator.hasNext()) {
source.append(',').append(getDotName((String) iterator.next())).append(" arg").append(i++); //$NON-NLS-1$
}
}
source.append(')');
if (method.isAbstract() || method.isNative()) {
// No body for abstract and native methods
source.append(";\n"); //$NON-NLS-1$
} else {
source.append('{').append('\n');
source.append(getReturnStatement(method.returnTypeName()));
source.append('}').append('\n');
}
return source;
}
private String getReturnStatement(String returnTypeName) {
String typeName= getSimpleName(returnTypeName);
if (typeName.charAt(typeName.length() - 1) == ']') {
return "return null;\n"; //$NON-NLS-1$
}
switch (typeName.charAt(0)) {
case 'v':
return ""; //$NON-NLS-1$
case 'b':
if (typeName.charAt(1) == 'o') {
return "return false;\n"; //$NON-NLS-1$
}
case 's':
case 'c':
case 'i':
case 'l':
case 'd':
case 'f':
return "return 0;\n"; //$NON-NLS-1$
default:
return "return null;\n"; //$NON-NLS-1$
}
}
private String getDotName(String typeName) {
return typeName.replace('$', '.');
}
private boolean isAnonymousTypeName(String typeName) {
char char0 = getSimpleName(typeName).charAt(0);
return '0' <= char0 && char0 <= '9';
}
private String getSimpleName(String qualifiedName) {
int pos = qualifiedName.lastIndexOf('$');
if (pos == -1) {
pos = qualifiedName.lastIndexOf('.');
}
return ((pos == -1)? qualifiedName : qualifiedName.substring(pos + 1));
}
private String getPackageName(String qualifiedName) {
int pos = qualifiedName.lastIndexOf('.');
return ((pos == -1)? null : qualifiedName.substring(0, pos));
}
private boolean isADirectInnerType(String typeName, String nestedTypeName) {
String end= nestedTypeName.substring(typeName.length() + 1);
return end.indexOf('$') == -1;
}
private boolean isInStaticMethod() {
return fIsInStaticMethod;
}
public StringBuffer getSource() {
return fSource;
}
public int getCodeSnippetPosition() {
return fCodeSnippetPosition;
}
public String getCompilationUnitName() {
return fCompilationUnitName;
}
public int getSnippetStart() {
return fCodeSnippetPosition - 2;
}
public int getRunMethodStart() {
return fCodeSnippetPosition - fRunMethodStartOffset;
}
public int getRunMethodLength() {
return fRunMethodLength;
}
}