Copyright (c) 2011-2016 Igor Fedorenko This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: Igor Fedorenko - initial API and implementation
/******************************************************************************* * Copyright (c) 2011-2016 Igor Fedorenko * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Igor Fedorenko - initial API and implementation *******************************************************************************/
package org.eclipse.jdt.internal.launching.sourcelookup.advanced; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; import java.util.Iterator; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.jdt.debug.core.IJavaObject; import org.eclipse.jdt.debug.core.IJavaReferenceType; import org.eclipse.jdt.debug.core.IJavaStackFrame; import org.eclipse.jdt.debug.core.IJavaType; import org.eclipse.jdt.debug.core.IJavaValue; import org.eclipse.jdt.debug.core.IJavaVariable; public final class JDIHelpers implements IJDIHelpers { // must match ClassfileTransformer.STRATA_ID public static final String STRATA_ID = "jdt"; //$NON-NLS-1$ JDIHelpers() { } // jdt debug boilerplate and other ideas were originally "borrowed" from // org.eclipse.pde.internal.launching.sourcelookup.PDESourceLookupQuery.run() @Override public File getClassesLocation(Object element) throws DebugException { IJavaReferenceType declaringType = null; if (element instanceof IJavaStackFrame) { IJavaStackFrame stackFrame = (IJavaStackFrame) element; declaringType = stackFrame.getReferenceType(); } else if (element instanceof IJavaObject) { IJavaType javaType = ((IJavaObject) element).getJavaType(); if (javaType instanceof IJavaReferenceType) { declaringType = (IJavaReferenceType) javaType; } } else if (element instanceof IJavaReferenceType) { declaringType = (IJavaReferenceType) element; } else if (element instanceof IJavaVariable) { IJavaVariable javaVariable = (IJavaVariable) element; IJavaType javaType = ((IJavaValue) javaVariable.getValue()).getJavaType(); if (javaType instanceof IJavaReferenceType) { declaringType = (IJavaReferenceType) javaType; } } if (declaringType != null) { String[] locations = declaringType.getSourceNames(STRATA_ID); if (locations == null || locations.length < 2) { return null; } try { URL url = new URL(locations[1]); if ("file".equals(url.getProtocol())) { //$NON-NLS-1$ return new File(url.getPath()).toPath().normalize().toFile(); } } catch (MalformedURLException e) { // fall through } } return null; } @Override public String getSourcePath(Object element) throws DebugException { IJavaReferenceType declaringType = null; if (element instanceof IJavaStackFrame) { IJavaStackFrame stackFrame = (IJavaStackFrame) element; // under JSR 45 source path from the stack frame is more precise than anything derived from the type String sourcePath = stackFrame.getSourcePath(STRATA_ID); if (sourcePath != null) { return sourcePath; } declaringType = stackFrame.getReferenceType(); } else if (element instanceof IJavaObject) { IJavaType javaType = ((IJavaObject) element).getJavaType(); if (javaType instanceof IJavaReferenceType) { declaringType = (IJavaReferenceType) javaType; } } else if (element instanceof IJavaReferenceType) { declaringType = (IJavaReferenceType) element; } else if (element instanceof IJavaVariable) { IJavaType javaType = ((IJavaVariable) element).getJavaType(); if (javaType instanceof IJavaReferenceType) { declaringType = (IJavaReferenceType) javaType; } } if (declaringType != null) { String[] sourcePaths = declaringType.getSourcePaths(STRATA_ID); if (sourcePaths != null && sourcePaths.length > 0 && sourcePaths[0] != null) { return sourcePaths[0]; } return generateSourceName(declaringType.getName()); } return null; } private static final IStackFrame[] EMPTY_STACK = new IStackFrame[0]; private IStackFrame[] getStackFrames(Object element) throws DebugException { if (element instanceof IStackFrame) { IStackFrame[] frames = ((IStackFrame) element).getThread().getStackFrames(); for (int i = 0; i < frames.length - 1; i++) { if (frames[i] == element) { return Arrays.copyOfRange(frames, i + 1, frames.length); } } } return EMPTY_STACK; } @Override public Iterable<File> getStackFramesClassesLocations(Object element) throws DebugException { IStackFrame[] stack = getStackFrames(element); return new Iterable<File>() { @Override public Iterator<File> iterator() { return Arrays.stream(stack) // .map(frame -> getClassesLocation(frame)) // .filter(frameLocation -> frameLocation != null) // .iterator(); } File getClassesLocation(IStackFrame frame) { // TODO consider ignoring DebugException for all IJDIHeloper methods try { return JDIHelpers.this.getClassesLocation(frame); } catch (DebugException e) { return null; } } }; } // copy&paste from org.eclipse.pde.internal.launching.sourcelookup.PDESourceLookupQuery.generateSourceName(String) private static String generateSourceName(String qualifiedTypeName) { int index = qualifiedTypeName.indexOf('$'); if (index >= 0) { qualifiedTypeName = qualifiedTypeName.substring(0, index); } return qualifiedTypeName.replace('.', File.separatorChar) + ".java"; //$NON-NLS-1$ } }