diff --git a/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/JavaEditorOperator.java b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/JavaEditorOperator.java new file mode 100644 index 0000000..bdf1355 --- /dev/null +++ b/org.ntlab.reverseDebugger/src/org/ntlab/reversedebugger/JavaEditorOperator.java @@ -0,0 +1,216 @@ +package org.ntlab.reversedebugger; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IMethod; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.ui.JavaUI; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.PartInitException; +import org.ntlab.debuggingControl.MethodCaller; + +import com.sun.jdi.ClassNotLoadedException; +import com.sun.jdi.IncompatibleThreadStateException; +import com.sun.jdi.InvalidTypeException; +import com.sun.jdi.InvocationException; +import com.sun.jdi.ObjectReference; +import com.sun.jdi.StringReference; +import com.sun.jdi.ThreadReference; +import com.sun.jdi.Value; +import com.sun.jdi.VirtualMachine; + +public class JavaEditorOperator { + private static final String TRACE = "org.ntlab.traceCollector.tracer.trace"; + + public void openSrcFile(MethodCaller alias) { + System.out.println("JavaEditorOpenSrcFile(MethodCaller)���Ă΂ꂽ��!"); + try { + ObjectReference methodExecution = (ObjectReference)alias.callInstanceMethod("getMethodExecution"); + MethodCaller meCaller = new MethodCaller(alias.getVm(), alias.getThread(), methodExecution); + openSrcFileOfMethodExecution(meCaller); + } catch (InvalidTypeException | ClassNotLoadedException + | InvocationException | IncompatibleThreadStateException e) { + e.printStackTrace(); + } + } + + /** + * �����œn����meCaller���ɂ���methodExecution����`����Ă���N���X�̃\�[�X�R�[�h��Ώ�Eclipse�̃G�f�B�^�ŊJ������ + * + * @param meCaller + */ + private void openSrcFileOfMethodExecution(MethodCaller meCaller) + throws InvalidTypeException, ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + IType type = findIType(meCaller); + if (type != null) { + IMethod method = findIMethod(meCaller, type); + if (method != null) { + openSrcFileOfIMethod(type, method); + } + } + } + + /** + * �����œn����IType��IMethod�ɑΉ�����\�[�X�R�[�h��Ώ�Eclipse�̃G�f�B�^�ŊJ������ + * + * @param type + * @param method + */ + private void openSrcFileOfIMethod(IType type, IMethod method) throws InvalidTypeException, ClassNotLoadedException, + InvocationException, IncompatibleThreadStateException { + openInJavaEditor(type, method); + } + + private IType findIType(MethodCaller meCaller) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + StringReference declaringClassName = (StringReference)meCaller.callInstanceMethod("getDeclaringClassName"); + String projectPath = getLoaderPath(meCaller, declaringClassName); + IType type = null; + if (projectPath != null) { + IJavaProject javaProject = findJavaProject(projectPath); + if (javaProject != null) { + StringReference methodSignature = (StringReference)meCaller.callInstanceMethod("getSignature"); + try { + type = javaProject.findType(declaringClassName.value()); + } catch (JavaModelException e) { + e.printStackTrace(); + } + } + } + return type; + } + + private String getLoaderPath(MethodCaller meCaller, StringReference declaringClassName) + throws InvalidTypeException, ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + ObjectReference classInfo = (ObjectReference)meCaller.callStaticMethod(TRACE, "TraceJSON", "getClassInfo", declaringClassName); + if (classInfo == null) { + declaringClassName = (StringReference)meCaller.callInstanceMethod("getThisClassName"); + classInfo = (ObjectReference)meCaller.callStaticMethod(TRACE, "TraceJSON", "getClassInfo", declaringClassName); + } + String loaderPath = null; + if (classInfo != null) { + // �Ȃ���loaderPath���擾�ł��Ă��Ȃ����߁A���ۂɏo�͂����JSON�g���[�X���Q�l�ɂ���path����^���Ă݂� + MethodCaller classInfoMethodCaller = new MethodCaller(meCaller.getVm(), meCaller.getThread(), classInfo); + String path = ((StringReference)classInfoMethodCaller.callInstanceMethod("getPath")).value(); + String declaringClassNameString = declaringClassName.value().replace(".", "/"); + loaderPath = path.substring(0, path.indexOf(declaringClassNameString)); // path����N���X�̊��S���薼�ȍ~��S�ĊO�������̂�projectPath�ɂ��Ă݂� + } + return loaderPath; + } + + private IJavaProject findJavaProject(String projectPath) { + IJavaProject javaProject = null; + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + IProject[] projects = root.getProjects(); + for (IProject project : projects) { + if (checkProjectPath(project, projectPath)) { + javaProject = JavaCore.create(project); + break; + } + } + return javaProject; + } + + private boolean checkProjectPath(IProject project, String projectPath) { + String projectLocation = project.getLocation().toString(); + if (projectPath.startsWith(projectLocation)) { + String[] projectPathSplit = projectPath.split(projectLocation); + return (projectPathSplit[1].charAt(0) == '/'); // �v���W�F�N�g���̑O����v�ɂ�鑼�v���W�F�N�g�Ƃ̌딻�������� + } + return false; + } + + private void openInJavaEditor(IType type, IMethod method) { + try { + if (type != null && method != null) { + IEditorPart editor = JavaUI.openInEditor(type); + if (!type.isLocal() && !type.isMember()) { + JavaUI.revealInEditor(editor, (IJavaElement) method); + } + } + } catch (PartInitException | JavaModelException e) { + e.printStackTrace(); + } + } + + private IMethod findIMethod(MethodCaller meCaller, IType type) throws InvalidTypeException, + ClassNotLoadedException, InvocationException, IncompatibleThreadStateException { + IMethod method = null; + if (type != null) { + StringReference methodSignature = (StringReference)meCaller.callInstanceMethod("getSignature"); + method = findIMethod(type, methodSignature.value()); + } + return method; + } + + private IMethod findIMethod(IType type, String methodSignature) { + try { + for (IMethod method : type.getMethods()) { + if (checkMethodSignature(type, method, methodSignature)) { + return method; + } + } + } catch (JavaModelException e) { + e.printStackTrace(); + } + return null; + } + + private boolean checkMethodSignature(IType type, IMethod method, String methodSignature) { + String fqcn = type.getFullyQualifiedName(); + try { + StringBuilder jdtMethodSignature = new StringBuilder(); + jdtMethodSignature.append((method.isConstructor()) ? (fqcn + "(") : (fqcn + "." + method.getElementName() + "(")); + if (methodSignature.contains(jdtMethodSignature)) { + // ������v���Ă����ꍇ�Ɍ���A�������X�g����������ł���v���邩�ǂ����𔻒� (�I�[�o�[���[�h�ɂ��딻��������) + jdtMethodSignature.append(String.join(",", parseFQCNParameters(type, method)) + ")"); // �S�����̃V�O�l�`�������S����N���X���ɕϊ�����,�ŋ�؂��������� + return methodSignature.contains(jdtMethodSignature); + } + } catch (JavaModelException e) { + e.printStackTrace(); + } + return false; + } + + /** + * IMethod����擾�ł���S�����̃V�O�l�`�������S����N���X���ɒu�������Ċi�[�������X�g��Ԃ� + * + * @param type + * @param method + * @return + */ + private List parseFQCNParameters(IType type, IMethod method) throws JavaModelException { + List parameters = new ArrayList<>(); + for (String parameterType : method.getParameterTypes()) { + String readableType = Signature.toString(parameterType); // �V�O�l�`���̕�������^���̕�����ɕϊ� (�z��͌���[]���‚�) + String[] readableTypeSplit = { "", "" }; // �^����[]�̕����p + int firstBracketIndex = readableType.indexOf("[]"); + final int NO_BRACKET_INDEX = -1; + if (firstBracketIndex == NO_BRACKET_INDEX) { + readableTypeSplit[0] = readableType; // �^�� + } else { + readableTypeSplit[0] = readableType.substring(0, firstBracketIndex); // �^�� + readableTypeSplit[1] = readableType.substring(firstBracketIndex); // �^���̌���[]�S�� + } + String[][] resolveType = type.resolveType(readableTypeSplit[0]); // �p�b�P�[�W���ƃN���X���̑g�ݍ��킹���擾 + if (resolveType != null) { + if (resolveType[0][0].isEmpty()) { + readableTypeSplit[0] = (resolveType[0][1]); // �f�t�H���g�p�b�P�[�W�̏ꍇ�̓p�b�P�[�W����.�͓���Ȃ� + } else { + readableTypeSplit[0] = (resolveType[0][0] + "." + resolveType[0][1]); // ���S����N���X�� + } + } + parameters.add(readableTypeSplit[0] + readableTypeSplit[1]); + } + return parameters; + } +}