)this.getData()) {
+ switch (property) {
+ case created:
+ combo.add("�V�K�쐬");
+ combo.setText("�V�K�쐬");
+ break;
+ case modified:
+ combo.add("�C������");
+ combo.setText("�C������");
+ break;
+ case unmodified:
+ combo.add("�C���Ȃ�");
+ combo.setText("�C���Ȃ�");
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ public void updateDiscription(MethodExecution me) {
+ String text = "";
+ text += "Current Method : " + me.getSignature() + "\n";
+ discription.setText(text);
+ }
+
+
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/interactivefeaturelocator/views/TraceView.java b/org.ntlab.interactiveFeatureLocator/src/interactivefeaturelocator/views/TraceView.java
new file mode 100644
index 0000000..625b358
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/interactivefeaturelocator/views/TraceView.java
@@ -0,0 +1,154 @@
+package interactivefeaturelocator.views;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+
+import interactivefeaturelocator.model.DerivationManager;
+import interactivefeaturelocator.model.DerivationUnit;
+import interactivefeaturelocator.model.TreeModel;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.part.*;
+import org.eclipse.jface.viewers.*;
+import org.eclipse.swt.SWT;
+import org.ntlab.trace.ThreadInstance;
+import org.ntlab.trace.Trace;
+
+
+/**
+ * This sample class demonstrates how to plug-in a new
+ * workbench view. The view shows data obtained from the
+ * model. The sample creates a dummy model on the fly,
+ * but a real implementation would connect to the model
+ * available either in this or another plug-in (e.g. the workspace).
+ * The view is connected to the model using a content provider.
+ *
+ * The view uses a label provider to define how model
+ * objects should be presented in the view. Each
+ * view can present the same model objects using
+ * different labels and icons, if needed. Alternatively,
+ * a single label provider can be shared between views
+ * in order to ensure that objects of the same type are
+ * presented in the same way everywhere.
+ *
+ */
+
+public class TraceView extends ViewPart {
+
+ public static TraceView theInstance = null;
+ public static final String ID = "interactivefeaturelocator.views.traceview";
+ private TreeViewer viewer;
+// private HashMap threads = new HashMap<>();
+ private TreeNode focusNode = null;
+ private InteractiveDerivationView selectMethodView;
+ private ArrayList traces = new ArrayList<>();
+ private DerivationManager inferenceManager;
+
+ public TraceView() {
+
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+ // TODO Auto-generated method stub
+ theInstance = this;
+ selectMethodView = InteractiveDerivationView.theInstance;
+
+ viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+ viewer.setContentProvider(new TreeNodeContentProvider());
+ viewer.setLabelProvider(new ViewLabelProvider());
+ viewer.setInput(makeData(null));
+ viewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+ // �m�[�h���I�����ꂽ�Ƃ��̏���
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ // TODO Auto-generated method stub
+ StructuredSelection selection = (StructuredSelection)event.getSelection();
+ if (selection.getFirstElement() != null) {
+ setFocusNode((TreeNode)selection.getFirstElement());
+ if (getFocusNode() != null) {
+ selectMethodView.changeFolder(0);
+ }
+ }
+ }
+ });
+ }
+
+ // Viewer�̍X�V
+ public void updateViewer() {
+ traces.clear();
+ if (selectMethodView == null) {
+ selectMethodView = InteractiveDerivationView.theInstance;
+ }
+ for (int i = 0; i < inferenceManager.getInferenceUnitCount(); i++) {
+ DerivationUnit unit = inferenceManager.getInferenceUnit(i);
+ Trace plusTrace = unit.getPlusTrace();
+ traces.add(plusTrace);
+ selectMethodView.createTabFolder(unit);
+ System.out.println(plusTrace.getFileName());
+ }
+ viewer.setInput(makeData(traces));
+ StructuredSelection selection = new StructuredSelection(getFocusNode());
+ viewer.setSelection(selection);
+ }
+
+ @Override
+ public void setFocus() {
+ // TODO Auto-generated method stub
+ if (getFocusNode() != null) {
+ StructuredSelection selection = new StructuredSelection(getFocusNode());
+ viewer.setSelection(selection);
+ }
+ viewer.getControl().setFocus();
+ }
+
+ // �f�[�^�쐬���\�b�h
+ private TreeNode[] makeData(ArrayList traces) {
+// if (selectMethodView == null) {
+// selectMethodView = SelectMethodView.theInstance;
+// }
+ if (traces == null) {
+ return null;
+ }
+ setFocusNode(null);
+ TreeNode[] node = new TreeNode[traces.size()];
+ for (int i = 0; i < traces.size(); i++) {
+ Trace trace = traces.get(i);
+ node[i] = new TreeNode(new TreeModel(trace.getFileName(), 1));
+ if (getFocusNode() == null) {
+ setFocusNode(node[i]);
+ }
+ }
+ return node;
+ }
+
+ public TreeNode getFocusNode() {
+ return focusNode;
+ }
+
+ public void setFocusNode(TreeNode focus) {
+ this.focusNode = focus;
+ }
+
+ public DerivationManager getIm() {
+ return inferenceManager;
+ }
+
+ public void setInferanceManager(DerivationManager im) {
+ this.inferenceManager = im;
+ }
+
+ public void dispose() {
+ super.dispose();
+ theInstance = null;
+ }
+}
\ No newline at end of file
diff --git a/org.ntlab.interactiveFeatureLocator/src/interactivefeaturelocator/views/ViewLabelProvider.java b/org.ntlab.interactiveFeatureLocator/src/interactivefeaturelocator/views/ViewLabelProvider.java
new file mode 100644
index 0000000..d733442
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/interactivefeaturelocator/views/ViewLabelProvider.java
@@ -0,0 +1,35 @@
+package interactivefeaturelocator.views;
+
+import interactivefeaturelocator.model.TreeModel;
+
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.TreeNode;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+
+public class ViewLabelProvider extends LabelProvider {
+
+ public String getText(Object obj) {
+ if (obj instanceof TreeNode) {
+ return ((TreeNode) obj).getValue().toString();
+ }
+ return "";
+ }
+
+ public Image getImage(Object obj) {
+ String imageKey = ISharedImages.IMG_OBJ_ELEMENT;
+ TreeModel model = null;
+ if (obj instanceof TreeNode) {
+ model = (TreeModel)((TreeNode) obj).getValue();
+ if (model.getType() == 1) {
+ imageKey = ISharedImages.IMG_OBJ_FOLDER;
+ } else if (model.getType() == 2) {
+ imageKey = ISharedImages.IMG_OBJ_FILE;
+ }
+ return PlatformUI.getWorkbench().getSharedImages().getImage(imageKey);
+ }
+
+ return null;
+ }
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/AugmentationInfo.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/AugmentationInfo.java
new file mode 100644
index 0000000..55bfbbe
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/AugmentationInfo.java
@@ -0,0 +1,5 @@
+package org.ntlab.trace;
+
+abstract public class AugmentationInfo {
+
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/FieldAccess.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/FieldAccess.java
new file mode 100644
index 0000000..28ee265
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/FieldAccess.java
@@ -0,0 +1,50 @@
+package org.ntlab.trace;
+
+public class FieldAccess extends Statement {
+ private String containerClassName;
+ private String containerObjId;
+ private String valueClassName;
+ private String valueObjId;
+ protected String thisClassName;
+ protected String thisObjId;
+
+ public FieldAccess(String valueClassName, String valueObjId, String containerClassName,
+ String containerObjId, String thisClassName, String thisObjId, String lineNo,
+ String threadNo) {
+ super(lineNo, threadNo);
+ this.containerClassName = containerClassName;
+ this.containerObjId = containerObjId;
+ this.valueClassName = valueClassName;
+ this.valueObjId = valueObjId;
+ this.thisClassName = thisClassName;
+ this.thisObjId = thisObjId;
+ }
+
+ public String getContainerClassName() {
+ return containerClassName;
+ }
+
+ public String getContainerObjId() {
+ return containerObjId;
+ }
+
+ public String getValueClassName() {
+ return valueClassName;
+ }
+
+ public String getValueObjId() {
+ return valueObjId;
+ }
+
+ public String getThisClassName() {
+ return thisClassName;
+ }
+
+ public String getThisObjId() {
+ return thisObjId;
+ }
+
+ public Reference getReference() {
+ return new Reference(containerObjId, valueObjId, containerClassName, valueClassName);
+ }
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/FieldUpdate.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/FieldUpdate.java
new file mode 100644
index 0000000..99bd99c
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/FieldUpdate.java
@@ -0,0 +1,38 @@
+package org.ntlab.trace;
+
+public class FieldUpdate extends Statement {
+
+ private String containerClassName;
+ private String containerObjId;
+ private String valueClassName;
+ private String valueObjId;
+
+ public FieldUpdate(String valueClassName, String valueObjId, String containerClassName, String containerObjId,
+ String lineNo, String threadNo) {
+ super(lineNo, threadNo);
+ this.containerClassName = containerClassName;
+ this.containerObjId = containerObjId;
+ this.valueClassName = valueClassName;
+ this.valueObjId = valueObjId;
+ }
+
+ public String getContainerClassName() {
+ return containerClassName;
+ }
+
+ public String getContainerObjId() {
+ return containerObjId;
+ }
+
+ public String getValueClassName() {
+ return valueClassName;
+ }
+
+ public String getValueObjId() {
+ return valueObjId;
+ }
+
+ public Reference getReference() {
+ return new Reference(containerObjId, valueObjId, containerClassName, valueClassName);
+ }
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/IBoundaryChecker.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/IBoundaryChecker.java
new file mode 100644
index 0000000..f5860a1
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/IBoundaryChecker.java
@@ -0,0 +1,5 @@
+package org.ntlab.trace;
+
+public interface IBoundaryChecker {
+ abstract public boolean withinBoundary(String methodSignature);
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/IMethodExecutionVisitor.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/IMethodExecutionVisitor.java
new file mode 100644
index 0000000..54d368f
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/IMethodExecutionVisitor.java
@@ -0,0 +1,10 @@
+package org.ntlab.trace;
+
+import java.util.ArrayList;
+
+public interface IMethodExecutionVisitor {
+ abstract public boolean preVisitThread(ThreadInstance thread);
+ abstract public boolean postVisitThread(ThreadInstance thread);
+ abstract public boolean preVisitMethodExecution(MethodExecution methodExecution);
+ abstract public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children);
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/IStatementVisitor.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/IStatementVisitor.java
new file mode 100644
index 0000000..aac4f2a
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/IStatementVisitor.java
@@ -0,0 +1,6 @@
+package org.ntlab.trace;
+
+public interface IStatementVisitor {
+ abstract public boolean preVisitStatement(Statement statement);
+ abstract public boolean postVisitStatement(Statement statement);
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/MethodExecution.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/MethodExecution.java
new file mode 100644
index 0000000..99b5012
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/MethodExecution.java
@@ -0,0 +1,232 @@
+package org.ntlab.trace;
+
+import interactivefeaturelocator.model.MethodInfo;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+public class MethodExecution {
+ private String signature;
+ private String callerSideSignature;
+ private String thisClassName;
+ private String thisObjId;
+ private ArrayList arguments;
+ private ObjectReference returnValue = null;
+ private boolean isConstractor;
+ private boolean isStatic;
+ private boolean isCollectionType;
+ private ArrayList statements = new ArrayList();
+ private ArrayList children = new ArrayList();
+ private MethodExecution callerMethodExecution = null;
+ private int callerStatementExecution = -1;
+ private boolean isTerminated = false;
+ private AugmentationInfo augmentation = null;
+
+ private long timeStamp = 0L;
+ public MethodExecution(String signature, String callerSideSignature,
+ String thisClassName, String thisObjId, boolean isConstractor,
+ boolean isStatic, long timeStamp) {
+ this.signature = signature;
+ this.callerSideSignature = callerSideSignature;
+ this.thisClassName = thisClassName;
+ this.thisObjId = thisObjId;
+ this.isConstractor = isConstractor;
+ this.isStatic = isStatic;
+ this.isCollectionType = false;
+ this.isTerminated = false;
+ this.timeStamp = timeStamp;
+ this.augmentation = new MethodInfo();
+ }
+
+ public void setArguments(ArrayList arguments) {
+ this.arguments = arguments;
+ }
+
+ public void setThisObjeId(String thisObjId) {
+ this.thisObjId = thisObjId;
+ }
+
+ public void setReturnValue(ObjectReference returnValue) {
+ this.returnValue = returnValue;
+ }
+
+ public void setCollectionType(boolean isCollectionType) {
+ this.isCollectionType = isCollectionType;
+ }
+
+ public void setTerminated(boolean isTerminated) {
+ this.isTerminated = isTerminated;
+ }
+
+ public String getSignature() {
+ return signature;
+ }
+
+ public String getCallerSideSignature() {
+ return callerSideSignature;
+ }
+
+ public String getThisClassName() {
+ return thisClassName;
+ }
+
+ public String getThisObjId() {
+ if (isStatic) return Trace.getNull();
+ return thisObjId;
+ }
+
+ public ArrayList getArguments() {
+ if (arguments == null) arguments = new ArrayList();
+ return arguments;
+ }
+
+ public ObjectReference getReturnValue() {
+ return returnValue;
+ }
+
+ public boolean isConstractor() {
+ return isConstractor;
+ }
+
+ public boolean isStatic() {
+ return isStatic;
+ }
+
+ public boolean isCollectionType() {
+ return isCollectionType;
+ }
+
+ public boolean isTerminated() {
+ return isTerminated;
+ }
+
+ public long getTimeStamp() {
+ return timeStamp;
+ }
+
+ public void addStatement(Statement statement) {
+ statements.add(statement);
+ if (statement instanceof MethodInvocation) {
+ children.add(((MethodInvocation)statement).getCalledMethodExecution());
+ }
+ }
+
+ public ArrayList getStatements() {
+ return statements;
+ }
+
+ public ArrayList getChildren() {
+ return children;
+ }
+
+ public void setCaller(MethodExecution callerMethodExecution, int callerStatementExecution) {
+ this.callerMethodExecution = callerMethodExecution;
+ this.callerStatementExecution = callerStatementExecution;
+ }
+
+ public MethodExecution getParent() {
+ return callerMethodExecution;
+ }
+
+ public TracePoint getEntryPoint() {
+ return new TracePoint(this, 0);
+ }
+
+ public TracePoint getExitPoint() {
+ return new TracePoint(this, statements.size() - 1);
+ }
+
+ public TracePoint getExitOutPoint() {
+ return new TracePoint(this, statements.size());
+ }
+
+ public MethodExecution getCallerMethodExecution() {
+ return callerMethodExecution;
+ }
+
+ public int getCallerStatementExecution() {
+ return callerStatementExecution;
+ }
+
+ public TracePoint getCallerTracePoint() {
+ if (callerMethodExecution == null) return null;
+ return new TracePoint(callerMethodExecution, callerStatementExecution);
+ }
+
+ /**
+ * ���̃��\�b�h���s����т��̑S�Ăяo������Ăяo���̒��ŋt�����ɒT������(�������Avisitor �� true ��Ԃ��܂�)
+ * @param visitor �r�W�^�[
+ * @return�@true -- �T���𒆒f����, false -- �Ō�܂ŒT������
+ */
+ public boolean traverseMethodExecutionsBackward(IMethodExecutionVisitor visitor) {
+ if (visitor.preVisitMethodExecution(this)) return true;
+ ArrayList calledMethodExecutions = getChildren();
+ for (int i = calledMethodExecutions.size() - 1; i >= 0; i--) {
+ MethodExecution child = calledMethodExecutions.get(i);
+ if (child.traverseMethodExecutionsBackward(visitor)) return true;
+ }
+ if (visitor.postVisitMethodExecution(this, null)) return true;
+ return false;
+ }
+
+ public void traverseMarkedMethodExecutions(IMethodExecutionVisitor visitor, long markStart, long markEnd) {
+ if (timeStamp <= markEnd) {
+ if (timeStamp >= markStart) {
+ ArrayList markedChildren = new ArrayList();
+ visitor.preVisitMethodExecution(this);
+ for (int i = 0; i < children.size(); i++) {
+ MethodExecution child = children.get(i);
+ if (child.getTimeStamp() <= markEnd) {
+ child.traverseMarkedMethodExecutions(visitor, markStart, markEnd);
+ markedChildren.add(child);
+ } else {
+ break;
+ }
+ }
+ visitor.postVisitMethodExecution(this, markedChildren);
+ } else {
+ for (int i = 0; i < children.size(); i++) {
+ MethodExecution child = children.get(i);
+ if (child.getTimeStamp() <= markEnd) {
+ child.traverseMarkedMethodExecutions(visitor, markStart, markEnd);
+ }
+ }
+ }
+ }
+ }
+
+ public void getMarkedMethodSignatures(HashSet signatures, long markStart, long markEnd) {
+ if (timeStamp <= markEnd) {
+ if (timeStamp >= markStart) {
+ signatures.add(getSignature());
+ }
+ for (int i = 0; i < children.size(); i++) {
+ MethodExecution child = children.get(i);
+ child.getMarkedMethodSignatures(signatures, markStart, markEnd);
+ }
+ }
+ }
+
+ public void getUnmarkedMethodSignatures(HashSet signatures, long markStart, long markEnd) {
+ if (timeStamp < markStart || timeStamp > markEnd) {
+ signatures.add(getSignature());
+ }
+ }
+
+ public AugmentationInfo getAugmentation() {
+ return augmentation;
+ }
+
+ public void setAugmentation(AugmentationInfo augmentation) {
+ this.augmentation = augmentation;
+ }
+
+ public String getMethodName() {
+ String signature = getSignature();
+ int n = signature.indexOf("(");
+ String str = signature.substring(0, n);
+ String[] str2 = str.split("\\.");
+ String methodName = str2[str2.length-1] + signature.substring(n);
+ return methodName;
+ }
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/MethodInvocation.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/MethodInvocation.java
new file mode 100644
index 0000000..56b2f8e
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/MethodInvocation.java
@@ -0,0 +1,27 @@
+package org.ntlab.trace;
+
+public class MethodInvocation extends Statement {
+ private MethodExecution calledMethodExecution;
+ protected String thisClassName;
+ protected String thisObjId;
+
+ public MethodInvocation(MethodExecution methodExecution, String thisClassName, String thisObjId,
+ String lineNo, String threadNo) {
+ super(lineNo, threadNo);
+ this.calledMethodExecution = methodExecution;
+ this.thisClassName = thisClassName;
+ this.thisObjId = thisObjId;
+ }
+
+ public MethodExecution getCalledMethodExecution() {
+ return calledMethodExecution;
+ }
+
+ public String getThisClassName() {
+ return thisClassName;
+ }
+
+ public String getThisObjId() {
+ return thisObjId;
+ }
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/ObjectReference.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/ObjectReference.java
new file mode 100644
index 0000000..50dc6fc
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/ObjectReference.java
@@ -0,0 +1,70 @@
+package org.ntlab.trace;
+
+public class ObjectReference {
+ private String id;
+ private String actualType = null; // ���ۂ̌^
+ private String calleeType = null; // �Ăяo���惁�\�b�h���ł̌^(�ÓI�Ɍ���ł���^)
+ private String callerType = null; // �Ăяo�������\�b�h���ł̌^(�ÓI�Ɍ���ł���^)
+
+ public ObjectReference(String id) {
+ this.id = id;
+ this.actualType = null;
+ }
+
+ public ObjectReference(String id, String actualType) {
+ this.id = id;
+ this.actualType = actualType;
+ }
+
+ public ObjectReference(String id, String actualType, String calleeType) {
+ this.id = id;
+ this.actualType = actualType;
+ this.calleeType = calleeType;
+ }
+
+ public ObjectReference(String id, String actualType, String calleeType, String callerType) {
+ this.id = id;
+ this.actualType = actualType;
+ this.calleeType = calleeType;
+ this.callerType = callerType;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getActualType() {
+ return actualType;
+ }
+
+ public String getCalleeType() {
+ return calleeType;
+ }
+
+ public String getCallerType() {
+ return callerType;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public void setActualType(String actualType) {
+ this.actualType = actualType;
+ }
+
+ public void setCalleeType(String calleeType) {
+ this.calleeType = calleeType;
+ }
+
+ public void setCallerType(String callerType) {
+ this.callerType = callerType;
+ }
+
+ public boolean equals(Object other) {
+ if (this == other) return true;
+ if (!(other instanceof ObjectReference)) return false;
+ if (id != null && id.equals(((ObjectReference)other).id)) return true;
+ return false;
+ }
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/Reference.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/Reference.java
new file mode 100644
index 0000000..ac61644
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/Reference.java
@@ -0,0 +1,119 @@
+package org.ntlab.trace;
+
+public class Reference {
+ private String id;
+ private ObjectReference srcObj; // �Q�ƌ��I�u�W�F�N�g
+ private ObjectReference dstObj; // �Q�Ɛ�I�u�W�F�N�g
+ private boolean bCreation = false; // �Q�ƌ��I�u�W�F�N�g���Q�Ɛ�I�u�W�F�N�g��������?
+ private boolean bArray = false; // �Q�ƌ��I�u�W�F�N�g���z��ŎQ�Ɛ�I�u�W�F�N�g��v�f�Ƃ��ĕێ����Ă��邩?
+ private boolean bCollection = false; // �Q�ƌ��I�u�W�F�N�g���R���N�V�����ŎQ�Ɛ�I�u�W�F�N�g��v�f�Ƃ��ĕێ����Ă��邩?
+ private boolean bFinalLocal = false; // �Q�ƌ��I�u�W�F�N�g�������܂��͓����N���X�̂Ƃ��Q�Ɛ�I�u�W�F�N�g���O���N���X�� final local �ϐ��Ƃ��ĎQ�Ƃ��Ă��邩?
+
+ public Reference(String srcObjectId, String dstObjectId, String srcClassName,
+ String dstClassName) {
+ srcObj = new ObjectReference(srcObjectId, srcClassName);
+ dstObj = new ObjectReference(dstObjectId, dstClassName);
+ }
+
+ public Reference(ObjectReference srcObj, ObjectReference dstObj) {
+ this.srcObj = srcObj;
+ this.dstObj = dstObj;
+ }
+
+ public ObjectReference getSrcObject() {
+ return srcObj;
+ }
+
+ public ObjectReference getDstObject() {
+ return dstObj;
+ }
+
+ public void setSrcClassName(String srcClassName) {
+ this.srcObj.setActualType(srcClassName);
+ }
+
+ public void setDstClassName(String dstClassName) {
+ this.dstObj.setActualType(dstClassName);
+ }
+
+ public void setSrcObjectId(String srcObjectId) {
+ this.srcObj.setId(srcObjectId);
+ }
+
+ public void setDstObjectId(String dstObjectId) {
+ this.dstObj.setId(dstObjectId);
+ }
+
+ public String getSrcClassName() {
+ return srcObj.getActualType();
+ }
+
+ public String getDstClassName() {
+ return dstObj.getActualType();
+ }
+
+ public String getSrcObjectId() {
+ return srcObj.getId();
+ }
+
+ public String getDstObjectId() {
+ return dstObj.getId();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public void setCreation(boolean bCreation) {
+ this.bCreation = bCreation;
+ }
+
+ public boolean isCreation(){
+ return bCreation;
+ }
+
+ public void setArray(boolean bArray) {
+ this.bArray = bArray;
+ }
+
+ public boolean isArray() {
+ return bArray;
+ }
+
+ public void setCollection(boolean bCollection) {
+ this.bCollection = bCollection;
+ }
+
+ public boolean isCollection() {
+ return bCollection;
+ }
+
+ public void setFinalLocal(boolean bFinalLocal) {
+ this.bFinalLocal = bFinalLocal;
+ }
+
+ public boolean isFinalLocal() {
+ return bFinalLocal;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o instanceof Reference) {
+ if (this.hashCode() != o.hashCode()) return false;
+ return (this.srcObj.getId().equals(((Reference)o).srcObj.getId()) && this.dstObj.getId().equals(((Reference)o).dstObj.getId()));
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ return Integer.parseInt(srcObj.getId()) + Integer.parseInt(dstObj.getId());
+ }
+
+ public String toString() {
+ return srcObj.getId() + "(" + srcObj.getActualType() + ")" + "->" + dstObj.getId() + "(" + dstObj.getActualType() + ")";
+ }
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/SoftwareReconnaissance.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/SoftwareReconnaissance.java
new file mode 100644
index 0000000..8e92d69
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/SoftwareReconnaissance.java
@@ -0,0 +1,16 @@
+package org.ntlab.trace;
+
+import java.util.HashSet;
+
+public class SoftwareReconnaissance {
+
+ public HashSet result(HashSet plus, HashSet minus) {
+ HashSet result = new HashSet(plus);
+ result.removeAll(minus);
+ System.out.println("===== Software Reconnaissance =====");
+ for (String method: result) {
+ System.out.println(method);
+ }
+ return result;
+ }
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/Statement.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/Statement.java
new file mode 100644
index 0000000..9d40b3a
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/Statement.java
@@ -0,0 +1,20 @@
+package org.ntlab.trace;
+
+public class Statement {
+ protected String lineNo;
+ protected String threadNo;
+
+ public Statement(String lineNo, String threadNo) {
+ this.lineNo = lineNo;
+ this.threadNo = threadNo;
+ }
+
+ public String getLineNo() {
+ return lineNo;
+ }
+
+ public String getThreadNo() {
+ return threadNo;
+ }
+
+}
\ No newline at end of file
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/TestTrace.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/TestTrace.java
new file mode 100644
index 0000000..c7c6315
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/TestTrace.java
@@ -0,0 +1,128 @@
+package org.ntlab.trace;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+
+public class TestTrace {
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args) {
+ Trace tracePlus = new Trace("documents\\1593375.trace");
+ Trace traceMinus = new Trace("documents\\1593375-.trace");
+// HashSet marked = tracePlus.getMarkedMethodSignatures(1255991806833871L, 1255991808597322L);
+// System.out.println("===== Marked Methods =====");
+// for (String method: marked) {
+// System.out.println(method);
+// }
+// HashSet unmarked = tracePlus.getUnmarkedMethodSignatures(1255991806833871L, 1255991808597322L);
+// System.out.println("===== Unmarked Methods =====");
+// for (String method: unmarked) {
+// System.out.println(method);
+// }
+
+/*
+ * ����������
+ *
+===== Marked Methods =====
+void worstCase.O.passL(worstCase.L)
+worstCase.L worstCase.I.getL()
+worstCase.L worstCase.K.getL()
+worstCase.M worstCase.L.getM()
+worstCase.K worstCase.J.getK()
+void worstCase.N.passI(worstCase.I)
+void worstCase.P.setM(worstCase.M)
+===== Unmarked Methods =====
+worstCase.F worstCase.C.getF()
+worstCase.E worstCase.D.getE()
+worstCase.A()
+public worstCase.M()
+worstCase.F()
+void worstCase.A.m()
+public static void worstCase.main.main(java.lang.String[])
+worstCase.G()
+worstCase.H()
+worstCase.I()
+worstCase.B()
+worstCase.C()
+worstCase.D()
+worstCase.E()
+worstCase.N()
+worstCase.O()
+worstCase.P()
+worstCase.F worstCase.E.getF()
+worstCase.J()
+worstCase.K()
+worstCase.L()
+worstCase.I worstCase.F.getI()
+worstCase.H worstCase.G.getH()
+worstCase.I worstCase.H.getI()
+worstCase.I worstCase.B.getI()
+ */
+ HashSet allPlus = tracePlus.getAllMethodSignatures();
+ HashSet allMinus = traceMinus.getAllMethodSignatures();
+ System.out.println("===== AllPlus Methods =====");
+ for (String method: allPlus) {
+ System.out.println(method);
+ }
+ System.out.println("===== AllMinus Methods =====");
+ for (String method: allMinus) {
+ System.out.println(method);
+ }
+ SoftwareReconnaissance sr = new SoftwareReconnaissance();
+ sr.result(allPlus, allMinus);
+/*
+ * ����������
+ *
+===== All Methods =====
+worstCase.F worstCase.C.getF()
+worstCase.E worstCase.D.getE()
+worstCase.A()
+void worstCase.P.setM(worstCase.M)
+public worstCase.M()
+worstCase.M worstCase.L.getM()
+worstCase.L worstCase.I.getL()
+worstCase.L worstCase.K.getL()
+void worstCase.N.passI(worstCase.I)
+void worstCase.A.m()
+worstCase.F()
+public static void worstCase.main.main(java.lang.String[])
+worstCase.G()
+void worstCase.O.passL(worstCase.L)
+worstCase.H()
+worstCase.I()
+worstCase.B()
+worstCase.C()
+worstCase.D()
+worstCase.E()
+worstCase.N()
+worstCase.O()
+worstCase.K worstCase.J.getK()
+worstCase.F worstCase.E.getF()
+worstCase.P()
+worstCase.J()
+worstCase.K()
+worstCase.I worstCase.F.getI()
+worstCase.I worstCase.H.getI()
+worstCase.H worstCase.G.getH()
+worstCase.L()
+worstCase.I worstCase.B.getI()
+ */
+
+// ArrayList specified = tracePlus.getMethodExecutions("void");
+// System.out.println("===== Specified Methods =====");
+// for (MethodExecution method: specified) {
+// System.out.println(method.getSignature());
+// }
+ }
+/*
+ * ����������
+ *
+===== Specified Methods =====
+void worstCase.A.m()
+void worstCase.N.passI(worstCase.I)
+void worstCase.O.passL(worstCase.L)
+void worstCase.P.setM(worstCase.M) *
+ */
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/ThreadInstance.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/ThreadInstance.java
new file mode 100644
index 0000000..f994c00
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/ThreadInstance.java
@@ -0,0 +1,103 @@
+package org.ntlab.trace;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+
+public class ThreadInstance {
+ private ArrayList roots = new ArrayList();
+ private MethodExecution curMethodExecution = null;
+ private String id;
+
+ public ThreadInstance(String id) {
+ this.id = id;
+ }
+
+ public void addRoot(MethodExecution root) {
+ this.roots.add(root);
+ curMethodExecution = root;
+ }
+
+ public ArrayList getRoot() {
+ return roots;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void callMethod(String signature, String callerSideSignature, String receiverClassName, String receiverObjId,
+ boolean isConstractor, boolean isStatic, String lineNo, long timeStamp) {
+ MethodExecution newMethodExecution = new MethodExecution(signature, callerSideSignature, receiverClassName, receiverObjId, isConstractor, isStatic, timeStamp);
+ if (curMethodExecution != null) {
+ curMethodExecution.addStatement(new MethodInvocation(newMethodExecution, curMethodExecution.getThisClassName(), curMethodExecution.getThisObjId(), lineNo, id));
+ newMethodExecution.setCaller(curMethodExecution, curMethodExecution.getStatements().size() - 1);
+ curMethodExecution = newMethodExecution;
+ } else {
+ addRoot(newMethodExecution);
+ }
+ }
+
+ public void setArgments(ArrayList arguments) {
+ curMethodExecution.setArguments(arguments);
+ }
+
+ public void returnMethod(ObjectReference returnValue, String thisObjId, boolean isCollectionType) {
+ if (curMethodExecution == null) return;
+ curMethodExecution.setReturnValue(returnValue);
+ if (curMethodExecution.getThisObjId().equals("0")) {
+ curMethodExecution.setThisObjeId(thisObjId);
+ }
+ curMethodExecution.setCollectionType(isCollectionType);
+ curMethodExecution = curMethodExecution.getParent();
+ }
+
+ public void terminateMethod() {
+ if (curMethodExecution == null) return;
+ curMethodExecution.setTerminated(true);
+ curMethodExecution = curMethodExecution.getParent();
+ }
+
+ public void fieldAccess(String valueClassName, String valueObjId, String containerClassName, String containerObjId, String thisClassName, String thisId, String lineNo, String threadNo) {
+ FieldAccess fieldAccess = new FieldAccess(valueClassName, valueObjId, containerClassName, containerObjId, thisClassName, thisId, lineNo, threadNo);
+ if (curMethodExecution != null) curMethodExecution.addStatement(fieldAccess);
+ }
+
+ public void fieldUpdate(String valueClassName, String valueObjId, String containerClassName, String containerObjId, String lineNo, String threadNo) {
+ FieldUpdate fieldUpdate = new FieldUpdate(valueClassName, valueObjId, containerClassName, containerObjId, lineNo, threadNo);
+ if (curMethodExecution != null) curMethodExecution.addStatement(fieldUpdate);
+ }
+
+ public void traverseMethodExecutionsBackward(IMethodExecutionVisitor visitor) {
+ visitor.preVisitThread(this);
+ for (int i = 0; i < roots.size(); i++) {
+ MethodExecution root = roots.get(i);
+ root.traverseMethodExecutionsBackward(visitor);
+ }
+ visitor.postVisitThread(this);
+ }
+
+ public void traverseMarkedMethodExecutions(IMethodExecutionVisitor visitor, long markStart, long markEnd) {
+ visitor.preVisitThread(this);
+ for (int i = 0; i < roots.size(); i++) {
+ MethodExecution root = roots.get(i);
+ if (root.getTimeStamp() <= markEnd) {
+ root.traverseMarkedMethodExecutions(visitor, markStart, markEnd);
+ } else {
+ break;
+ }
+ }
+ visitor.postVisitThread(this);
+ }
+
+ public void getUnmarkedMethodSignatures(HashSet signatures, long markStart, long markEnd) {
+ for (int i = 0; i < roots.size(); i++) {
+ MethodExecution root = roots.get(i);
+ root.getUnmarkedMethodSignatures(signatures, markStart, markEnd);
+ }
+ }
+
+ public MethodExecution getCuurentMethodExecution() {
+ return curMethodExecution;
+ }
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/Trace.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/Trace.java
new file mode 100644
index 0000000..e9faff5
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/Trace.java
@@ -0,0 +1,940 @@
+package org.ntlab.trace;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Stack;
+
+public class Trace {
+ private static final boolean EAGER_DETECTION_OF_ARRAY_SET = false; // �z��v�f�ւ̑���̌��o�𑽂����ς��邩?(�������ς����False Positive�ɂȂ�\��������)
+
+ private HashMap threads = new HashMap();
+ private String fileName = null;
+
+ public Trace(String traceFile) {
+ BufferedReader file;
+ try {
+ file = new BufferedReader(new FileReader(traceFile));
+ // �g���[�X�t�@�C���ǂݍ���
+ String line, prevLine = null;
+ String signature;
+ String callerSideSignature;
+ String threadNo = null;
+ String[] methodData;
+ String[] argData;
+ String[] returnData;
+ String[] accessData;
+ String[] updateData;
+ String thisObjectId;
+ String thisClassName;
+ boolean isConstractor = false;
+ boolean isCollectionType = false;
+ boolean isStatic = false;
+ long timeStamp = 0L;
+ ThreadInstance thread = null;
+ HashMap> stacks = new HashMap>();
+ String[] fragments = traceFile.split("\\\\");
+ setFileName(fragments[fragments.length-1]);
+ while ((line = file.readLine()) != null) {
+ // �g���[�X�t�@�C���̉��
+ if (line.startsWith("Method")) {
+ // ���\�b�h�Ăяo���i�R���X�g���N�^�Ăяo�����܂ށj
+ methodData = line.split(":");
+ int n = methodData[0].indexOf(',');
+ signature = methodData[0].substring(n + 1);
+ threadNo = methodData[methodData.length - 1].split(" ")[1];
+ thisObjectId = methodData[1];
+ thisClassName = methodData[0].substring(0, n).split(" ")[1];
+ isConstractor = false;
+ isStatic = false;
+ if (signature.contains("static ")) {
+ isStatic = true;
+ }
+ callerSideSignature = signature;
+ timeStamp = Long.parseLong(methodData[methodData.length - 2]);
+ if (prevLine != null) {
+ if (prevLine.startsWith("New")) {
+ isConstractor = true;
+ } else if (prevLine.startsWith("Invoke")) {
+ callerSideSignature = prevLine.split(":")[1];
+ }
+ }
+ thread = threads.get(threadNo);
+ Stack stack;
+ if (thread == null) {
+ thread = new ThreadInstance(threadNo);
+ threads.put(threadNo, thread);
+ stack = new Stack();
+ stacks.put(threadNo, stack);
+ } else {
+ stack = stacks.get(threadNo);
+ }
+ stack.push(line);
+ thread.callMethod(signature, callerSideSignature, thisClassName, thisObjectId, isConstractor, isStatic, null, timeStamp);
+ } else if (line.startsWith("Args")) {
+ // ���\�b�h�Ăяo���̈���
+ argData = line.split(":");
+ threadNo = argData[argData.length - 1].split(" ")[1];
+ thread = threads.get(threadNo);
+ ArrayList arguments = new ArrayList();
+ for (int k = 1; k < argData.length - 2; k += 2) {
+ arguments.add(new ObjectReference(argData[k+1], argData[k]));
+ }
+ thread.setArgments(arguments);
+ } else if (line.startsWith("Return")) {
+ // ���\�b�h����̕��A
+ returnData = line.split(":");
+ threadNo = returnData[returnData.length - 1].split(" ")[1];
+ Stack stack = stacks.get(threadNo);
+ if (stack != null && !stack.isEmpty()) {
+ String line2 = stack.peek();
+ if (line2.split("\\(")[0].endsWith(line.split("\\(")[1])) {
+ stack.pop();
+ } else {
+ do {
+ line2 = stack.pop();
+ thread.terminateMethod();
+ } while (!stack.isEmpty() && !line2.split("\\(")[0].endsWith(line.split("\\(")[1]));
+ }
+ thread = threads.get(threadNo);
+ ObjectReference returnValue = new ObjectReference(returnData[2], returnData[1]);
+ thisObjectId = returnData[2];
+ isCollectionType = false;
+ String curLine = returnData[0];
+ if(curLine.contains("Return call(List")
+ || curLine.contains("Return call(Vector")
+ || curLine.contains("Return call(Iterator")
+ || curLine.contains("Return call(ListIterator")
+ || curLine.contains("Return call(ArrayList")
+ || curLine.contains("Return call(Stack")
+ || curLine.contains("Return call(Hash")
+ || curLine.contains("Return call(Map")
+ || curLine.contains("Return call(Set")
+ || curLine.contains("Return call(Linked")
+ || curLine.contains("Return call(Thread")) {
+ isCollectionType = true;
+ }
+ thread.returnMethod(returnValue, thisObjectId, isCollectionType);
+ }
+ } else if (line.startsWith("get")) {
+ // �t�B�[���h�A�N�Z�X
+ accessData = line.split(":");
+ threadNo = accessData[8].split(" ")[1];
+ thread = threads.get(threadNo);
+ if (thread != null) thread.fieldAccess(accessData[5], accessData[6], accessData[3], accessData[4], accessData[1], accessData[2],
+ null, threadNo);
+ } else if (line.startsWith("set")) {
+ // �t�B�[���h�X�V
+ updateData = line.split(":");
+ threadNo = updateData[6].split(" ")[1];
+ thread = threads.get(threadNo);
+ if (thread != null) thread.fieldUpdate(updateData[3], updateData[4], updateData[1], updateData[2], null, threadNo);
+ }
+ prevLine = line;
+ }
+ file.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * �w�肵���X���b�h��Ō��ݎ��s���̃��\�b�h���s���擾����(�I�����C����͗p)
+ * @param thread �ΏۃX���b�h
+ * @return thread ��Ō��ݎ��s���̃��\�b�h���s
+ */
+ public MethodExecution getCurrentMethodExecution(Thread thread) {
+ ThreadInstance t = threads.get(thread.getId());
+ return t.getCuurentMethodExecution();
+ }
+
+ /**
+ * methodSignature �ɑO����v���郁�\�b�h���������\�b�h�̍Ō�̎��s
+ * @param methodSignature ���\�b�h��(�O����v��������)
+ * @return �Y������Ō�̃��\�b�h���s
+ */
+ public MethodExecution getLastMethodExecution(final String methodSignature) {
+ return traverseMethodEntriesInTraceBackward(new IMethodExecutionVisitor() {
+ @Override
+ public boolean preVisitThread(ThreadInstance thread) { return false; }
+ @Override
+ public boolean postVisitThread(ThreadInstance thread) { return false; }
+ @Override
+ public boolean preVisitMethodExecution(MethodExecution methodExecution) { return false; }
+ @Override
+ public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) {
+ if (methodExecution.getSignature().startsWith(methodSignature)) return true;
+ return false;
+ }
+ });
+ }
+
+ public MethodExecution traverseMethodEntriesInTraceBackward(IMethodExecutionVisitor visitor) {
+ HashMap> threadRoots = new HashMap>();
+ HashMap threadLastPoints = new HashMap();
+ Iterator threadsIterator = threads.keySet().iterator();
+ // �e�X���b�h�ɂ����Ĉ�ԍŌ�ɊJ�n�������\�b�h���s��T��
+ long traceLastTime = 0;
+ String traceLastThread = null;
+ long traceLastTime2 = 0;
+ String traceLastThread2 = null;
+ for (; threadsIterator.hasNext();) {
+ String threadId = threadsIterator.next();
+ ThreadInstance thread = threads.get(threadId);
+ ArrayList rootExecutions = (ArrayList)thread.getRoot().clone();
+ threadRoots.put(threadId, rootExecutions);
+ TracePoint threadLastTp = getLastMethodEntryInThread(rootExecutions);
+ threadLastPoints.put(threadId, threadLastTp);
+ if (threadLastTp != null) {
+ long threadLastTime = threadLastTp.getMethodExecution().getTimeStamp();
+ if (traceLastTime < threadLastTime) {
+ traceLastTime2 = traceLastTime;
+ traceLastThread2 = traceLastThread;
+ traceLastTime = threadLastTime;
+ traceLastThread = threadId;
+ }
+ }
+ }
+ return traverseMethodEntriesInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2);
+ }
+
+ /**
+ * methodSignature �ɑO����v���郁�\�b�h���������\�b�h�� before �ȑO�̍Ō�̎��s
+ * @param methodSignature ���\�b�h��(�O����v��������)
+ * @param before�@�T���J�n�g���[�X�|�C���g(������ȑO��T��)
+ * @return�@�Y������Ō�̃��\�b�h���s
+ */
+ public MethodExecution getLastMethodExecution(final String methodSignature, TracePoint before) {
+ return traverseMethodEntriesInTraceBackward(new IMethodExecutionVisitor() {
+ @Override
+ public boolean preVisitThread(ThreadInstance thread) { return false; }
+ @Override
+ public boolean postVisitThread(ThreadInstance thread) { return false; }
+ @Override
+ public boolean preVisitMethodExecution(MethodExecution methodExecution) { return false; }
+ @Override
+ public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) {
+ if (methodExecution.getSignature().startsWith(methodSignature)) return true;
+ return false;
+ }
+ }, before);
+ }
+
+ public MethodExecution traverseMethodEntriesInTraceBackward(IMethodExecutionVisitor visitor, TracePoint before) {
+ HashMap> threadRoots = new HashMap>();
+ HashMap threadLastPoints = new HashMap();
+ Iterator threadsIterator = threads.keySet().iterator();
+ String traceLastThread = null;
+ long traceLastTime2 = 0;
+ String traceLastThread2 = null;
+ ThreadInstance thread = threads.get(before.getStatement().getThreadNo());
+ ArrayList rootExecutions = (ArrayList)thread.getRoot().clone();
+ for (int n = rootExecutions.size() - 1; n >= 0; n--) {
+ MethodExecution root = rootExecutions.get(n);
+ if (root.getTimeStamp() > before.getMethodExecution().getTimeStamp()) {
+ rootExecutions.remove(n);
+ } else {
+ break;
+ }
+ }
+ if (rootExecutions.size() > 0) {
+ rootExecutions.remove(rootExecutions.size() - 1);
+ }
+ before = getLastMethodEntryInThread(rootExecutions, before);
+ for (; threadsIterator.hasNext();) {
+ String threadId = threadsIterator.next();
+ ThreadInstance t = threads.get(threadId);
+ if (t == thread) {
+ threadRoots.put(threadId, rootExecutions);
+ traceLastThread = threadId;
+ threadLastPoints.put(threadId, before);
+ } else {
+ ArrayList rootExes = (ArrayList)t.getRoot().clone();
+ threadRoots.put(threadId, rootExes);
+ MethodExecution threadLastExecution = rootExes.remove(rootExes.size() - 1);
+ TracePoint threadBeforeTp = getLastMethodEntryInThread(rootExes, threadLastExecution.getExitOutPoint(), before.getMethodExecution().getTimeStamp());
+ threadLastPoints.put(threadId, threadBeforeTp);
+ if (threadBeforeTp != null) {
+ long threadLastTime = threadBeforeTp.getMethodExecution().getTimeStamp();
+ if (traceLastTime2 < threadLastTime) {
+ traceLastTime2 = threadLastTime;
+ traceLastThread2 = threadId;
+ }
+ }
+ }
+ }
+ return traverseMethodEntriesInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2);
+ }
+
+ private MethodExecution traverseMethodEntriesInTraceBackwardSub(
+ final IMethodExecutionVisitor visitor,
+ HashMap> threadRoots, HashMap threadLastPoints,
+ String traceLastThread, String traceLastThread2, long traceLastTime2) {
+ // �S�X���b�h�̓������Ƃ�Ȃ���t�����Ƀ��\�b�h���s��T������
+ for (;;) {
+ // �T���Ώۂ̃X���b�h���̋t�����T��
+ TracePoint threadLastTp = threadLastPoints.get(traceLastThread);
+ MethodExecution threadLastExecution = threadLastTp.getMethodExecution();
+ do {
+ threadLastTp.stepBackOver();
+ // ���̃X���b�h�̎��̃��\�b�h���s�J�n���_�܂ŒT������
+ threadLastTp = getLastMethodEntryInThread(threadRoots.get(traceLastThread), threadLastTp);
+ if (threadLastTp == null) break;
+ if (visitor.postVisitMethodExecution(threadLastExecution, threadLastExecution.getChildren())) {
+ // �Y�����郁�\�b�h���s��������
+ return threadLastExecution;
+ }
+ threadLastExecution = threadLastTp.getMethodExecution();
+ } while (threadLastExecution.getTimeStamp() > traceLastTime2);
+ threadLastPoints.put(traceLastThread, threadLastTp);
+ traceLastThread = traceLastThread2;
+ // ���̎��ɒT�����ׂ��X���b�h(���T���̗̈悪��ԍŌ�܂Ŏc���Ă���X���b�h)�����肷��
+ traceLastTime2 = 0;
+ traceLastThread2 = null;
+ boolean continueTraverse = false;
+ Iterator threadIterator = threadLastPoints.keySet().iterator();
+ for (; threadIterator.hasNext();) {
+ String threadId = threadIterator.next();
+ if (!threadId.equals(traceLastThread)) {
+ TracePoint lastTp = threadLastPoints.get(threadId);
+ if (lastTp != null) {
+ continueTraverse = true;
+ long threadLastTime = lastTp.getMethodExecution().getTimeStamp();
+ if (traceLastTime2 < threadLastTime) {
+ traceLastTime2 = threadLastTime;
+ traceLastThread2 = threadId;
+ }
+ }
+ }
+ }
+ if (!continueTraverse && threadLastPoints.get(traceLastThread) == null) break;
+ }
+ return null;
+ }
+
+ /**
+ * ���\�b�h���� methodSignature�@�ɑO����v���郁�\�b�h���s��S�ẴX���b�h������o��
+ * @param methodSignature ����������
+ * @return ��v�����S���\�b�h���s
+ */
+ public ArrayList getMethodExecutions(final String methodSignature) {
+ Iterator threadsIterator = threads.keySet().iterator();
+ final ArrayList results = new ArrayList();
+ for (; threadsIterator.hasNext();) {
+ ThreadInstance thread = threads.get(threadsIterator.next());
+ thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() {
+ @Override
+ public boolean preVisitThread(ThreadInstance thread) {
+ return false;
+ }
+ @Override
+ public boolean preVisitMethodExecution(MethodExecution methodExecution) {
+ if (methodExecution.getSignature().startsWith(methodSignature)) {
+ results.add(methodExecution);
+ }
+ return false;
+ }
+ @Override
+ public boolean postVisitThread(ThreadInstance thread) {
+ return false;
+ }
+ @Override
+ public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) {
+ return false;
+ }
+ });
+ }
+ return results;
+ }
+
+ /**
+ * �Ăяo�����̎����� markStart ���� markEnd �̊Ԃɂ���S�X���b�h���̑S���\�b�h���s��T������
+ * @param visitor�@�r�W�^�[
+ * @param markStart �J�n����
+ * @param markEnd �I������
+ */
+ public void traverseMarkedMethodExecutions(IMethodExecutionVisitor visitor, long markStart, long markEnd) {
+ Iterator threadsIterator = threads.keySet().iterator();
+ for (; threadsIterator.hasNext();) {
+ ThreadInstance thread = threads.get(threadsIterator.next());
+ thread.traverseMarkedMethodExecutions(visitor, markStart, markEnd);
+ }
+ }
+
+ /**
+ * �S���\�b�h�̃V�O�j�`�����擾����
+ * @return �S���\�b�h�V�O�j�`��
+ */
+ public HashSet getAllMethodSignatures() {
+ final HashSet signatures = new HashSet();
+ Iterator threadsIterator = threads.keySet().iterator();
+ for (; threadsIterator.hasNext();) {
+ ThreadInstance thread = threads.get(threadsIterator.next());
+ thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() {
+ @Override
+ public boolean preVisitThread(ThreadInstance thread) {
+ return false;
+ }
+ @Override
+ public boolean postVisitThread(ThreadInstance thread) {
+ return false;
+ }
+ @Override
+ public boolean preVisitMethodExecution(MethodExecution methodExecution) {
+ signatures.add(methodExecution.getSignature());
+ return false;
+ }
+ @Override
+ public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) {
+ return false;
+ }
+ });
+ }
+ return signatures;
+ }
+
+ /**
+ * �}�[�N���Ŏ��s���J�n���ꂽ�S���\�b�h�̃V�O�j�`�����擾����
+ * @param markStart �}�[�N�̊J�n����
+ * @param markEnd �}�[�N�̏I������
+ * @return �Y�����郁�\�b�h�V�O�j�`��
+ */
+ public HashSet getMarkedMethodSignatures(final long markStart, final long markEnd) {
+ final HashSet signatures = new HashSet();
+ Iterator threadsIterator = threads.keySet().iterator();
+ for (; threadsIterator.hasNext();) {
+ ThreadInstance thread = threads.get(threadsIterator.next());
+ thread.traverseMarkedMethodExecutions(new IMethodExecutionVisitor() {
+ @Override
+ public boolean preVisitThread(ThreadInstance thread) {
+ return false;
+ }
+ @Override
+ public boolean postVisitThread(ThreadInstance thread) {
+ return false;
+ }
+ @Override
+ public boolean preVisitMethodExecution(MethodExecution methodExecution) {
+ signatures.add(methodExecution.getSignature());
+ return false;
+ }
+ @Override
+ public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) {
+ return false;
+ }
+ }, markStart, markEnd);
+ }
+ return signatures;
+ }
+
+ /**
+ * �}�[�N�O�Ŏ��s���J�n���ꂽ�S���\�b�h�̃V�O�j�`�����擾����
+ * @param markStart �}�[�N�̊J�n����
+ * @param markEnd �}�[�N�̏I������
+ * @return �Y�����郁�\�b�h�V�O�j�`��
+ */
+ public HashSet getUnmarkedMethodSignatures(long markStart, long markEnd) {
+ HashSet signatures = new HashSet();
+ Iterator threadsIterator = threads.keySet().iterator();
+ for (; threadsIterator.hasNext();) {
+ ThreadInstance thread = threads.get(threadsIterator.next());
+ thread.getUnmarkedMethodSignatures(signatures, markStart, markEnd);
+ }
+ return signatures;
+ }
+
+ public TracePoint traverseStatementsInTraceBackward(IStatementVisitor visitor) {
+ HashMap> threadRoots = new HashMap>();
+ HashMap threadLastPoints = new HashMap();
+ Iterator threadsIterator = threads.keySet().iterator();
+ // �e�X���b�h�ɂ����Ĉ�ԍŌ�ɊJ�n�������\�b�h���s��T��
+ long traceLastTime = 0;
+ String traceLastThread = null;
+ long traceLastTime2 = 0;
+ String traceLastThread2 = null;
+ for (; threadsIterator.hasNext();) {
+ String threadId = threadsIterator.next();
+ ThreadInstance thread = threads.get(threadId);
+ ArrayList root = (ArrayList)thread.getRoot().clone();
+ threadRoots.put(threadId, root);
+ TracePoint threadLastTp;
+ do {
+ MethodExecution threadLastExecution = root.remove(root.size() - 1);
+ threadLastTp = threadLastExecution.getExitPoint();
+ } while (!threadLastTp.isValid() && root.size() > 0);
+ if (threadLastTp.isValid()) {
+ threadLastPoints.put(threadId, threadLastTp);
+ if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, threadLastTp)) return threadLastTp;
+ long methodEntry = threadLastTp.getMethodExecution().getTimeStamp();
+ if (traceLastTime < methodEntry) {
+ traceLastTime2 = traceLastTime;
+ traceLastThread2 = traceLastThread;
+ traceLastTime = methodEntry;
+ traceLastThread = threadId;
+ }
+ } else {
+ threadLastPoints.put(threadId, null);
+ }
+ }
+ return traverseStatementsInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2);
+ }
+
+ public TracePoint traverseStatementsInTraceBackward(IStatementVisitor visitor, TracePoint before) {
+ if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, before)) return before;
+ HashMap> threadRoots = new HashMap>();
+ HashMap threadLastPoints = new HashMap();
+ Iterator threadsIterator = threads.keySet().iterator();
+ String traceLastThread = null;
+ long traceLastTime2 = 0;
+ String traceLastThread2 = null;
+ ThreadInstance thread = threads.get(before.getStatement().getThreadNo());
+ for (; threadsIterator.hasNext();) {
+ String threadId = threadsIterator.next();
+ ThreadInstance t = threads.get(threadId);
+ ArrayList rootExecutions = (ArrayList)t.getRoot().clone();
+ threadRoots.put(threadId, rootExecutions);
+ if (t == thread) {
+ traceLastThread = threadId;
+ threadLastPoints.put(threadId, before);
+ for (int n = rootExecutions.size() - 1; n >= 0; n--) {
+ MethodExecution root = rootExecutions.get(n);
+ if (root.getTimeStamp() > before.getMethodExecution().getTimeStamp()) {
+ rootExecutions.remove(n);
+ } else {
+ break;
+ }
+ }
+ if (rootExecutions.size() > 0) {
+ rootExecutions.remove(rootExecutions.size() - 1);
+ }
+ } else {
+ MethodExecution threadLastExecution = rootExecutions.remove(rootExecutions.size() - 1);
+ TracePoint threadBeforeTp = getLastMethodEntryInThread(rootExecutions, threadLastExecution.getExitOutPoint(), before.getMethodExecution().getTimeStamp());
+ threadLastPoints.put(threadId, threadBeforeTp);
+ if (threadBeforeTp != null) {
+ long threadLastTime = threadBeforeTp.getMethodExecution().getTimeStamp();
+ if (traceLastTime2 < threadLastTime) {
+ traceLastTime2 = threadLastTime;
+ traceLastThread2 = threadId;
+ }
+ }
+ }
+ }
+ return traverseStatementsInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2);
+ }
+
+ private TracePoint traverseStatementsInTraceBackwardSub(IStatementVisitor visitor,
+ HashMap> threadRoots,
+ HashMap threadLastPoints,
+ String traceLastThread, String traceLastThread2, long traceLastTime2) {
+ // �S�X���b�h�̓������Ƃ�Ȃ���t�����Ɏ��s����T������
+ for (;;) {
+ // �T���Ώۂ̃X���b�h���̋t�����T��
+ TracePoint lastTp = threadLastPoints.get(traceLastThread);
+ do {
+ if (lastTp.stepBackOver()) {
+ // ���̃X���b�h�̎��̃��\�b�h���s�J�n���_�܂ŒT������
+ if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, lastTp)) return lastTp;
+ } else {
+ // �Ăяo�����ɖ߂����ꍇ
+ if (!lastTp.isValid()) {
+ // �Ăяo���̊J�n���_�܂ŒT�����I�����ꍇ
+ ArrayList root = threadRoots.get(traceLastThread);
+ while (!lastTp.isValid() && root.size() > 0) {
+ // ���̌Ăяo�������������Ōォ��T��
+ MethodExecution lastExecution = root.remove(root.size() - 1);
+ lastTp = lastExecution.getExitPoint();
+ }
+ if (lastTp.isValid()) {
+ // ���̌Ăяo�������������Ōォ��T��
+ threadLastPoints.put(traceLastThread, lastTp);
+ if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, lastTp)) return lastTp;
+ } else {
+ // ���̃X���b�h�̒T�������ׂďI�������ꍇ
+ threadLastPoints.put(traceLastThread, null);
+ break;
+ }
+ }
+ }
+ } while (lastTp.getMethodExecution().getTimeStamp() > traceLastTime2);
+ traceLastThread = traceLastThread2;
+ // ���̎��ɒT�����ׂ��X���b�h(���T���̗̈悪��ԍŌ�܂Ŏc���Ă���X���b�h)�����肷��
+ traceLastTime2 = 0;
+ traceLastThread2 = null;
+ boolean continueTraverse = false;
+ Iterator threadsIterator = threadLastPoints.keySet().iterator();
+ for (; threadsIterator.hasNext();) {
+ String threadId = threadsIterator.next();
+ if (!threadId.equals(traceLastThread)) {
+ TracePoint threadLastTp = threadLastPoints.get(threadId);
+ if (threadLastTp != null) {
+ continueTraverse = true;
+ long threadLastTime = threadLastTp.getMethodExecution().getTimeStamp();
+ if (traceLastTime2 < threadLastTime) {
+ traceLastTime2 = threadLastTime;
+ traceLastThread2 = threadId;
+ }
+ }
+ }
+ }
+ if (!continueTraverse && threadLastPoints.get(traceLastThread) == null) break;
+ }
+ return null;
+ }
+
+ private TracePoint getLastMethodEntryInThread(ArrayList rootExecutions) {
+ MethodExecution lastExecution = rootExecutions.remove(rootExecutions.size() - 1);
+ return getLastMethodEntryInThread(rootExecutions, lastExecution.getExitOutPoint());
+ }
+
+ private TracePoint getLastMethodEntryInThread(ArrayList rootExecutions, TracePoint start) {
+ return getLastMethodEntryInThread(rootExecutions, start, -1L);
+ }
+
+ private TracePoint getLastMethodEntryInThread(ArrayList rootExecutions, TracePoint start, final long before) {
+ final TracePoint cp[] = new TracePoint[1];
+ cp[0] = start;
+ for (;;) {
+ if (!cp[0].isStepBackOut() && traverseMethodExecutionsInCallTreeBackward(
+ new IMethodExecutionVisitor() {
+ @Override
+ public boolean preVisitThread(ThreadInstance thread) { return false; }
+ @Override
+ public boolean preVisitMethodExecution(MethodExecution methodExecution) { return false; }
+ @Override
+ public boolean postVisitThread(ThreadInstance thread) { return false; }
+ @Override
+ public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) {
+ if (methodExecution.getTimeStamp() < before || before == -1L) {
+ cp[0] = methodExecution.getEntryPoint();
+ return true;
+ }
+ return false;
+ }
+ }, cp[0])) {
+ return cp[0];
+ }
+ if (rootExecutions.size() == 0) break;
+ MethodExecution lastExecution = rootExecutions.remove(rootExecutions.size() - 1);
+ cp[0] = lastExecution.getExitOutPoint();
+ }
+ return null;
+ }
+
+ /**
+ * before �Ŏw�肵���g���[�X�|�C���g�ȑO�̓���Ăяo���ؓ��̑S���s�����t�����ɒT������(�������Avisitor �� true ��Ԃ��܂�)
+ * @param visitor �r�W�^�[
+ * @param before �T���̊J�n�_(�T���ΏۃX���b�h���w�肵�Ă���)
+ * @return true -- �T���𒆒f����, false -- �Ō�܂ŒT������
+ */
+ public boolean traverseStatementsInCallTreeBackward(IStatementVisitor visitor, TracePoint before) {
+ for (;;) {
+ if (traverseStatamentsInCallTreeBackwardNoReturn(visitor, before)) return true;
+ before.stepBackOver();
+ if (!before.isValid()) break;
+ }
+ return false;
+ }
+
+ private boolean traverseStatamentsInCallTreeBackwardNoReturn(IStatementVisitor visitor, TracePoint before) {
+ for (;;) {
+ Statement statement = before.getStatement();
+ if (statement instanceof MethodInvocation) {
+ // ���\�b�h�Ăяo�����̏ꍇ�́A�Ăяo���̑O��� preVisit �� postVisit ��ʁX�Ɏ��s����
+ if (visitor.preVisitStatement(statement)) return true;
+ before.stepBackNoReturn();
+ if (!before.isValid()) {
+ // �Ăяo����̃��\�b�h�Ŏ��s�����L�^����Ă��Ȃ��ꍇ
+ before.stepBackOver();
+ if (visitor.postVisitStatement(statement)) return true;
+ if (before.isMethodEntry()) return false;
+ before.stepBackOver();
+ }
+ } else {
+ if (visitor.preVisitStatement(statement)) return true;
+ if (visitor.postVisitStatement(statement)) return true;
+ if (before.isMethodEntry()) return false;
+ before.stepBackNoReturn();
+ }
+ }
+ }
+
+ /**
+ * before �Ŏw�肵���g���[�X�|�C���g�ȑO�̓���X���b�h���̑S���\�b�h���s���Ăяo���̒��ŋt�����ɒT������(�������Avisitor �� true ��Ԃ��܂�)
+ * @param visitor �r�W�^�[
+ * @param before �T���̊J�n�_(�T���ΏۃX���b�h���w�肵�Ă���)
+ * @return true -- �T���𒆒f����, false -- �Ō�܂ŒT������
+ */
+ public boolean traverseMethodExecutionsInCallTreeBackward(IMethodExecutionVisitor visitor, TracePoint before) {
+ ArrayList prevMethodExecutions = before.getPreviouslyCalledMethods();
+ for (int i = prevMethodExecutions.size() - 1; i >= 0; i--) {
+ MethodExecution child = prevMethodExecutions.get(i);
+ if (child.traverseMethodExecutionsBackward(visitor)) return true;
+ }
+ MethodExecution methodExecution = before.getMethodExecution();
+ if (visitor.postVisitMethodExecution(methodExecution, null)) return true;
+ TracePoint caller = methodExecution.getCallerTracePoint();
+ if (caller != null) {
+ if (traverseMethodExecutionsInCallTreeBackward(visitor, caller)) return true;
+ }
+ return false;
+ }
+
+ public TracePoint getCreationTracePoint(final ObjectReference newObjectId, TracePoint before) {
+ before = before.duplicate();
+ before = traverseStatementsInTraceBackward(
+ new IStatementVisitor() {
+ @Override
+ public boolean preVisitStatement(Statement statement) {
+ if (statement instanceof MethodInvocation) {
+ MethodInvocation mi = (MethodInvocation)statement;
+ if (mi.getCalledMethodExecution().isConstractor()
+ && mi.getCalledMethodExecution().getReturnValue().equals(newObjectId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ @Override
+ public boolean postVisitStatement(Statement statement) { return false; }
+ }, before);
+ if (before != null) {
+ return before;
+ }
+ return null;
+ }
+
+ public TracePoint getFieldUpdateTracePoint(final Reference ref, TracePoint before) {
+ before = before.duplicate();
+ final String srcType = ref.getSrcClassName();
+ final String dstType = ref.getDstClassName();
+ final String srcObjId = ref.getSrcObjectId();
+ final String dstObjId = ref.getDstObjectId();
+
+ before = traverseStatementsInTraceBackward(new IStatementVisitor() {
+ @Override
+ public boolean preVisitStatement(Statement statement) {
+ if (statement instanceof FieldUpdate) {
+ FieldUpdate fu = (FieldUpdate)statement;
+ if (fu.getContainerObjId().equals(srcObjId)
+ && fu.getValueObjId().equals(dstObjId)) {
+ // �I�u�W�F�N�gID���݂��Ɉ�v�����ꍇ
+ return true;
+ } else if ((srcObjId == null || isNull(srcObjId)) && fu.getContainerClassName().equals(srcType)) {
+ if ((dstObjId == null || isNull(dstObjId)) && fu.getValueClassName().equals(dstType)) {
+ // ref �ɃI�u�W�F�N�gID���w�肵�Ă��Ȃ������ꍇ
+ ref.setSrcObjectId(fu.getContainerObjId());
+ ref.setDstObjectId(fu.getValueObjId());
+ return true;
+ } else if (fu.getValueObjId().equals(dstObjId)) {
+ // �N���X�ϐ��ւ̑���̏ꍇ
+ ref.setSrcObjectId(srcObjId);
+ ref.setDstClassName(dstType);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ @Override
+ public boolean postVisitStatement(Statement statement) { return false; }
+ }, before);
+ if (before != null) {
+ return before;
+ }
+ return null;
+ }
+
+ public TracePoint getCollectionAddTracePoint(final Reference ref, TracePoint before) {
+ final TracePoint[] result = new TracePoint[1];
+ if (traverseMethodEntriesInTraceBackward(new IMethodExecutionVisitor() {
+ @Override
+ public boolean preVisitThread(ThreadInstance thread) {
+ return false;
+ }
+ @Override
+ public boolean postVisitThread(ThreadInstance thread) {
+ return false;
+ }
+ @Override
+ public boolean preVisitMethodExecution(MethodExecution methodExecution) {
+ return false;
+ }
+ @Override
+ public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList children) {
+ String srcType = ref.getSrcClassName();
+ String dstType = ref.getDstClassName();
+ String srcObjId = ref.getSrcObjectId();
+ String dstObjId = ref.getDstObjectId();
+ if (methodExecution.isCollectionType() && isCollectionAdd(methodExecution.getSignature())) {
+ if (dstObjId != null && methodExecution.getThisObjId().equals(srcObjId)) {
+ ArrayList args = methodExecution.getArguments();
+ for (int i = 0; i < args.size(); i++) {
+ ObjectReference arg = args.get(i);
+ if (arg.getId().equals(dstObjId)) {
+ ref.setSrcClassName(methodExecution.getThisClassName());
+ ref.setDstClassName(arg.getActualType());
+ result[0] = methodExecution.getCallerTracePoint();
+ return true;
+ }
+ }
+ } else if (dstObjId == null && methodExecution.getThisClassName().equals(srcType)) {
+ ArrayList args = methodExecution.getArguments();
+ for (int i = 0; i < args.size(); i++) {
+ ObjectReference arg = args.get(i);
+ if (arg.getActualType().equals(dstType)) {
+ ref.setSrcObjectId(methodExecution.getThisObjId());
+ ref.setDstObjectId(arg.getId());
+ result[0] = methodExecution.getCallerTracePoint();
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ }, before) != null) {
+ return result[0];
+ }
+ return null;
+ }
+
+ private boolean isCollectionAdd(String methodSignature) {
+ return (methodSignature.contains("add(") || methodSignature.contains("set(") || methodSignature.contains("put(") || methodSignature.contains("push("));
+ }
+
+ public TracePoint getArraySetTracePoint(final Reference ref, TracePoint before) {
+ final TracePoint start = before.duplicate();
+ before = traverseStatementsInTraceBackward(new IStatementVisitor() {
+ @Override
+ public boolean preVisitStatement(Statement statement) {
+ if (statement instanceof FieldAccess) {
+ if (isArraySet(ref, start)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ @Override
+ public boolean postVisitStatement(Statement statement) { return false; }
+ }, start);
+ if (before != null) {
+ return before;
+ }
+ return null;
+ }
+
+ private boolean isArraySet(Reference ref, TracePoint fieldAccessPoint) {
+ FieldAccess fieldAccess = (FieldAccess)fieldAccessPoint.getStatement();
+ String srcObjId = ref.getSrcObjectId();
+ String dstObjId = ref.getDstObjectId();
+ if (fieldAccess.getValueClassName().startsWith("[L")
+ && fieldAccess.getValueObjId().equals(srcObjId)) {
+ // srcId �͔z��
+ // ���\�b�h���s�J�n���� fieldAccessPoint �܂ł̊Ԃ̃��\�b�h���s���� dstId ���o��������?
+ TracePoint p = fieldAccessPoint.duplicate();
+ while (p.stepBackOver()) {
+ Statement statement = p.getStatement();
+ if (statement instanceof MethodInvocation) {
+ MethodExecution calledMethod = ((MethodInvocation)statement).getCalledMethodExecution();
+ if (calledMethod.getReturnValue().getId().equals(dstObjId)) {
+ // dstId �͖߂�l�Ƃ��ďo��
+ ref.setSrcClassName(fieldAccess.getValueClassName());
+ ref.setDstClassName(calledMethod.getReturnValue().getActualType());
+ return true;
+ } else if (dstObjId == null || isNull(dstObjId) && calledMethod.getReturnValue().getActualType().equals(ref.getDstClassName())) {
+ // dstClassName �͖߂�l�̌^�Ƃ��ďo��
+ ref.setSrcObjectId(fieldAccess.getValueObjId());
+ ref.setDstObjectId(calledMethod.getReturnValue().getId());
+ return true;
+ }
+ }
+ if (EAGER_DETECTION_OF_ARRAY_SET) {
+ if (statement instanceof FieldAccess) {
+ if (((FieldAccess)statement).getContainerObjId().equals(dstObjId)) {
+ // dstId �̓t�B�[���h�ɏo��
+ ref.setSrcClassName(fieldAccess.getValueClassName());
+ ref.setDstClassName(((FieldAccess)statement).getContainerClassName());
+ return true;
+ } else if (dstObjId == null || isNull(dstObjId) && ((FieldAccess)statement).getContainerClassName().equals(ref.getDstClassName())) {
+ // dstClassName �̓t�B�[���h�̌^�Ƃ��ďo��
+ ref.setSrcObjectId(fieldAccess.getValueObjId());
+ ref.setDstObjectId(((FieldAccess)statement).getContainerObjId());
+ return true;
+ }
+ }
+ }
+ }
+ ArrayList args = fieldAccessPoint.getMethodExecution().getArguments();
+ int argindex = args.indexOf(new ObjectReference(dstObjId));
+ if (argindex != -1) {
+ // dstId �͈����ɏo��
+ ref.setSrcClassName(fieldAccess.getValueClassName());
+ ref.setDstClassName(args.get(argindex).getActualType());
+ return true;
+ } else if (dstObjId == null || isNull(dstObjId)) {
+ for (int j = 0; j < args.size(); j++) {
+ if (args.get(j).getActualType().equals(ref.getDstClassName())) {
+ // dstClassName �͈����̌^�ɏo��
+ ref.setSrcObjectId(fieldAccess.getValueObjId());
+ ref.setDstObjectId(args.get(j).getId());
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public static String getDeclaringType(String methodSignature, boolean isContructor) {
+ if (isContructor) {
+ String[] fragments = methodSignature.split("\\(");
+ return fragments[0].substring(fragments[0].lastIndexOf(' ') + 1);
+ }
+ String[] fragments = methodSignature.split("\\(");
+ return fragments[0].substring(fragments[0].lastIndexOf(' ') + 1, fragments[0].lastIndexOf('.'));
+ }
+
+ public static String getMethodName(String methodSignature) {
+ String[] fragments = methodSignature.split("\\(");
+ String[] fragments2 = fragments[0].split("\\.");
+ return fragments2[fragments2.length - 1];
+ }
+
+ public static String getReturnType(String methodSignature) {
+ String[] fragments = methodSignature.split(" ");
+ for (int i = 0; i < fragments.length; i++) {
+ if (!fragments[i].equals("public") && !fragments[i].equals("private") && !fragments[i].equals("protected")
+ && !fragments[i].equals("abstract") && !fragments[i].equals("final") && !fragments[i].equals("static")
+ && !fragments[i].equals("synchronized") && !fragments[i].equals("native")) {
+ return fragments[i];
+ }
+ }
+ return "";
+ }
+
+ public HashMap getThreads() {
+ return threads;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+
+
+ public static boolean isNull(String objectId) {
+ return objectId.equals("0");
+ }
+
+ public static String getNull() {
+ return "0";
+ }
+}
diff --git a/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/TracePoint.java b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/TracePoint.java
new file mode 100644
index 0000000..380b846
--- /dev/null
+++ b/org.ntlab.interactiveFeatureLocator/src/org/ntlab/trace/TracePoint.java
@@ -0,0 +1,175 @@
+package org.ntlab.trace;
+
+import java.util.ArrayList;
+
+public class TracePoint {
+ private MethodExecution methodExecution;
+ private int order = 0;
+
+ public TracePoint(MethodExecution methodExecution, int order) {
+ this.methodExecution = methodExecution;
+ this.order = order;
+ }
+
+ public TracePoint duplicate() {
+ return new TracePoint(methodExecution, order);
+ }
+
+ public Statement getStatement() {
+ return methodExecution.getStatements().get(order);
+ }
+
+ public MethodExecution getMethodExecution() {
+ return methodExecution;
+ }
+
+ public ArrayList getPreviouslyCalledMethods() {
+ ArrayList children = new ArrayList();
+ ArrayList statements = methodExecution.getStatements();
+ for (int i = 0; i < order; i++) {
+ Statement statement = statements.get(i);
+ if (statement instanceof MethodInvocation) {
+ MethodExecution child = ((MethodInvocation)statement).getCalledMethodExecution();
+ children.add(child);
+ }
+ }
+ return children;
+ }
+
+ /**
+ * �������̑S�T��(�������A���s�����L�^����Ă��Ȃ����\�b�h���s�ɂ͐���Ȃ�)
+ * @return false: ����ȏ�H��Ȃ��ꍇ, true: ����ȊO
+ */
+ public boolean stepFull() {
+ if (getStatement() instanceof MethodInvocation) {
+ MethodExecution calledMethodExecution = ((MethodInvocation)getStatement()).getCalledMethodExecution();
+ if (calledMethodExecution.getStatements().size() > 0) {
+ methodExecution = calledMethodExecution;
+ order = 0;
+ return true;
+ }
+ }
+ while (order >= methodExecution.getStatements().size() - 1) {
+ order = methodExecution.getCallerStatementExecution();
+ methodExecution = methodExecution.getCallerMethodExecution();
+ if (methodExecution == null) {
+ order = -1;
+ return false;
+ }
+ }
+ order++;
+ return true;
+ }
+
+ /**
+ * �t�����̑S�T��(�������A���s�����L�^����Ă��Ȃ����\�b�h���s�ɂ͐���Ȃ��B�܂��A�Ăяo����̃��\�b�h���s����T��������ɁA�Ăяo�����̃��\�b�h�Ăяo������K�₷��̂Œ���!!)
+ * @return false: ����ȏ�H��Ȃ��ꍇ, true: ����ȊO
+ */
+ public boolean stepBackFull() {
+ if (order <= 0) {
+ order = methodExecution.getCallerStatementExecution();
+ methodExecution = methodExecution.getCallerMethodExecution();
+ if (methodExecution == null) {
+ order = -1;
+ return false;
+ }
+ return true;
+ }
+ order--;
+ while (getStatement() instanceof MethodInvocation) {
+ MethodExecution calledMethodExecution = ((MethodInvocation)getStatement()).getCalledMethodExecution();
+ if (calledMethodExecution.getStatements().size() == 0) break;
+ methodExecution = calledMethodExecution;
+ order = methodExecution.getStatements().size() - 1;
+ }
+ return true;
+ }
+
+ /**
+ * �������ɒT������B�Ăяo�����ɖ߂邪�Ăяo����ɂ͐���Ȃ��B
+ * @return false: �Ăяo�����ɖ߂����ꍇ�܂��͂���ȏ�H��Ȃ��ꍇ, true: ����ȊO
+ */
+ public boolean stepOver() {
+ if (order < methodExecution.getStatements().size() - 1) {
+ order++;
+ return true;
+ }
+ order = methodExecution.getCallerStatementExecution();
+ methodExecution = methodExecution.getCallerMethodExecution();
+ if (methodExecution == null) {
+ order = -1;
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ * �t�����ɒT������B�Ăяo�����ɖ߂邪�Ăяo����ɂ͐���Ȃ��B
+ * @return false: �Ăяo�����ɖ߂����ꍇ�܂��͂���ȏ�H��Ȃ��ꍇ, true: ����ȊO
+ */
+ public boolean stepBackOver() {
+ if (order > 0) {
+ order--;
+ return true;
+ }
+ order = methodExecution.getCallerStatementExecution();
+ methodExecution = methodExecution.getCallerMethodExecution();
+ if (methodExecution == null) {
+ order = -1;
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ * �������ɒT������B�Ăяo�����H�邪�Ăяo�����ɂ͖߂�Ȃ��B
+ * @return false: �Ăяo����Ɉڂ����ꍇ�܂��͂���ȏ�H��Ȃ��ꍇ, true: ����ȊO
+ */
+ public boolean stepNoReturn() {
+ if (getStatement() instanceof MethodInvocation) {
+ methodExecution = ((MethodInvocation)getStatement()).getCalledMethodExecution();
+ if (methodExecution.getStatements().size() > 0) {
+ order = 0;
+ } else {
+ order = -1; // �Ăяo����Ŏ��s�����L�^����Ă��Ȃ��ꍇ
+ }
+ return false;
+ }
+ order++;
+ if (order < methodExecution.getStatements().size()) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * �t�����ɒT������B�Ăяo�����H�邪�Ăяo�����ɂ͖߂�Ȃ��B(��ɌĂяo�����̃��\�b�h�Ăяo������K�₵�Ă���Ăяo����̃��\�b�h���s��K�₷��̂Œ���!!)
+ * @return�@false: �Ăяo����Ɉڂ����ꍇ�܂��͂���ȏ�H��Ȃ��ꍇ, true: ����ȊO
+ */
+ public boolean stepBackNoReturn() {
+ if (getStatement() instanceof MethodInvocation) {
+ methodExecution = ((MethodInvocation)getStatement()).getCalledMethodExecution();
+ order = methodExecution.getStatements().size() - 1; // -1 �ɂȂ�ꍇ������(�Ăяo����Ŏ��s�����L�^����Ă��Ȃ��ꍇ)
+ return false;
+ }
+ order--;
+ if (order >= 0) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isValid() {
+ if (methodExecution == null || order == -1 || order >= methodExecution.getStatements().size()) return false;
+ return true;
+ }
+
+ public boolean isMethodEntry() {
+ return (order == 0);
+ }
+
+ public boolean isStepBackOut() {
+ if (order < 0) return true;
+ return false;
+ }
+}