package org.ntlab.reverseDebugger;
import java.util.ArrayList;
import org.ntlab.traceCollector.tracer.trace.ArrayAccess;
import org.ntlab.traceCollector.tracer.trace.ArrayCreate;
import org.ntlab.traceCollector.tracer.trace.ArrayUpdate;
import org.ntlab.traceCollector.tracer.trace.FieldAccess;
import org.ntlab.traceCollector.tracer.trace.FieldUpdate;
import org.ntlab.traceCollector.tracer.trace.MethodExecution;
import org.ntlab.traceCollector.tracer.trace.MethodInvocation;
import org.ntlab.traceCollector.tracer.trace.ObjectReference;
import org.ntlab.traceCollector.tracer.trace.Statement;
import org.ntlab.traceCollector.tracer.trace.Trace;
import org.ntlab.traceCollector.tracer.trace.TracePoint;
/**
* オブジェクトの参照情報(エイリアス)を表すクラス
* @author Isitani
*
*/
public class Alias {
private String objectId;
private TracePoint occurrencePoint; // 当該オブジェクトの参照が行われている実行箇所に対応するTracePoint
/**
* 当該オブジェクトの参照がTracePointにおいてどこに現れているかを表す<br>
* 0 フィールドアクセス時のコンテナ もしくは メソッド呼び出し時のレシーバ<br>
* 1, 2, 3 …… n フィールドアクセス時のフィールド(1) もしくは メソッド呼び出し時のn番目の実引数 (1から順番に)<br>
* -1 メソッド呼び出し時の戻り値<br>
* <br>
* 例1: d = a.m(b, c);<br>
* <br>
* 例1の実行文において, aはメソッド呼び出しのレシーバなので0, bはメソッド呼び出しの1番目の実引数なので1,<br>
* cはメソッド呼び出しの2番目の実引数なので2, a.m(b, c)の戻り値は-1 となる.<br>
* <br>
* 例2: d = a.f;<br>
* 例2の実行文において, aはフィールドのコンテナなので0, bはフィールドなので1 となる.
*
*/
private int occurrenceExp;
public static final int OCCURRENCE_EXP_CONTAINER = 0;
public static final int OCCURRENCE_EXP_RECEIVER = 0;
public static final int OCCURRENCE_EXP_FIELD = 1;
public static final int OCCURRENCE_EXP_ARRAY = 1;
public static final int OCCURRENCE_EXP_FIRST_ARG = 1;
public static final int OCCURRENCE_EXP_RETURN = -1;
public Alias(String objectId, TracePoint occurrencePoint, int occurrenceExp) {
this.objectId = objectId;
this.occurrencePoint = occurrencePoint;
this.occurrenceExp = occurrenceExp;
}
public String getObjectId() {
return objectId;
}
public TracePoint getOccurrencePoint() {
return occurrencePoint;
}
public int getOccurrenceExp() {
return occurrenceExp;
}
public MethodExecution getMethodExecution() {
return occurrencePoint.getMethodExecution();
}
public String getMethodExecutionClassName() {
MethodExecution methodExecution = occurrencePoint.getMethodExecution();
return Trace.getDeclaringType(methodExecution.getSignature(), methodExecution.isConstructor());
}
public String getMethodSignature() {
return occurrencePoint.getMethodExecution().getCallerSideSignature();
}
public int getLineNo() {
Statement statement = occurrencePoint.getStatement();
return statement.getLineNo();
}
public String getStatementType() {
Statement statement = occurrencePoint.getStatement();
String statementType = "";
if (statement instanceof FieldAccess) {
FieldAccess fa = (FieldAccess)statement;
statementType = "FieldAccess";
} else if (statement instanceof FieldUpdate) {
FieldUpdate fu = (FieldUpdate)statement;
statementType = "FieldUpdate";
} else if (statement instanceof ArrayAccess) {
ArrayAccess aa = (ArrayAccess)statement;
statementType = "ArrayAccess";
} else if (statement instanceof ArrayUpdate) {
ArrayUpdate au = (ArrayUpdate)statement;
statementType = "ArrayUpdate";
} else if (statement instanceof ArrayCreate) {
ArrayCreate ac = (ArrayCreate)statement;
statementType = "ArrayCreate";
} else if (statement instanceof MethodInvocation) {
MethodExecution me = ((MethodInvocation)statement).getCalledMethodExecution();
statementType = "MethodInvocation";
}
return statementType;
}
public String getStatementSignature() {
Statement statement = occurrencePoint.getStatement();
String statementSignature = "";
if (statement instanceof FieldAccess) {
FieldAccess fa = (FieldAccess)statement;
statementSignature = fa.getFieldName();
} else if (statement instanceof FieldUpdate) {
FieldUpdate fu = (FieldUpdate)statement;
statementSignature = fu.getFieldName();
} else if (statement instanceof ArrayAccess) {
ArrayAccess aa = (ArrayAccess)statement;
statementSignature = aa.getArrayClassName() + "[" + aa.getIndex() + "]";
} else if (statement instanceof ArrayUpdate) {
ArrayUpdate au = (ArrayUpdate)statement;
statementSignature = au.getArrayClassName() + "[" + au.getIndex() + "]";
} else if (statement instanceof ArrayCreate) {
ArrayCreate ac = (ArrayCreate)statement;
statementSignature = ac.getArrayClassName();
} else if (statement instanceof MethodInvocation) {
MethodExecution me = ((MethodInvocation)statement).getCalledMethodExecution();
statementSignature = me.getCallerSideSignature();
}
return statementSignature;
}
public String getClassName() {
Statement statement = occurrencePoint.getStatement();
String className = "";
if (statement instanceof FieldAccess) {
if (occurrenceExp == OCCURRENCE_EXP_CONTAINER) {
className = ((FieldAccess) statement).getContainerClassName();
} else if (occurrenceExp == OCCURRENCE_EXP_FIELD) {
className = ((FieldAccess) statement).getValueClassName();
}
} else if (statement instanceof FieldUpdate) {
if (occurrenceExp == OCCURRENCE_EXP_CONTAINER) {
className = ((FieldUpdate) statement).getContainerClassName();
} else if (occurrenceExp == OCCURRENCE_EXP_FIELD) {
className = ((FieldUpdate) statement).getValueClassName();
}
} else if (statement instanceof ArrayAccess) {
className = ((ArrayAccess) statement).getValueClassName();
} else if (statement instanceof ArrayUpdate) {
className = ((ArrayUpdate) statement).getValueClassName();
} else if (statement instanceof ArrayCreate) {
className = ((ArrayCreate) statement).getArrayClassName();
} else if (statement instanceof MethodInvocation) {
MethodExecution me = ((MethodInvocation)statement).getCalledMethodExecution();
if (occurrenceExp == OCCURRENCE_EXP_RETURN) {
className = me.getReturnValue().getActualType();
} else if (occurrenceExp == OCCURRENCE_EXP_RECEIVER) {
className = me.getThisClassName();
} else {
int index = occurrenceExp - OCCURRENCE_EXP_FIRST_ARG;
ArrayList<ObjectReference> args = me.getArguments();
if (index >= 0 && index < args.size()) {
className = me.getArguments().get(index).getActualType();
}
}
}
return className;
}
public String getOccurrenceText() {
String statementType = getStatementType();
switch (statementType) {
case "FieldAccess":
case "FieldUpdate":
return (occurrenceExp == 0) ? "container" : "field";
case "ArrayAccess":
case "ArrayUpdate":
return (occurrenceExp == 0) ? "arrayObject" : "arrayValue";
case "ArrayCreate":
return "return";
case "MethodInvocation":
if (occurrenceExp <= 0) {
return (occurrenceExp == 0) ? "receiver" : "return";
}
final String[] ORDER_TEXT = {"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th", "th", "th", "th", "th"}; // 0-13に対応
final String ARG = " arg";
if (occurrenceExp % 100 >= ORDER_TEXT.length) {
return occurrenceExp + ORDER_TEXT[occurrenceExp % 10] + ARG; // 下2桁が14以上なら, 下1桁の数字に対応させる
} else if (occurrenceExp % 100 >= 0) {
return occurrenceExp + ORDER_TEXT[occurrenceExp % 100] + ARG; // 下2桁が0以上13以下なら, 下2桁の数字に対応させる
}
}
return String.valueOf(occurrenceExp);
}
// @Override
// public String toString() {
// Statement statement = occurrencePoint.getStatement();
// String className = getClassName();
// String methodSignature = getMethodSignature();
// String statementType = getStatementType();
// String statementSigunarure = getStatementSignature();
// String indent = " ";
// StringBuilder str = new StringBuilder();
// str.append("objId: " + objectId + " (class = " + className + ")" + "\n");
// str.append("tp: " + occurrencePoint + "\n");
// str.append(indent + "signature: " + methodSignature + "\n");
// str.append(indent + "lineNo: " + statement.getLineNo() + "\n");
// str.append(indent + "statementType: " + statementType + " -> " + statementSigunarure + "\n");
// str.append("occurrenceExp: " + occurrenceExp + "\n");
// return str.toString();
// }
}